Merge "Use single clang-tidy build rule and clang-tidy.sh"
diff --git a/android/Android.bp b/android/Android.bp
index 8eb55d2..65332b2 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -107,6 +107,7 @@
         "deptag_test.go",
         "expand_test.go",
         "fixture_test.go",
+        "gen_notice_test.go",
         "license_kind_test.go",
         "license_test.go",
         "licenses_test.go",
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 017f16d..a5e7cd6 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -46,6 +46,8 @@
 		"bootable/recovery/tools/recovery_l10n": Bp2BuildDefaultTrue,
 		"build/bazel/examples/apex/minimal":     Bp2BuildDefaultTrueRecursively,
 		"build/bazel/examples/soong_config_variables":        Bp2BuildDefaultTrueRecursively,
+		"build/bazel/examples/python":                        Bp2BuildDefaultTrueRecursively,
+		"build/bazel/examples/gensrcs":                       Bp2BuildDefaultTrueRecursively,
 		"build/make/target/product/security":                 Bp2BuildDefaultTrue,
 		"build/make/tools/signapk":                           Bp2BuildDefaultTrue,
 		"build/make/tools/zipalign":                          Bp2BuildDefaultTrueRecursively,
@@ -177,8 +179,10 @@
 		"prebuilts/clang/host/linux-x86":                     Bp2BuildDefaultTrueRecursively,
 		"prebuilts/tools/common/m2":                          Bp2BuildDefaultTrue,
 		"system/apex":                                        Bp2BuildDefaultFalse, // TODO(b/207466993): flaky failures
+		"system/apex/apexer":                                 Bp2BuildDefaultTrue,
 		"system/apex/libs":                                   Bp2BuildDefaultTrueRecursively,
 		"system/apex/proto":                                  Bp2BuildDefaultTrueRecursively,
+		"system/apex/tools":                                  Bp2BuildDefaultTrueRecursively,
 		"system/core/debuggerd":                              Bp2BuildDefaultTrueRecursively,
 		"system/core/diagnose_usb":                           Bp2BuildDefaultTrueRecursively,
 		"system/core/libasyncio":                             Bp2BuildDefaultTrue,
@@ -200,6 +204,7 @@
 		"system/libziparchive":                               Bp2BuildDefaultTrueRecursively,
 		"system/logging/liblog":                              Bp2BuildDefaultTrueRecursively,
 		"system/media/audio":                                 Bp2BuildDefaultTrueRecursively,
+		"system/memory/libion":                               Bp2BuildDefaultTrueRecursively,
 		"system/memory/libmemunreachable":                    Bp2BuildDefaultTrueRecursively,
 		"system/sepolicy/apex":                               Bp2BuildDefaultTrueRecursively,
 		"system/timezone/apex":                               Bp2BuildDefaultTrueRecursively,
@@ -259,21 +264,23 @@
 
 	Bp2buildModuleAlwaysConvertList = []string{
 		// cc mainline modules
-		"libnativeloader-headers",
-		"libgui_bufferqueue_sources",
 		"code_coverage.policy",
 		"code_coverage.policy.other",
 		"codec2_soft_exports",
 		"com.android.media.swcodec-ld.config.txt",
-		"libcodec2_headers",
-		"libcodec2_internal",
 		"com.android.media.swcodec-mediaswcodec.rc",
 		"flatbuffer_headers",
 		"gemmlowp_headers",
 		"gl_headers",
-		"libbluetooth-types-header",
 		"libaudioclient_aidl_conversion_util",
 		"libaudioutils_fixedfft",
+		"libbluetooth-types-header",
+		"libcodec2_headers",
+		"libcodec2_internal",
+		"libdmabufheap",
+		"libgui_bufferqueue_sources",
+		"libnativeloader-headers",
+		"libsync",
 
 		//external/avb
 		"avbtool",
@@ -318,19 +325,20 @@
 		"gen-kotlin-build-file.py",                  // TODO(b/198619163) module has same name as source
 		"libgtest_ndk_c++", "libgtest_main_ndk_c++", // TODO(b/201816222): Requires sdk_version support.
 		"linkerconfig", "mdnsd", // TODO(b/202876379): has arch-variant static_executable
-		"linker",       // TODO(b/228316882): cc_binary uses link_crt
-		"libdebuggerd", // TODO(b/228314770): support product variable-specific header_libs
-		"versioner",    // TODO(b/228313961):  depends on prebuilt shared library libclang-cpp_host as a shared library, which does not supply expected providers for a shared library
-		"f2fs.fibmap",  // ld.lld: error: undefined symbol: _IO
-		"f2fscrypt",    // TODO(b/234340806):  error: incompatible integer to pointer conversion initializing 'FILE *' (aka 'struct _IO_FILE *') with an expression of type 'int', and  error: incomplete definition of type 'struct mntent'
+		"linker",                // TODO(b/228316882): cc_binary uses link_crt
+		"libdebuggerd",          // TODO(b/228314770): support product variable-specific header_libs
+		"versioner",             // TODO(b/228313961):  depends on prebuilt shared library libclang-cpp_host as a shared library, which does not supply expected providers for a shared library
+		"f2fs.fibmap",           // ld.lld: error: undefined symbol: _IO
+		"f2fscrypt",             // TODO(b/234340806):  error: incompatible integer to pointer conversion initializing 'FILE *' (aka 'struct _IO_FILE *') with an expression of type 'int', and  error: incomplete definition of type 'struct mntent'
+		"apexer", "apexer_test", // Requires aapt2
+		"apexer_test_host_tools",
+		"host_apex_verifier",
 
 		// java bugs
 		"libbase_ndk", // TODO(b/186826477): fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
 
 		// python protos
-		"libprotobuf-python",                           // TODO(b/196084681): contains .proto sources
-		"apex_build_info_proto", "apex_manifest_proto", // TODO(b/196084681): a python lib with proto sources
-		"linker_config_proto", // TODO(b/196084681): contains .proto sources
+		"libprotobuf-python", // Has a handcrafted alternative
 
 		// genrule incompatibilities
 		"brotli-fuzzer-corpus",                                       // TODO(b/202015218): outputs are in location incompatible with bazel genrule handling.
diff --git a/android/androidmk.go b/android/androidmk.go
index 5c715b4..6b675a6 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -288,6 +288,8 @@
 
 // The contributions to the dist.
 type distContributions struct {
+	// Path to license metadata file.
+	licenseMetadataFile Path
 	// List of goals and the dist copy instructions.
 	copiesForGoals []*copiesForGoals
 }
@@ -364,6 +366,8 @@
 	// Collate the contributions this module makes to the dist.
 	distContributions := &distContributions{}
 
+	distContributions.licenseMetadataFile = amod.licenseMetadataFile
+
 	// Iterate over this module's dist structs, merged from the dist and dists properties.
 	for _, dist := range amod.Dists() {
 		// Get the list of goals this dist should be enabled for. e.g. sdk, droidcore
@@ -456,6 +460,10 @@
 		for _, c := range d.copies {
 			ret = append(
 				ret,
+				fmt.Sprintf("$(if $(strip $(ALL_TARGETS.%s.META_LIC)),,$(eval ALL_TARGETS.%s.META_LIC := %s))\n",
+					c.from.String(), c.from.String(), distContributions.licenseMetadataFile.String()))
+			ret = append(
+				ret,
 				fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)\n", d.goals, c.from.String(), c.dest))
 		}
 	}
diff --git a/android/androidmk_test.go b/android/androidmk_test.go
index caf11f1..ae2187f 100644
--- a/android/androidmk_test.go
+++ b/android/androidmk_test.go
@@ -50,6 +50,8 @@
 
 func (m *customModule) GenerateAndroidBuildActions(ctx ModuleContext) {
 
+	m.base().licenseMetadataFile = PathForOutput(ctx, "meta_lic")
+
 	// If the dist_output_file: true then create an output file that is stored in
 	// the OutputFile property of the AndroidMkEntry.
 	if proptools.BoolDefault(m.properties.Dist_output_file, true) {
@@ -198,10 +200,13 @@
 		},
 	}
 
+	dc.licenseMetadataFile = PathForTesting("meta_lic")
 	makeOutput := generateDistContributionsForMake(dc)
 
 	assertStringEquals(t, `.PHONY: my_goal
+$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))
 $(call dist-for-goals,my_goal,one.out:one.out)
+$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))
 $(call dist-for-goals,my_goal,two.out:other.out)
 `, strings.Join(makeOutput, ""))
 }
@@ -243,18 +248,26 @@
 
 	expectedAndroidMkLines := []string{
 		".PHONY: my_second_goal\n",
+		"$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))\n",
 		"$(call dist-for-goals,my_second_goal,two.out:two.out)\n",
+		"$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))\n",
 		"$(call dist-for-goals,my_second_goal,three/four.out:four.out)\n",
 		".PHONY: my_third_goal\n",
+		"$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
 		"$(call dist-for-goals,my_third_goal,one.out:test/dir/one.out)\n",
 		".PHONY: my_fourth_goal\n",
+		"$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
 		"$(call dist-for-goals,my_fourth_goal,one.out:one.suffix.out)\n",
 		".PHONY: my_fifth_goal\n",
+		"$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
 		"$(call dist-for-goals,my_fifth_goal,one.out:new-name)\n",
 		".PHONY: my_sixth_goal\n",
+		"$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
 		"$(call dist-for-goals,my_sixth_goal,one.out:some/dir/new-name.suffix)\n",
 		".PHONY: my_goal my_other_goal\n",
+		"$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))\n",
 		"$(call dist-for-goals,my_goal my_other_goal,two.out:two.out)\n",
+		"$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))\n",
 		"$(call dist-for-goals,my_goal my_other_goal,three/four.out:four.out)\n",
 	}
 
@@ -274,7 +287,7 @@
 		)
 	}
 	for idx, line := range androidMkLines {
-		expectedLine := expectedAndroidMkLines[idx]
+		expectedLine := strings.ReplaceAll(expectedAndroidMkLines[idx], "meta_lic", module.base().licenseMetadataFile.String())
 		if line != expectedLine {
 			t.Errorf(
 				"Expected AndroidMk line to be '%s', got '%s'",
diff --git a/android/gen_notice_test.go b/android/gen_notice_test.go
new file mode 100644
index 0000000..4ad2ecf
--- /dev/null
+++ b/android/gen_notice_test.go
@@ -0,0 +1,164 @@
+package android
+
+import (
+	"testing"
+
+	"github.com/google/blueprint"
+)
+
+var genNoticeTests = []struct {
+	name           string
+	fs             MockFS
+	expectedErrors []string
+}{
+	{
+		name: "gen_notice must not accept licenses property",
+		fs: map[string][]byte{
+			"top/Android.bp": []byte(`
+				gen_notice {
+					name: "top_license",
+					licenses: ["other_license"],
+				}`),
+		},
+		expectedErrors: []string{
+			`unrecognized property "licenses"`,
+		},
+	},
+	{
+		name: "bad gen_notice",
+		fs: map[string][]byte{
+			"top/Android.bp": []byte(`
+				gen_notice {
+					name: "top_notice",
+					for: ["top_rule"],
+				}`),
+			"other/Android.bp": []byte(`
+				mock_genrule {
+					name: "other_rule",
+					dep: ["top_notice"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "top_notice": for: no "top_rule" module exists`,
+		},
+	},
+	{
+		name: "doubly bad gen_notice",
+		fs: map[string][]byte{
+			"top/Android.bp": []byte(`
+				gen_notice {
+					name: "top_notice",
+					for: ["top_rule", "other_rule"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "top_notice": for: modules "top_rule", "other_rule" do not exist`,
+		},
+	},
+	{
+		name: "good gen_notice",
+		fs: map[string][]byte{
+			"top/Android.bp": []byte(`
+				gen_notice {
+					name: "top_notice",
+					for: ["top_rule"],
+				}
+
+				mock_genrule {
+					name: "top_rule",
+					dep: ["top_notice"],
+				}`),
+			"other/Android.bp": []byte(`
+				mock_genrule {
+					name: "other_rule",
+					dep: ["top_notice"],
+				}`),
+		},
+	},
+	{
+		name: "multiple license kinds",
+		fs: map[string][]byte{
+			"top/Android.bp": []byte(`
+				gen_notice {
+					name: "top_notice",
+					for: ["top_rule"],
+				}
+
+				gen_notice {
+					name: "top_html_notice",
+					html: true,
+					for: ["top_rule"],
+				}
+
+				gen_notice {
+					name: "top_xml_notice",
+					xml: true,
+					for: ["top_notice"],
+				}
+
+				mock_genrule {
+					name: "top_rule",
+					dep: [
+						"top_notice",
+						"top_html_notice",
+						"top_xml_notice",
+					],
+				}`),
+			"other/Android.bp": []byte(`
+				mock_genrule {
+					name: "other_rule",
+					dep: ["top_xml_notice"],
+				}`),
+		},
+	},
+}
+
+func TestGenNotice(t *testing.T) {
+	for _, test := range genNoticeTests {
+		t.Run(test.name, func(t *testing.T) {
+			GroupFixturePreparers(
+				PrepareForTestWithGenNotice,
+				FixtureRegisterWithContext(func(ctx RegistrationContext) {
+					ctx.RegisterModuleType("mock_genrule", newMockGenruleModule)
+				}),
+				test.fs.AddToFixture(),
+			).
+				ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)).
+				RunTest(t)
+		})
+	}
+}
+
+type mockGenruleProperties struct {
+	Dep []string
+}
+
+type mockGenruleModule struct {
+	ModuleBase
+	DefaultableModuleBase
+
+	properties mockGenruleProperties
+}
+
+func newMockGenruleModule() Module {
+	m := &mockGenruleModule{}
+	m.AddProperties(&m.properties)
+	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
+	InitDefaultableModule(m)
+	return m
+}
+
+type genruleDepTag struct {
+	blueprint.BaseDependencyTag
+}
+
+func (j *mockGenruleModule) DepsMutator(ctx BottomUpMutatorContext) {
+	m, ok := ctx.Module().(Module)
+	if !ok {
+		return
+	}
+	ctx.AddDependency(m, genruleDepTag{}, j.properties.Dep...)
+}
+
+func (p *mockGenruleModule) GenerateAndroidBuildActions(ModuleContext) {
+}
diff --git a/android/licenses.go b/android/licenses.go
index 81c557e..c47b3e6 100644
--- a/android/licenses.go
+++ b/android/licenses.go
@@ -331,6 +331,8 @@
 func licensesMakeVarsProvider(ctx MakeVarsContext) {
 	ctx.Strict("BUILD_LICENSE_METADATA",
 		ctx.Config().HostToolPath(ctx, "build_license_metadata").String())
+	ctx.Strict("COPY_LICENSE_METADATA",
+		ctx.Config().HostToolPath(ctx, "copy_license_metadata").String())
 	ctx.Strict("HTMLNOTICE", ctx.Config().HostToolPath(ctx, "htmlnotice").String())
 	ctx.Strict("XMLNOTICE", ctx.Config().HostToolPath(ctx, "xmlnotice").String())
 	ctx.Strict("TEXTNOTICE", ctx.Config().HostToolPath(ctx, "textnotice").String())
diff --git a/android/module.go b/android/module.go
index 21d5a3d..8bbfd8a 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1181,33 +1181,89 @@
 	archVariantProps := mod.GetArchVariantProperties(ctx, &commonProperties{})
 
 	var enabledProperty bazel.BoolAttribute
-	if props.Enabled != nil {
-		enabledProperty.Value = props.Enabled
+
+	onlyAndroid := false
+	neitherHostNorDevice := false
+
+	osSupport := map[string]bool{}
+
+	// if the target is enabled and supports arch variance, determine the defaults based on the module
+	// type's host or device property and host_supported/device_supported properties
+	if mod.commonProperties.ArchSpecific {
+		moduleSupportsDevice := mod.DeviceSupported()
+		moduleSupportsHost := mod.HostSupported()
+		if moduleSupportsHost && !moduleSupportsDevice {
+			// for host only, we specify as unsupported on android rather than listing all host osSupport
+			// TODO(b/220874839): consider replacing this with a constraint that covers all host osSupport
+			// instead
+			enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, Android.Name, proptools.BoolPtr(false))
+		} else if moduleSupportsDevice && !moduleSupportsHost {
+			enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, Android.Name, proptools.BoolPtr(true))
+			// specify as a positive to ensure any target-specific enabled can be resolved
+			// also save that a target is only android, as if there is only the positive restriction on
+			// android, it'll be dropped, so we may need to add it back later
+			onlyAndroid = true
+		} else if !moduleSupportsHost && !moduleSupportsDevice {
+			neitherHostNorDevice = true
+		}
+
+		for _, os := range OsTypeList() {
+			if os.Class == Host {
+				osSupport[os.Name] = moduleSupportsHost
+			} else if os.Class == Device {
+				osSupport[os.Name] = moduleSupportsDevice
+			}
+		}
+	}
+
+	if neitherHostNorDevice {
+		// we can't build this, disable
+		enabledProperty.Value = proptools.BoolPtr(false)
+	} else if props.Enabled != nil {
+		enabledProperty.SetValue(props.Enabled)
+		if !*props.Enabled {
+			for os, enabled := range osSupport {
+				if val := enabledProperty.SelectValue(bazel.OsConfigurationAxis, os); enabled && val != nil && *val {
+					// if this should be disabled by default, clear out any enabling we've done
+					enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, os, nil)
+				}
+			}
+		}
 	}
 
 	for axis, configToProps := range archVariantProps {
 		for config, _props := range configToProps {
 			if archProps, ok := _props.(*commonProperties); ok {
 				required.SetSelectValue(axis, config, depsToLabelList(archProps.Required).Value)
-				if archProps.Enabled != nil {
-					enabledProperty.SetSelectValue(axis, config, archProps.Enabled)
+				if !neitherHostNorDevice {
+					if archProps.Enabled != nil {
+						if axis != bazel.OsConfigurationAxis || osSupport[config] {
+							enabledProperty.SetSelectValue(axis, config, archProps.Enabled)
+						}
+					}
 				}
 			}
 		}
 	}
 
-	if enabledPropertyOverrides.Value != nil {
-		enabledProperty.Value = enabledPropertyOverrides.Value
-	}
-	for _, axis := range enabledPropertyOverrides.SortedConfigurationAxes() {
-		configToBools := enabledPropertyOverrides.ConfigurableValues[axis]
-		for cfg, val := range configToBools {
-			enabledProperty.SetSelectValue(axis, cfg, &val)
+	if !neitherHostNorDevice {
+		if enabledPropertyOverrides.Value != nil {
+			enabledProperty.Value = enabledPropertyOverrides.Value
+		}
+		for _, axis := range enabledPropertyOverrides.SortedConfigurationAxes() {
+			configToBools := enabledPropertyOverrides.ConfigurableValues[axis]
+			for cfg, val := range configToBools {
+				if axis != bazel.OsConfigurationAxis || osSupport[cfg] {
+					enabledProperty.SetSelectValue(axis, cfg, &val)
+				}
+			}
 		}
 	}
 
 	productConfigEnabledLabels := []bazel.Label{}
-	if !proptools.BoolDefault(enabledProperty.Value, true) {
+	// TODO(b/234497586): Soong config variables and product variables have different overriding behavior, we
+	// should handle it correctly
+	if !proptools.BoolDefault(enabledProperty.Value, true) && !neitherHostNorDevice {
 		// If the module is not enabled by default, then we can check if a
 		// product variable enables it
 		productConfigEnabledLabels = productVariableConfigEnableLabels(ctx)
@@ -1224,11 +1280,6 @@
 		productConfigEnabledLabels, nil,
 	})
 
-	moduleSupportsDevice := mod.commonProperties.HostOrDeviceSupported&deviceSupported == deviceSupported
-	if mod.commonProperties.HostOrDeviceSupported != NeitherHostNorDeviceSupported && !moduleSupportsDevice {
-		enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, Android.Name, proptools.BoolPtr(false))
-	}
-
 	platformEnabledAttribute, err := enabledProperty.ToLabelListAttribute(
 		bazel.LabelList{[]bazel.Label{bazel.Label{Label: "@platforms//:incompatible"}}, nil},
 		bazel.LabelList{[]bazel.Label{}, nil})
@@ -1236,6 +1287,13 @@
 		ctx.ModuleErrorf("Error processing platform enabled attribute: %s", err)
 	}
 
+	// if android is the only arch/os enabled, then add a restriction to only be compatible with android
+	if platformEnabledAttribute.IsNil() && onlyAndroid {
+		l := bazel.LabelAttribute{}
+		l.SetValue(bazel.Label{Label: bazel.OsConfigurationAxis.SelectKey(Android.Name)})
+		platformEnabledAttribute.Add(&l)
+	}
+
 	data.Append(required)
 
 	constraints := constraintAttributes{}
diff --git a/apex/androidmk.go b/apex/androidmk.go
index e094a12..938c8ed 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -412,6 +412,7 @@
 					fmt.Fprintln(w, ".PHONY:", goal)
 					fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
 						goal, a.installedFilesFile.String(), distFile)
+					fmt.Fprintf(w, "$(call declare-0p-target,%s)\n", a.installedFilesFile.String())
 				}
 				for _, dist := range data.Entries.GetDistForGoals(a) {
 					fmt.Fprintf(w, dist)
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 3affcb0..ab31581 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -27,17 +27,21 @@
 	"github.com/google/blueprint/proptools"
 )
 
+type artifactId int
+type depsetId int
+type pathFragmentId int
+
 // artifact contains relevant portions of Bazel's aquery proto, Artifact.
 // Represents a single artifact, whether it's a source file or a derived output file.
 type artifact struct {
-	Id             int
-	PathFragmentId int
+	Id             artifactId
+	PathFragmentId pathFragmentId
 }
 
 type pathFragment struct {
-	Id       int
+	Id       pathFragmentId
 	Label    string
-	ParentId int
+	ParentId pathFragmentId
 }
 
 // KeyValuePair represents Bazel's aquery proto, KeyValuePair.
@@ -63,9 +67,9 @@
 // Represents a data structure containing one or more files. Depsets in Bazel are an efficient
 // data structure for storing large numbers of file paths.
 type depSetOfFiles struct {
-	Id                  int
-	DirectArtifactIds   []int
-	TransitiveDepSetIds []int
+	Id                  depsetId
+	DirectArtifactIds   []artifactId
+	TransitiveDepSetIds []depsetId
 }
 
 // action contains relevant portions of Bazel's aquery proto, Action.
@@ -73,9 +77,9 @@
 type action struct {
 	Arguments            []string
 	EnvironmentVariables []KeyValuePair
-	InputDepSetIds       []int
+	InputDepSetIds       []depsetId
 	Mnemonic             string
-	OutputIds            []int
+	OutputIds            []artifactId
 	TemplateContent      string
 	Substitutions        []KeyValuePair
 }
@@ -113,20 +117,20 @@
 	// Maps depset id to AqueryDepset, a representation of depset which is
 	// post-processed for middleman artifact handling, unhandled artifact
 	// dropping, content hashing, etc.
-	depsetIdToAqueryDepset map[int]AqueryDepset
+	depsetIdToAqueryDepset map[depsetId]AqueryDepset
 	// Maps content hash to AqueryDepset.
 	depsetHashToAqueryDepset map[string]AqueryDepset
 
 	// depsetIdToArtifactIdsCache is a memoization of depset flattening, because flattening
 	// may be an expensive operation.
 	depsetHashToArtifactPathsCache map[string][]string
-	// Maps artifact ContentHash to fully expanded path.
-	artifactIdToPath map[int]string
+	// Maps artifact ids to fully expanded paths.
+	artifactIdToPath map[artifactId]string
 }
 
 // The tokens should be substituted with the value specified here, instead of the
 // one returned in 'substitutions' of TemplateExpand action.
-var TemplateActionOverriddenTokens = map[string]string{
+var templateActionOverriddenTokens = map[string]string{
 	// Uses "python3" for %python_binary% instead of the value returned by aquery
 	// which is "py3wrapper.sh". See removePy3wrapperScript.
 	"%python_binary%": "python3",
@@ -138,13 +142,20 @@
 // The file name of py3wrapper.sh, which is used by py_binary targets.
 const py3wrapperFileName = "/py3wrapper.sh"
 
-func newAqueryHandler(aqueryResult actionGraphContainer) (*aqueryArtifactHandler, error) {
-	pathFragments := map[int]pathFragment{}
-	for _, pathFragment := range aqueryResult.PathFragments {
-		pathFragments[pathFragment.Id] = pathFragment
+func indexBy[K comparable, V any](values []V, keyFn func(v V) K) map[K]V {
+	m := map[K]V{}
+	for _, v := range values {
+		m[keyFn(v)] = v
 	}
+	return m
+}
 
-	artifactIdToPath := map[int]string{}
+func newAqueryHandler(aqueryResult actionGraphContainer) (*aqueryArtifactHandler, error) {
+	pathFragments := indexBy(aqueryResult.PathFragments, func(pf pathFragment) pathFragmentId {
+		return pf.Id
+	})
+
+	artifactIdToPath := map[artifactId]string{}
 	for _, artifact := range aqueryResult.Artifacts {
 		artifactPath, err := expandPathFragment(artifact.PathFragmentId, pathFragments)
 		if err != nil {
@@ -158,7 +169,7 @@
 	// if we find a middleman action which has outputs [foo, bar], and output [baz_middleman], then,
 	// for each other action which has input [baz_middleman], we add [foo, bar] to the inputs for
 	// that action instead.
-	middlemanIdToDepsetIds := map[int][]int{}
+	middlemanIdToDepsetIds := map[artifactId][]depsetId{}
 	for _, actionEntry := range aqueryResult.Actions {
 		if actionEntry.Mnemonic == "Middleman" {
 			for _, outputId := range actionEntry.OutputIds {
@@ -167,19 +178,12 @@
 		}
 	}
 
-	// Store all depset IDs to validate all depset links are resolvable.
-	depsetIds := map[int]bool{}
-	for _, depset := range aqueryResult.DepSetOfFiles {
-		depsetIds[depset.Id] = true
-	}
-
-	depsetIdToDepset := map[int]depSetOfFiles{}
-	for _, depset := range aqueryResult.DepSetOfFiles {
-		depsetIdToDepset[depset.Id] = depset
-	}
+	depsetIdToDepset := indexBy(aqueryResult.DepSetOfFiles, func(d depSetOfFiles) depsetId {
+		return d.Id
+	})
 
 	aqueryHandler := aqueryArtifactHandler{
-		depsetIdToAqueryDepset:         map[int]AqueryDepset{},
+		depsetIdToAqueryDepset:         map[depsetId]AqueryDepset{},
 		depsetHashToAqueryDepset:       map[string]AqueryDepset{},
 		depsetHashToArtifactPathsCache: map[string][]string{},
 		artifactIdToPath:               artifactIdToPath,
@@ -198,12 +202,12 @@
 
 // Ensures that the handler's depsetIdToAqueryDepset map contains an entry for the given
 // depset.
-func (a *aqueryArtifactHandler) populateDepsetMaps(depset depSetOfFiles, middlemanIdToDepsetIds map[int][]int, depsetIdToDepset map[int]depSetOfFiles) (AqueryDepset, error) {
+func (a *aqueryArtifactHandler) populateDepsetMaps(depset depSetOfFiles, middlemanIdToDepsetIds map[artifactId][]depsetId, depsetIdToDepset map[depsetId]depSetOfFiles) (AqueryDepset, error) {
 	if aqueryDepset, containsDepset := a.depsetIdToAqueryDepset[depset.Id]; containsDepset {
 		return aqueryDepset, nil
 	}
 	transitiveDepsetIds := depset.TransitiveDepSetIds
-	directArtifactPaths := []string{}
+	var directArtifactPaths []string
 	for _, artifactId := range depset.DirectArtifactIds {
 		path, pathExists := a.artifactIdToPath[artifactId]
 		if !pathExists {
@@ -232,7 +236,7 @@
 		}
 	}
 
-	childDepsetHashes := []string{}
+	var childDepsetHashes []string
 	for _, childDepsetId := range transitiveDepsetIds {
 		childDepset, exists := depsetIdToDepset[childDepsetId]
 		if !exists {
@@ -258,8 +262,8 @@
 // input paths contained in these depsets.
 // This is a potentially expensive operation, and should not be invoked except
 // for actions which need specialized input handling.
-func (a *aqueryArtifactHandler) getInputPaths(depsetIds []int) ([]string, error) {
-	inputPaths := []string{}
+func (a *aqueryArtifactHandler) getInputPaths(depsetIds []depsetId) ([]string, error) {
+	var inputPaths []string
 
 	for _, inputDepSetId := range depsetIds {
 		depset := a.depsetIdToAqueryDepset[inputDepSetId]
@@ -296,7 +300,7 @@
 }
 
 // AqueryBuildStatements returns a slice of BuildStatements and a slice of AqueryDepset
-// which should be registered (and output  to a ninja file) to correspond with Bazel's
+// which should be registered (and output to a ninja file) to correspond with Bazel's
 // action graph, as described by the given action graph json proto.
 // BuildStatements are one-to-one with actions in the given action graph, and AqueryDepsets
 // are one-to-one with Bazel's depSetOfFiles objects.
@@ -338,7 +342,7 @@
 	}
 
 	depsetsByHash := map[string]AqueryDepset{}
-	depsets := []AqueryDepset{}
+	var depsets []AqueryDepset
 	for _, aqueryDepset := range aqueryHandler.depsetIdToAqueryDepset {
 		if prevEntry, hasKey := depsetsByHash[aqueryDepset.ContentHash]; hasKey {
 			// Two depsets collide on hash. Ensure that their contents are identical.
@@ -391,8 +395,8 @@
 	return fullHash
 }
 
-func (a *aqueryArtifactHandler) depsetContentHashes(inputDepsetIds []int) ([]string, error) {
-	hashes := []string{}
+func (a *aqueryArtifactHandler) depsetContentHashes(inputDepsetIds []depsetId) ([]string, error) {
+	var hashes []string
 	for _, depsetId := range inputDepsetIds {
 		if aqueryDepset, exists := a.depsetIdToAqueryDepset[depsetId]; !exists {
 			return nil, fmt.Errorf("undefined input depsetId %d", depsetId)
@@ -452,7 +456,7 @@
 	// See go/python-binary-host-mixed-build for more details.
 	pythonZipFilePath := outputPaths[0]
 	pyBinaryFound := false
-	for i, _ := range prevBuildStatements {
+	for i := range prevBuildStatements {
 		if len(prevBuildStatements[i].OutputPaths) == 1 && prevBuildStatements[i].OutputPaths[0]+".zip" == pythonZipFilePath {
 			prevBuildStatements[i].InputPaths = append(prevBuildStatements[i].InputPaths, pythonZipFilePath)
 			pyBinaryFound = true
@@ -565,7 +569,7 @@
 	replacerString := []string{}
 	for _, pair := range actionEntry.Substitutions {
 		value := pair.Value
-		if val, ok := TemplateActionOverriddenTokens[pair.Key]; ok {
+		if val, ok := templateActionOverriddenTokens[pair.Key]; ok {
 			value = val
 		}
 		replacerString = append(replacerString, pair.Key, value)
@@ -662,8 +666,8 @@
 	return false
 }
 
-func expandPathFragment(id int, pathFragmentsMap map[int]pathFragment) (string, error) {
-	labels := []string{}
+func expandPathFragment(id pathFragmentId, pathFragmentsMap map[pathFragmentId]pathFragment) (string, error) {
+	var labels []string
 	currId := id
 	// Only positive IDs are valid for path fragments. An ID of zero indicates a terminal node.
 	for currId > 0 {
diff --git a/bazel/properties.go b/bazel/properties.go
index f956031..e29b9e1 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -409,6 +409,11 @@
 	return false
 }
 
+// SetValue sets value for the no config axis
+func (ba *BoolAttribute) SetValue(value *bool) {
+	ba.SetSelectValue(NoConfigAxis, "", value)
+}
+
 // SetSelectValue sets value for the given axis/config.
 func (ba *BoolAttribute) SetSelectValue(axis ConfigurationAxis, config string, value *bool) {
 	axis.validateConfig(config)
@@ -652,6 +657,11 @@
 	}
 }
 
+// MakeSingleLabelListAttribute initializes a LabelListAttribute as a non-arch specific list with 1 element, the given Label.
+func MakeSingleLabelListAttribute(value Label) LabelListAttribute {
+	return MakeLabelListAttribute(MakeLabelList([]Label{value}))
+}
+
 func (lla *LabelListAttribute) SetValue(list LabelList) {
 	lla.SetSelectValue(NoConfigAxis, "", list)
 }
diff --git a/bp2build/android_app_certificate_conversion_test.go b/bp2build/android_app_certificate_conversion_test.go
index 035a352..173b4e4 100644
--- a/bp2build/android_app_certificate_conversion_test.go
+++ b/bp2build/android_app_certificate_conversion_test.go
@@ -42,7 +42,7 @@
 }
 `,
 		expectedBazelTargets: []string{
-			makeBazelTarget("android_app_certificate", "com.android.apogee.cert", attrNameToString{
+			makeBazelTargetNoRestrictions("android_app_certificate", "com.android.apogee.cert", attrNameToString{
 				"certificate": `"chamber_of_secrets_dir"`,
 			}),
 		}})
diff --git a/bp2build/apex_key_conversion_test.go b/bp2build/apex_key_conversion_test.go
index 1d949901..dfa96a2 100644
--- a/bp2build/apex_key_conversion_test.go
+++ b/bp2build/apex_key_conversion_test.go
@@ -42,7 +42,7 @@
         private_key: "com.android.apogee.pem",
 }
 `,
-		expectedBazelTargets: []string{makeBazelTarget("apex_key", "com.android.apogee.key", attrNameToString{
+		expectedBazelTargets: []string{makeBazelTargetNoRestrictions("apex_key", "com.android.apogee.key", attrNameToString{
 			"private_key": `"com.android.apogee.pem"`,
 			"public_key":  `"com.android.apogee.avbpubkey"`,
 		}),
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 0f6e139..19209f6 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -201,7 +201,7 @@
 			config := android.TestConfig(buildDir, nil, testCase.bp, nil)
 			ctx := android.NewTestContext(config)
 
-			ctx.RegisterModuleType("custom", customModuleFactory)
+			ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
 			ctx.Register()
 
 			_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
@@ -501,6 +501,215 @@
 	}
 }
 
+func TestBp2buildHostAndDevice(t *testing.T) {
+	testCases := []bp2buildTestCase{
+		{
+			description:                "host and device, device only",
+			moduleTypeUnderTest:        "custom",
+			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+			blueprint: `custom {
+		name: "foo",
+		bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{
+				makeBazelTargetHostOrDevice("custom", "foo", attrNameToString{}, android.DeviceSupported),
+			},
+		},
+		{
+			description:                "host and device, both",
+			moduleTypeUnderTest:        "custom",
+			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+			blueprint: `custom {
+		name: "foo",
+		host_supported: true,
+		bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{
+				makeBazelTargetNoRestrictions("custom", "foo", attrNameToString{}),
+			},
+		},
+		{
+			description:                "host and device, host explicitly disabled",
+			moduleTypeUnderTest:        "custom",
+			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+			blueprint: `custom {
+		name: "foo",
+		host_supported: false,
+		bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{
+				makeBazelTargetHostOrDevice("custom", "foo", attrNameToString{}, android.DeviceSupported),
+			},
+		},
+		{
+			description:                "host and device, neither",
+			moduleTypeUnderTest:        "custom",
+			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+			blueprint: `custom {
+		name: "foo",
+		host_supported: false,
+		device_supported: false,
+		bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{
+				makeBazelTargetNoRestrictions("custom", "foo", attrNameToString{
+					"target_compatible_with": `["@platforms//:incompatible"]`,
+				}),
+			},
+		},
+		{
+			description:                "host and device, neither, cannot override with product_var",
+			moduleTypeUnderTest:        "custom",
+			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+			blueprint: `custom {
+		name: "foo",
+		host_supported: false,
+		device_supported: false,
+		product_variables: { unbundled_build: { enabled: true } },
+		bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{
+				makeBazelTargetNoRestrictions("custom", "foo", attrNameToString{
+					"target_compatible_with": `["@platforms//:incompatible"]`,
+				}),
+			},
+		},
+		{
+			description:                "host and device, both, disabled overrided with product_var",
+			moduleTypeUnderTest:        "custom",
+			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+			blueprint: `custom {
+		name: "foo",
+		host_supported: true,
+		device_supported: true,
+		enabled: false,
+		product_variables: { unbundled_build: { enabled: true } },
+		bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{
+				makeBazelTargetNoRestrictions("custom", "foo", attrNameToString{
+					"target_compatible_with": `["//build/bazel/product_variables:unbundled_build"]`,
+				}),
+			},
+		},
+		{
+			description:                "host and device, neither, cannot override with arch enabled",
+			moduleTypeUnderTest:        "custom",
+			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+			blueprint: `custom {
+		name: "foo",
+		host_supported: false,
+		device_supported: false,
+		arch: { x86: { enabled: true } },
+		bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{
+				makeBazelTargetNoRestrictions("custom", "foo", attrNameToString{
+					"target_compatible_with": `["@platforms//:incompatible"]`,
+				}),
+			},
+		},
+		{
+			description:                "host and device, host only",
+			moduleTypeUnderTest:        "custom",
+			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+			blueprint: `custom {
+		name: "foo",
+		host_supported: true,
+		device_supported: false,
+		bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{
+				makeBazelTargetHostOrDevice("custom", "foo", attrNameToString{}, android.HostSupported),
+			},
+		},
+		{
+			description:                "host only",
+			moduleTypeUnderTest:        "custom",
+			moduleTypeUnderTestFactory: customModuleFactoryHostSupported,
+			blueprint: `custom {
+		name: "foo",
+		bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{
+				makeBazelTargetHostOrDevice("custom", "foo", attrNameToString{}, android.HostSupported),
+			},
+		},
+		{
+			description:                "device only",
+			moduleTypeUnderTest:        "custom",
+			moduleTypeUnderTestFactory: customModuleFactoryDeviceSupported,
+			blueprint: `custom {
+		name: "foo",
+		bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{
+				makeBazelTargetHostOrDevice("custom", "foo", attrNameToString{}, android.DeviceSupported),
+			},
+		},
+		{
+			description:                "host and device default, default",
+			moduleTypeUnderTest:        "custom",
+			moduleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
+			blueprint: `custom {
+		name: "foo",
+		bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{
+				makeBazelTargetNoRestrictions("custom", "foo", attrNameToString{}),
+			},
+		},
+		{
+			description:                "host and device default, device only",
+			moduleTypeUnderTest:        "custom",
+			moduleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
+			blueprint: `custom {
+		name: "foo",
+		host_supported: false,
+		bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{
+				makeBazelTargetHostOrDevice("custom", "foo", attrNameToString{}, android.DeviceSupported),
+			},
+		},
+		{
+			description:                "host and device default, host only",
+			moduleTypeUnderTest:        "custom",
+			moduleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
+			blueprint: `custom {
+		name: "foo",
+		device_supported: false,
+		bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{
+				makeBazelTargetHostOrDevice("custom", "foo", attrNameToString{}, android.HostSupported),
+			},
+		},
+		{
+			description:                "host and device default, neither",
+			moduleTypeUnderTest:        "custom",
+			moduleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
+			blueprint: `custom {
+		name: "foo",
+		host_supported: false,
+		device_supported: false,
+		bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{
+				makeBazelTargetNoRestrictions("custom", "foo", attrNameToString{
+					"target_compatible_with": `["@platforms//:incompatible"]`,
+				}),
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.description, func(t *testing.T) {
+			runBp2BuildTestCaseSimple(t, tc)
+		})
+	}
+}
+
 func TestLoadStatements(t *testing.T) {
 	testCases := []struct {
 		bazelTargets           BazelTargets
@@ -610,6 +819,7 @@
 		{
 			bp: `custom {
     name: "bar",
+    host_supported: true,
     one_to_many_prop: true,
     bazel_module: { bp2build_available: true  },
 }`,
@@ -634,7 +844,7 @@
 	for _, testCase := range testCases {
 		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
 		ctx := android.NewTestContext(config)
-		ctx.RegisterModuleType("custom", customModuleFactory)
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
@@ -680,7 +890,7 @@
     bazel_module: { bp2build_available: true },
 }`,
 			expectedBazelTargets: []string{
-				makeBazelTarget("filegroup", "fg_foo", map[string]string{}),
+				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
 			},
 		},
 		{
@@ -693,7 +903,7 @@
     bazel_module: { bp2build_available: true },
 }`,
 			expectedBazelTargets: []string{
-				makeBazelTarget("filegroup", "fg_foo", map[string]string{}),
+				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
 			},
 		},
 		{
@@ -706,7 +916,7 @@
     bazel_module: { bp2build_available: true },
 }`,
 			expectedBazelTargets: []string{
-				makeBazelTarget("filegroup", "fg_foo", map[string]string{
+				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"srcs": `[
         "a",
         "b",
@@ -725,7 +935,7 @@
     bazel_module: { bp2build_available: true },
 }`,
 			expectedBazelTargets: []string{
-				makeBazelTarget("filegroup", "fg_foo", map[string]string{
+				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"srcs": `["b"]`,
 				}),
 			},
@@ -740,7 +950,7 @@
     bazel_module: { bp2build_available: true },
 }`,
 			expectedBazelTargets: []string{
-				makeBazelTarget("filegroup", "fg_foo", map[string]string{
+				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"srcs": `[
         "other/a.txt",
         "other/b.txt",
@@ -772,7 +982,7 @@
 				"other/file":         "",
 			},
 			expectedBazelTargets: []string{
-				makeBazelTarget("filegroup", "fg_foo", map[string]string{
+				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"srcs": `[
         "a.txt",
         "b.txt",
@@ -801,7 +1011,7 @@
 }`,
 			},
 			expectedBazelTargets: []string{
-				makeBazelTarget("filegroup", "fg_foo", map[string]string{
+				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"srcs": `[
         "//other:foo",
         "c",
@@ -884,7 +1094,7 @@
 		{
 			description:                "generates more than 1 target if needed",
 			moduleTypeUnderTest:        "custom",
-			moduleTypeUnderTestFactory: customModuleFactory,
+			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
 			bp: `custom {
     name: "foo",
     one_to_many_prop: true,
@@ -1092,7 +1302,7 @@
 				"other/BUILD.bazel": `// definition for fg_bar`,
 			},
 			expectedBazelTargets: []string{
-				makeBazelTarget("filegroup", "fg_foo", map[string]string{}),
+				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
 				`// definition for fg_bar`,
 			},
 		},
@@ -1118,7 +1328,7 @@
         },
     }`,
 			expectedBazelTargets: []string{
-				makeBazelTarget("filegroup", "fg_bar", map[string]string{}),
+				makeBazelTargetNoRestrictions("filegroup", "fg_bar", map[string]string{}),
 				`// BUILD file`,
 			},
 		},
@@ -1203,7 +1413,7 @@
 				"dir/f.txt":      "",
 			},
 			expectedBazelTargets: []string{
-				makeBazelTarget("filegroup", "fg_foo", map[string]string{
+				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"srcs": `[
         "a.txt",
         "b.txt",
@@ -1234,7 +1444,7 @@
 				"dir/subdir/f.txt":      "",
 			},
 			expectedBazelTargets: []string{
-				makeBazelTarget("filegroup", "fg_foo", map[string]string{
+				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"srcs": `[
         "a.txt",
         "//dir/subdir:e.txt",
@@ -1265,7 +1475,7 @@
     bazel_module: { bp2build_available: true },
 }`,
 			expectedBazelTargets: []string{
-				makeBazelTarget("filegroup", "fg_foo", map[string]string{
+				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"data": `[":reqd"]`,
 				}),
 			},
@@ -1337,7 +1547,7 @@
     bazel_module: { bp2build_available: true },
 }`,
 			expectedBazelTargets: []string{
-				makeBazelTarget("filegroup", "fg_foo", map[string]string{
+				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"data": `[":reqd"]`,
 				}),
 			},
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index 30be997..4794269 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -34,10 +34,11 @@
 	attrs attrNameToString
 }
 
-func generateBazelTargetsForTest(targets []testBazelTarget) []string {
+func generateBazelTargetsForTest(targets []testBazelTarget, hod android.HostOrDeviceSupported) []string {
 	ret := make([]string, 0, len(targets))
 	for _, t := range targets {
-		ret = append(ret, makeBazelTarget(t.typ, t.name, t.attrs))
+		attrs := t.attrs.clone()
+		ret = append(ret, makeBazelTargetHostOrDevice(t.typ, t.name, attrs, hod))
 	}
 	return ret
 }
@@ -65,42 +66,33 @@
 	runCcHostBinaryTestCase(t, tc)
 }
 
-func runCcBinaryTestCase(t *testing.T, tc ccBinaryBp2buildTestCase) {
+func runCcBinaryTestCase(t *testing.T, testCase ccBinaryBp2buildTestCase) {
 	t.Helper()
 	moduleTypeUnderTest := "cc_binary"
-	testCase := bp2buildTestCase{
-		expectedBazelTargets:       generateBazelTargetsForTest(tc.targets),
-		moduleTypeUnderTest:        moduleTypeUnderTest,
-		moduleTypeUnderTestFactory: cc.BinaryFactory,
-		description:                fmt.Sprintf("%s %s", moduleTypeUnderTest, tc.description),
-		blueprint:                  binaryReplacer.Replace(tc.blueprint),
-	}
-	t.Run(testCase.description, func(t *testing.T) {
+
+	description := fmt.Sprintf("%s %s", moduleTypeUnderTest, testCase.description)
+	t.Run(description, func(t *testing.T) {
 		t.Helper()
-		runBp2BuildTestCase(t, registerCcBinaryModuleTypes, testCase)
+		runBp2BuildTestCase(t, registerCcBinaryModuleTypes, bp2buildTestCase{
+			expectedBazelTargets:       generateBazelTargetsForTest(testCase.targets, android.DeviceSupported),
+			moduleTypeUnderTest:        moduleTypeUnderTest,
+			moduleTypeUnderTestFactory: cc.BinaryFactory,
+			description:                description,
+			blueprint:                  binaryReplacer.Replace(testCase.blueprint),
+		})
 	})
 }
 
-func runCcHostBinaryTestCase(t *testing.T, tc ccBinaryBp2buildTestCase) {
+func runCcHostBinaryTestCase(t *testing.T, testCase ccBinaryBp2buildTestCase) {
 	t.Helper()
-	testCase := tc
-	for i, tar := range testCase.targets {
-		switch tar.typ {
-		case "cc_binary", "proto_library", "cc_lite_proto_library", "genlex":
-			tar.attrs["target_compatible_with"] = `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`
-		}
-		testCase.targets[i] = tar
-	}
 	moduleTypeUnderTest := "cc_binary_host"
-	t.Run(testCase.description, func(t *testing.T) {
+	description := fmt.Sprintf("%s %s", moduleTypeUnderTest, testCase.description)
+	t.Run(description, func(t *testing.T) {
 		runBp2BuildTestCase(t, registerCcBinaryModuleTypes, bp2buildTestCase{
-			expectedBazelTargets:       generateBazelTargetsForTest(testCase.targets),
+			expectedBazelTargets:       generateBazelTargetsForTest(testCase.targets, android.HostSupported),
 			moduleTypeUnderTest:        moduleTypeUnderTest,
 			moduleTypeUnderTestFactory: cc.BinaryHostFactory,
-			description:                fmt.Sprintf("%s %s", moduleTypeUnderTest, tc.description),
+			description:                description,
 			blueprint:                  hostBinaryReplacer.Replace(testCase.blueprint),
 		})
 	})
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index a0bc9e7..b7de452 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -2278,6 +2278,7 @@
 		blueprint: soongCcProtoPreamble + `cc_library {
 	name: "foo",
 	srcs: ["foo.cpp"],
+	host_supported: true,
 	target: {
 		darwin: {
 			enabled: false,
@@ -2313,6 +2314,7 @@
 	name: "foo",
 	srcs: ["foo.cpp"],
   enabled: false,
+	host_supported: true,
 	target: {
 		darwin: {
 			enabled: true,
@@ -2377,6 +2379,7 @@
 		moduleTypeUnderTestFactory: cc.LibraryFactory,
 		blueprint: soongCcProtoPreamble + `cc_library {
 	name: "foo",
+	host_supported: true,
 	srcs: ["foo.cpp"],
 	shared: {
 		enabled: false
diff --git a/bp2build/genrule_conversion_test.go b/bp2build/genrule_conversion_test.go
index 9244b99..4504892 100644
--- a/bp2build/genrule_conversion_test.go
+++ b/bp2build/genrule_conversion_test.go
@@ -56,6 +56,7 @@
 		moduleType string
 		factory    android.ModuleFactory
 		genDir     string
+		hod        android.HostOrDeviceSupported
 	}{
 		{
 			moduleType: "genrule",
@@ -66,16 +67,19 @@
 			moduleType: "cc_genrule",
 			factory:    cc.GenRuleFactory,
 			genDir:     "$(RULEDIR)",
+			hod:        android.DeviceSupported,
 		},
 		{
 			moduleType: "java_genrule",
 			factory:    java.GenRuleFactory,
 			genDir:     "$(RULEDIR)",
+			hod:        android.DeviceSupported,
 		},
 		{
 			moduleType: "java_genrule_host",
 			factory:    java.GenRuleFactoryHost,
 			genDir:     "$(RULEDIR)",
+			hod:        android.HostSupported,
 		},
 	}
 
@@ -104,15 +108,8 @@
 			"tools": `[":foo.tool"]`,
 		}
 
-		if tc.moduleType == "java_genrule_host" {
-			moduleAttrs["target_compatible_with"] = `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`
-		}
-
 		expectedBazelTargets := []string{
-			makeBazelTarget("genrule", "foo", moduleAttrs),
+			makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
 		}
 
 		t.Run(tc.moduleType, func(t *testing.T) {
@@ -131,6 +128,7 @@
 	testCases := []struct {
 		moduleType string
 		factory    android.ModuleFactory
+		hod        android.HostOrDeviceSupported
 	}{
 		{
 			moduleType: "genrule",
@@ -139,14 +137,17 @@
 		{
 			moduleType: "cc_genrule",
 			factory:    cc.GenRuleFactory,
+			hod:        android.DeviceSupported,
 		},
 		{
 			moduleType: "java_genrule",
 			factory:    java.GenRuleFactory,
+			hod:        android.DeviceSupported,
 		},
 		{
 			moduleType: "java_genrule_host",
 			factory:    java.GenRuleFactoryHost,
+			hod:        android.HostSupported,
 		},
 	}
 
@@ -183,18 +184,9 @@
 			"srcs": `["foo_tool.in"]`,
 		}
 
-		if tc.moduleType == "java_genrule_host" {
-			compatibilityAttrs := `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`
-			fooAttrs["target_compatible_with"] = compatibilityAttrs
-			fooToolsAttrs["target_compatible_with"] = compatibilityAttrs
-		}
-
 		expectedBazelTargets := []string{
-			makeBazelTarget("genrule", "foo", fooAttrs),
-			makeBazelTarget("genrule", "foo.tools", fooToolsAttrs),
+			makeBazelTargetHostOrDevice("genrule", "foo", fooAttrs, tc.hod),
+			makeBazelTargetHostOrDevice("genrule", "foo.tools", fooToolsAttrs, tc.hod),
 		}
 
 		t.Run(tc.moduleType, func(t *testing.T) {
@@ -213,6 +205,7 @@
 	testCases := []struct {
 		moduleType string
 		factory    android.ModuleFactory
+		hod        android.HostOrDeviceSupported
 	}{
 		{
 			moduleType: "genrule",
@@ -221,14 +214,17 @@
 		{
 			moduleType: "cc_genrule",
 			factory:    cc.GenRuleFactory,
+			hod:        android.DeviceSupported,
 		},
 		{
 			moduleType: "java_genrule",
 			factory:    java.GenRuleFactory,
+			hod:        android.DeviceSupported,
 		},
 		{
 			moduleType: "java_genrule_host",
 			factory:    java.GenRuleFactoryHost,
+			hod:        android.HostSupported,
 		},
 	}
 
@@ -249,15 +245,8 @@
 			"tools": `["//other:foo.tool"]`,
 		}
 
-		if tc.moduleType == "java_genrule_host" {
-			moduleAttrs["target_compatible_with"] = `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`
-		}
-
 		expectedBazelTargets := []string{
-			makeBazelTarget("genrule", "foo", moduleAttrs),
+			makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
 		}
 
 		t.Run(tc.moduleType, func(t *testing.T) {
@@ -277,6 +266,7 @@
 	testCases := []struct {
 		moduleType string
 		factory    android.ModuleFactory
+		hod        android.HostOrDeviceSupported
 	}{
 		{
 			moduleType: "genrule",
@@ -285,14 +275,17 @@
 		{
 			moduleType: "cc_genrule",
 			factory:    cc.GenRuleFactory,
+			hod:        android.DeviceSupported,
 		},
 		{
 			moduleType: "java_genrule",
 			factory:    java.GenRuleFactory,
+			hod:        android.DeviceSupported,
 		},
 		{
 			moduleType: "java_genrule_host",
 			factory:    java.GenRuleFactoryHost,
+			hod:        android.HostSupported,
 		},
 	}
 
@@ -313,15 +306,8 @@
 			"tools": `["//other:foo.tool"]`,
 		}
 
-		if tc.moduleType == "java_genrule_host" {
-			moduleAttrs["target_compatible_with"] = `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`
-		}
-
 		expectedBazelTargets := []string{
-			makeBazelTarget("genrule", "foo", moduleAttrs),
+			makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
 		}
 
 		t.Run(tc.moduleType, func(t *testing.T) {
@@ -341,6 +327,7 @@
 	testCases := []struct {
 		moduleType string
 		factory    android.ModuleFactory
+		hod        android.HostOrDeviceSupported
 	}{
 		{
 			moduleType: "genrule",
@@ -349,14 +336,17 @@
 		{
 			moduleType: "cc_genrule",
 			factory:    cc.GenRuleFactory,
+			hod:        android.DeviceSupported,
 		},
 		{
 			moduleType: "java_genrule",
 			factory:    java.GenRuleFactory,
+			hod:        android.DeviceSupported,
 		},
 		{
 			moduleType: "java_genrule_host",
 			factory:    java.GenRuleFactoryHost,
+			hod:        android.HostSupported,
 		},
 	}
 
@@ -380,15 +370,8 @@
     ]`,
 		}
 
-		if tc.moduleType == "java_genrule_host" {
-			moduleAttrs["target_compatible_with"] = `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`
-		}
-
 		expectedBazelTargets := []string{
-			makeBazelTarget("genrule", "foo", moduleAttrs),
+			makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
 		}
 
 		t.Run(tc.moduleType, func(t *testing.T) {
@@ -408,6 +391,7 @@
 	testCases := []struct {
 		moduleType string
 		factory    android.ModuleFactory
+		hod        android.HostOrDeviceSupported
 	}{
 		{
 			moduleType: "genrule",
@@ -416,14 +400,17 @@
 		{
 			moduleType: "cc_genrule",
 			factory:    cc.GenRuleFactory,
+			hod:        android.DeviceSupported,
 		},
 		{
 			moduleType: "java_genrule",
 			factory:    java.GenRuleFactory,
+			hod:        android.DeviceSupported,
 		},
 		{
 			moduleType: "java_genrule_host",
 			factory:    java.GenRuleFactoryHost,
+			hod:        android.HostSupported,
 		},
 	}
 
@@ -447,15 +434,8 @@
     ]`,
 		}
 
-		if tc.moduleType == "java_genrule_host" {
-			moduleAttrs["target_compatible_with"] = `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`
-		}
-
 		expectedBazelTargets := []string{
-			makeBazelTarget("genrule", "foo", moduleAttrs),
+			makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
 		}
 
 		t.Run(tc.moduleType, func(t *testing.T) {
@@ -475,6 +455,7 @@
 	testCases := []struct {
 		moduleType string
 		factory    android.ModuleFactory
+		hod        android.HostOrDeviceSupported
 	}{
 		{
 			moduleType: "genrule",
@@ -483,14 +464,17 @@
 		{
 			moduleType: "cc_genrule",
 			factory:    cc.GenRuleFactory,
+			hod:        android.DeviceSupported,
 		},
 		{
 			moduleType: "java_genrule",
 			factory:    java.GenRuleFactory,
+			hod:        android.DeviceSupported,
 		},
 		{
 			moduleType: "java_genrule_host",
 			factory:    java.GenRuleFactoryHost,
+			hod:        android.HostSupported,
 		},
 	}
 
@@ -509,15 +493,8 @@
 			"srcs": `["foo.in"]`,
 		}
 
-		if tc.moduleType == "java_genrule_host" {
-			moduleAttrs["target_compatible_with"] = `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`
-		}
-
 		expectedBazelTargets := []string{
-			makeBazelTarget("genrule", "foo", moduleAttrs),
+			makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
 		}
 
 		t.Run(tc.moduleType, func(t *testing.T) {
@@ -549,7 +526,7 @@
 }
 `,
 			expectedBazelTargets: []string{
-				makeBazelTarget("genrule", "gen", attrNameToString{
+				makeBazelTargetNoRestrictions("genrule", "gen", attrNameToString{
 					"cmd":  `"do-something $(SRCS) $(OUTS)"`,
 					"outs": `["out"]`,
 					"srcs": `["in1"]`,
@@ -574,7 +551,7 @@
 }
 `,
 			expectedBazelTargets: []string{
-				makeBazelTarget("genrule", "gen", attrNameToString{
+				makeBazelTargetNoRestrictions("genrule", "gen", attrNameToString{
 					"cmd": `"do-something $(SRCS) $(OUTS)"`,
 					"outs": `[
         "out-from-defaults",
@@ -607,7 +584,7 @@
 }
 `,
 			expectedBazelTargets: []string{
-				makeBazelTarget("genrule", "gen", attrNameToString{
+				makeBazelTargetNoRestrictions("genrule", "gen", attrNameToString{
 					"cmd":  `"cp $(SRCS) $(OUTS)"`,
 					"outs": `["out"]`,
 					"srcs": `["in1"]`,
@@ -644,7 +621,7 @@
 }
 `,
 			expectedBazelTargets: []string{
-				makeBazelTarget("genrule", "gen", attrNameToString{
+				makeBazelTargetNoRestrictions("genrule", "gen", attrNameToString{
 					"cmd": `"cmd1 $(SRCS) $(OUTS)"`,
 					"outs": `[
         "out-from-3",
diff --git a/bp2build/gensrcs_conversion_test.go b/bp2build/gensrcs_conversion_test.go
new file mode 100644
index 0000000..ebe60bf
--- /dev/null
+++ b/bp2build/gensrcs_conversion_test.go
@@ -0,0 +1,80 @@
+// 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"
+	"android/soong/genrule"
+	"testing"
+)
+
+func TestGensrcs(t *testing.T) {
+	testcases := []struct {
+		name               string
+		bp                 string
+		expectedBazelAttrs attrNameToString
+	}{
+		{
+			name: "gensrcs with common usage of properties",
+			bp: `
+			gensrcs {
+                name: "foo",
+                srcs: ["test/input.txt", ":external_files"],
+                tool_files: ["program.py"],
+                cmd: "$(location program.py) $(in) $(out)",
+                output_extension: "out",
+                bazel_module: { bp2build_available: true },
+			}`,
+			expectedBazelAttrs: attrNameToString{
+				"srcs": `[
+        "test/input.txt",
+        ":external_files__BP2BUILD__MISSING__DEP",
+    ]`,
+				"tools":            `["program.py"]`,
+				"output_extension": `"out"`,
+				"cmd":              `"$(location program.py) $(SRC) $(OUT)"`,
+			},
+		},
+		{
+			name: "gensrcs with out_extension unset",
+			bp: `
+			gensrcs {
+                name: "foo",
+                srcs: ["input.txt"],
+                cmd: "cat $(in) > $(out)",
+                bazel_module: { bp2build_available: true },
+			}`,
+			expectedBazelAttrs: attrNameToString{
+				"srcs": `["input.txt"]`,
+				"cmd":  `"cat $(SRC) > $(OUT)"`,
+			},
+		},
+	}
+
+	for _, test := range testcases {
+		expectedBazelTargets := []string{
+			makeBazelTarget("gensrcs", "foo", test.expectedBazelAttrs),
+		}
+		t.Run(test.name, func(t *testing.T) {
+			runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+				bp2buildTestCase{
+					moduleTypeUnderTest:        "gensrcs",
+					moduleTypeUnderTestFactory: genrule.GenSrcsFactory,
+					blueprint:                  test.bp,
+					expectedBazelTargets:       expectedBazelTargets,
+				})
+		})
+	}
+}
diff --git a/bp2build/python_library_conversion_test.go b/bp2build/python_library_conversion_test.go
index 66c2290..f51f106 100644
--- a/bp2build/python_library_conversion_test.go
+++ b/bp2build/python_library_conversion_test.go
@@ -305,3 +305,46 @@
 		},
 	})
 }
+
+func TestPythonLibraryWithProtobufs(t *testing.T) {
+	runPythonLibraryTestCases(t, pythonLibBp2BuildTestCase{
+		description: "test %s protobuf",
+		filesystem: map[string]string{
+			"dir/mylib.py":      "",
+			"dir/myproto.proto": "",
+		},
+		blueprint: `%s {
+					 name: "foo",
+					 srcs: [
+						"dir/mylib.py",
+						"dir/myproto.proto",
+					 ],
+				 }`,
+		expectedBazelTargets: []testBazelTarget{
+			{
+				typ:  "proto_library",
+				name: "foo_proto",
+				attrs: attrNameToString{
+					"srcs": `["dir/myproto.proto"]`,
+				},
+			},
+			{
+				typ:  "py_proto_library",
+				name: "foo_py_proto",
+				attrs: attrNameToString{
+					"deps": `[":foo_proto"]`,
+				},
+			},
+			{
+				typ:  "py_library",
+				name: "foo",
+				attrs: attrNameToString{
+					"srcs":         `["dir/mylib.py"]`,
+					"srcs_version": `"PY3"`,
+					"imports":      `["."]`,
+					"deps":         `[":foo_py_proto"]`,
+				},
+			},
+		},
+	})
+}
diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go
index b1e1fb2..8460cae 100644
--- a/bp2build/soong_config_module_type_conversion_test.go
+++ b/bp2build/soong_config_module_type_conversion_test.go
@@ -49,6 +49,7 @@
 custom_cc_library_static {
 	name: "foo",
 	bazel_module: { bp2build_available: true },
+	host_supported: true,
 	soong_config_variables: {
 		feature1: {
 			conditions_default: {
@@ -94,6 +95,7 @@
 custom_cc_library_static {
 	name: "foo",
 	bazel_module: { bp2build_available: true },
+	host_supported: true,
 	soong_config_variables: {
 		feature1: {
 			conditions_default: {
@@ -141,6 +143,7 @@
 custom_cc_library_static {
 	name: "foo",
 	bazel_module: { bp2build_available: true },
+	host_supported: true,
 	soong_config_variables: {
 		board: {
 			soc_a: {
@@ -200,6 +203,7 @@
 custom_cc_library_static {
 	name: "foo",
 	bazel_module: { bp2build_available: true },
+	host_supported: true,
 	soong_config_variables: {
 		feature1: {
 			conditions_default: {
@@ -268,6 +272,7 @@
 custom_cc_library_static {
 	name: "foo",
 	bazel_module: { bp2build_available: true },
+	host_supported: true,
 	soong_config_variables: {
 		board: {
 			soc_a: {
@@ -356,6 +361,7 @@
 	name: "lib",
 	defaults: ["foo_defaults_2"],
 	bazel_module: { bp2build_available: true },
+	host_supported: true,
 }
 `
 
@@ -429,12 +435,14 @@
 	name: "lib",
 	defaults: ["foo_defaults", "bar_defaults"],
 	bazel_module: { bp2build_available: true },
+	host_supported: true,
 }
 
 cc_library_static {
 	name: "lib2",
 	defaults: ["bar_defaults", "foo_defaults"],
 	bazel_module: { bp2build_available: true },
+	host_supported: true,
 }
 `
 
@@ -550,6 +558,7 @@
 	name: "lib",
 	defaults: ["foo_defaults", "qux_defaults"],
 	bazel_module: { bp2build_available: true },
+	host_supported: true,
 }
 `
 
@@ -615,6 +624,7 @@
 library_linking_strategy_cc_defaults {
     name: "library_linking_strategy_merged_defaults",
     defaults: ["library_linking_strategy_lib_a_defaults"],
+    host_supported: true,
     soong_config_variables: {
         library_linking_strategy: {
             prefer_static: {
@@ -714,6 +724,7 @@
 
 cc_binary {
     name: "library_linking_strategy_sample_binary",
+    host_supported: true,
     srcs: ["library_linking_strategy.cc"],
     defaults: ["library_linking_strategy_sample_defaults"],
 }`
@@ -800,6 +811,7 @@
 
 cc_binary {
     name: "alphabet_binary",
+    host_supported: true,
     srcs: ["main.cc"],
     defaults: ["alphabet_sample_cc_defaults"],
 }`
@@ -861,6 +873,7 @@
 cc_binary {
     name: "alphabet_binary",
     srcs: ["main.cc"],
+    host_supported: true,
     defaults: ["alphabet_sample_cc_defaults"],
     enabled: false,
     arch: {
@@ -958,6 +971,7 @@
 
 alphabet_cc_defaults {
     name: "alphabet_sample_cc_defaults",
+    host_supported: true,
     soong_config_variables: {
         special_build: {
             enabled: true,
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 9341495..580bac4 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -213,12 +213,36 @@
 	return module
 }
 
-func customModuleFactory() android.Module {
+func customModuleFactoryHostAndDevice() android.Module {
 	m := customModuleFactoryBase()
 	android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibBoth)
 	return m
 }
 
+func customModuleFactoryDeviceSupported() android.Module {
+	m := customModuleFactoryBase()
+	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibBoth)
+	return m
+}
+
+func customModuleFactoryHostSupported() android.Module {
+	m := customModuleFactoryBase()
+	android.InitAndroidArchModule(m, android.HostSupported, android.MultilibBoth)
+	return m
+}
+
+func customModuleFactoryHostAndDeviceDefault() android.Module {
+	m := customModuleFactoryBase()
+	android.InitAndroidArchModule(m, android.HostAndDeviceDefault, android.MultilibBoth)
+	return m
+}
+
+func customModuleFactoryNeitherHostNorDeviceSupported() android.Module {
+	m := customModuleFactoryBase()
+	android.InitAndroidArchModule(m, android.NeitherHostNorDeviceSupported, android.MultilibBoth)
+	return m
+}
+
 type testProps struct {
 	Test_prop struct {
 		Test_string_prop string
@@ -355,7 +379,7 @@
 }
 
 func registerCustomModuleForBp2buildConversion(ctx *android.TestContext) {
-	ctx.RegisterModuleType("custom", customModuleFactory)
+	ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
 	ctx.RegisterForBazelConversion()
 }
 
@@ -369,7 +393,29 @@
 
 type attrNameToString map[string]string
 
-func makeBazelTarget(typ, name string, attrs attrNameToString) string {
+func (a attrNameToString) clone() attrNameToString {
+	newAttrs := make(attrNameToString, len(a))
+	for k, v := range a {
+		newAttrs[k] = v
+	}
+	return newAttrs
+}
+
+// makeBazelTargetNoRestrictions returns bazel target build file definition that can be host or
+// device specific, or independent of host/device.
+func makeBazelTargetHostOrDevice(typ, name string, attrs attrNameToString, hod android.HostOrDeviceSupported) string {
+	if _, ok := attrs["target_compatible_with"]; !ok {
+		switch hod {
+		case android.HostSupported:
+			attrs["target_compatible_with"] = `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`
+		case android.DeviceSupported:
+			attrs["target_compatible_with"] = `["//build/bazel/platforms/os:android"]`
+		}
+	}
+
 	attrStrings := make([]string, 0, len(attrs)+1)
 	attrStrings = append(attrStrings, fmt.Sprintf(`    name = "%s",`, name))
 	for _, k := range android.SortedStringKeys(attrs) {
@@ -379,3 +425,16 @@
 %s
 )`, typ, strings.Join(attrStrings, "\n"))
 }
+
+// makeBazelTargetNoRestrictions returns bazel target build file definition that does not add a
+// target_compatible_with.  This is useful for module types like filegroup and genrule that arch not
+// arch variant
+func makeBazelTargetNoRestrictions(typ, name string, attrs attrNameToString) string {
+	return makeBazelTargetHostOrDevice(typ, name, attrs, android.HostAndDeviceDefault)
+}
+
+// makeBazelTargetNoRestrictions returns bazel target build file definition that is device specific
+// as this is the most common default in Soong.
+func makeBazelTarget(typ, name string, attrs attrNameToString) string {
+	return makeBazelTargetHostOrDevice(typ, name, attrs, android.DeviceSupported)
+}
diff --git a/cc/builder.go b/cc/builder.go
index 9248f97..72f7d12 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -829,24 +829,13 @@
 	deps = append(deps, crtBegin...)
 	deps = append(deps, crtEnd...)
 
-	var depFile android.WritablePath
-	var depFileLdFlags string
-	depsType := blueprint.DepsNone
-	if !ctx.Windows() && !ctx.Darwin() {
-		// lld only supports --dependency-file for elf files
-		depFile = outputFile.ReplaceExtension(ctx, "d")
-		depFileLdFlags = " -Wl,--dependency-file=" + depFile.String()
-		depsType = blueprint.DepsGCC
-		implicitOutputs = append(implicitOutputs, depFile)
-	}
-
 	rule := ld
 	args := map[string]string{
 		"ldCmd":         ldCmd,
 		"crtBegin":      strings.Join(crtBegin.Strings(), " "),
 		"libFlags":      strings.Join(libFlagsList, " "),
 		"extraLibFlags": flags.extraLibFlags,
-		"ldFlags":       flags.globalLdFlags + " " + flags.localLdFlags + depFileLdFlags,
+		"ldFlags":       flags.globalLdFlags + " " + flags.localLdFlags,
 		"crtEnd":        strings.Join(crtEnd.Strings(), " "),
 	}
 	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
@@ -857,8 +846,6 @@
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:            rule,
-		Deps:            depsType,
-		Depfile:         depFile,
 		Description:     "link " + outputFile.Base(),
 		Output:          outputFile,
 		ImplicitOutputs: implicitOutputs,
@@ -931,9 +918,10 @@
 	return outputFile
 }
 
-// sourceAbiDiff registers a build statement to compare linked sAbi dump files (.ldump).
+// sourceAbiDiff registers a build statement to compare linked sAbi dump files (.lsdump).
 func sourceAbiDiff(ctx android.ModuleContext, inputDump android.Path, referenceDump android.Path,
-	baseName, exportedHeaderFlags string, checkAllApis, isLlndk, isNdk, isVndkExt bool) android.OptionalPath {
+	baseName, exportedHeaderFlags string, diffFlags []string,
+	checkAllApis, isLlndk, isNdk, isVndkExt bool) android.OptionalPath {
 
 	outputFile := android.PathForModuleOut(ctx, baseName+".abidiff")
 	libName := strings.TrimSuffix(baseName, filepath.Ext(baseName))
@@ -964,6 +952,8 @@
 	if isVndkExt {
 		extraFlags = append(extraFlags, "-allow-extensions")
 	}
+	// TODO(b/232891473): Simplify the above logic with diffFlags.
+	extraFlags = append(extraFlags, diffFlags...)
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        sAbiDiff,
@@ -1012,33 +1002,18 @@
 
 	ldCmd := "${config.ClangBin}/clang++"
 
-	var implicitOutputs android.WritablePaths
-	var depFile android.WritablePath
-	var depFileLdFlags string
-	depsType := blueprint.DepsNone
-	if !ctx.Windows() && !ctx.Darwin() {
-		// lld only supports --dependency-file for elf files
-		depFile = outputFile.ReplaceExtension(ctx, "d")
-		depFileLdFlags = " -Wl,--dependency-file=" + depFile.String()
-		depsType = blueprint.DepsGCC
-		implicitOutputs = append(implicitOutputs, depFile)
-	}
-
 	rule := partialLd
 	args := map[string]string{
 		"ldCmd":   ldCmd,
-		"ldFlags": flags.globalLdFlags + " " + flags.localLdFlags + depFileLdFlags,
+		"ldFlags": flags.globalLdFlags + " " + flags.localLdFlags,
 	}
 	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
 		rule = partialLdRE
 		args["inCommaList"] = strings.Join(objFiles.Strings(), ",")
 		args["implicitInputs"] = strings.Join(deps.Strings(), ",")
-		args["implicitOutputs"] = strings.Join(implicitOutputs.Strings(), ",")
 	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        rule,
-		Deps:        depsType,
-		Depfile:     depFile,
 		Description: "link " + outputFile.Base(),
 		Output:      outputFile,
 		Inputs:      objFiles,
diff --git a/cc/library.go b/cc/library.go
index d819c62..0fa01d7 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -110,6 +110,9 @@
 		// Run checks on all APIs (in addition to the ones referred by
 		// one of exported ELF symbols.)
 		Check_all_apis *bool
+
+		// Extra flags passed to header-abi-diff
+		Diff_flags []string
 	}
 
 	// Inject boringssl hash into the shared library.  This is only intended for use by external/boringssl.
@@ -1634,6 +1637,7 @@
 		if refAbiDumpFile != nil {
 			library.sAbiDiff = sourceAbiDiff(ctx, library.sAbiOutputFile.Path(),
 				refAbiDumpFile, fileName, exportedHeaderFlags,
+				library.Properties.Header_abi_checker.Diff_flags,
 				Bool(library.Properties.Header_abi_checker.Check_all_apis),
 				ctx.IsLlndk(), ctx.isNdk(ctx.Config()), ctx.IsVndkExt())
 		}
@@ -2432,7 +2436,6 @@
 		rule := android.NewRuleBuilder(pctx, ctx)
 		rule.Command().
 			BuiltTool("bssl_inject_hash").
-			Flag("-sha256").
 			FlagWithInput("-in-object ", outputFile).
 			FlagWithOutput("-o ", hashedOutputfile)
 		rule.Build("injectCryptoHash", "inject crypto hash")
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index a51db36..bd5a1bd 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -166,8 +166,7 @@
 	touch(shared.JoinPath(topDir, queryviewMarker))
 }
 
-func writeMetrics(configuration android.Config, eventHandler metrics.EventHandler) {
-	metricsDir := configuration.Getenv("LOG_DIR")
+func writeMetrics(configuration android.Config, eventHandler metrics.EventHandler, metricsDir string) {
 	if len(metricsDir) < 1 {
 		fmt.Fprintf(os.Stderr, "\nMissing required env var for generating soong metrics: LOG_DIR\n")
 		os.Exit(1)
@@ -221,7 +220,7 @@
 // doChosenActivity runs Soong for a specific activity, like bp2build, queryview
 // or the actual Soong build for the build.ninja file. Returns the top level
 // output file of the specific activity.
-func doChosenActivity(configuration android.Config, extraNinjaDeps []string) string {
+func doChosenActivity(configuration android.Config, extraNinjaDeps []string, logDir string) string {
 	mixedModeBuild := configuration.BazelContext.BazelEnabled()
 	generateBazelWorkspace := bp2buildMarker != ""
 	generateQueryView := bazelQueryViewDir != ""
@@ -285,7 +284,7 @@
 		}
 	}
 
-	writeMetrics(configuration, *ctx.EventHandler)
+	writeMetrics(configuration, *ctx.EventHandler, logDir)
 	return cmdlineArgs.OutFile
 }
 
@@ -341,7 +340,11 @@
 		extraNinjaDeps = append(extraNinjaDeps, filepath.Join(configuration.SoongOutDir(), "always_rerun_for_delve"))
 	}
 
-	finalOutputFile := doChosenActivity(configuration, extraNinjaDeps)
+	// Bypass configuration.Getenv, as LOG_DIR does not need to be dependency tracked. By definition, it will
+	// change between every CI build, so tracking it would require re-running Soong for every build.
+	logDir := availableEnv["LOG_DIR"]
+
+	finalOutputFile := doChosenActivity(configuration, extraNinjaDeps, logDir)
 
 	writeUsedEnvironmentFile(configuration, finalOutputFile)
 }
@@ -475,88 +478,88 @@
 // Bazel BUILD files instead of Ninja files.
 func runBp2Build(configuration android.Config, extraNinjaDeps []string) {
 	eventHandler := metrics.EventHandler{}
-	eventHandler.Begin("bp2build")
+	var metrics bp2build.CodegenMetrics
+	eventHandler.Do("bp2build", func() {
 
-	// Register an alternate set of singletons and mutators for bazel
-	// conversion for Bazel conversion.
-	bp2buildCtx := android.NewContext(configuration)
+		// Register an alternate set of singletons and mutators for bazel
+		// conversion for Bazel conversion.
+		bp2buildCtx := android.NewContext(configuration)
 
-	// Soong internals like LoadHooks behave differently when running as
-	// bp2build. This is the bit to differentiate between Soong-as-Soong and
-	// Soong-as-bp2build.
-	bp2buildCtx.SetRunningAsBp2build()
+		// Soong internals like LoadHooks behave differently when running as
+		// bp2build. This is the bit to differentiate between Soong-as-Soong and
+		// Soong-as-bp2build.
+		bp2buildCtx.SetRunningAsBp2build()
 
-	// Propagate "allow misssing dependencies" bit. This is normally set in
-	// newContext(), but we create bp2buildCtx without calling that method.
-	bp2buildCtx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
-	bp2buildCtx.SetNameInterface(newNameResolver(configuration))
-	bp2buildCtx.RegisterForBazelConversion()
+		// Propagate "allow misssing dependencies" bit. This is normally set in
+		// newContext(), but we create bp2buildCtx without calling that method.
+		bp2buildCtx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
+		bp2buildCtx.SetNameInterface(newNameResolver(configuration))
+		bp2buildCtx.RegisterForBazelConversion()
 
-	// The bp2build process is a purely functional process that only depends on
-	// Android.bp files. It must not depend on the values of per-build product
-	// configurations or variables, since those will generate different BUILD
-	// files based on how the user has configured their tree.
-	bp2buildCtx.SetModuleListFile(cmdlineArgs.ModuleListFile)
-	modulePaths, err := bp2buildCtx.ListModulePaths(".")
-	if err != nil {
-		panic(err)
-	}
+		// The bp2build process is a purely functional process that only depends on
+		// Android.bp files. It must not depend on the values of per-build product
+		// configurations or variables, since those will generate different BUILD
+		// files based on how the user has configured their tree.
+		bp2buildCtx.SetModuleListFile(cmdlineArgs.ModuleListFile)
+		modulePaths, err := bp2buildCtx.ListModulePaths(".")
+		if err != nil {
+			panic(err)
+		}
 
-	extraNinjaDeps = append(extraNinjaDeps, modulePaths...)
+		extraNinjaDeps = append(extraNinjaDeps, modulePaths...)
 
-	// Run the loading and analysis pipeline to prepare the graph of regular
-	// Modules parsed from Android.bp files, and the BazelTargetModules mapped
-	// from the regular Modules.
-	blueprintArgs := cmdlineArgs
-	ninjaDeps := bootstrap.RunBlueprint(blueprintArgs, bootstrap.StopBeforePrepareBuildActions, bp2buildCtx.Context, configuration)
-	ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
+		// Run the loading and analysis pipeline to prepare the graph of regular
+		// Modules parsed from Android.bp files, and the BazelTargetModules mapped
+		// from the regular Modules.
+		blueprintArgs := cmdlineArgs
+		ninjaDeps := bootstrap.RunBlueprint(blueprintArgs, bootstrap.StopBeforePrepareBuildActions, bp2buildCtx.Context, configuration)
+		ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
 
-	globListFiles := writeBuildGlobsNinjaFile(bp2buildCtx, configuration.SoongOutDir(), configuration)
-	ninjaDeps = append(ninjaDeps, globListFiles...)
+		globListFiles := writeBuildGlobsNinjaFile(bp2buildCtx, configuration.SoongOutDir(), configuration)
+		ninjaDeps = append(ninjaDeps, globListFiles...)
 
-	// Run the code-generation phase to convert BazelTargetModules to BUILD files
-	// and print conversion metrics to the user.
-	codegenContext := bp2build.NewCodegenContext(configuration, *bp2buildCtx, bp2build.Bp2Build)
-	metrics := bp2build.Codegen(codegenContext)
+		// Run the code-generation phase to convert BazelTargetModules to BUILD files
+		// and print conversion metrics to the user.
+		codegenContext := bp2build.NewCodegenContext(configuration, *bp2buildCtx, bp2build.Bp2Build)
+		metrics = bp2build.Codegen(codegenContext)
 
-	generatedRoot := shared.JoinPath(configuration.SoongOutDir(), "bp2build")
-	workspaceRoot := shared.JoinPath(configuration.SoongOutDir(), "workspace")
+		generatedRoot := shared.JoinPath(configuration.SoongOutDir(), "bp2build")
+		workspaceRoot := shared.JoinPath(configuration.SoongOutDir(), "workspace")
 
-	excludes := []string{
-		"bazel-bin",
-		"bazel-genfiles",
-		"bazel-out",
-		"bazel-testlogs",
-		"bazel-" + filepath.Base(topDir),
-	}
+		excludes := []string{
+			"bazel-bin",
+			"bazel-genfiles",
+			"bazel-out",
+			"bazel-testlogs",
+			"bazel-" + filepath.Base(topDir),
+		}
 
-	if outDir[0] != '/' {
-		excludes = append(excludes, outDir)
-	}
+		if outDir[0] != '/' {
+			excludes = append(excludes, outDir)
+		}
 
-	existingBazelRelatedFiles, err := getExistingBazelRelatedFiles(topDir)
-	if err != nil {
-		fmt.Fprintf(os.Stderr, "Error determining existing Bazel-related files: %s\n", err)
-		os.Exit(1)
-	}
+		existingBazelRelatedFiles, err := getExistingBazelRelatedFiles(topDir)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "Error determining existing Bazel-related files: %s\n", err)
+			os.Exit(1)
+		}
 
-	pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(topDir, generatedRoot, existingBazelRelatedFiles, configuration.IsEnvTrue("BP2BUILD_VERBOSE"))
-	excludes = append(excludes, pathsToIgnoredBuildFiles...)
+		pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(topDir, generatedRoot, existingBazelRelatedFiles, configuration.IsEnvTrue("BP2BUILD_VERBOSE"))
+		excludes = append(excludes, pathsToIgnoredBuildFiles...)
 
-	excludes = append(excludes, getTemporaryExcludes()...)
+		excludes = append(excludes, getTemporaryExcludes()...)
 
-	symlinkForestDeps := bp2build.PlantSymlinkForest(
-		topDir, workspaceRoot, generatedRoot, ".", excludes)
+		symlinkForestDeps := bp2build.PlantSymlinkForest(
+			topDir, workspaceRoot, generatedRoot, ".", excludes)
 
-	ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
-	ninjaDeps = append(ninjaDeps, symlinkForestDeps...)
+		ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
+		ninjaDeps = append(ninjaDeps, symlinkForestDeps...)
 
-	writeDepFile(bp2buildMarker, eventHandler, ninjaDeps)
+		writeDepFile(bp2buildMarker, eventHandler, ninjaDeps)
 
-	// Create an empty bp2build marker file.
-	touch(shared.JoinPath(topDir, bp2buildMarker))
-
-	eventHandler.End("bp2build")
+		// Create an empty bp2build marker file.
+		touch(shared.JoinPath(topDir, bp2buildMarker))
+	})
 
 	// Only report metrics when in bp2build mode. The metrics aren't relevant
 	// for queryview, since that's a total repo-wide conversion and there's a
diff --git a/compliance/copy_license_metadata/Android.bp b/compliance/copy_license_metadata/Android.bp
new file mode 100644
index 0000000..83019eb
--- /dev/null
+++ b/compliance/copy_license_metadata/Android.bp
@@ -0,0 +1,30 @@
+// Copyright 2022 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+blueprint_go_binary {
+    name: "copy_license_metadata",
+    srcs: [
+        "copy_license_metadata.go",
+    ],
+    deps: [
+        "license_metadata_proto",
+        "golang-protobuf-proto",
+        "golang-protobuf-encoding-prototext",
+        "soong-response",
+    ],
+}
diff --git a/compliance/copy_license_metadata/copy_license_metadata.go b/compliance/copy_license_metadata/copy_license_metadata.go
new file mode 100644
index 0000000..36b9489
--- /dev/null
+++ b/compliance/copy_license_metadata/copy_license_metadata.go
@@ -0,0 +1,144 @@
+// Copyright 2022 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 (
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"strings"
+
+	"google.golang.org/protobuf/encoding/prototext"
+	"google.golang.org/protobuf/proto"
+
+	"android/soong/compliance/license_metadata_proto"
+	"android/soong/response"
+)
+
+func newMultiString(flags *flag.FlagSet, name, usage string) *multiString {
+	var f multiString
+	flags.Var(&f, name, usage)
+	return &f
+}
+
+type multiString []string
+
+func (ms *multiString) String() string     { return strings.Join(*ms, ", ") }
+func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
+
+func main() {
+	var expandedArgs []string
+	for _, arg := range os.Args[1:] {
+		if strings.HasPrefix(arg, "@") {
+			f, err := os.Open(strings.TrimPrefix(arg, "@"))
+			if err != nil {
+				fmt.Fprintln(os.Stderr, err.Error())
+				os.Exit(1)
+			}
+
+			respArgs, err := response.ReadRspFile(f)
+			f.Close()
+			if err != nil {
+				fmt.Fprintln(os.Stderr, err.Error())
+				os.Exit(1)
+			}
+			expandedArgs = append(expandedArgs, respArgs...)
+		} else {
+			expandedArgs = append(expandedArgs, arg)
+		}
+	}
+
+	flags := flag.NewFlagSet("flags", flag.ExitOnError)
+
+	installed := flags.String("i", "", "installed target")
+	sources := newMultiString(flags, "s", "source (input) file")
+	dep := flags.String("d", "", "license metadata file dependency")
+	outFile := flags.String("o", "", "output file")
+
+	flags.Parse(expandedArgs)
+
+	if len(*dep) == 0 || len(*installed) == 0 || len(*sources) == 0 {
+		flags.Usage()
+		if len(*dep) == 0 {
+			fmt.Fprintf(os.Stderr, "source license metadata (-d flag) required\n")
+		}
+		if len(*sources) == 0 {
+			fmt.Fprintf(os.Stderr, "source copy (-s flag required\n")
+		}
+		if len(*installed) == 0 {
+			fmt.Fprintf(os.Stderr, "installed copy (-i flag) required\n")
+		}
+		os.Exit(1)
+	}
+
+	src_metadata := license_metadata_proto.LicenseMetadata{}
+	err := readMetadata(*dep, &src_metadata)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
+		os.Exit(2)
+	}
+
+	metadata := src_metadata
+	metadata.Built = nil
+	metadata.InstallMap = nil
+	metadata.Installed = []string{*installed}
+	metadata.Sources = *sources
+	metadata.Deps = []*license_metadata_proto.AnnotatedDependency{&license_metadata_proto.AnnotatedDependency{
+		File:        proto.String(*dep),
+		Annotations: []string{"static"},
+	}}
+
+	err = writeMetadata(*outFile, &metadata)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
+		os.Exit(2)
+	}
+}
+
+func readMetadata(file string, metadata *license_metadata_proto.LicenseMetadata) error {
+	if file == "" {
+		return fmt.Errorf("source metadata file (-d) required")
+	}
+	buf, err := ioutil.ReadFile(file)
+	if err != nil {
+		return fmt.Errorf("error reading textproto %q: %w", file, err)
+	}
+
+	err = prototext.Unmarshal(buf, metadata)
+	if err != nil {
+		return fmt.Errorf("error unmarshalling textproto: %w", err)
+	}
+
+	return nil
+}
+
+func writeMetadata(file string, metadata *license_metadata_proto.LicenseMetadata) error {
+	buf, err := prototext.MarshalOptions{Multiline: true}.Marshal(metadata)
+	if err != nil {
+		return fmt.Errorf("error marshalling textproto: %w", err)
+	}
+
+	if file != "" {
+		err = ioutil.WriteFile(file, buf, 0666)
+		if err != nil {
+			return fmt.Errorf("error writing textproto %q: %w", file, err)
+		}
+	} else {
+		_, _ = os.Stdout.Write(buf)
+	}
+
+	return nil
+}
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index ab9e418..64cd46a 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -250,8 +250,9 @@
 }
 
 type globalConfigAndRaw struct {
-	global *GlobalConfig
-	data   []byte
+	global     *GlobalConfig
+	data       []byte
+	pathErrors []error
 }
 
 // GetGlobalConfig returns the global dexpreopt.config that's created in the
@@ -272,16 +273,26 @@
 var globalConfigOnceKey = android.NewOnceKey("DexpreoptGlobalConfig")
 var testGlobalConfigOnceKey = android.NewOnceKey("TestDexpreoptGlobalConfig")
 
+type pathContextErrorCollector struct {
+	android.PathContext
+	errors []error
+}
+
+func (p *pathContextErrorCollector) Errorf(format string, args ...interface{}) {
+	p.errors = append(p.errors, fmt.Errorf(format, args...))
+}
+
 func getGlobalConfigRaw(ctx android.PathContext) globalConfigAndRaw {
-	return ctx.Config().Once(globalConfigOnceKey, func() interface{} {
+	config := ctx.Config().Once(globalConfigOnceKey, func() interface{} {
 		if data, err := ctx.Config().DexpreoptGlobalConfig(ctx); err != nil {
 			panic(err)
 		} else if data != nil {
-			globalConfig, err := ParseGlobalConfig(ctx, data)
+			pathErrorCollectorCtx := &pathContextErrorCollector{PathContext: ctx}
+			globalConfig, err := ParseGlobalConfig(pathErrorCollectorCtx, data)
 			if err != nil {
 				panic(err)
 			}
-			return globalConfigAndRaw{globalConfig, data}
+			return globalConfigAndRaw{globalConfig, data, pathErrorCollectorCtx.errors}
 		}
 
 		// No global config filename set, see if there is a test config set
@@ -291,16 +302,35 @@
 				DisablePreopt:           true,
 				DisablePreoptBootImages: true,
 				DisableGenerateProfile:  true,
-			}, nil}
+			}, nil, nil}
 		})
 	}).(globalConfigAndRaw)
+
+	// Avoid non-deterministic errors by reporting cached path errors on all callers.
+	for _, err := range config.pathErrors {
+		if ctx.Config().AllowMissingDependencies() {
+			// When AllowMissingDependencies it set, report errors through AddMissingDependencies.
+			// If AddMissingDependencies doesn't exist on the current context (for example when
+			// called with a SingletonContext), just swallow the errors since there is no way to
+			// report them.
+			if missingDepsCtx, ok := ctx.(interface {
+				AddMissingDependencies(missingDeps []string)
+			}); ok {
+				missingDepsCtx.AddMissingDependencies([]string{err.Error()})
+			}
+		} else {
+			android.ReportPathErrorf(ctx, "%w", err)
+		}
+	}
+
+	return config
 }
 
 // SetTestGlobalConfig sets a GlobalConfig that future calls to GetGlobalConfig
 // will return. It must be called before the first call to GetGlobalConfig for
 // the config.
 func SetTestGlobalConfig(config android.Config, globalConfig *GlobalConfig) {
-	config.Once(testGlobalConfigOnceKey, func() interface{} { return globalConfigAndRaw{globalConfig, nil} })
+	config.Once(testGlobalConfigOnceKey, func() interface{} { return globalConfigAndRaw{globalConfig, nil, nil} })
 }
 
 // This struct is required to convert ModuleConfig from/to JSON.
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 8649b15..818e1bc 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -805,6 +805,7 @@
 func GenSrcsFactory() android.Module {
 	m := NewGenSrcs()
 	android.InitAndroidModule(m)
+	android.InitBazelModule(m)
 	return m
 }
 
@@ -816,6 +817,13 @@
 	Shard_size *int64
 }
 
+type bazelGensrcsAttributes struct {
+	Srcs             bazel.LabelListAttribute
+	Output_extension *string
+	Tools            bazel.LabelListAttribute
+	Cmd              string
+}
+
 const defaultShardSize = 50
 
 func NewGenRule() *Module {
@@ -880,8 +888,14 @@
 	// Replace in and out variables with $< and $@
 	var cmd string
 	if m.properties.Cmd != nil {
-		cmd = strings.Replace(*m.properties.Cmd, "$(in)", "$(SRCS)", -1)
-		cmd = strings.Replace(cmd, "$(out)", "$(OUTS)", -1)
+		if ctx.ModuleType() == "gensrcs" {
+			cmd = strings.ReplaceAll(*m.properties.Cmd, "$(in)", "$(SRC)")
+			cmd = strings.ReplaceAll(cmd, "$(out)", "$(OUT)")
+		} else {
+			cmd = strings.Replace(*m.properties.Cmd, "$(in)", "$(SRCS)", -1)
+			cmd = strings.Replace(cmd, "$(out)", "$(OUTS)", -1)
+		}
+
 		genDir := "$(GENDIR)"
 		if t := ctx.ModuleType(); t == "cc_genrule" || t == "java_genrule" || t == "java_genrule_host" {
 			genDir = "$(RULEDIR)"
@@ -901,30 +915,50 @@
 		}
 	}
 
-	// The Out prop is not in an immediately accessible field
-	// in the Module struct, so use GetProperties and cast it
-	// to the known struct prop.
-	var outs []string
-	for _, propIntf := range m.GetProperties() {
-		if props, ok := propIntf.(*genRuleProperties); ok {
-			outs = props.Out
-			break
+	if ctx.ModuleType() == "gensrcs" {
+		// The Output_extension prop is not in an immediately accessible field
+		// in the Module struct, so use GetProperties and cast it
+		// to the known struct prop.
+		var outputExtension *string
+		for _, propIntf := range m.GetProperties() {
+			if props, ok := propIntf.(*genSrcsProperties); ok {
+				outputExtension = props.Output_extension
+				break
+			}
 		}
+		props := bazel.BazelTargetModuleProperties{
+			Rule_class:        "gensrcs",
+			Bzl_load_location: "//build/bazel/rules:gensrcs.bzl",
+		}
+		attrs := &bazelGensrcsAttributes{
+			Srcs:             srcs,
+			Output_extension: outputExtension,
+			Cmd:              cmd,
+			Tools:            tools,
+		}
+		ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+	} else {
+		// The Out prop is not in an immediately accessible field
+		// in the Module struct, so use GetProperties and cast it
+		// to the known struct prop.
+		var outs []string
+		for _, propIntf := range m.GetProperties() {
+			if props, ok := propIntf.(*genRuleProperties); ok {
+				outs = props.Out
+				break
+			}
+		}
+		attrs := &bazelGenruleAttributes{
+			Srcs:  srcs,
+			Outs:  outs,
+			Cmd:   cmd,
+			Tools: tools,
+		}
+		props := bazel.BazelTargetModuleProperties{
+			Rule_class: "genrule",
+		}
+		ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
 	}
-
-	attrs := &bazelGenruleAttributes{
-		Srcs:  srcs,
-		Outs:  outs,
-		Cmd:   cmd,
-		Tools: tools,
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class: "genrule",
-	}
-
-	// Create the BazelTargetModule.
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
 }
 
 var Bool = proptools.Bool
diff --git a/go.mod b/go.mod
index 14444b3..8c1a9f0 100644
--- a/go.mod
+++ b/go.mod
@@ -16,4 +16,4 @@
 // Indirect dep from go-cmp
 exclude golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
 
-go 1.15
+go 1.18
diff --git a/java/Android.bp b/java/Android.bp
index df0d1eb..e25accf 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -87,6 +87,7 @@
         "dexpreopt_bootjars_test.go",
         "droiddoc_test.go",
         "droidstubs_test.go",
+        "genrule_test.go",
         "hiddenapi_singleton_test.go",
         "jacoco_test.go",
         "java_test.go",
@@ -97,6 +98,7 @@
         "platform_compat_config_test.go",
         "plugin_test.go",
         "prebuilt_apis_test.go",
+        "proto_test.go",
         "rro_test.go",
         "sdk_test.go",
         "sdk_library_test.go",
diff --git a/java/androidmk.go b/java/androidmk.go
index 330e594..82ef413 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -623,6 +623,7 @@
 					if dstubs.apiLintReport != nil {
 						fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n", dstubs.Name()+"-api-lint",
 							dstubs.apiLintReport.String(), "apilint/"+dstubs.Name()+"-lint-report.txt")
+						fmt.Fprintf(w, "$(call declare-0p-target,%s)\n", dstubs.apiLintReport.String())
 					}
 				}
 				if dstubs.checkNullabilityWarningsTimestamp != nil {
diff --git a/java/app.go b/java/app.go
index 86238d5..c61c4e5 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1012,7 +1012,7 @@
 func AndroidTestFactory() android.Module {
 	module := &AndroidTest{}
 
-	module.Module.dexProperties.Optimize.EnabledByDefault = true
+	module.Module.dexProperties.Optimize.EnabledByDefault = false
 
 	module.Module.properties.Instrument = true
 	module.Module.properties.Supports_static_instrumentation = true
@@ -1066,6 +1066,7 @@
 func AndroidTestHelperAppFactory() android.Module {
 	module := &AndroidTestHelperApp{}
 
+	// TODO(b/192032291): Disable by default after auditing downstream usage.
 	module.Module.dexProperties.Optimize.EnabledByDefault = true
 
 	module.Module.properties.Installable = proptools.BoolPtr(true)
diff --git a/java/config/config.go b/java/config/config.go
index d744002..e728b7d 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -95,6 +95,8 @@
 	}, dexerJavaVmFlagsList...))
 	exportedVars.ExportStringListStaticVariable("R8Flags", append([]string{
 		"-JXmx2048M",
+		// Disable this optimization as it can impact weak reference semantics. See b/233432839.
+		"-JDcom.android.tools.r8.disableEnqueuerDeferredTracing=true",
 	}, dexerJavaVmFlagsList...))
 
 	exportedVars.ExportStringListStaticVariable("CommonJdkFlags", []string{
diff --git a/java/dex.go b/java/dex.go
index 13d6e4a..c943938 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -36,8 +36,8 @@
 	Main_dex_rules []string `android:"path"`
 
 	Optimize struct {
-		// If false, disable all optimization.  Defaults to true for android_app and android_test
-		// modules, false for java_library and java_test modules.
+		// If false, disable all optimization.  Defaults to true for android_app and
+		// android_test_helper_app modules, false for android_test, java_library, and java_test modules.
 		Enabled *bool
 		// True if the module containing this has it set by default.
 		EnabledByDefault bool `blueprint:"mutated"`
diff --git a/java/java_test.go b/java/java_test.go
index 4c93824..56a4248 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -723,9 +723,9 @@
 		t.Errorf("atestNoOptimize should not optimize APK")
 	}
 
-	atestDefault := ctx.ModuleForTests("atestDefault", "android_common").MaybeRule("r8")
+	atestDefault := ctx.ModuleForTests("atestDefault", "android_common").MaybeRule("d8")
 	if atestDefault.Output == nil {
-		t.Errorf("atestDefault should optimize APK")
+		t.Errorf("atestDefault should not optimize APK")
 	}
 }
 
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index 6257e49..10c9187 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -272,7 +272,9 @@
 	entries := android.AndroidMkEntriesForTest(t, result.TestContext, platformBootclasspath)
 	goals := entries[0].GetDistForGoals(platformBootclasspath)
 	android.AssertStringEquals(t, "platform dist goals phony", ".PHONY: droidcore\n", goals[0])
-	android.AssertStringEquals(t, "platform dist goals call", "$(call dist-for-goals,droidcore,out/soong/hiddenapi/hiddenapi-flags.csv:hiddenapi-flags.csv)\n", android.StringRelativeToTop(result.Config, goals[1]))
+	android.AssertStringDoesContain(t, "platform dist goals meta check", goals[1], "$(if $(strip $(ALL_TARGETS.")
+	android.AssertStringDoesContain(t, "platform dist goals meta assign", goals[1], "),,$(eval ALL_TARGETS.")
+	android.AssertStringEquals(t, "platform dist goals call", "$(call dist-for-goals,droidcore,out/soong/hiddenapi/hiddenapi-flags.csv:hiddenapi-flags.csv)\n", android.StringRelativeToTop(result.Config, goals[2]))
 }
 
 func TestPlatformBootclasspath_HiddenAPIMonolithicFiles(t *testing.T) {
diff --git a/python/library.go b/python/library.go
index 3a27591..5071b74 100644
--- a/python/library.go
+++ b/python/library.go
@@ -50,6 +50,10 @@
 	Srcs_version *string
 }
 
+type bazelPythonProtoLibraryAttributes struct {
+	Deps bazel.LabelListAttribute
+}
+
 func pythonLibBp2Build(ctx android.TopDownMutatorContext, m *Module) {
 	// TODO(b/182306917): this doesn't fully handle all nested props versioned
 	// by the python version, which would have been handled by the version split
@@ -96,6 +100,7 @@
 	}
 
 	baseAttrs := m.makeArchVariantBaseAttributes(ctx)
+
 	attrs := &bazelPythonLibraryAttributes{
 		Srcs:         baseAttrs.Srcs,
 		Deps:         baseAttrs.Deps,
diff --git a/python/python.go b/python/python.go
index b100cc3..7e4cb83 100644
--- a/python/python.go
+++ b/python/python.go
@@ -207,6 +207,29 @@
 			}
 		}
 	}
+
+	partitionedSrcs := bazel.PartitionLabelListAttribute(ctx, &attrs.Srcs, bazel.LabelPartitions{
+		"proto": android.ProtoSrcLabelPartition,
+		"py":    bazel.LabelPartition{Keep_remainder: true},
+	})
+	attrs.Srcs = partitionedSrcs["py"]
+
+	if !partitionedSrcs["proto"].IsEmpty() {
+		protoInfo, _ := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, partitionedSrcs["proto"])
+		protoLabel := bazel.Label{Label: ":" + protoInfo.Name}
+
+		pyProtoLibraryName := m.Name() + "_py_proto"
+		ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{
+			Rule_class:        "py_proto_library",
+			Bzl_load_location: "//build/bazel/rules/python:py_proto.bzl",
+		}, android.CommonAttributes{
+			Name: pyProtoLibraryName,
+		}, &bazelPythonProtoLibraryAttributes{
+			Deps: bazel.MakeSingleLabelListAttribute(protoLabel),
+		})
+
+		attrs.Deps.Add(bazel.MakeLabelAttribute(":" + pyProtoLibraryName))
+	}
 	return attrs
 }
 
diff --git a/rust/config/global.go b/rust/config/global.go
index d11665c..554cfe2 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
 var pctx = android.NewPackageContext("android/soong/rust/config")
 
 var (
-	RustDefaultVersion = "1.60.0"
+	RustDefaultVersion = "1.61.0"
 	RustDefaultBase    = "prebuilts/rust/"
 	DefaultEdition     = "2021"
 	Stdlibs            = []string{