Merge "Update apex/allowed_deps.txt"
diff --git a/android/Android.bp b/android/Android.bp
index 69aa037..efa70a9 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -59,6 +59,7 @@
         "sandbox.go",
         "sdk.go",
         "singleton.go",
+        "singleton_module.go",
         "soong_config_modules.go",
         "test_suites.go",
         "testing.go",
@@ -95,6 +96,7 @@
         "paths_test.go",
         "prebuilt_test.go",
         "rule_builder_test.go",
+        "singleton_module_test.go",
         "soong_config_modules_test.go",
         "util_test.go",
         "variable_test.go",
diff --git a/android/config.go b/android/config.go
index ddb2de3..a7e0b67 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1256,6 +1256,27 @@
 	return HasAnyPrefix(path, c.productVariables.CFIIncludePaths)
 }
 
+func (c *config) MemtagHeapDisabledForPath(path string) bool {
+	if len(c.productVariables.MemtagHeapExcludePaths) == 0 {
+		return false
+	}
+	return HasAnyPrefix(path, c.productVariables.MemtagHeapExcludePaths)
+}
+
+func (c *config) MemtagHeapAsyncEnabledForPath(path string) bool {
+	if len(c.productVariables.MemtagHeapAsyncIncludePaths) == 0 {
+		return false
+	}
+	return HasAnyPrefix(path, c.productVariables.MemtagHeapAsyncIncludePaths)
+}
+
+func (c *config) MemtagHeapSyncEnabledForPath(path string) bool {
+	if len(c.productVariables.MemtagHeapSyncIncludePaths) == 0 {
+		return false
+	}
+	return HasAnyPrefix(path, c.productVariables.MemtagHeapSyncIncludePaths)
+}
+
 func (c *config) VendorConfig(name string) VendorConfig {
 	return soongconfig.Config(c.productVariables.VendorVars[name])
 }
diff --git a/android/makevars.go b/android/makevars.go
index 546abcf..40c0ccd 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -134,8 +134,6 @@
 
 // SingletonMakeVarsProvider is a Singleton with an extra method to provide extra values to be exported to Make.
 type SingletonMakeVarsProvider interface {
-	Singleton
-
 	// MakeVars uses a MakeVarsContext to provide extra values to be exported to Make.
 	MakeVars(ctx MakeVarsContext)
 }
diff --git a/android/module.go b/android/module.go
index b0ad89b..17035bb 100644
--- a/android/module.go
+++ b/android/module.go
@@ -454,6 +454,7 @@
 	InstallForceOS() (*OsType, *ArchType)
 	HideFromMake()
 	IsHideFromMake() bool
+	IsSkipInstall() bool
 	MakeUninstallable()
 	ReplacedByPrebuilt()
 	IsReplacedByPrebuilt() bool
@@ -1398,6 +1399,12 @@
 	m.commonProperties.SkipInstall = true
 }
 
+// IsSkipInstall returns true if this variant is marked to not create install
+// rules when ctx.Install* are called.
+func (m *ModuleBase) IsSkipInstall() bool {
+	return m.commonProperties.SkipInstall
+}
+
 // Similar to HideFromMake, but if the AndroidMk entry would set
 // LOCAL_UNINSTALLABLE_MODULE then this variant may still output that entry
 // rather than leaving it out altogether. That happens in cases where it would
diff --git a/android/paths.go b/android/paths.go
index 10d8d0d..592b9e1 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1742,6 +1742,19 @@
 	return ioutil.WriteFile(absolutePath(path.String()), data, perm)
 }
 
+func RemoveAllOutputDir(path WritablePath) error {
+	return os.RemoveAll(absolutePath(path.String()))
+}
+
+func CreateOutputDirIfNonexistent(path WritablePath, perm os.FileMode) error {
+	dir := absolutePath(path.String())
+	if _, err := os.Stat(dir); os.IsNotExist(err) {
+		return os.MkdirAll(dir, os.ModePerm)
+	} else {
+		return err
+	}
+}
+
 func absolutePath(path string) string {
 	if filepath.IsAbs(path) {
 		return path
diff --git a/android/queryview.go b/android/queryview.go
index 1b7e77d..9e3e45a 100644
--- a/android/queryview.go
+++ b/android/queryview.go
@@ -26,7 +26,6 @@
 // for calling the soong_build primary builder in the main build.ninja file.
 func init() {
 	RegisterSingletonType("bazel_queryview", BazelQueryViewSingleton)
-	RegisterSingletonType("bazel_converter", BazelConverterSingleton)
 }
 
 // BazelQueryViewSingleton is the singleton responsible for registering the
@@ -52,13 +51,7 @@
 
 func generateBuildActionsForBazelConversion(ctx SingletonContext, converterMode bool) {
 	name := "queryview"
-	additionalEnvVars := ""
 	descriptionTemplate := "[EXPERIMENTAL, PRE-PRODUCTION] Creating the Bazel QueryView workspace with %s at $outDir"
-	if converterMode {
-		name = "bp2build"
-		additionalEnvVars = "CONVERT_TO_BAZEL=true"
-		descriptionTemplate = "[EXPERIMENTAL, PRE-PRODUCTION] Converting all Android.bp to Bazel BUILD files with %s at $outDir"
-	}
 
 	// Create a build and rule statement, using the Bazel QueryView's WORKSPACE
 	// file as the output file marker.
@@ -74,9 +67,8 @@
 		blueprint.RuleParams{
 			Command: fmt.Sprintf(
 				"rm -rf ${outDir}/* && "+
-					"%s %s --bazel_queryview_dir ${outDir} %s && "+
+					"%s --bazel_queryview_dir ${outDir} %s && "+
 					"echo WORKSPACE: `cat %s` > ${outDir}/.queryview-depfile.d",
-				additionalEnvVars,
 				primaryBuilder.String(),
 				strings.Join(os.Args[1:], " "),
 				moduleListFilePath.String(), // Use the contents of Android.bp.list as the depfile.
diff --git a/android/register.go b/android/register.go
index b26f9b9..ca658f5 100644
--- a/android/register.go
+++ b/android/register.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"reflect"
 
 	"github.com/google/blueprint"
 )
@@ -26,6 +27,7 @@
 }
 
 var moduleTypes []moduleType
+var moduleTypesForDocs = map[string]reflect.Value{}
 
 type singleton struct {
 	name    string
@@ -35,6 +37,9 @@
 var singletons []singleton
 var preSingletons []singleton
 
+var bazelConverterSingletons []singleton
+var bazelConverterPreSingletons []singleton
+
 type mutator struct {
 	name            string
 	bottomUpMutator blueprint.BottomUpMutator
@@ -69,6 +74,16 @@
 
 func RegisterModuleType(name string, factory ModuleFactory) {
 	moduleTypes = append(moduleTypes, moduleType{name, factory})
+	RegisterModuleTypeForDocs(name, reflect.ValueOf(factory))
+}
+
+// RegisterModuleTypeForDocs associates a module type name with a reflect.Value of the factory
+// function that has documentation for the module type.  It is normally called automatically
+// by RegisterModuleType, but can be called manually after RegisterModuleType in order to
+// override the factory method used for documentation, for example if the method passed to
+// RegisterModuleType was a lambda.
+func RegisterModuleTypeForDocs(name string, factory reflect.Value) {
+	moduleTypesForDocs[name] = factory
 }
 
 func RegisterSingletonType(name string, factory SingletonFactory) {
@@ -79,6 +94,14 @@
 	preSingletons = append(preSingletons, singleton{name, factory})
 }
 
+func RegisterBazelConverterSingletonType(name string, factory SingletonFactory) {
+	bazelConverterSingletons = append(bazelConverterSingletons, singleton{name, factory})
+}
+
+func RegisterBazelConverterPreSingletonType(name string, factory SingletonFactory) {
+	bazelConverterPreSingletons = append(bazelConverterPreSingletons, singleton{name, factory})
+}
+
 type Context struct {
 	*blueprint.Context
 	config Config
@@ -94,13 +117,17 @@
 // singletons, module types and mutators to register for converting Blueprint
 // files to semantically equivalent BUILD files.
 func (ctx *Context) RegisterForBazelConversion() {
+	for _, t := range bazelConverterPreSingletons {
+		ctx.RegisterPreSingletonType(t.name, SingletonFactoryAdaptor(ctx, t.factory))
+	}
+
 	for _, t := range moduleTypes {
 		ctx.RegisterModuleType(t.name, ModuleFactoryAdaptor(t.factory))
 	}
 
-	bazelConverterSingleton := singleton{"bp2build", BazelConverterSingleton}
-	ctx.RegisterSingletonType(bazelConverterSingleton.name,
-		SingletonFactoryAdaptor(ctx, bazelConverterSingleton.factory))
+	for _, t := range bazelConverterSingletons {
+		ctx.RegisterSingletonType(t.name, SingletonFactoryAdaptor(ctx, t.factory))
+	}
 
 	registerMutatorsForBazelConversion(ctx.Context)
 }
@@ -142,12 +169,17 @@
 	return ret
 }
 
+func ModuleTypeFactoriesForDocs() map[string]reflect.Value {
+	return moduleTypesForDocs
+}
+
 // Interface for registering build components.
 //
 // Provided to allow registration of build components to be shared between the runtime
 // and test environments.
 type RegistrationContext interface {
 	RegisterModuleType(name string, factory ModuleFactory)
+	RegisterSingletonModuleType(name string, factory SingletonModuleFactory)
 	RegisterSingletonType(name string, factory SingletonFactory)
 	PreArchMutators(f RegisterMutatorFunc)
 
@@ -186,8 +218,9 @@
 var _ RegistrationContext = (*TestContext)(nil)
 
 type initRegistrationContext struct {
-	moduleTypes    map[string]ModuleFactory
-	singletonTypes map[string]SingletonFactory
+	moduleTypes        map[string]ModuleFactory
+	singletonTypes     map[string]SingletonFactory
+	moduleTypesForDocs map[string]reflect.Value
 }
 
 func (ctx *initRegistrationContext) RegisterModuleType(name string, factory ModuleFactory) {
@@ -196,6 +229,17 @@
 	}
 	ctx.moduleTypes[name] = factory
 	RegisterModuleType(name, factory)
+	RegisterModuleTypeForDocs(name, reflect.ValueOf(factory))
+}
+
+func (ctx *initRegistrationContext) RegisterSingletonModuleType(name string, factory SingletonModuleFactory) {
+	s, m := SingletonModuleFactoryAdaptor(name, factory)
+	ctx.RegisterSingletonType(name, s)
+	ctx.RegisterModuleType(name, m)
+	// Overwrite moduleTypesForDocs with the original factory instead of the lambda returned by
+	// SingletonModuleFactoryAdaptor so that docs can find the module type documentation on the
+	// factory method.
+	RegisterModuleTypeForDocs(name, reflect.ValueOf(factory))
 }
 
 func (ctx *initRegistrationContext) RegisterSingletonType(name string, factory SingletonFactory) {
diff --git a/android/singleton_module.go b/android/singleton_module.go
new file mode 100644
index 0000000..2351738
--- /dev/null
+++ b/android/singleton_module.go
@@ -0,0 +1,146 @@
+// 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.
+
+package android
+
+import (
+	"fmt"
+	"sync"
+
+	"github.com/google/blueprint"
+)
+
+// A SingletonModule is halfway between a Singleton and a Module.  It has access to visiting
+// other modules via its GenerateSingletonBuildActions method, but must be defined in an Android.bp
+// file and can also be depended on like a module.  It must be used zero or one times in an
+// Android.bp file, and it can only have a single variant.
+//
+// The SingletonModule's GenerateAndroidBuildActions method will be called before any normal or
+// singleton module that depends on it, but its GenerateSingletonBuildActions method will be called
+// after all modules, in registration order with other singletons and singleton modules.
+// GenerateAndroidBuildActions and GenerateSingletonBuildActions will not be called if the
+// SingletonModule was not instantiated in an Android.bp file.
+//
+// Since the SingletonModule rules likely depend on the modules visited during
+// GenerateSingletonBuildActions, the GenerateAndroidBuildActions is unlikely to produce any
+// rules directly.  Instead, it will probably set some providers to paths that will later have rules
+// generated to produce them in GenerateSingletonBuildActions.
+//
+// The expected use case for a SingletonModule is a module that produces files that depend on all
+// modules in the tree and will be used by other modules.  For example it could produce a text
+// file that lists all modules that meet a certain criteria, and that text file could be an input
+// to another module.  Care must be taken that the ninja rules produced by the SingletonModule
+// don't produce a cycle by referencing output files of rules of modules that depend on the
+// SingletonModule.
+//
+// A SingletonModule must embed a SingletonModuleBase struct, and its factory method must be
+// registered with RegisterSingletonModuleType from an init() function.
+//
+// A SingletonModule can also implement SingletonMakeVarsProvider to export values to Make.
+type SingletonModule interface {
+	Module
+	GenerateSingletonBuildActions(SingletonContext)
+	singletonModuleBase() *SingletonModuleBase
+}
+
+// SingletonModuleBase must be embedded into implementers of the SingletonModule interface.
+type SingletonModuleBase struct {
+	ModuleBase
+
+	lock    sync.Mutex
+	bp      string
+	variant string
+}
+
+// GenerateBuildActions wraps the ModuleBase GenerateBuildActions method, verifying it was only
+// called once to prevent multiple variants of a SingletonModule.
+func (smb *SingletonModuleBase) GenerateBuildActions(ctx blueprint.ModuleContext) {
+	smb.lock.Lock()
+	if smb.variant != "" {
+		ctx.ModuleErrorf("GenerateAndroidBuildActions already called for variant %q, SingletonModules can only  have one variant", smb.variant)
+	}
+	smb.variant = ctx.ModuleSubDir()
+	smb.lock.Unlock()
+
+	smb.ModuleBase.GenerateBuildActions(ctx)
+}
+
+// InitAndroidSingletonModule must be called from the SingletonModule's factory function to
+// initialize SingletonModuleBase.
+func InitAndroidSingletonModule(sm SingletonModule) {
+	InitAndroidModule(sm)
+}
+
+// singletonModuleBase retrieves the embedded SingletonModuleBase from a SingletonModule.
+func (smb *SingletonModuleBase) singletonModuleBase() *SingletonModuleBase { return smb }
+
+// SingletonModuleFactory is a factory method that returns a SingletonModule.
+type SingletonModuleFactory func() SingletonModule
+
+// SingletonModuleFactoryAdaptor converts a SingletonModuleFactory into a SingletonFactory and a
+// ModuleFactory.
+func SingletonModuleFactoryAdaptor(name string, factory SingletonModuleFactory) (SingletonFactory, ModuleFactory) {
+	// The sm variable acts as a static holder of the only SingletonModule instance.  Calls to the
+	// returned SingletonFactory and ModuleFactory lambdas will always return the same sm value.
+	// The SingletonFactory is only expected to be called once, but the ModuleFactory may be
+	// called multiple times if the module is replaced with a clone of itself at the end of
+	// blueprint.ResolveDependencies.
+	var sm SingletonModule
+	s := func() Singleton {
+		sm = factory()
+		return &singletonModuleSingletonAdaptor{sm}
+	}
+	m := func() Module {
+		if sm == nil {
+			panic(fmt.Errorf("Singleton %q for SingletonModule was not instantiated", name))
+		}
+
+		// Check for multiple uses of a SingletonModule in a LoadHook.  Checking directly in the
+		// factory would incorrectly flag when the factory was called again when the module is
+		// replaced with a clone of itself at the end of blueprint.ResolveDependencies.
+		AddLoadHook(sm, func(ctx LoadHookContext) {
+			smb := sm.singletonModuleBase()
+			smb.lock.Lock()
+			defer smb.lock.Unlock()
+			if smb.bp != "" {
+				ctx.ModuleErrorf("Duplicate SingletonModule %q, previously used in %s", name, smb.bp)
+			}
+			smb.bp = ctx.BlueprintsFile()
+		})
+		return sm
+	}
+	return s, m
+}
+
+// singletonModuleSingletonAdaptor makes a SingletonModule into a Singleton by translating the
+// GenerateSingletonBuildActions method to Singleton.GenerateBuildActions.
+type singletonModuleSingletonAdaptor struct {
+	sm SingletonModule
+}
+
+// GenerateBuildActions calls the SingletonModule's GenerateSingletonBuildActions method, but only
+// if the module was defined in an Android.bp file.
+func (smsa *singletonModuleSingletonAdaptor) GenerateBuildActions(ctx SingletonContext) {
+	if smsa.sm.singletonModuleBase().bp != "" {
+		smsa.sm.GenerateSingletonBuildActions(ctx)
+	}
+}
+
+func (smsa *singletonModuleSingletonAdaptor) MakeVars(ctx MakeVarsContext) {
+	if smsa.sm.singletonModuleBase().bp != "" {
+		if makeVars, ok := smsa.sm.(SingletonMakeVarsProvider); ok {
+			makeVars.MakeVars(ctx)
+		}
+	}
+}
diff --git a/android/singleton_module_test.go b/android/singleton_module_test.go
new file mode 100644
index 0000000..9232eb4
--- /dev/null
+++ b/android/singleton_module_test.go
@@ -0,0 +1,149 @@
+// 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 android
+
+import (
+	"reflect"
+	"strings"
+	"testing"
+)
+
+type testSingletonModule struct {
+	SingletonModuleBase
+	ops []string
+}
+
+func (tsm *testSingletonModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+	tsm.ops = append(tsm.ops, "GenerateAndroidBuildActions")
+}
+
+func (tsm *testSingletonModule) GenerateSingletonBuildActions(ctx SingletonContext) {
+	tsm.ops = append(tsm.ops, "GenerateSingletonBuildActions")
+}
+
+func (tsm *testSingletonModule) MakeVars(ctx MakeVarsContext) {
+	tsm.ops = append(tsm.ops, "MakeVars")
+}
+
+func testSingletonModuleFactory() SingletonModule {
+	tsm := &testSingletonModule{}
+	InitAndroidSingletonModule(tsm)
+	return tsm
+}
+
+func runSingletonModuleTest(bp string) (*TestContext, []error) {
+	config := TestConfig(buildDir, nil, bp, nil)
+	// Enable Kati output to test SingletonModules with MakeVars.
+	config.katiEnabled = true
+	ctx := NewTestContext(config)
+	ctx.RegisterSingletonModuleType("test_singleton_module", testSingletonModuleFactory)
+	ctx.RegisterSingletonType("makevars", makeVarsSingletonFunc)
+	ctx.Register()
+
+	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
+	if len(errs) > 0 {
+		return ctx, errs
+	}
+
+	_, errs = ctx.PrepareBuildActions(config)
+	return ctx, errs
+}
+
+func TestSingletonModule(t *testing.T) {
+	bp := `
+		test_singleton_module {
+			name: "test_singleton_module",
+		}
+	`
+	ctx, errs := runSingletonModuleTest(bp)
+	if len(errs) > 0 {
+		t.Fatal(errs)
+	}
+
+	ops := ctx.ModuleForTests("test_singleton_module", "").Module().(*testSingletonModule).ops
+	wantOps := []string{"GenerateAndroidBuildActions", "GenerateSingletonBuildActions", "MakeVars"}
+	if !reflect.DeepEqual(ops, wantOps) {
+		t.Errorf("Expected operations %q, got %q", wantOps, ops)
+	}
+}
+
+func TestDuplicateSingletonModule(t *testing.T) {
+	bp := `
+		test_singleton_module {
+			name: "test_singleton_module",
+		}
+
+		test_singleton_module {
+			name: "test_singleton_module2",
+		}
+	`
+	_, errs := runSingletonModuleTest(bp)
+	if len(errs) == 0 {
+		t.Fatal("expected duplicate SingletonModule error")
+	}
+	if len(errs) != 1 || !strings.Contains(errs[0].Error(), `Duplicate SingletonModule "test_singleton_module", previously used in`) {
+		t.Fatalf("expected duplicate SingletonModule error, got %q", errs)
+	}
+}
+
+func TestUnusedSingletonModule(t *testing.T) {
+	bp := ``
+	ctx, errs := runSingletonModuleTest(bp)
+	if len(errs) > 0 {
+		t.Fatal(errs)
+	}
+
+	singleton := ctx.SingletonForTests("test_singleton_module").Singleton()
+	sm := singleton.(*singletonModuleSingletonAdaptor).sm
+	ops := sm.(*testSingletonModule).ops
+	if ops != nil {
+		t.Errorf("Expected no operations, got %q", ops)
+	}
+}
+
+func testVariantSingletonModuleMutator(ctx BottomUpMutatorContext) {
+	if _, ok := ctx.Module().(*testSingletonModule); ok {
+		ctx.CreateVariations("a", "b")
+	}
+}
+
+func TestVariantSingletonModule(t *testing.T) {
+	bp := `
+		test_singleton_module {
+			name: "test_singleton_module",
+		}
+	`
+
+	config := TestConfig(buildDir, nil, bp, nil)
+	ctx := NewTestContext(config)
+	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
+		ctx.BottomUp("test_singleton_module_mutator", testVariantSingletonModuleMutator)
+	})
+	ctx.RegisterSingletonModuleType("test_singleton_module", testSingletonModuleFactory)
+	ctx.Register()
+
+	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
+
+	if len(errs) == 0 {
+		_, errs = ctx.PrepareBuildActions(config)
+	}
+
+	if len(errs) == 0 {
+		t.Fatal("expected duplicate SingletonModule error")
+	}
+	if len(errs) != 1 || !strings.Contains(errs[0].Error(), `GenerateAndroidBuildActions already called for variant`) {
+		t.Fatalf("expected duplicate SingletonModule error, got %q", errs)
+	}
+}
diff --git a/android/testing.go b/android/testing.go
index 6539063..a66b1e1 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -103,6 +103,12 @@
 	ctx.Context.RegisterModuleType(name, ModuleFactoryAdaptor(factory))
 }
 
+func (ctx *TestContext) RegisterSingletonModuleType(name string, factory SingletonModuleFactory) {
+	s, m := SingletonModuleFactoryAdaptor(name, factory)
+	ctx.RegisterSingletonType(name, s)
+	ctx.RegisterModuleType(name, m)
+}
+
 func (ctx *TestContext) RegisterSingletonType(name string, factory SingletonFactory) {
 	ctx.Context.RegisterSingletonType(name, SingletonFactoryAdaptor(ctx.Context, factory))
 }
diff --git a/android/variable.go b/android/variable.go
index 7532797..41cd337 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -139,10 +139,6 @@
 			Enabled *bool
 		}
 
-		Experimental_mte struct {
-			Cflags []string `android:"arch_variant"`
-		} `android:"arch_variant"`
-
 		Native_coverage struct {
 			Src          *string  `android:"arch_variant"`
 			Srcs         []string `android:"arch_variant"`
@@ -264,7 +260,9 @@
 
 	DisableScudo *bool `json:",omitempty"`
 
-	Experimental_mte *bool `json:",omitempty"`
+	MemtagHeapExcludePaths      []string `json:",omitempty"`
+	MemtagHeapAsyncIncludePaths []string `json:",omitempty"`
+	MemtagHeapSyncIncludePaths  []string `json:",omitempty"`
 
 	VendorPath    *string `json:",omitempty"`
 	OdmPath       *string `json:",omitempty"`
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index 9ccf18a..43c53de 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -117,6 +117,7 @@
 androidx.savedstate_savedstate-ktx(minSdkVersion:14)
 androidx.slidingpanelayout_slidingpanelayout(minSdkVersion:14)
 androidx.swiperefreshlayout_swiperefreshlayout(minSdkVersion:14)
+androidx.tracing_tracing(minSdkVersion:14)
 androidx.transition_transition(minSdkVersion:14)
 androidx.vectordrawable_vectordrawable(minSdkVersion:14)
 androidx.vectordrawable_vectordrawable-animated(minSdkVersion:14)
@@ -397,6 +398,7 @@
 libprocessgroup_headers(minSdkVersion:29)
 libprocpartition(minSdkVersion:(no version))
 libprofile-clang-extras(minSdkVersion:(no version))
+libprofile-clang-extras_cfi_support(minSdkVersion:(no version))
 libprofile-clang-extras_ndk(minSdkVersion:(no version))
 libprofile-extras(minSdkVersion:(no version))
 libprofile-extras_ndk(minSdkVersion:(no version))
@@ -529,6 +531,8 @@
 neuralnetworks_utils_hal_1_3(minSdkVersion:30)
 neuralnetworks_utils_hal_common(minSdkVersion:30)
 neuralnetworks_utils_hal_service(minSdkVersion:30)
+note_memtag_heap_async(minSdkVersion:16)
+note_memtag_heap_sync(minSdkVersion:16)
 offlinelocationtimezoneprovider(minSdkVersion:current)
 PermissionController(minSdkVersion:30)
 permissioncontroller-statsd(minSdkVersion:current)
@@ -597,6 +601,7 @@
 prebuilt_androidx.savedstate_savedstate-nodeps(minSdkVersion:(no version))
 prebuilt_androidx.slidingpanelayout_slidingpanelayout-nodeps(minSdkVersion:(no version))
 prebuilt_androidx.swiperefreshlayout_swiperefreshlayout-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.tracing_tracing-nodeps(minSdkVersion:(no version))
 prebuilt_androidx.transition_transition-nodeps(minSdkVersion:(no version))
 prebuilt_androidx.vectordrawable_vectordrawable-animated-nodeps(minSdkVersion:(no version))
 prebuilt_androidx.vectordrawable_vectordrawable-nodeps(minSdkVersion:(no version))
diff --git a/apex/apex.go b/apex/apex.go
index 33abdd0..3a333ba 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -168,6 +168,10 @@
 	// used in tests.
 	Test_only_unsigned_payload *bool
 
+	// Whenever apex should be compressed, regardless of product flag used. Should be only
+	// used in tests.
+	Test_only_force_compression *bool
+
 	IsCoverageVariant bool `blueprint:"mutated"`
 
 	// List of sanitizer names that this APEX is enabled for
@@ -1241,6 +1245,11 @@
 	return proptools.Bool(a.properties.Test_only_unsigned_payload)
 }
 
+// See the test_only_force_compression property
+func (a *apexBundle) testOnlyShouldForceCompression() bool {
+	return proptools.Bool(a.properties.Test_only_force_compression)
+}
+
 // These functions are interfacing with cc/sanitizer.go. The entire APEX (along with all of its
 // members) can be sanitized, either forcibly, or by the global configuration. For some of the
 // sanitizers, extra dependencies can be forcibly added as well.
diff --git a/apex/builder.go b/apex/builder.go
index 106302b..bc1b566 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -763,9 +763,13 @@
 	})
 	a.outputFile = signedOutputFile
 
-	// Process APEX compression if enabled
+	// Process APEX compression if enabled or forced
+	if ctx.ModuleDir() != "system/apex/apexd/apexd_testdata" && a.testOnlyShouldForceCompression() {
+		ctx.PropertyErrorf("test_only_force_compression", "not available")
+		return
+	}
 	compressionEnabled := ctx.Config().CompressedApex() && proptools.BoolDefault(a.properties.Compressible, true)
-	if compressionEnabled && apexType == imageApex {
+	if apexType == imageApex && (compressionEnabled || a.testOnlyShouldForceCompression()) {
 		a.isCompressed = true
 		unsignedCompressedOutputFile := android.PathForModuleOut(ctx, a.Name()+".capex.unsigned")
 
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
new file mode 100644
index 0000000..49587f4
--- /dev/null
+++ b/bp2build/Android.bp
@@ -0,0 +1,23 @@
+bootstrap_go_package {
+    name: "soong-bp2build",
+    pkgPath: "android/soong/bp2build",
+    srcs: [
+        "androidbp_to_build_templates.go",
+        "bp2build.go",
+        "build_conversion.go",
+        "bzl_conversion.go",
+        "conversion.go",
+    ],
+    deps: [
+        "soong-android",
+    ],
+    testSrcs: [
+        "build_conversion_test.go",
+        "bzl_conversion_test.go",
+        "conversion_test.go",
+        "testing.go",
+    ],
+    pluginFor: [
+        "soong_build",
+    ],
+}
diff --git a/cmd/soong_build/queryview_templates.go b/bp2build/androidbp_to_build_templates.go
similarity index 98%
rename from cmd/soong_build/queryview_templates.go
rename to bp2build/androidbp_to_build_templates.go
index 359c0d8..75c3ccb 100644
--- a/cmd/soong_build/queryview_templates.go
+++ b/bp2build/androidbp_to_build_templates.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package bp2build
 
 const (
 	// The default `load` preamble for every generated BUILD file.
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
new file mode 100644
index 0000000..30f298a
--- /dev/null
+++ b/bp2build/bp2build.go
@@ -0,0 +1,77 @@
+// 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.
+
+package bp2build
+
+import (
+	"android/soong/android"
+	"os"
+)
+
+// The Bazel bp2build singleton is responsible for writing .bzl files that are equivalent to
+// Android.bp files that are capable of being built with Bazel.
+func init() {
+	android.RegisterBazelConverterPreSingletonType("androidbp_to_build", AndroidBpToBuildSingleton)
+}
+
+func AndroidBpToBuildSingleton() android.Singleton {
+	return &androidBpToBuildSingleton{
+		name: "bp2build",
+	}
+}
+
+type androidBpToBuildSingleton struct {
+	name      string
+	outputDir android.OutputPath
+}
+
+func (s *androidBpToBuildSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	s.outputDir = android.PathForOutput(ctx, s.name)
+	android.RemoveAllOutputDir(s.outputDir)
+
+	if !ctx.Config().IsEnvTrue("CONVERT_TO_BAZEL") {
+		return
+	}
+
+	ruleShims := CreateRuleShims(android.ModuleTypeFactories())
+
+	buildToTargets := GenerateSoongModuleTargets(ctx)
+
+	filesToWrite := CreateBazelFiles(ruleShims, buildToTargets)
+	for _, f := range filesToWrite {
+		if err := s.writeFile(ctx, f); err != nil {
+			ctx.Errorf("Failed to write %q (dir %q) due to %q", f.Basename, f.Dir, err)
+		}
+	}
+}
+
+func (s *androidBpToBuildSingleton) getOutputPath(ctx android.PathContext, dir string) android.OutputPath {
+	return s.outputDir.Join(ctx, dir)
+}
+
+func (s *androidBpToBuildSingleton) writeFile(ctx android.PathContext, f BazelFile) error {
+	return writeReadOnlyFile(ctx, s.getOutputPath(ctx, f.Dir), f.Basename, f.Contents)
+}
+
+// The auto-conversion directory should be read-only, sufficient for bazel query. The files
+// are not intended to be edited by end users.
+func writeReadOnlyFile(ctx android.PathContext, dir android.OutputPath, baseName, content string) error {
+	android.CreateOutputDirIfNonexistent(dir, os.ModePerm)
+	pathToFile := dir.Join(ctx, baseName)
+
+	// 0444 is read-only
+	err := android.WriteFileToOutputDir(pathToFile, []byte(content), 0444)
+
+	return err
+}
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
new file mode 100644
index 0000000..0329685
--- /dev/null
+++ b/bp2build/build_conversion.go
@@ -0,0 +1,305 @@
+// 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.
+
+package bp2build
+
+import (
+	"android/soong/android"
+	"fmt"
+	"reflect"
+	"strings"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+type BazelAttributes struct {
+	Attrs map[string]string
+}
+
+type BazelTarget struct {
+	name    string
+	content string
+}
+
+type bpToBuildContext interface {
+	ModuleName(module blueprint.Module) string
+	ModuleDir(module blueprint.Module) string
+	ModuleSubDir(module blueprint.Module) string
+	ModuleType(module blueprint.Module) string
+
+	VisitAllModulesBlueprint(visit func(blueprint.Module))
+	VisitDirectDeps(module android.Module, visit func(android.Module))
+}
+
+// props is an unsorted map. This function ensures that
+// the generated attributes are sorted to ensure determinism.
+func propsToAttributes(props map[string]string) string {
+	var attributes string
+	for _, propName := range android.SortedStringKeys(props) {
+		if shouldGenerateAttribute(propName) {
+			attributes += fmt.Sprintf("    %s = %s,\n", propName, props[propName])
+		}
+	}
+	return attributes
+}
+
+func GenerateSoongModuleTargets(ctx bpToBuildContext) map[string][]BazelTarget {
+	buildFileToTargets := make(map[string][]BazelTarget)
+	ctx.VisitAllModulesBlueprint(func(m blueprint.Module) {
+		dir := ctx.ModuleDir(m)
+		t := generateSoongModuleTarget(ctx, m)
+		buildFileToTargets[ctx.ModuleDir(m)] = append(buildFileToTargets[dir], t)
+	})
+	return buildFileToTargets
+}
+
+// Convert a module and its deps and props into a Bazel macro/rule
+// representation in the BUILD file.
+func generateSoongModuleTarget(ctx bpToBuildContext, m blueprint.Module) BazelTarget {
+	props := getBuildProperties(ctx, m)
+
+	// TODO(b/163018919): DirectDeps can have duplicate (module, variant)
+	// items, if the modules are added using different DependencyTag. Figure
+	// out the implications of that.
+	depLabels := map[string]bool{}
+	if aModule, ok := m.(android.Module); ok {
+		ctx.VisitDirectDeps(aModule, func(depModule android.Module) {
+			depLabels[qualifiedTargetLabel(ctx, depModule)] = true
+		})
+	}
+	attributes := propsToAttributes(props.Attrs)
+
+	depLabelList := "[\n"
+	for depLabel, _ := range depLabels {
+		depLabelList += fmt.Sprintf("        %q,\n", depLabel)
+	}
+	depLabelList += "    ]"
+
+	targetName := targetNameWithVariant(ctx, m)
+	return BazelTarget{
+		name: targetName,
+		content: fmt.Sprintf(
+			soongModuleTarget,
+			targetName,
+			ctx.ModuleName(m),
+			canonicalizeModuleType(ctx.ModuleType(m)),
+			ctx.ModuleSubDir(m),
+			depLabelList,
+			attributes),
+	}
+}
+
+func getBuildProperties(ctx bpToBuildContext, m blueprint.Module) BazelAttributes {
+	var allProps map[string]string
+	// TODO: this omits properties for blueprint modules (blueprint_go_binary,
+	// bootstrap_go_binary, bootstrap_go_package), which will have to be handled separately.
+	if aModule, ok := m.(android.Module); ok {
+		allProps = ExtractModuleProperties(aModule)
+	}
+
+	return BazelAttributes{
+		Attrs: allProps,
+	}
+}
+
+// Generically extract module properties and types into a map, keyed by the module property name.
+func ExtractModuleProperties(aModule android.Module) map[string]string {
+	ret := map[string]string{}
+
+	// Iterate over this android.Module's property structs.
+	for _, properties := range aModule.GetProperties() {
+		propertiesValue := reflect.ValueOf(properties)
+		// Check that propertiesValue is a pointer to the Properties struct, like
+		// *cc.BaseLinkerProperties or *java.CompilerProperties.
+		//
+		// propertiesValue can also be type-asserted to the structs to
+		// manipulate internal props, if needed.
+		if isStructPtr(propertiesValue.Type()) {
+			structValue := propertiesValue.Elem()
+			for k, v := range extractStructProperties(structValue, 0) {
+				ret[k] = v
+			}
+		} else {
+			panic(fmt.Errorf(
+				"properties must be a pointer to a struct, got %T",
+				propertiesValue.Interface()))
+		}
+	}
+
+	return ret
+}
+
+func isStructPtr(t reflect.Type) bool {
+	return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
+}
+
+// prettyPrint a property value into the equivalent Starlark representation
+// recursively.
+func prettyPrint(propertyValue reflect.Value, indent int) (string, error) {
+	if isZero(propertyValue) {
+		// A property value being set or unset actually matters -- Soong does set default
+		// values for unset properties, like system_shared_libs = ["libc", "libm", "libdl"] at
+		// https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=281-287;drc=f70926eef0b9b57faf04c17a1062ce50d209e480
+		//
+		// In Bazel-parlance, we would use "attr.<type>(default = <default value>)" to set the default
+		// value of unset attributes.
+		return "", nil
+	}
+
+	var ret string
+	switch propertyValue.Kind() {
+	case reflect.String:
+		ret = fmt.Sprintf("\"%v\"", escapeString(propertyValue.String()))
+	case reflect.Bool:
+		ret = strings.Title(fmt.Sprintf("%v", propertyValue.Interface()))
+	case reflect.Int, reflect.Uint, reflect.Int64:
+		ret = fmt.Sprintf("%v", propertyValue.Interface())
+	case reflect.Ptr:
+		return prettyPrint(propertyValue.Elem(), indent)
+	case reflect.Slice:
+		ret = "[\n"
+		for i := 0; i < propertyValue.Len(); i++ {
+			indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1)
+			if err != nil {
+				return "", err
+			}
+
+			if indexedValue != "" {
+				ret += makeIndent(indent + 1)
+				ret += indexedValue
+				ret += ",\n"
+			}
+		}
+		ret += makeIndent(indent)
+		ret += "]"
+	case reflect.Struct:
+		ret = "{\n"
+		// Sort and print the struct props by the key.
+		structProps := extractStructProperties(propertyValue, indent)
+		for _, k := range android.SortedStringKeys(structProps) {
+			ret += makeIndent(indent + 1)
+			ret += fmt.Sprintf("%q: %s,\n", k, structProps[k])
+		}
+		ret += makeIndent(indent)
+		ret += "}"
+	case reflect.Interface:
+		// TODO(b/164227191): implement pretty print for interfaces.
+		// Interfaces are used for for arch, multilib and target properties.
+		return "", nil
+	default:
+		return "", fmt.Errorf(
+			"unexpected kind for property struct field: %s", propertyValue.Kind())
+	}
+	return ret, nil
+}
+
+// Converts a reflected property struct value into a map of property names and property values,
+// which each property value correctly pretty-printed and indented at the right nest level,
+// since property structs can be nested. In Starlark, nested structs are represented as nested
+// dicts: https://docs.bazel.build/skylark/lib/dict.html
+func extractStructProperties(structValue reflect.Value, indent int) map[string]string {
+	if structValue.Kind() != reflect.Struct {
+		panic(fmt.Errorf("Expected a reflect.Struct type, but got %s", structValue.Kind()))
+	}
+
+	ret := map[string]string{}
+	structType := structValue.Type()
+	for i := 0; i < structValue.NumField(); i++ {
+		field := structType.Field(i)
+		if shouldSkipStructField(field) {
+			continue
+		}
+
+		fieldValue := structValue.Field(i)
+		if isZero(fieldValue) {
+			// Ignore zero-valued fields
+			continue
+		}
+
+		propertyName := proptools.PropertyNameForField(field.Name)
+		prettyPrintedValue, err := prettyPrint(fieldValue, indent+1)
+		if err != nil {
+			panic(
+				fmt.Errorf(
+					"Error while parsing property: %q. %s",
+					propertyName,
+					err))
+		}
+		if prettyPrintedValue != "" {
+			ret[propertyName] = prettyPrintedValue
+		}
+	}
+
+	return ret
+}
+
+func isZero(value reflect.Value) bool {
+	switch value.Kind() {
+	case reflect.Func, reflect.Map, reflect.Slice:
+		return value.IsNil()
+	case reflect.Array:
+		valueIsZero := true
+		for i := 0; i < value.Len(); i++ {
+			valueIsZero = valueIsZero && isZero(value.Index(i))
+		}
+		return valueIsZero
+	case reflect.Struct:
+		valueIsZero := true
+		for i := 0; i < value.NumField(); i++ {
+			if value.Field(i).CanSet() {
+				valueIsZero = valueIsZero && isZero(value.Field(i))
+			}
+		}
+		return valueIsZero
+	case reflect.Ptr:
+		if !value.IsNil() {
+			return isZero(reflect.Indirect(value))
+		} else {
+			return true
+		}
+	default:
+		zeroValue := reflect.Zero(value.Type())
+		result := value.Interface() == zeroValue.Interface()
+		return result
+	}
+}
+
+func escapeString(s string) string {
+	s = strings.ReplaceAll(s, "\\", "\\\\")
+	return strings.ReplaceAll(s, "\"", "\\\"")
+}
+
+func makeIndent(indent int) string {
+	if indent < 0 {
+		panic(fmt.Errorf("indent column cannot be less than 0, but got %d", indent))
+	}
+	return strings.Repeat("    ", indent)
+}
+
+func targetNameWithVariant(c bpToBuildContext, logicModule blueprint.Module) string {
+	name := ""
+	if c.ModuleSubDir(logicModule) != "" {
+		// TODO(b/162720883): Figure out a way to drop the "--" variant suffixes.
+		name = c.ModuleName(logicModule) + "--" + c.ModuleSubDir(logicModule)
+	} else {
+		name = c.ModuleName(logicModule)
+	}
+
+	return strings.Replace(name, "//", "", 1)
+}
+
+func qualifiedTargetLabel(c bpToBuildContext, logicModule blueprint.Module) string {
+	return fmt.Sprintf("//%s:%s", c.ModuleDir(logicModule), targetNameWithVariant(c, logicModule))
+}
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
new file mode 100644
index 0000000..8230ad8
--- /dev/null
+++ b/bp2build/build_conversion_test.go
@@ -0,0 +1,221 @@
+// 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.
+
+package bp2build
+
+import (
+	"android/soong/android"
+	"testing"
+)
+
+func TestGenerateSoongModuleTargets(t *testing.T) {
+	testCases := []struct {
+		bp                  string
+		expectedBazelTarget string
+	}{
+		{
+			bp: `custom {
+	name: "foo",
+}
+		`,
+			expectedBazelTarget: `soong_module(
+    name = "foo",
+    module_name = "foo",
+    module_type = "custom",
+    module_variant = "",
+    module_deps = [
+    ],
+)`,
+		},
+		{
+			bp: `custom {
+	name: "foo",
+	ramdisk: true,
+}
+		`,
+			expectedBazelTarget: `soong_module(
+    name = "foo",
+    module_name = "foo",
+    module_type = "custom",
+    module_variant = "",
+    module_deps = [
+    ],
+    ramdisk = True,
+)`,
+		},
+		{
+			bp: `custom {
+	name: "foo",
+	owner: "a_string_with\"quotes\"_and_\\backslashes\\\\",
+}
+		`,
+			expectedBazelTarget: `soong_module(
+    name = "foo",
+    module_name = "foo",
+    module_type = "custom",
+    module_variant = "",
+    module_deps = [
+    ],
+    owner = "a_string_with\"quotes\"_and_\\backslashes\\\\",
+)`,
+		},
+		{
+			bp: `custom {
+	name: "foo",
+	required: ["bar"],
+}
+		`,
+			expectedBazelTarget: `soong_module(
+    name = "foo",
+    module_name = "foo",
+    module_type = "custom",
+    module_variant = "",
+    module_deps = [
+    ],
+    required = [
+        "bar",
+    ],
+)`,
+		},
+		{
+			bp: `custom {
+	name: "foo",
+	target_required: ["qux", "bazqux"],
+}
+		`,
+			expectedBazelTarget: `soong_module(
+    name = "foo",
+    module_name = "foo",
+    module_type = "custom",
+    module_variant = "",
+    module_deps = [
+    ],
+    target_required = [
+        "qux",
+        "bazqux",
+    ],
+)`,
+		},
+		{
+			bp: `custom {
+	name: "foo",
+	dist: {
+		targets: ["goal_foo"],
+		tag: ".foo",
+	},
+	dists: [
+		{
+			targets: ["goal_bar"],
+			tag: ".bar",
+		},
+	],
+}
+		`,
+			expectedBazelTarget: `soong_module(
+    name = "foo",
+    module_name = "foo",
+    module_type = "custom",
+    module_variant = "",
+    module_deps = [
+    ],
+    dist = {
+        "tag": ".foo",
+        "targets": [
+            "goal_foo",
+        ],
+    },
+    dists = [
+        {
+            "tag": ".bar",
+            "targets": [
+                "goal_bar",
+            ],
+        },
+    ],
+)`,
+		},
+		{
+			bp: `custom {
+	name: "foo",
+	required: ["bar"],
+	target_required: ["qux", "bazqux"],
+	ramdisk: true,
+	owner: "custom_owner",
+	dists: [
+		{
+			tag: ".tag",
+			targets: ["my_goal"],
+		},
+	],
+}
+		`,
+			expectedBazelTarget: `soong_module(
+    name = "foo",
+    module_name = "foo",
+    module_type = "custom",
+    module_variant = "",
+    module_deps = [
+    ],
+    dists = [
+        {
+            "tag": ".tag",
+            "targets": [
+                "my_goal",
+            ],
+        },
+    ],
+    owner = "custom_owner",
+    ramdisk = True,
+    required = [
+        "bar",
+    ],
+    target_required = [
+        "qux",
+        "bazqux",
+    ],
+)`,
+		},
+	}
+
+	dir := "."
+	for _, testCase := range testCases {
+		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
+		ctx := android.NewTestContext(config)
+		ctx.RegisterModuleType("custom", customModuleFactory)
+		ctx.Register()
+
+		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
+		android.FailIfErrored(t, errs)
+		_, errs = ctx.PrepareBuildActions(config)
+		android.FailIfErrored(t, errs)
+
+		bp2BuildCtx := bp2buildBlueprintWrapContext{
+			bpCtx: ctx.Context.Context,
+		}
+
+		bazelTargets := GenerateSoongModuleTargets(&bp2BuildCtx)[dir]
+		if g, w := len(bazelTargets), 1; g != w {
+			t.Fatalf("Expected %d bazel target, got %d", w, g)
+		}
+
+		actualBazelTarget := bazelTargets[0]
+		if actualBazelTarget.content != testCase.expectedBazelTarget {
+			t.Errorf(
+				"Expected generated Bazel target to be '%s', got '%s'",
+				testCase.expectedBazelTarget,
+				actualBazelTarget,
+			)
+		}
+	}
+}
diff --git a/bp2build/bzl_conversion.go b/bp2build/bzl_conversion.go
new file mode 100644
index 0000000..04c4542
--- /dev/null
+++ b/bp2build/bzl_conversion.go
@@ -0,0 +1,230 @@
+// 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.
+
+package bp2build
+
+import (
+	"android/soong/android"
+	"fmt"
+	"reflect"
+	"runtime"
+	"sort"
+	"strings"
+
+	"github.com/google/blueprint/proptools"
+)
+
+var (
+	// An allowlist of prop types that are surfaced from module props to rule
+	// attributes. (nested) dictionaries are notably absent here, because while
+	// Soong supports multi value typed and nested dictionaries, Bazel's rule
+	// attr() API supports only single-level string_dicts.
+	allowedPropTypes = map[string]bool{
+		"int":         true, // e.g. 42
+		"bool":        true, // e.g. True
+		"string_list": true, // e.g. ["a", "b"]
+		"string":      true, // e.g. "a"
+	}
+)
+
+type rule struct {
+	name  string
+	attrs string
+}
+
+type RuleShim struct {
+	// The rule class shims contained in a bzl file. e.g. ["cc_object", "cc_library", ..]
+	rules []string
+
+	// The generated string content of the bzl file.
+	content string
+}
+
+// Create <module>.bzl containing Bazel rule shims for every module type available in Soong and
+// user-specified Go plugins.
+//
+// This function reuses documentation generation APIs to ensure parity between modules-as-docs
+// and modules-as-code, including the names and types of morule properties.
+func CreateRuleShims(moduleTypeFactories map[string]android.ModuleFactory) map[string]RuleShim {
+	ruleShims := map[string]RuleShim{}
+	for pkg, rules := range generateRules(moduleTypeFactories) {
+		shim := RuleShim{
+			rules: make([]string, 0, len(rules)),
+		}
+		shim.content = "load(\"//build/bazel/queryview_rules:providers.bzl\", \"SoongModuleInfo\")\n"
+
+		bzlFileName := strings.ReplaceAll(pkg, "android/soong/", "")
+		bzlFileName = strings.ReplaceAll(bzlFileName, ".", "_")
+		bzlFileName = strings.ReplaceAll(bzlFileName, "/", "_")
+
+		for _, r := range rules {
+			shim.content += fmt.Sprintf(moduleRuleShim, r.name, r.attrs)
+			shim.rules = append(shim.rules, r.name)
+		}
+		sort.Strings(shim.rules)
+		ruleShims[bzlFileName] = shim
+	}
+	return ruleShims
+}
+
+// Generate the content of soong_module.bzl with the rule shim load statements
+// and mapping of module_type to rule shim map for every module type in Soong.
+func generateSoongModuleBzl(bzlLoads map[string]RuleShim) string {
+	var loadStmts string
+	var moduleRuleMap string
+	for _, bzlFileName := range android.SortedStringKeys(bzlLoads) {
+		loadStmt := "load(\"//build/bazel/queryview_rules:"
+		loadStmt += bzlFileName
+		loadStmt += ".bzl\""
+		ruleShim := bzlLoads[bzlFileName]
+		for _, rule := range ruleShim.rules {
+			loadStmt += fmt.Sprintf(", %q", rule)
+			moduleRuleMap += "    \"" + rule + "\": " + rule + ",\n"
+		}
+		loadStmt += ")\n"
+		loadStmts += loadStmt
+	}
+
+	return fmt.Sprintf(soongModuleBzl, loadStmts, moduleRuleMap)
+}
+
+func generateRules(moduleTypeFactories map[string]android.ModuleFactory) map[string][]rule {
+	// TODO: add shims for bootstrap/blueprint go modules types
+
+	rules := make(map[string][]rule)
+	// TODO: allow registration of a bzl rule when registring a factory
+	for _, moduleType := range android.SortedStringKeys(moduleTypeFactories) {
+		factory := moduleTypeFactories[moduleType]
+		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]),
+`
+		attrs += getAttributes(factory)
+		attrs += "    },"
+
+		r := rule{
+			name:  canonicalizeModuleType(moduleType),
+			attrs: attrs,
+		}
+
+		rules[pkg] = append(rules[pkg], r)
+	}
+	return rules
+}
+
+type property struct {
+	name             string
+	starlarkAttrType string
+	properties       []property
+}
+
+const (
+	attributeIndent = "        "
+)
+
+func (p *property) attributeString() string {
+	if !shouldGenerateAttribute(p.name) {
+		return ""
+	}
+
+	if _, ok := allowedPropTypes[p.starlarkAttrType]; !ok {
+		// a struct -- let's just comment out sub-props
+		s := fmt.Sprintf(attributeIndent+"# %s start\n", p.name)
+		for _, nestedP := range p.properties {
+			s += "# " + nestedP.attributeString()
+		}
+		s += fmt.Sprintf(attributeIndent+"# %s end\n", p.name)
+		return s
+	}
+	return fmt.Sprintf(attributeIndent+"%q: attr.%s(),\n", p.name, p.starlarkAttrType)
+}
+
+func extractPropertyDescriptionsFromStruct(structType reflect.Type) []property {
+	properties := make([]property, 0)
+	for i := 0; i < structType.NumField(); i++ {
+		field := structType.Field(i)
+		if shouldSkipStructField(field) {
+			continue
+		}
+
+		properties = append(properties, extractPropertyDescriptions(field.Name, field.Type)...)
+	}
+	return properties
+}
+
+func extractPropertyDescriptions(name string, t reflect.Type) []property {
+	name = proptools.PropertyNameForField(name)
+
+	// TODO: handle android:paths tags, they should be changed to label types
+
+	starlarkAttrType := fmt.Sprintf("%s", t.Name())
+	props := make([]property, 0)
+
+	switch t.Kind() {
+	case reflect.Bool, reflect.String:
+		// do nothing
+	case reflect.Uint, reflect.Int, reflect.Int64:
+		starlarkAttrType = "int"
+	case reflect.Slice:
+		if t.Elem().Kind() != reflect.String {
+			// TODO: handle lists of non-strings (currently only list of Dist)
+			return []property{}
+		}
+		starlarkAttrType = "string_list"
+	case reflect.Struct:
+		props = extractPropertyDescriptionsFromStruct(t)
+	case reflect.Ptr:
+		return extractPropertyDescriptions(name, t.Elem())
+	case reflect.Interface:
+		// Interfaces are used for for arch, multilib and target properties, which are handled at runtime.
+		// These will need to be handled in a bazel-specific version of the arch mutator.
+		return []property{}
+	}
+
+	prop := property{
+		name:             name,
+		starlarkAttrType: starlarkAttrType,
+		properties:       props,
+	}
+
+	return []property{prop}
+}
+
+func getPropertyDescriptions(props []interface{}) []property {
+	// there may be duplicate properties, e.g. from defaults libraries
+	propertiesByName := make(map[string]property)
+	for _, p := range props {
+		for _, prop := range extractPropertyDescriptionsFromStruct(reflect.ValueOf(p).Elem().Type()) {
+			propertiesByName[prop.name] = prop
+		}
+	}
+
+	properties := make([]property, 0, len(propertiesByName))
+	for _, key := range android.SortedStringKeys(propertiesByName) {
+		properties = append(properties, propertiesByName[key])
+	}
+
+	return properties
+}
+
+func getAttributes(factory android.ModuleFactory) string {
+	attrs := ""
+	for _, p := range getPropertyDescriptions(factory().GetProperties()) {
+		attrs += p.attributeString()
+	}
+	return attrs
+}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
new file mode 100644
index 0000000..8bea3f6
--- /dev/null
+++ b/bp2build/bzl_conversion_test.go
@@ -0,0 +1,208 @@
+// 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.
+
+package bp2build
+
+import (
+	"android/soong/android"
+	"io/ioutil"
+	"os"
+	"strings"
+	"testing"
+)
+
+var buildDir string
+
+func setUp() {
+	var err error
+	buildDir, err = ioutil.TempDir("", "bazel_queryview_test")
+	if err != nil {
+		panic(err)
+	}
+}
+
+func tearDown() {
+	os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+	run := func() int {
+		setUp()
+		defer tearDown()
+
+		return m.Run()
+	}
+
+	os.Exit(run())
+}
+
+func TestGenerateModuleRuleShims(t *testing.T) {
+	moduleTypeFactories := map[string]android.ModuleFactory{
+		"custom":          customModuleFactoryBase,
+		"custom_test":     customTestModuleFactoryBase,
+		"custom_defaults": customDefaultsModuleFactoryBasic,
+	}
+	ruleShims := CreateRuleShims(moduleTypeFactories)
+
+	if len(ruleShims) != 1 {
+		t.Errorf("Expected to generate 1 rule shim, but got %d", len(ruleShims))
+	}
+
+	ruleShim := ruleShims["bp2build"]
+	expectedRules := []string{
+		"custom",
+		"custom_defaults",
+		"custom_test_",
+	}
+
+	if len(ruleShim.rules) != len(expectedRules) {
+		t.Errorf("Expected %d rules, but got %d", len(expectedRules), len(ruleShim.rules))
+	}
+
+	for i, rule := range ruleShim.rules {
+		if rule != expectedRules[i] {
+			t.Errorf("Expected rule shim to contain %s, but got %s", expectedRules[i], rule)
+		}
+	}
+	expectedBzl := `load("//build/bazel/queryview_rules:providers.bzl", "SoongModuleInfo")
+
+def _custom_impl(ctx):
+    return [SoongModuleInfo()]
+
+custom = rule(
+    implementation = _custom_impl,
+    attrs = {
+        "module_name": attr.string(mandatory = True),
+        "module_variant": attr.string(),
+        "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+        "bool_prop": attr.bool(),
+        "bool_ptr_prop": attr.bool(),
+        "int64_ptr_prop": attr.int(),
+        # nested_props start
+#         "nested_prop": attr.string(),
+        # nested_props end
+        # nested_props_ptr start
+#         "nested_prop": attr.string(),
+        # nested_props_ptr end
+        "string_list_prop": attr.string_list(),
+        "string_prop": attr.string(),
+        "string_ptr_prop": attr.string(),
+    },
+)
+
+def _custom_defaults_impl(ctx):
+    return [SoongModuleInfo()]
+
+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]),
+        "bool_prop": attr.bool(),
+        "bool_ptr_prop": attr.bool(),
+        "int64_ptr_prop": attr.int(),
+        # nested_props start
+#         "nested_prop": attr.string(),
+        # nested_props end
+        # nested_props_ptr start
+#         "nested_prop": attr.string(),
+        # nested_props_ptr end
+        "string_list_prop": attr.string_list(),
+        "string_prop": attr.string(),
+        "string_ptr_prop": attr.string(),
+    },
+)
+
+def _custom_test__impl(ctx):
+    return [SoongModuleInfo()]
+
+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]),
+        "bool_prop": attr.bool(),
+        "bool_ptr_prop": attr.bool(),
+        "int64_ptr_prop": attr.int(),
+        # nested_props start
+#         "nested_prop": attr.string(),
+        # nested_props end
+        # nested_props_ptr start
+#         "nested_prop": attr.string(),
+        # nested_props_ptr end
+        "string_list_prop": attr.string_list(),
+        "string_prop": attr.string(),
+        "string_ptr_prop": attr.string(),
+        # test_prop start
+#         "test_string_prop": attr.string(),
+        # test_prop end
+    },
+)
+`
+
+	if ruleShim.content != expectedBzl {
+		t.Errorf(
+			"Expected the generated rule shim bzl to be:\n%s\nbut got:\n%s",
+			expectedBzl,
+			ruleShim.content)
+	}
+}
+
+func TestGenerateSoongModuleBzl(t *testing.T) {
+	ruleShims := map[string]RuleShim{
+		"file1": RuleShim{
+			rules:   []string{"a", "b"},
+			content: "irrelevant",
+		},
+		"file2": RuleShim{
+			rules:   []string{"c", "d"},
+			content: "irrelevant",
+		},
+	}
+	files := CreateBazelFiles(ruleShims, make(map[string][]BazelTarget))
+
+	var actualSoongModuleBzl BazelFile
+	for _, f := range files {
+		if f.Basename == "soong_module.bzl" {
+			actualSoongModuleBzl = f
+		}
+	}
+
+	expectedLoad := `load("//build/bazel/queryview_rules:file1.bzl", "a", "b")
+load("//build/bazel/queryview_rules:file2.bzl", "c", "d")
+`
+	expectedRuleMap := `soong_module_rule_map = {
+    "a": a,
+    "b": b,
+    "c": c,
+    "d": d,
+}`
+	if !strings.Contains(actualSoongModuleBzl.Contents, expectedLoad) {
+		t.Errorf(
+			"Generated soong_module.bzl:\n\n%s\n\n"+
+				"Could not find the load statement in the generated soong_module.bzl:\n%s",
+			actualSoongModuleBzl.Contents,
+			expectedLoad)
+	}
+
+	if !strings.Contains(actualSoongModuleBzl.Contents, expectedRuleMap) {
+		t.Errorf(
+			"Generated soong_module.bzl:\n\n%s\n\n"+
+				"Could not find the module -> rule map in the generated soong_module.bzl:\n%s",
+			actualSoongModuleBzl.Contents,
+			expectedRuleMap)
+	}
+}
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
new file mode 100644
index 0000000..cdfb38b
--- /dev/null
+++ b/bp2build/conversion.go
@@ -0,0 +1,118 @@
+package bp2build
+
+import (
+	"android/soong/android"
+	"reflect"
+	"sort"
+	"strings"
+
+	"github.com/google/blueprint/proptools"
+)
+
+type BazelFile struct {
+	Dir      string
+	Basename string
+	Contents string
+}
+
+func CreateBazelFiles(
+	ruleShims map[string]RuleShim,
+	buildToTargets map[string][]BazelTarget) []BazelFile {
+	files := make([]BazelFile, 0, len(ruleShims)+len(buildToTargets)+numAdditionalFiles)
+
+	// Write top level files: WORKSPACE and BUILD. These files are empty.
+	files = append(files, newFile("", "WORKSPACE", ""))
+	// Used to denote that the top level directory is a package.
+	files = append(files, newFile("", "BUILD", ""))
+
+	files = append(files, newFile(bazelRulesSubDir, "BUILD", ""))
+	files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl))
+
+	for bzlFileName, ruleShim := range ruleShims {
+		files = append(files, newFile(bazelRulesSubDir, bzlFileName+".bzl", ruleShim.content))
+	}
+	files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims)))
+
+	files = append(files, createBuildFiles(buildToTargets)...)
+
+	return files
+}
+
+func createBuildFiles(buildToTargets map[string][]BazelTarget) []BazelFile {
+	files := make([]BazelFile, 0, len(buildToTargets))
+	for _, dir := range android.SortedStringKeys(buildToTargets) {
+		content := soongModuleLoad
+		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
+		}
+		files = append(files, newFile(dir, "BUILD.bazel", content))
+	}
+	return files
+}
+
+func newFile(dir, basename, content string) BazelFile {
+	return BazelFile{
+		Dir:      dir,
+		Basename: basename,
+		Contents: content,
+	}
+}
+
+const (
+	bazelRulesSubDir = "build/bazel/queryview_rules"
+
+	// additional files:
+	//  * workspace file
+	//  * base BUILD file
+	//  * rules BUILD file
+	//  * rules providers.bzl file
+	//  * rules soong_module.bzl file
+	numAdditionalFiles = 5
+)
+
+var (
+	// Certain module property names are blocklisted/ignored here, for the reasons commented.
+	ignoredPropNames = map[string]bool{
+		"name":       true, // redundant, since this is explicitly generated for every target
+		"from":       true, // reserved keyword
+		"in":         true, // reserved keyword
+		"arch":       true, // interface prop type is not supported yet.
+		"multilib":   true, // interface prop type is not supported yet.
+		"target":     true, // interface prop type is not supported yet.
+		"visibility": true, // Bazel has native visibility semantics. Handle later.
+		"features":   true, // There is already a built-in attribute 'features' which cannot be overridden.
+	}
+)
+
+func shouldGenerateAttribute(prop string) bool {
+	return !ignoredPropNames[prop]
+}
+
+func shouldSkipStructField(field reflect.StructField) bool {
+	if field.PkgPath != "" {
+		// Skip unexported fields. Some properties are
+		// internal to Soong only, and these fields do not have PkgPath.
+		return true
+	}
+	// fields with tag `blueprint:"mutated"` are exported to enable modification in mutators, etc
+	// but cannot be set in a .bp file
+	if proptools.HasTag(field, "blueprint", "mutated") {
+		return true
+	}
+	return false
+}
+
+// FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as
+// testonly = True, forcing other rules that depend on _test rules to also be
+// marked as testonly = True. This semantic constraint is not present in Soong.
+// To work around, rename "*_test" rules to "*_test_".
+func canonicalizeModuleType(moduleName string) string {
+	if strings.HasSuffix(moduleName, "_test") {
+		return moduleName + "_"
+	}
+
+	return moduleName
+}
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
new file mode 100644
index 0000000..a38fa6a
--- /dev/null
+++ b/bp2build/conversion_test.go
@@ -0,0 +1,73 @@
+// 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.
+
+package bp2build
+
+import (
+	"sort"
+	"testing"
+)
+
+func TestCreateBazelFiles_AddsTopLevelFiles(t *testing.T) {
+	files := CreateBazelFiles(map[string]RuleShim{}, map[string][]BazelTarget{})
+	expectedFilePaths := []struct {
+		dir      string
+		basename string
+	}{
+		{
+			dir:      "",
+			basename: "BUILD",
+		},
+		{
+			dir:      "",
+			basename: "WORKSPACE",
+		},
+		{
+			dir:      bazelRulesSubDir,
+			basename: "BUILD",
+		},
+		{
+			dir:      bazelRulesSubDir,
+			basename: "providers.bzl",
+		},
+		{
+			dir:      bazelRulesSubDir,
+			basename: "soong_module.bzl",
+		},
+	}
+
+	if g, w := len(files), len(expectedFilePaths); g != w {
+		t.Errorf("Expected %d files, got %d", w, g)
+	}
+
+	sort.Slice(files, func(i, j int) bool {
+		if dir1, dir2 := files[i].Dir, files[j].Dir; dir1 == dir2 {
+			return files[i].Basename < files[j].Basename
+		} else {
+			return dir1 < dir2
+		}
+	})
+
+	for i := range files {
+		if g, w := files[i], expectedFilePaths[i]; g.Dir != w.dir || g.Basename != w.basename {
+			t.Errorf("Did not find expected file %s/%s", g.Dir, g.Basename)
+		} else if g.Basename == "BUILD" || g.Basename == "WORKSPACE" {
+			if g.Contents != "" {
+				t.Errorf("Expected %s to have no content.", g)
+			}
+		} else if g.Contents == "" {
+			t.Errorf("Contents of %s unexpected empty.", g)
+		}
+	}
+}
diff --git a/bp2build/testing.go b/bp2build/testing.go
new file mode 100644
index 0000000..160412d
--- /dev/null
+++ b/bp2build/testing.go
@@ -0,0 +1,136 @@
+package bp2build
+
+import (
+	"android/soong/android"
+
+	"github.com/google/blueprint"
+)
+
+type nestedProps struct {
+	Nested_prop string
+}
+
+type customProps struct {
+	Bool_prop     bool
+	Bool_ptr_prop *bool
+	// Ensure that properties tagged `blueprint:mutated` are omitted
+	Int_prop         int `blueprint:"mutated"`
+	Int64_ptr_prop   *int64
+	String_prop      string
+	String_ptr_prop  *string
+	String_list_prop []string
+
+	Nested_props     nestedProps
+	Nested_props_ptr *nestedProps
+}
+
+type customModule struct {
+	android.ModuleBase
+
+	props customProps
+}
+
+// OutputFiles is needed because some instances of this module use dist with a
+// tag property which requires the module implements OutputFileProducer.
+func (m *customModule) OutputFiles(tag string) (android.Paths, error) {
+	return android.PathsForTesting("path" + tag), nil
+}
+
+func (m *customModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// nothing for now.
+}
+
+func customModuleFactoryBase() android.Module {
+	module := &customModule{}
+	module.AddProperties(&module.props)
+	return module
+}
+
+func customModuleFactory() android.Module {
+	m := customModuleFactoryBase()
+	android.InitAndroidModule(m)
+	return m
+}
+
+type testProps struct {
+	Test_prop struct {
+		Test_string_prop string
+	}
+}
+
+type customTestModule struct {
+	android.ModuleBase
+
+	props      customProps
+	test_props testProps
+}
+
+func (m *customTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// nothing for now.
+}
+
+func customTestModuleFactoryBase() android.Module {
+	m := &customTestModule{}
+	m.AddProperties(&m.props)
+	m.AddProperties(&m.test_props)
+	return m
+}
+
+func customTestModuleFactory() android.Module {
+	m := customTestModuleFactoryBase()
+	android.InitAndroidModule(m)
+	return m
+}
+
+type customDefaultsModule struct {
+	android.ModuleBase
+	android.DefaultsModuleBase
+}
+
+func customDefaultsModuleFactoryBase() android.DefaultsModule {
+	module := &customDefaultsModule{}
+	module.AddProperties(&customProps{})
+	return module
+}
+
+func customDefaultsModuleFactoryBasic() android.Module {
+	return customDefaultsModuleFactoryBase()
+}
+
+func customDefaultsModuleFactory() android.Module {
+	m := customDefaultsModuleFactoryBase()
+	android.InitDefaultsModule(m)
+	return m
+}
+
+type bp2buildBlueprintWrapContext struct {
+	bpCtx *blueprint.Context
+}
+
+func (ctx *bp2buildBlueprintWrapContext) ModuleName(module blueprint.Module) string {
+	return ctx.bpCtx.ModuleName(module)
+}
+
+func (ctx *bp2buildBlueprintWrapContext) ModuleDir(module blueprint.Module) string {
+	return ctx.bpCtx.ModuleDir(module)
+}
+
+func (ctx *bp2buildBlueprintWrapContext) ModuleSubDir(module blueprint.Module) string {
+	return ctx.bpCtx.ModuleSubDir(module)
+}
+
+func (ctx *bp2buildBlueprintWrapContext) ModuleType(module blueprint.Module) string {
+	return ctx.bpCtx.ModuleType(module)
+}
+
+func (ctx *bp2buildBlueprintWrapContext) VisitAllModulesBlueprint(visit func(blueprint.Module)) {
+	ctx.bpCtx.VisitAllModules(visit)
+}
+
+func (ctx *bp2buildBlueprintWrapContext) VisitDirectDeps(module android.Module, visit func(android.Module)) {
+	ctx.bpCtx.VisitDirectDeps(module, func(m blueprint.Module) {
+		if aModule, ok := m.(android.Module); ok {
+			visit(aModule)
+		}
+	})
+}
diff --git a/cc/cc.go b/cc/cc.go
index c0c85f9..7fa3840 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -420,6 +420,7 @@
 type ModuleContextIntf interface {
 	static() bool
 	staticBinary() bool
+	testBinary() bool
 	header() bool
 	binary() bool
 	object() bool
@@ -455,6 +456,7 @@
 	nativeCoverage() bool
 	directlyInAnyApex() bool
 	isPreventInstall() bool
+	isCfiAssemblySupportEnabled() bool
 }
 
 type ModuleContext interface {
@@ -1229,6 +1231,11 @@
 	return c.kytheFiles
 }
 
+func (c *Module) isCfiAssemblySupportEnabled() bool {
+	return c.sanitize != nil &&
+		Bool(c.sanitize.Properties.Sanitize.Config.Cfi_assembly_support)
+}
+
 type baseModuleContext struct {
 	android.BaseModuleContext
 	moduleContextImpl
@@ -1261,6 +1268,10 @@
 	return ctx.mod.staticBinary()
 }
 
+func (ctx *moduleContextImpl) testBinary() bool {
+	return ctx.mod.testBinary()
+}
+
 func (ctx *moduleContextImpl) header() bool {
 	return ctx.mod.Header()
 }
@@ -1390,6 +1401,10 @@
 	return ctx.mod.Properties.PreventInstall
 }
 
+func (ctx *moduleContextImpl) isCfiAssemblySupportEnabled() bool {
+	return ctx.mod.isCfiAssemblySupportEnabled()
+}
+
 func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
 	return &Module{
 		hod:      hod,
@@ -2961,6 +2976,15 @@
 	return false
 }
 
+func (c *Module) testBinary() bool {
+	if test, ok := c.linker.(interface {
+		testBinary() bool
+	}); ok {
+		return test.testBinary()
+	}
+	return false
+}
+
 // Header returns true if the module is a header-only variant. (See cc/library.go header()).
 func (c *Module) Header() bool {
 	if h, ok := c.linker.(interface {
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 3502d5f..3399e93 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -738,12 +738,29 @@
 			},
 			nocrt: true,
 		}
+
+		cc_library {
+			name: "libllndk",
+			llndk_stubs: "libllndk.llndk",
+		}
+
+		llndk_library {
+			name: "libllndk.llndk",
+			symbol_file: "",
+			export_llndk_headers: ["libllndk_headers"],
+		}
+
+		llndk_headers {
+			name: "libllndk_headers",
+			export_include_dirs: ["include"],
+		}
 	`)
 
 	checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{
 		"LLNDK: libc.so",
 		"LLNDK: libdl.so",
 		"LLNDK: libft2.so",
+		"LLNDK: libllndk.so",
 		"LLNDK: libm.so",
 		"VNDK-SP: libc++.so",
 		"VNDK-core: libvndk-private.so",
@@ -4461,3 +4478,138 @@
 		t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
 	}
 }
+
+func checkHasImplicitDep(t *testing.T, m android.TestingModule, name string) {
+	implicits := m.Rule("ld").Implicits
+	for _, lib := range implicits {
+		if strings.Contains(lib.Rel(), name) {
+			return
+		}
+	}
+
+	t.Errorf("%q is not found in implicit deps of module %q", name, m.Module().(*Module).Name())
+}
+
+func checkDoesNotHaveImplicitDep(t *testing.T, m android.TestingModule, name string) {
+	implicits := m.Rule("ld").Implicits
+	for _, lib := range implicits {
+		if strings.Contains(lib.Rel(), name) {
+			t.Errorf("%q is found in implicit deps of module %q", name, m.Module().(*Module).Name())
+		}
+	}
+}
+
+func TestSanitizeMemtagHeap(t *testing.T) {
+	rootBp := `
+		cc_library_static {
+			name: "libstatic",
+			sanitize: { memtag_heap: true },
+		}
+
+		cc_library_shared {
+			name: "libshared",
+			sanitize: { memtag_heap: true },
+		}
+
+		cc_library {
+			name: "libboth",
+			sanitize: { memtag_heap: true },
+		}
+
+		cc_binary {
+			name: "binary",
+			shared_libs: [ "libshared" ],
+			static_libs: [ "libstatic" ],
+		}
+
+		cc_binary {
+			name: "binary_true",
+			sanitize: { memtag_heap: true },
+		}
+
+		cc_binary {
+			name: "binary_true_sync",
+			sanitize: { memtag_heap: true, diag: { memtag_heap: true }, },
+		}
+
+		cc_binary {
+			name: "binary_false",
+			sanitize: { memtag_heap: false },
+		}
+
+		cc_test {
+			name: "test",
+			gtest: false,
+		}
+
+		cc_test {
+			name: "test_true",
+			gtest: false,
+			sanitize: { memtag_heap: true },
+		}
+
+		cc_test {
+			name: "test_false",
+			gtest: false,
+			sanitize: { memtag_heap: false },
+		}
+
+		cc_test {
+			name: "test_true_async",
+			gtest: false,
+			sanitize: { memtag_heap: true, diag: { memtag_heap: false }  },
+		}
+
+		`
+
+	subdirAsyncBp := `
+		cc_binary {
+			name: "binary_async",
+		}
+		`
+
+	subdirSyncBp := `
+		cc_binary {
+			name: "binary_sync",
+		}
+		`
+
+	mockFS := map[string][]byte{
+		"subdir_async/Android.bp": []byte(subdirAsyncBp),
+		"subdir_sync/Android.bp":  []byte(subdirSyncBp),
+	}
+
+	config := TestConfig(buildDir, android.Android, nil, rootBp, mockFS)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.MemtagHeapAsyncIncludePaths = []string{"subdir_async"}
+	config.TestProductVariables.MemtagHeapSyncIncludePaths = []string{"subdir_sync"}
+	ctx := CreateTestContext(config)
+	ctx.Register()
+
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp", "subdir_sync/Android.bp", "subdir_async/Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+
+	variant := "android_arm64_armv8-a"
+	note_async := "note_memtag_heap_async"
+	note_sync := "note_memtag_heap_sync"
+	note_any := "note_memtag_"
+
+	checkDoesNotHaveImplicitDep(t, ctx.ModuleForTests("libshared", "android_arm64_armv8-a_shared"), note_any)
+	checkDoesNotHaveImplicitDep(t, ctx.ModuleForTests("libboth", "android_arm64_armv8-a_shared"), note_any)
+
+	checkDoesNotHaveImplicitDep(t, ctx.ModuleForTests("binary", variant), note_any)
+	checkHasImplicitDep(t, ctx.ModuleForTests("binary_true", variant), note_async)
+	checkHasImplicitDep(t, ctx.ModuleForTests("binary_true_sync", variant), note_sync)
+	checkDoesNotHaveImplicitDep(t, ctx.ModuleForTests("binary_false", variant), note_any)
+
+	checkHasImplicitDep(t, ctx.ModuleForTests("test", variant), note_sync)
+	checkHasImplicitDep(t, ctx.ModuleForTests("test_true", variant), note_async)
+	checkDoesNotHaveImplicitDep(t, ctx.ModuleForTests("test_false", variant), note_any)
+	checkHasImplicitDep(t, ctx.ModuleForTests("test_true_async", variant), note_async)
+
+	checkHasImplicitDep(t, ctx.ModuleForTests("binary_async", variant), note_async)
+	checkHasImplicitDep(t, ctx.ModuleForTests("binary_sync", variant), note_sync)
+}
diff --git a/cc/config/global.go b/cc/config/global.go
index fa8e0fb..d47e0ce 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -215,10 +215,6 @@
 			"frameworks/native/opengl/include",
 			"frameworks/av/include",
 		})
-	// This is used by non-NDK modules to get jni.h. export_include_dirs doesn't help
-	// with this, since there is no associated library.
-	pctx.PrefixedExistentPathsForSourcesVariable("CommonNativehelperInclude", "-I",
-		[]string{"libnativehelper/include_jni"})
 
 	pctx.SourcePathVariable("ClangDefaultBase", ClangDefaultBase)
 	pctx.VariableFunc("ClangBase", func(ctx android.PackageVarContext) string {
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index 4ac9e58..0df17bc 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -21,23 +21,28 @@
 
 func init() {
 	// Most Android source files are not clang-tidy clean yet.
-	// Global tidy checks include only google*, performance*,
-	// and misc-macro-parentheses, but not google-readability*
-	// or google-runtime-references.
+	// Default global tidy checks must exclude all checks that
+	// have found too many warnings.
 	pctx.VariableFunc("TidyDefaultGlobalChecks", func(ctx android.PackageVarContext) string {
 		if override := ctx.Config().Getenv("DEFAULT_GLOBAL_TIDY_CHECKS"); override != "" {
 			return override
 		}
 		return strings.Join([]string{
-			"-*",
-			"bugprone*",
-			"clang-diagnostic-unused-command-line-argument",
-			"google*",
-			"misc-macro-parentheses",
-			"performance*",
+			"*",
+			"-altera-*",
 			"-bugprone-narrowing-conversions",
-			"-google-readability*",
+			"-cppcoreguidelines-*",
+			"-fuchsia-*",
+			"-google-readability-*",
 			"-google-runtime-references",
+			"-hicpp-*",
+			"-llvm-*",
+			"-llvmlibc-*",
+			"-misc-no-recursion",
+			"-misc-non-private-member-variables-in-classes",
+			"-misc-unused-parameters",
+			"-modernize-*",
+			"-readability-*",
 		}, ",")
 	})
 
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index 91956ae..53600ba 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -18,6 +18,7 @@
 // For these libraries, the vendor variants must be installed even if the device
 // has VndkUseCoreVariant set.
 var VndkMustUseVendorVariantList = []string{
+	"android.hardware.authsecret-unstable-ndk_platform",
 	"android.hardware.automotive.occupant_awareness-ndk_platform",
 	"android.hardware.gnss-unstable-ndk_platform",
 	"android.hardware.light-ndk_platform",
diff --git a/cc/coverage.go b/cc/coverage.go
index acf98dd..5b5ccf2 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -58,6 +58,8 @@
 func getClangProfileLibraryName(ctx ModuleContextIntf) string {
 	if ctx.useSdk() {
 		return "libprofile-clang-extras_ndk"
+	} else if ctx.isCfiAssemblySupportEnabled() {
+		return "libprofile-clang-extras_cfi_support"
 	} else {
 		return "libprofile-clang-extras"
 	}
diff --git a/cc/image.go b/cc/image.go
index 13095fc..f89194f 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -264,31 +264,34 @@
 		productVndkVersion = platformVndkVersion
 	}
 
-	if boardVndkVersion == "" {
+	_, isLLNDKLibrary := m.linker.(*llndkStubDecorator)
+	_, isLLNDKHeaders := m.linker.(*llndkHeadersDecorator)
+	lib := moduleLibraryInterface(m)
+	hasLLNDKStubs := lib != nil && lib.hasLLNDKStubs()
+
+	if isLLNDKLibrary || isLLNDKHeaders || hasLLNDKStubs {
+		// This is an LLNDK library.  The implementation of the library will be on /system,
+		// and vendor and product variants will be created with LLNDK stubs.
+		// The LLNDK libraries need vendor variants even if there is no VNDK.
+		// The obsolete llndk_library and llndk_headers modules also need the vendor variants
+		// so the cc_library LLNDK stubs can depend on them.
+		if hasLLNDKStubs {
+			coreVariantNeeded = true
+		}
+		if platformVndkVersion != "" {
+			vendorVariants = append(vendorVariants, platformVndkVersion)
+			productVariants = append(productVariants, platformVndkVersion)
+		}
+		if boardVndkVersion != "" {
+			vendorVariants = append(vendorVariants, boardVndkVersion)
+		}
+		if productVndkVersion != "" {
+			productVariants = append(productVariants, productVndkVersion)
+		}
+	} else if boardVndkVersion == "" {
 		// If the device isn't compiling against the VNDK, we always
 		// use the core mode.
 		coreVariantNeeded = true
-	} else if _, ok := m.linker.(*llndkStubDecorator); ok {
-		// LL-NDK stubs only exist in the vendor and product variants,
-		// since the real libraries will be used in the core variant.
-		vendorVariants = append(vendorVariants,
-			platformVndkVersion,
-			boardVndkVersion,
-		)
-		productVariants = append(productVariants,
-			platformVndkVersion,
-			productVndkVersion,
-		)
-	} else if _, ok := m.linker.(*llndkHeadersDecorator); ok {
-		// ... and LL-NDK headers as well
-		vendorVariants = append(vendorVariants,
-			platformVndkVersion,
-			boardVndkVersion,
-		)
-		productVariants = append(productVariants,
-			platformVndkVersion,
-			productVndkVersion,
-		)
 	} else if m.isSnapshotPrebuilt() {
 		// Make vendor variants only for the versions in BOARD_VNDK_VERSION and
 		// PRODUCT_EXTRA_VNDK_VERSIONS.
@@ -346,18 +349,6 @@
 		} else {
 			vendorVariants = append(vendorVariants, platformVndkVersion)
 		}
-	} else if lib := moduleLibraryInterface(m); lib != nil && lib.hasLLNDKStubs() {
-		// This is an LLNDK library.  The implementation of the library will be on /system,
-		// and vendor and product variants will be created with LLNDK stubs.
-		coreVariantNeeded = true
-		vendorVariants = append(vendorVariants,
-			platformVndkVersion,
-			boardVndkVersion,
-		)
-		productVariants = append(productVariants,
-			platformVndkVersion,
-			productVndkVersion,
-		)
 	} else {
 		// This is either in /system (or similar: /data), or is a
 		// modules built with the NDK. Modules built with the NDK
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index bd48501..a46b31c 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -161,6 +161,13 @@
 	*libraryDecorator
 }
 
+func (llndk *llndkHeadersDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
+	deps.HeaderLibs = append(deps.HeaderLibs, llndk.Properties.Llndk.Export_llndk_headers...)
+	deps.ReexportHeaderLibHeaders = append(deps.ReexportHeaderLibHeaders,
+		llndk.Properties.Llndk.Export_llndk_headers...)
+	return deps
+}
+
 // llndk_headers contains a set of c/c++ llndk headers files which are imported
 // by other soongs cc modules.
 func llndkHeadersFactory() android.Module {
@@ -178,11 +185,6 @@
 	module.installer = nil
 	module.library = decorator
 
-	module.AddProperties(
-		&module.Properties,
-		&library.MutatedProperties,
-		&library.flagExporter.Properties)
-
 	module.Init()
 
 	return module
diff --git a/cc/makevars.go b/cc/makevars.go
index 8301c6b..48d5636 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -154,16 +154,6 @@
 	ctx.Strict("SOONG_STRIP_PATH", "${stripPath}")
 	ctx.Strict("XZ", "${xzCmd}")
 
-	nativeHelperIncludeFlags, err := ctx.Eval("${config.CommonNativehelperInclude}")
-	if err != nil {
-		panic(err)
-	}
-	nativeHelperIncludes, nativeHelperSystemIncludes := splitSystemIncludes(ctx, nativeHelperIncludeFlags)
-	if len(nativeHelperSystemIncludes) > 0 {
-		panic("native helper may not have any system includes")
-	}
-	ctx.Strict("JNI_H_INCLUDE", strings.Join(nativeHelperIncludes, " "))
-
 	includeFlags, err := ctx.Eval("${config.CommonGlobalIncludes}")
 	if err != nil {
 		panic(err)
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 5992611..af17490 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -89,6 +89,7 @@
 	cfi
 	scs
 	Fuzzer
+	memtag_heap
 )
 
 // Name of the sanitizer variation for this sanitizer type
@@ -106,6 +107,8 @@
 		return "cfi"
 	case scs:
 		return "scs"
+	case memtag_heap:
+		return "memtag_heap"
 	case Fuzzer:
 		return "fuzzer"
 	default:
@@ -120,6 +123,8 @@
 		return "address"
 	case hwasan:
 		return "hwaddress"
+	case memtag_heap:
+		return "memtag_heap"
 	case tsan:
 		return "thread"
 	case intOverflow:
@@ -179,6 +184,7 @@
 	Integer_overflow *bool    `android:"arch_variant"`
 	Scudo            *bool    `android:"arch_variant"`
 	Scs              *bool    `android:"arch_variant"`
+	Memtag_heap      *bool    `android:"arch_variant"`
 
 	// A modifier for ASAN and HWASAN for write only instrumentation
 	Writeonly *bool `android:"arch_variant"`
@@ -190,6 +196,7 @@
 		Undefined        *bool    `android:"arch_variant"`
 		Cfi              *bool    `android:"arch_variant"`
 		Integer_overflow *bool    `android:"arch_variant"`
+		Memtag_heap      *bool    `android:"arch_variant"`
 		Misc_undefined   []string `android:"arch_variant"`
 		No_recover       []string `android:"arch_variant"`
 	} `android:"arch_variant"`
@@ -330,6 +337,11 @@
 			}
 			s.Writeonly = boolPtr(true)
 		}
+		if found, globalSanitizers = removeFromList("memtag_heap", globalSanitizers); found && s.Memtag_heap == nil {
+			if !ctx.Config().MemtagHeapDisabledForPath(ctx.ModuleDir()) {
+				s.Memtag_heap = boolPtr(true)
+			}
+		}
 
 		if len(globalSanitizers) > 0 {
 			ctx.ModuleErrorf("unknown global sanitizer option %s", globalSanitizers[0])
@@ -351,6 +363,25 @@
 		}
 	}
 
+	// cc_test targets default to SYNC MemTag.
+	if ctx.testBinary() && s.Memtag_heap == nil {
+		if !ctx.Config().MemtagHeapDisabledForPath(ctx.ModuleDir()) {
+			s.Memtag_heap = boolPtr(true)
+			s.Diag.Memtag_heap = boolPtr(true)
+		}
+	}
+
+	// Enable Memtag for all components in the include paths (for Aarch64 only)
+	if s.Memtag_heap == nil && ctx.Arch().ArchType == android.Arm64 {
+		if ctx.Config().MemtagHeapSyncEnabledForPath(ctx.ModuleDir()) {
+			s.Memtag_heap = boolPtr(true)
+			s.Diag.Memtag_heap = boolPtr(true)
+		} else if ctx.Config().MemtagHeapAsyncEnabledForPath(ctx.ModuleDir()) {
+			s.Memtag_heap = boolPtr(true)
+			s.Diag.Memtag_heap = boolPtr(false)
+		}
+	}
+
 	// Enable CFI for all components in the include paths (for Aarch64 only)
 	if s.Cfi == nil && ctx.Config().CFIEnabledForPath(ctx.ModuleDir()) && ctx.Arch().ArchType == android.Arm64 {
 		s.Cfi = boolPtr(true)
@@ -381,6 +412,11 @@
 		s.Scs = nil
 	}
 
+	// memtag_heap is only implemented on AArch64.
+	if ctx.Arch().ArchType != android.Arm64 {
+		s.Memtag_heap = nil
+	}
+
 	// Also disable CFI if ASAN is enabled.
 	if Bool(s.Address) || Bool(s.Hwaddress) {
 		s.Cfi = boolPtr(false)
@@ -435,7 +471,7 @@
 
 	if ctx.Os() != android.Windows && (Bool(s.All_undefined) || Bool(s.Undefined) || Bool(s.Address) || Bool(s.Thread) ||
 		Bool(s.Fuzzer) || Bool(s.Safestack) || Bool(s.Cfi) || Bool(s.Integer_overflow) || len(s.Misc_undefined) > 0 ||
-		Bool(s.Scudo) || Bool(s.Hwaddress) || Bool(s.Scs)) {
+		Bool(s.Scudo) || Bool(s.Hwaddress) || Bool(s.Scs) || Bool(s.Memtag_heap)) {
 		sanitize.Properties.SanitizerEnabled = true
 	}
 
@@ -717,6 +753,8 @@
 		return sanitize.Properties.Sanitize.Cfi
 	case scs:
 		return sanitize.Properties.Sanitize.Scs
+	case memtag_heap:
+		return sanitize.Properties.Sanitize.Memtag_heap
 	case Fuzzer:
 		return sanitize.Properties.Sanitize.Fuzzer
 	default:
@@ -731,6 +769,7 @@
 		!sanitize.isSanitizerEnabled(tsan) &&
 		!sanitize.isSanitizerEnabled(cfi) &&
 		!sanitize.isSanitizerEnabled(scs) &&
+		!sanitize.isSanitizerEnabled(memtag_heap) &&
 		!sanitize.isSanitizerEnabled(Fuzzer)
 }
 
@@ -756,6 +795,8 @@
 		sanitize.Properties.Sanitize.Cfi = boolPtr(b)
 	case scs:
 		sanitize.Properties.Sanitize.Scs = boolPtr(b)
+	case memtag_heap:
+		sanitize.Properties.Sanitize.Memtag_heap = boolPtr(b)
 	case Fuzzer:
 		sanitize.Properties.Sanitize.Fuzzer = boolPtr(b)
 	default:
@@ -1032,6 +1073,20 @@
 			sanitizers = append(sanitizers, "shadow-call-stack")
 		}
 
+		if Bool(c.sanitize.Properties.Sanitize.Memtag_heap) && c.binary() {
+			noteDep := "note_memtag_heap_async"
+			if Bool(c.sanitize.Properties.Sanitize.Diag.Memtag_heap) {
+				noteDep = "note_memtag_heap_sync"
+			}
+			depTag := libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: true}
+			variations := append(mctx.Target().Variations(),
+				blueprint.Variation{Mutator: "link", Variation: "static"})
+			if c.Device() {
+				variations = append(variations, c.ImageVariation())
+			}
+			mctx.AddFarVariationDependencies(variations, depTag, noteDep)
+		}
+
 		if Bool(c.sanitize.Properties.Sanitize.Fuzzer) {
 			sanitizers = append(sanitizers, "fuzzer-no-link")
 		}
diff --git a/cc/test.go b/cc/test.go
index 4ff5bf6..f715a8d 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -236,6 +236,10 @@
 	return BoolDefault(test.Properties.Gtest, true)
 }
 
+func (test *testDecorator) testBinary() bool {
+	return true
+}
+
 func (test *testDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
 	if !test.gtest() {
 		return flags
diff --git a/cc/testing.go b/cc/testing.go
index 8d92ea2..903f76c 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -445,6 +445,14 @@
 			stl: "none",
 			system_shared_libs: [],
 		}
+
+		cc_library_static {
+			name: "note_memtag_heap_async",
+		}
+
+		cc_library_static {
+			name: "note_memtag_heap_sync",
+		}
 	`
 
 	supportLinuxBionic := false
diff --git a/cmd/soong_build/Android.bp b/cmd/soong_build/Android.bp
index 441ea0d..6714978 100644
--- a/cmd/soong_build/Android.bp
+++ b/cmd/soong_build/Android.bp
@@ -20,6 +20,7 @@
         "golang-protobuf-proto",
         "soong",
         "soong-android",
+        "soong-bp2build",
         "soong-env",
         "soong-ui-metrics_proto",
     ],
@@ -27,10 +28,6 @@
         "main.go",
         "writedocs.go",
         "queryview.go",
-        "queryview_templates.go",
-    ],
-    testSrcs: [
-        "queryview_test.go",
     ],
     primaryBuilder: true,
 }
diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go
index f5aa685..3657ea8 100644
--- a/cmd/soong_build/queryview.go
+++ b/cmd/soong_build/queryview.go
@@ -16,512 +16,82 @@
 
 import (
 	"android/soong/android"
-	"fmt"
+	"android/soong/bp2build"
 	"io/ioutil"
 	"os"
 	"path/filepath"
-	"reflect"
-	"strings"
 
 	"github.com/google/blueprint"
-	"github.com/google/blueprint/bootstrap/bpdoc"
-	"github.com/google/blueprint/proptools"
 )
 
-var (
-	// An allowlist of prop types that are surfaced from module props to rule
-	// attributes. (nested) dictionaries are notably absent here, because while
-	// Soong supports multi value typed and nested dictionaries, Bazel's rule
-	// attr() API supports only single-level string_dicts.
-	allowedPropTypes = map[string]bool{
-		"int":         true, // e.g. 42
-		"bool":        true, // e.g. True
-		"string_list": true, // e.g. ["a", "b"]
-		"string":      true, // e.g. "a"
-	}
-
-	// Certain module property names are blocklisted/ignored here, for the reasons commented.
-	ignoredPropNames = map[string]bool{
-		"name":       true, // redundant, since this is explicitly generated for every target
-		"from":       true, // reserved keyword
-		"in":         true, // reserved keyword
-		"arch":       true, // interface prop type is not supported yet.
-		"multilib":   true, // interface prop type is not supported yet.
-		"target":     true, // interface prop type is not supported yet.
-		"visibility": true, // Bazel has native visibility semantics. Handle later.
-		"features":   true, // There is already a built-in attribute 'features' which cannot be overridden.
-	}
-)
-
-func targetNameWithVariant(c *blueprint.Context, logicModule blueprint.Module) string {
-	name := ""
-	if c.ModuleSubDir(logicModule) != "" {
-		// TODO(b/162720883): Figure out a way to drop the "--" variant suffixes.
-		name = c.ModuleName(logicModule) + "--" + c.ModuleSubDir(logicModule)
-	} else {
-		name = c.ModuleName(logicModule)
-	}
-
-	return strings.Replace(name, "//", "", 1)
+type queryviewContext struct {
+	bpCtx *blueprint.Context
 }
 
-func qualifiedTargetLabel(c *blueprint.Context, logicModule blueprint.Module) string {
-	return "//" +
-		packagePath(c, logicModule) +
-		":" +
-		targetNameWithVariant(c, logicModule)
+func (ctx *queryviewContext) ModuleName(module blueprint.Module) string {
+	return ctx.bpCtx.ModuleName(module)
 }
 
-func packagePath(c *blueprint.Context, logicModule blueprint.Module) string {
-	return filepath.Dir(c.BlueprintFile(logicModule))
+func (ctx *queryviewContext) ModuleDir(module blueprint.Module) string {
+	return ctx.bpCtx.ModuleDir(module)
 }
 
-func escapeString(s string) string {
-	s = strings.ReplaceAll(s, "\\", "\\\\")
-	return strings.ReplaceAll(s, "\"", "\\\"")
+func (ctx *queryviewContext) ModuleSubDir(module blueprint.Module) string {
+	return ctx.bpCtx.ModuleSubDir(module)
 }
 
-func makeIndent(indent int) string {
-	if indent < 0 {
-		panic(fmt.Errorf("indent column cannot be less than 0, but got %d", indent))
-	}
-	return strings.Repeat("    ", indent)
+func (ctx *queryviewContext) ModuleType(module blueprint.Module) string {
+	return ctx.bpCtx.ModuleType(module)
 }
 
-// prettyPrint a property value into the equivalent Starlark representation
-// recursively.
-func prettyPrint(propertyValue reflect.Value, indent int) (string, error) {
-	if isZero(propertyValue) {
-		// A property value being set or unset actually matters -- Soong does set default
-		// values for unset properties, like system_shared_libs = ["libc", "libm", "libdl"] at
-		// https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=281-287;drc=f70926eef0b9b57faf04c17a1062ce50d209e480
-		//
-		// In Bazel-parlance, we would use "attr.<type>(default = <default value>)" to set the default
-		// value of unset attributes.
-		return "", nil
-	}
-
-	var ret string
-	switch propertyValue.Kind() {
-	case reflect.String:
-		ret = fmt.Sprintf("\"%v\"", escapeString(propertyValue.String()))
-	case reflect.Bool:
-		ret = strings.Title(fmt.Sprintf("%v", propertyValue.Interface()))
-	case reflect.Int, reflect.Uint, reflect.Int64:
-		ret = fmt.Sprintf("%v", propertyValue.Interface())
-	case reflect.Ptr:
-		return prettyPrint(propertyValue.Elem(), indent)
-	case reflect.Slice:
-		ret = "[\n"
-		for i := 0; i < propertyValue.Len(); i++ {
-			indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1)
-			if err != nil {
-				return "", err
-			}
-
-			if indexedValue != "" {
-				ret += makeIndent(indent + 1)
-				ret += indexedValue
-				ret += ",\n"
-			}
-		}
-		ret += makeIndent(indent)
-		ret += "]"
-	case reflect.Struct:
-		ret = "{\n"
-		// Sort and print the struct props by the key.
-		structProps := extractStructProperties(propertyValue, indent)
-		for _, k := range android.SortedStringKeys(structProps) {
-			ret += makeIndent(indent + 1)
-			ret += fmt.Sprintf("%q: %s,\n", k, structProps[k])
-		}
-		ret += makeIndent(indent)
-		ret += "}"
-	case reflect.Interface:
-		// TODO(b/164227191): implement pretty print for interfaces.
-		// Interfaces are used for for arch, multilib and target properties.
-		return "", nil
-	default:
-		return "", fmt.Errorf(
-			"unexpected kind for property struct field: %s", propertyValue.Kind())
-	}
-	return ret, nil
+func (ctx *queryviewContext) VisitAllModulesBlueprint(visit func(blueprint.Module)) {
+	ctx.bpCtx.VisitAllModules(visit)
 }
 
-// Converts a reflected property struct value into a map of property names and property values,
-// which each property value correctly pretty-printed and indented at the right nest level,
-// since property structs can be nested. In Starlark, nested structs are represented as nested
-// dicts: https://docs.bazel.build/skylark/lib/dict.html
-func extractStructProperties(structValue reflect.Value, indent int) map[string]string {
-	if structValue.Kind() != reflect.Struct {
-		panic(fmt.Errorf("Expected a reflect.Struct type, but got %s", structValue.Kind()))
-	}
-
-	ret := map[string]string{}
-	structType := structValue.Type()
-	for i := 0; i < structValue.NumField(); i++ {
-		field := structType.Field(i)
-		if field.PkgPath != "" {
-			// Skip unexported fields. Some properties are
-			// internal to Soong only, and these fields do not have PkgPath.
-			continue
+func (ctx *queryviewContext) VisitDirectDeps(module android.Module, visit func(android.Module)) {
+	ctx.bpCtx.VisitDirectDeps(module, func(m blueprint.Module) {
+		if aModule, ok := m.(android.Module); ok {
+			visit(aModule)
 		}
-		if proptools.HasTag(field, "blueprint", "mutated") {
-			continue
-		}
-
-		fieldValue := structValue.Field(i)
-		if isZero(fieldValue) {
-			// Ignore zero-valued fields
-			continue
-		}
-
-		propertyName := proptools.PropertyNameForField(field.Name)
-		prettyPrintedValue, err := prettyPrint(fieldValue, indent+1)
-		if err != nil {
-			panic(
-				fmt.Errorf(
-					"Error while parsing property: %q. %s",
-					propertyName,
-					err))
-		}
-		if prettyPrintedValue != "" {
-			ret[propertyName] = prettyPrintedValue
-		}
-	}
-
-	return ret
-}
-
-func isStructPtr(t reflect.Type) bool {
-	return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
-}
-
-// Generically extract module properties and types into a map, keyed by the module property name.
-func extractModuleProperties(aModule android.Module) map[string]string {
-	ret := map[string]string{}
-
-	// Iterate over this android.Module's property structs.
-	for _, properties := range aModule.GetProperties() {
-		propertiesValue := reflect.ValueOf(properties)
-		// Check that propertiesValue is a pointer to the Properties struct, like
-		// *cc.BaseLinkerProperties or *java.CompilerProperties.
-		//
-		// propertiesValue can also be type-asserted to the structs to
-		// manipulate internal props, if needed.
-		if isStructPtr(propertiesValue.Type()) {
-			structValue := propertiesValue.Elem()
-			for k, v := range extractStructProperties(structValue, 0) {
-				ret[k] = v
-			}
-		} else {
-			panic(fmt.Errorf(
-				"properties must be a pointer to a struct, got %T",
-				propertiesValue.Interface()))
-		}
-
-	}
-
-	return ret
-}
-
-// FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as
-// testonly = True, forcing other rules that depend on _test rules to also be
-// marked as testonly = True. This semantic constraint is not present in Soong.
-// To work around, rename "*_test" rules to "*_test_".
-func canonicalizeModuleType(moduleName string) string {
-	if strings.HasSuffix(moduleName, "_test") {
-		return moduleName + "_"
-	}
-
-	return moduleName
-}
-
-type RuleShim struct {
-	// The rule class shims contained in a bzl file. e.g. ["cc_object", "cc_library", ..]
-	rules []string
-
-	// The generated string content of the bzl file.
-	content string
-}
-
-// Create <module>.bzl containing Bazel rule shims for every module type available in Soong and
-// user-specified Go plugins.
-//
-// This function reuses documentation generation APIs to ensure parity between modules-as-docs
-// and modules-as-code, including the names and types of module properties.
-func createRuleShims(packages []*bpdoc.Package) (map[string]RuleShim, error) {
-	var propToAttr func(prop bpdoc.Property, propName string) string
-	propToAttr = func(prop bpdoc.Property, propName string) string {
-		// dots are not allowed in Starlark attribute names. Substitute them with double underscores.
-		propName = strings.ReplaceAll(propName, ".", "__")
-		if !shouldGenerateAttribute(propName) {
-			return ""
-		}
-
-		// Canonicalize and normalize module property types to Bazel attribute types
-		starlarkAttrType := prop.Type
-		if starlarkAttrType == "list of string" {
-			starlarkAttrType = "string_list"
-		} else if starlarkAttrType == "int64" {
-			starlarkAttrType = "int"
-		} else if starlarkAttrType == "" {
-			var attr string
-			for _, nestedProp := range prop.Properties {
-				nestedAttr := propToAttr(nestedProp, propName+"__"+nestedProp.Name)
-				if nestedAttr != "" {
-					// TODO(b/167662930): Fix nested props resulting in too many attributes.
-					// Let's still generate these, but comment them out.
-					attr += "# " + nestedAttr
-				}
-			}
-			return attr
-		}
-
-		if !allowedPropTypes[starlarkAttrType] {
-			return ""
-		}
-
-		return fmt.Sprintf("        %q: attr.%s(),\n", propName, starlarkAttrType)
-	}
-
-	ruleShims := map[string]RuleShim{}
-	for _, pkg := range packages {
-		content := "load(\"//build/bazel/queryview_rules:providers.bzl\", \"SoongModuleInfo\")\n"
-
-		bzlFileName := strings.ReplaceAll(pkg.Path, "android/soong/", "")
-		bzlFileName = strings.ReplaceAll(bzlFileName, ".", "_")
-		bzlFileName = strings.ReplaceAll(bzlFileName, "/", "_")
-
-		rules := []string{}
-
-		for _, moduleTypeTemplate := range moduleTypeDocsToTemplates(pkg.ModuleTypes) {
-			attrs := `{
-        "module_name": attr.string(mandatory = True),
-        "module_variant": attr.string(),
-        "module_deps": attr.label_list(providers = [SoongModuleInfo]),
-`
-			for _, prop := range moduleTypeTemplate.Properties {
-				attrs += propToAttr(prop, prop.Name)
-			}
-
-			moduleTypeName := moduleTypeTemplate.Name
-
-			// Certain SDK-related module types dynamically inject properties, instead of declaring
-			// them as structs. These properties are registered in an SdkMemberTypesRegistry. If
-			// the module type name matches, add these properties into the rule definition.
-			var registeredTypes []android.SdkMemberType
-			if moduleTypeName == "module_exports" || moduleTypeName == "module_exports_snapshot" {
-				registeredTypes = android.ModuleExportsMemberTypes.RegisteredTypes()
-			} else if moduleTypeName == "sdk" || moduleTypeName == "sdk_snapshot" {
-				registeredTypes = android.SdkMemberTypes.RegisteredTypes()
-			}
-			for _, memberType := range registeredTypes {
-				attrs += fmt.Sprintf("        %q: attr.string_list(),\n", memberType.SdkPropertyName())
-			}
-
-			attrs += "    },"
-
-			rule := canonicalizeModuleType(moduleTypeTemplate.Name)
-			content += fmt.Sprintf(moduleRuleShim, rule, attrs)
-			rules = append(rules, rule)
-		}
-
-		ruleShims[bzlFileName] = RuleShim{content: content, rules: rules}
-	}
-	return ruleShims, nil
+	})
 }
 
 func createBazelQueryView(ctx *android.Context, bazelQueryViewDir string) error {
-	blueprintCtx := ctx.Context
-	blueprintCtx.VisitAllModules(func(module blueprint.Module) {
-		buildFile, err := buildFileForModule(blueprintCtx, module, bazelQueryViewDir)
-		if err != nil {
-			panic(err)
-		}
-
-		buildFile.Write([]byte(generateSoongModuleTarget(blueprintCtx, module) + "\n\n"))
-		buildFile.Close()
-	})
-	var err error
-
-	// Write top level files: WORKSPACE and BUILD. These files are empty.
-	if err = writeReadOnlyFile(bazelQueryViewDir, "WORKSPACE", ""); err != nil {
-		return err
+	qvCtx := queryviewContext{
+		bpCtx: ctx.Context,
 	}
+	ruleShims := bp2build.CreateRuleShims(android.ModuleTypeFactories())
+	buildToTargets := bp2build.GenerateSoongModuleTargets(&qvCtx)
 
-	// Used to denote that the top level directory is a package.
-	if err = writeReadOnlyFile(bazelQueryViewDir, "BUILD", ""); err != nil {
-		return err
-	}
-
-	packages, err := getPackages(ctx)
-	if err != nil {
-		return err
-	}
-	ruleShims, err := createRuleShims(packages)
-	if err != nil {
-		return err
-	}
-
-	// Write .bzl Starlark files into the bazel_rules top level directory (provider and rule definitions)
-	bazelRulesDir := bazelQueryViewDir + "/build/bazel/queryview_rules"
-	if err = writeReadOnlyFile(bazelRulesDir, "BUILD", ""); err != nil {
-		return err
-	}
-	if err = writeReadOnlyFile(bazelRulesDir, "providers.bzl", providersBzl); err != nil {
-		return err
-	}
-
-	for bzlFileName, ruleShim := range ruleShims {
-		if err = writeReadOnlyFile(bazelRulesDir, bzlFileName+".bzl", ruleShim.content); err != nil {
+	filesToWrite := bp2build.CreateBazelFiles(ruleShims, buildToTargets)
+	for _, f := range filesToWrite {
+		if err := writeReadOnlyFile(bazelQueryViewDir, f); err != nil {
 			return err
 		}
 	}
 
-	return writeReadOnlyFile(bazelRulesDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims))
+	return nil
 }
 
-// Generate the content of soong_module.bzl with the rule shim load statements
-// and mapping of module_type to rule shim map for every module type in Soong.
-func generateSoongModuleBzl(bzlLoads map[string]RuleShim) string {
-	var loadStmts string
-	var moduleRuleMap string
-	for bzlFileName, ruleShim := range bzlLoads {
-		loadStmt := "load(\"//build/bazel/queryview_rules:"
-		loadStmt += bzlFileName
-		loadStmt += ".bzl\""
-		for _, rule := range ruleShim.rules {
-			loadStmt += fmt.Sprintf(", %q", rule)
-			moduleRuleMap += "    \"" + rule + "\": " + rule + ",\n"
-		}
-		loadStmt += ")\n"
-		loadStmts += loadStmt
-	}
-
-	return fmt.Sprintf(soongModuleBzl, loadStmts, moduleRuleMap)
-}
-
-func shouldGenerateAttribute(prop string) bool {
-	return !ignoredPropNames[prop]
-}
-
-// props is an unsorted map. This function ensures that
-// the generated attributes are sorted to ensure determinism.
-func propsToAttributes(props map[string]string) string {
-	var attributes string
-	for _, propName := range android.SortedStringKeys(props) {
-		if shouldGenerateAttribute(propName) {
-			attributes += fmt.Sprintf("    %s = %s,\n", propName, props[propName])
-		}
-	}
-	return attributes
-}
-
-// Convert a module and its deps and props into a Bazel macro/rule
-// representation in the BUILD file.
-func generateSoongModuleTarget(
-	blueprintCtx *blueprint.Context,
-	module blueprint.Module) string {
-
-	var props map[string]string
-	if aModule, ok := module.(android.Module); ok {
-		props = extractModuleProperties(aModule)
-	}
-	attributes := propsToAttributes(props)
-
-	// TODO(b/163018919): DirectDeps can have duplicate (module, variant)
-	// items, if the modules are added using different DependencyTag. Figure
-	// out the implications of that.
-	depLabels := map[string]bool{}
-	blueprintCtx.VisitDirectDeps(module, func(depModule blueprint.Module) {
-		depLabels[qualifiedTargetLabel(blueprintCtx, depModule)] = true
-	})
-
-	depLabelList := "[\n"
-	for depLabel, _ := range depLabels {
-		depLabelList += fmt.Sprintf("        %q,\n", depLabel)
-	}
-	depLabelList += "    ]"
-
-	return fmt.Sprintf(
-		soongModuleTarget,
-		targetNameWithVariant(blueprintCtx, module),
-		blueprintCtx.ModuleName(module),
-		canonicalizeModuleType(blueprintCtx.ModuleType(module)),
-		blueprintCtx.ModuleSubDir(module),
-		depLabelList,
-		attributes)
-}
-
-func buildFileForModule(
-	ctx *blueprint.Context, module blueprint.Module, bazelQueryViewDir string) (*os.File, error) {
-	// Create nested directories for the BUILD file
-	dirPath := filepath.Join(bazelQueryViewDir, packagePath(ctx, module))
-	createDirectoryIfNonexistent(dirPath)
-	// Open the file for appending, and create it if it doesn't exist
-	f, err := os.OpenFile(
-		filepath.Join(dirPath, "BUILD.bazel"),
-		os.O_APPEND|os.O_CREATE|os.O_WRONLY,
-		0644)
-	if err != nil {
-		return nil, err
-	}
-
-	// If the file is empty, add the load statement for the `soong_module` rule
-	fi, err := f.Stat()
-	if err != nil {
-		return nil, err
-	}
-	if fi.Size() == 0 {
-		f.Write([]byte(soongModuleLoad + "\n"))
-	}
-
-	return f, nil
-}
-
-func createDirectoryIfNonexistent(dir string) {
-	if _, err := os.Stat(dir); os.IsNotExist(err) {
-		os.MkdirAll(dir, os.ModePerm)
-	}
-}
-
-// The QueryView directory should be read-only, sufficient for bazel query. The files
+// The auto-conversion directory should be read-only, sufficient for bazel query. The files
 // are not intended to be edited by end users.
-func writeReadOnlyFile(dir string, baseName string, content string) error {
-	createDirectoryIfNonexistent(dir)
-	pathToFile := filepath.Join(dir, baseName)
+func writeReadOnlyFile(dir string, f bp2build.BazelFile) error {
+	dir = filepath.Join(dir, f.Dir)
+	if err := createDirectoryIfNonexistent(dir); err != nil {
+		return err
+	}
+	pathToFile := filepath.Join(dir, f.Basename)
+
 	// 0444 is read-only
-	return ioutil.WriteFile(pathToFile, []byte(content), 0444)
+	err := ioutil.WriteFile(pathToFile, []byte(f.Contents), 0444)
+
+	return err
 }
 
-func isZero(value reflect.Value) bool {
-	switch value.Kind() {
-	case reflect.Func, reflect.Map, reflect.Slice:
-		return value.IsNil()
-	case reflect.Array:
-		valueIsZero := true
-		for i := 0; i < value.Len(); i++ {
-			valueIsZero = valueIsZero && isZero(value.Index(i))
-		}
-		return valueIsZero
-	case reflect.Struct:
-		valueIsZero := true
-		for i := 0; i < value.NumField(); i++ {
-			if value.Field(i).CanSet() {
-				valueIsZero = valueIsZero && isZero(value.Field(i))
-			}
-		}
-		return valueIsZero
-	case reflect.Ptr:
-		if !value.IsNil() {
-			return isZero(reflect.Indirect(value))
-		} else {
-			return true
-		}
-	default:
-		zeroValue := reflect.Zero(value.Type())
-		result := value.Interface() == zeroValue.Interface()
-		return result
+func createDirectoryIfNonexistent(dir string) error {
+	if _, err := os.Stat(dir); os.IsNotExist(err) {
+		return os.MkdirAll(dir, os.ModePerm)
+	} else {
+		return err
 	}
 }
diff --git a/cmd/soong_build/queryview_test.go b/cmd/soong_build/queryview_test.go
deleted file mode 100644
index 9471a91..0000000
--- a/cmd/soong_build/queryview_test.go
+++ /dev/null
@@ -1,470 +0,0 @@
-// 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.
-
-package main
-
-import (
-	"android/soong/android"
-	"io/ioutil"
-	"os"
-	"strings"
-	"testing"
-
-	"github.com/google/blueprint/bootstrap/bpdoc"
-)
-
-var buildDir string
-
-func setUp() {
-	var err error
-	buildDir, err = ioutil.TempDir("", "bazel_queryview_test")
-	if err != nil {
-		panic(err)
-	}
-}
-
-func tearDown() {
-	os.RemoveAll(buildDir)
-}
-
-func TestMain(m *testing.M) {
-	run := func() int {
-		setUp()
-		defer tearDown()
-
-		return m.Run()
-	}
-
-	os.Exit(run())
-}
-
-type customModule struct {
-	android.ModuleBase
-}
-
-// OutputFiles is needed because some instances of this module use dist with a
-// tag property which requires the module implements OutputFileProducer.
-func (m *customModule) OutputFiles(tag string) (android.Paths, error) {
-	return android.PathsForTesting("path" + tag), nil
-}
-
-func (m *customModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	// nothing for now.
-}
-
-func customModuleFactory() android.Module {
-	module := &customModule{}
-	android.InitAndroidModule(module)
-	return module
-}
-
-func TestGenerateBazelQueryViewFromBlueprint(t *testing.T) {
-	testCases := []struct {
-		bp                  string
-		expectedBazelTarget string
-	}{
-		{
-			bp: `custom {
-	name: "foo",
-}
-		`,
-			expectedBazelTarget: `soong_module(
-    name = "foo",
-    module_name = "foo",
-    module_type = "custom",
-    module_variant = "",
-    module_deps = [
-    ],
-)`,
-		},
-		{
-			bp: `custom {
-	name: "foo",
-	ramdisk: true,
-}
-		`,
-			expectedBazelTarget: `soong_module(
-    name = "foo",
-    module_name = "foo",
-    module_type = "custom",
-    module_variant = "",
-    module_deps = [
-    ],
-    ramdisk = True,
-)`,
-		},
-		{
-			bp: `custom {
-	name: "foo",
-	owner: "a_string_with\"quotes\"_and_\\backslashes\\\\",
-}
-		`,
-			expectedBazelTarget: `soong_module(
-    name = "foo",
-    module_name = "foo",
-    module_type = "custom",
-    module_variant = "",
-    module_deps = [
-    ],
-    owner = "a_string_with\"quotes\"_and_\\backslashes\\\\",
-)`,
-		},
-		{
-			bp: `custom {
-	name: "foo",
-	required: ["bar"],
-}
-		`,
-			expectedBazelTarget: `soong_module(
-    name = "foo",
-    module_name = "foo",
-    module_type = "custom",
-    module_variant = "",
-    module_deps = [
-    ],
-    required = [
-        "bar",
-    ],
-)`,
-		},
-		{
-			bp: `custom {
-	name: "foo",
-	target_required: ["qux", "bazqux"],
-}
-		`,
-			expectedBazelTarget: `soong_module(
-    name = "foo",
-    module_name = "foo",
-    module_type = "custom",
-    module_variant = "",
-    module_deps = [
-    ],
-    target_required = [
-        "qux",
-        "bazqux",
-    ],
-)`,
-		},
-		{
-			bp: `custom {
-	name: "foo",
-	dist: {
-		targets: ["goal_foo"],
-		tag: ".foo",
-	},
-	dists: [
-		{
-			targets: ["goal_bar"],
-			tag: ".bar",
-		},
-	],
-}
-		`,
-			expectedBazelTarget: `soong_module(
-    name = "foo",
-    module_name = "foo",
-    module_type = "custom",
-    module_variant = "",
-    module_deps = [
-    ],
-    dist = {
-        "tag": ".foo",
-        "targets": [
-            "goal_foo",
-        ],
-    },
-    dists = [
-        {
-            "tag": ".bar",
-            "targets": [
-                "goal_bar",
-            ],
-        },
-    ],
-)`,
-		},
-		{
-			bp: `custom {
-	name: "foo",
-	required: ["bar"],
-	target_required: ["qux", "bazqux"],
-	ramdisk: true,
-	owner: "custom_owner",
-	dists: [
-		{
-			tag: ".tag",
-			targets: ["my_goal"],
-		},
-	],
-}
-		`,
-			expectedBazelTarget: `soong_module(
-    name = "foo",
-    module_name = "foo",
-    module_type = "custom",
-    module_variant = "",
-    module_deps = [
-    ],
-    dists = [
-        {
-            "tag": ".tag",
-            "targets": [
-                "my_goal",
-            ],
-        },
-    ],
-    owner = "custom_owner",
-    ramdisk = True,
-    required = [
-        "bar",
-    ],
-    target_required = [
-        "qux",
-        "bazqux",
-    ],
-)`,
-		},
-	}
-
-	for _, testCase := range testCases {
-		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
-		ctx := android.NewTestContext(config)
-		ctx.RegisterModuleType("custom", customModuleFactory)
-		ctx.Register()
-
-		_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
-		android.FailIfErrored(t, errs)
-		_, errs = ctx.PrepareBuildActions(config)
-		android.FailIfErrored(t, errs)
-
-		module := ctx.ModuleForTests("foo", "").Module().(*customModule)
-		blueprintCtx := ctx.Context.Context
-
-		actualBazelTarget := generateSoongModuleTarget(blueprintCtx, module)
-		if actualBazelTarget != testCase.expectedBazelTarget {
-			t.Errorf(
-				"Expected generated Bazel target to be '%s', got '%s'",
-				testCase.expectedBazelTarget,
-				actualBazelTarget,
-			)
-		}
-	}
-}
-
-func createPackageFixtures() []*bpdoc.Package {
-	properties := []bpdoc.Property{
-		bpdoc.Property{
-			Name: "int64_prop",
-			Type: "int64",
-		},
-		bpdoc.Property{
-			Name: "int_prop",
-			Type: "int",
-		},
-		bpdoc.Property{
-			Name: "bool_prop",
-			Type: "bool",
-		},
-		bpdoc.Property{
-			Name: "string_prop",
-			Type: "string",
-		},
-		bpdoc.Property{
-			Name: "string_list_prop",
-			Type: "list of string",
-		},
-		bpdoc.Property{
-			Name: "nested_prop",
-			Type: "",
-			Properties: []bpdoc.Property{
-				bpdoc.Property{
-					Name: "int_prop",
-					Type: "int",
-				},
-				bpdoc.Property{
-					Name: "bool_prop",
-					Type: "bool",
-				},
-				bpdoc.Property{
-					Name: "string_prop",
-					Type: "string",
-				},
-			},
-		},
-		bpdoc.Property{
-			Name: "unknown_type",
-			Type: "unknown",
-		},
-	}
-
-	fooPropertyStruct := &bpdoc.PropertyStruct{
-		Name:       "FooProperties",
-		Properties: properties,
-	}
-
-	moduleTypes := []*bpdoc.ModuleType{
-		&bpdoc.ModuleType{
-			Name: "foo_library",
-			PropertyStructs: []*bpdoc.PropertyStruct{
-				fooPropertyStruct,
-			},
-		},
-
-		&bpdoc.ModuleType{
-			Name: "foo_binary",
-			PropertyStructs: []*bpdoc.PropertyStruct{
-				fooPropertyStruct,
-			},
-		},
-		&bpdoc.ModuleType{
-			Name: "foo_test",
-			PropertyStructs: []*bpdoc.PropertyStruct{
-				fooPropertyStruct,
-			},
-		},
-	}
-
-	return [](*bpdoc.Package){
-		&bpdoc.Package{
-			Name:        "foo_language",
-			Path:        "android/soong/foo",
-			ModuleTypes: moduleTypes,
-		},
-	}
-}
-
-func TestGenerateModuleRuleShims(t *testing.T) {
-	ruleShims, err := createRuleShims(createPackageFixtures())
-	if err != nil {
-		panic(err)
-	}
-
-	if len(ruleShims) != 1 {
-		t.Errorf("Expected to generate 1 rule shim, but got %d", len(ruleShims))
-	}
-
-	fooRuleShim := ruleShims["foo"]
-	expectedRules := []string{"foo_binary", "foo_library", "foo_test_"}
-
-	if len(fooRuleShim.rules) != 3 {
-		t.Errorf("Expected 3 rules, but got %d", len(fooRuleShim.rules))
-	}
-
-	for i, rule := range fooRuleShim.rules {
-		if rule != expectedRules[i] {
-			t.Errorf("Expected rule shim to contain %s, but got %s", expectedRules[i], rule)
-		}
-	}
-
-	expectedBzl := `load("//build/bazel/queryview_rules:providers.bzl", "SoongModuleInfo")
-
-def _foo_binary_impl(ctx):
-    return [SoongModuleInfo()]
-
-foo_binary = rule(
-    implementation = _foo_binary_impl,
-    attrs = {
-        "module_name": attr.string(mandatory = True),
-        "module_variant": attr.string(),
-        "module_deps": attr.label_list(providers = [SoongModuleInfo]),
-        "bool_prop": attr.bool(),
-        "int64_prop": attr.int(),
-        "int_prop": attr.int(),
-#         "nested_prop__int_prop": attr.int(),
-#         "nested_prop__bool_prop": attr.bool(),
-#         "nested_prop__string_prop": attr.string(),
-        "string_list_prop": attr.string_list(),
-        "string_prop": attr.string(),
-    },
-)
-
-def _foo_library_impl(ctx):
-    return [SoongModuleInfo()]
-
-foo_library = rule(
-    implementation = _foo_library_impl,
-    attrs = {
-        "module_name": attr.string(mandatory = True),
-        "module_variant": attr.string(),
-        "module_deps": attr.label_list(providers = [SoongModuleInfo]),
-        "bool_prop": attr.bool(),
-        "int64_prop": attr.int(),
-        "int_prop": attr.int(),
-#         "nested_prop__int_prop": attr.int(),
-#         "nested_prop__bool_prop": attr.bool(),
-#         "nested_prop__string_prop": attr.string(),
-        "string_list_prop": attr.string_list(),
-        "string_prop": attr.string(),
-    },
-)
-
-def _foo_test__impl(ctx):
-    return [SoongModuleInfo()]
-
-foo_test_ = rule(
-    implementation = _foo_test__impl,
-    attrs = {
-        "module_name": attr.string(mandatory = True),
-        "module_variant": attr.string(),
-        "module_deps": attr.label_list(providers = [SoongModuleInfo]),
-        "bool_prop": attr.bool(),
-        "int64_prop": attr.int(),
-        "int_prop": attr.int(),
-#         "nested_prop__int_prop": attr.int(),
-#         "nested_prop__bool_prop": attr.bool(),
-#         "nested_prop__string_prop": attr.string(),
-        "string_list_prop": attr.string_list(),
-        "string_prop": attr.string(),
-    },
-)
-`
-
-	if fooRuleShim.content != expectedBzl {
-		t.Errorf(
-			"Expected the generated rule shim bzl to be:\n%s\nbut got:\n%s",
-			expectedBzl,
-			fooRuleShim.content)
-	}
-}
-
-func TestGenerateSoongModuleBzl(t *testing.T) {
-	ruleShims, err := createRuleShims(createPackageFixtures())
-	if err != nil {
-		panic(err)
-	}
-	actualSoongModuleBzl := generateSoongModuleBzl(ruleShims)
-
-	expectedLoad := "load(\"//build/bazel/queryview_rules:foo.bzl\", \"foo_binary\", \"foo_library\", \"foo_test_\")"
-	expectedRuleMap := `soong_module_rule_map = {
-    "foo_binary": foo_binary,
-    "foo_library": foo_library,
-    "foo_test_": foo_test_,
-}`
-	if !strings.Contains(actualSoongModuleBzl, expectedLoad) {
-		t.Errorf(
-			"Generated soong_module.bzl:\n\n%s\n\n"+
-				"Could not find the load statement in the generated soong_module.bzl:\n%s",
-			actualSoongModuleBzl,
-			expectedLoad)
-	}
-
-	if !strings.Contains(actualSoongModuleBzl, expectedRuleMap) {
-		t.Errorf(
-			"Generated soong_module.bzl:\n\n%s\n\n"+
-				"Could not find the module -> rule map in the generated soong_module.bzl:\n%s",
-			actualSoongModuleBzl,
-			expectedRuleMap)
-	}
-}
diff --git a/cmd/soong_build/writedocs.go b/cmd/soong_build/writedocs.go
index 253979e..f2c2c9b 100644
--- a/cmd/soong_build/writedocs.go
+++ b/cmd/soong_build/writedocs.go
@@ -20,7 +20,6 @@
 	"html/template"
 	"io/ioutil"
 	"path/filepath"
-	"reflect"
 	"sort"
 
 	"github.com/google/blueprint/bootstrap"
@@ -97,12 +96,8 @@
 }
 
 func getPackages(ctx *android.Context) ([]*bpdoc.Package, error) {
-	moduleTypeFactories := android.ModuleTypeFactories()
-	bpModuleTypeFactories := make(map[string]reflect.Value)
-	for moduleType, factory := range moduleTypeFactories {
-		bpModuleTypeFactories[moduleType] = reflect.ValueOf(factory)
-	}
-	return bootstrap.ModuleTypeDocs(ctx.Context, bpModuleTypeFactories)
+	moduleTypeFactories := android.ModuleTypeFactoriesForDocs()
+	return bootstrap.ModuleTypeDocs(ctx.Context, moduleTypeFactories)
 }
 
 func writeDocs(ctx *android.Context, filename string) error {
diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go
index f911e71..82d6ac3 100644
--- a/java/legacy_core_platform_api_usage.go
+++ b/java/legacy_core_platform_api_usage.go
@@ -31,7 +31,6 @@
 	"api-stubs-docs",
 	"art_cts_jvmti_test_library",
 	"art-gtest-jars-MyClassNatives",
-	"atfwd",
 	"BackupEncryption",
 	"BackupFrameworksServicesRoboTests",
 	"backuplib",
@@ -50,8 +49,6 @@
 	"CertInstaller",
 	"com.qti.location.sdk",
 	"com.qti.media.secureprocessor",
-	"com.qti.snapdragon.sdk.display",
-	"ConfURIDialer",
 	"ConnectivityManagerTest",
 	"ContactsProvider",
 	"CorePerfTests",
@@ -61,7 +58,6 @@
 	"cronet_impl_platform_java",
 	"CtsAppExitTestCases",
 	"CtsContentTestCases",
-	"CtsIkeTestCases",
 	"CtsLibcoreWycheproofBCTestCases",
 	"CtsMediaTestCases",
 	"CtsNetTestCases",
@@ -69,7 +65,6 @@
 	"CtsSecurityTestCases",
 	"CtsSuspendAppsTestCases",
 	"CtsUsageStatsTestCases",
-	"datastatusnotification",
 	"DeadpoolService",
 	"DeadpoolServiceBtServices",
 	"DeviceInfo",
@@ -89,7 +84,6 @@
 	"ExternalStorageProvider",
 	"face-V1-0-javalib",
 	"FloralClocks",
-	"framework-all",
 	"framework-jobscheduler",
 	"framework-minus-apex",
 	"framework-minus-apex-intdefs",
@@ -108,8 +102,6 @@
 	"hid",
 	"hidl_test_java_java",
 	"hwbinder",
-	"ims",
-	"ims-ext-common",
 	"imssettings",
 	"izat.lib.glue",
 	"KeyChain",
@@ -130,28 +122,18 @@
 	"NetworkStackNextTests",
 	"NetworkStackTests",
 	"NetworkStackTestsLib",
-	"NfcNci",
 	"online-gcm-ref-docs",
 	"online-gts-docs",
 	"PerformanceMode",
-	"pixel-power-ext-java",
-	"pixel-power-ext-unstable-java",
-	"pixel-power-ext-V1-java",
 	"platform_library-docs",
 	"PowerStatsService",
 	"PrintSpooler",
 	"pxp-monitor",
 	"QColor",
 	"qcom.fmradio",
-	"qcrilhook",
-	"qcrilhook-static",
-	"qcrilmsgtunnel",
 	"QDCMMobileApp",
 	"Qmmi",
 	"QPerformance",
-	"QtiTelephonyService",
-	"QtiTelephonyServicelibrary",
-	"remoteSimLockAuthentication",
 	"remotesimlockmanagerlibrary",
 	"RollbackTest",
 	"sam",
@@ -172,10 +154,6 @@
 	"SettingsGoogleOverlayCoral",
 	"SettingsGoogleOverlayFlame",
 	"SettingsLib",
-	"SettingsOverlayG013A",
-	"SettingsOverlayG013B",
-	"SettingsOverlayG013C",
-	"SettingsOverlayG013D",
 	"SettingsOverlayG020A",
 	"SettingsOverlayG020B",
 	"SettingsOverlayG020C",
@@ -217,7 +195,6 @@
 	"Telecom",
 	"TelecomUnitTests",
 	"telephony-common",
-	"telephony-ext",
 	"TelephonyProviderTests",
 	"TeleService",
 	"testables",
@@ -237,7 +214,6 @@
 	"WallpaperBackup",
 	"WallpaperBackupAgentTests",
 	"WfdCommon",
-	"xdivert",
 }
 
 var legacyCorePlatformApiLookup = make(map[string]struct{})
diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh
index 6db870f..ea62af4 100755
--- a/scripts/build-mainline-modules.sh
+++ b/scripts/build-mainline-modules.sh
@@ -26,6 +26,7 @@
   platform-mainline-test-exports
   runtime-module-host-exports
   runtime-module-sdk
+  tzdata-module-test-exports
 )
 
 # List of libraries installed on the platform that are needed for ART chroot