Merge "Add a test to check the intall partitions"
diff --git a/android/androidmk.go b/android/androidmk.go
index 9317567..66a1036 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -546,7 +546,7 @@
 		}
 
 		if !amod.InRamdisk() && !amod.InVendorRamdisk() {
-			a.AddStrings("LOCAL_INIT_RC", amod.commonProperties.Init_rc...)
+			a.AddPaths("LOCAL_FULL_INIT_RC", amod.initRcPaths)
 		}
 		a.AddStrings("LOCAL_VINTF_FRAGMENTS", amod.commonProperties.Vintf_fragments...)
 		a.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(amod.commonProperties.Proprietary))
diff --git a/android/apex.go b/android/apex.go
index 7f9f0f5..cfda2aa 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -919,7 +919,7 @@
 					"Consider adding 'min_sdk_version: %q' to %q",
 					minSdkVersion, ctx.ModuleName(), err.Error(),
 					ctx.GetPathString(false),
-					minSdkVersion, ctx.ModuleName())
+					minSdkVersion, toName)
 				return false
 			}
 		}
diff --git a/android/bazel.go b/android/bazel.go
index b2170be..b54ae64 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -174,6 +174,18 @@
 		"liblinker_debuggerd_stub",      // ruperts@, cc_library_static, depends on //system/libbase
 		"libbionic_tests_headers_posix", // ruperts@, cc_library_static
 		"libc_dns",                      // ruperts@, cc_library_static
+
+		"note_memtag_heap_async", // jingwen@, b/185079815, features.h includes not found
+		"note_memtag_heap_sync",  // jingwen@, b/185079815, features.h includes not found
+
+		// List of all full_cc_libraries in //bionic, with their immediate failures
+		"libc",              // jingwen@, cc_library, depends on //external/gwp_asan
+		"libc_malloc_debug", // jingwen@, cc_library, fatal error: 'assert.h' file not found
+		"libc_malloc_hooks", // jingwen@, cc_library, fatal error: 'errno.h' file not found
+		"libdl",             // jingwen@, cc_library, ld.lld: error: no input files
+		"libm",              // jingwen@, cc_library, fatal error: 'freebsd-compat.h' file not found
+		"libseccomp_policy", // jingwen@, cc_library, fatal error: 'seccomp_policy.h' file not found
+		"libstdc++",         // jingwen@, cc_library, depends on //external/gwp_asan
 	}
 
 	// Used for quicker lookups
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 28c0e53..97eec30 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -117,21 +117,25 @@
 
 // A bazel context to use for tests.
 type MockBazelContext struct {
-	AllFiles map[string][]string
+	OutputBaseDir string
+
+	LabelToOutputFiles                 map[string][]string
+	LabelToOutputFilesAndCcObjectFiles map[string]cquery.GetOutputFilesAndCcObjectFiles_Result
+	LabelToCcStaticLibraryFiles        map[string][]string
 }
 
 func (m MockBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
-	result, ok := m.AllFiles[label]
+	result, ok := m.LabelToOutputFiles[label]
 	return result, ok
 }
 
 func (m MockBazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
-	result, ok := m.AllFiles[label]
-	return result, result, ok
+	result, ok := m.LabelToOutputFilesAndCcObjectFiles[label]
+	return result.OutputFiles, result.CcObjectFiles, ok
 }
 
 func (m MockBazelContext) GetPrebuiltCcStaticLibraryFiles(label string, archType ArchType) ([]string, bool) {
-	result, ok := m.AllFiles[label]
+	result, ok := m.LabelToCcStaticLibraryFiles[label]
 	return result, ok
 }
 
@@ -143,9 +147,7 @@
 	return true
 }
 
-func (m MockBazelContext) OutputBase() string {
-	return "outputbase"
-}
+func (m MockBazelContext) OutputBase() string { return m.OutputBaseDir }
 
 func (m MockBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
 	return []bazel.BuildStatement{}
@@ -352,15 +354,20 @@
 # This file is generated by soong_build. Do not edit.
 local_repository(
     name = "sourceroot",
-    path = "%s",
+    path = "%[1]s",
 )
 
 local_repository(
     name = "rules_cc",
-    path = "%s/build/bazel/rules_cc",
+    path = "%[1]s/build/bazel/rules_cc",
+)
+
+local_repository(
+    name = "bazel_skylib",
+    path = "%[1]s/build/bazel/bazel_skylib",
 )
 `
-	return []byte(fmt.Sprintf(formatString, context.workspaceDir, context.workspaceDir))
+	return []byte(fmt.Sprintf(formatString, context.workspaceDir))
 }
 
 func (context *bazelContext) mainBzlFileContents() []byte {
diff --git a/android/paths.go b/android/paths.go
index ba1ab11..37b04dd 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -421,6 +421,9 @@
 // bazel-compatible labels.  Properties passed as the paths or excludes argument must have been
 // annotated with struct tag `android:"path"` so that dependencies on other modules will have
 // already been handled by the path_properties mutator.
+//
+// With expanded globs, we can catch package boundaries problem instead of
+// silently failing to potentially missing files from Bazel's globs.
 func BazelLabelForModuleSrc(ctx BazelConversionPathContext, paths []string) bazel.LabelList {
 	return BazelLabelForModuleSrcExcludes(ctx, paths, []string(nil))
 }
@@ -431,6 +434,9 @@
 // passed as the paths or excludes argument must have been annotated with struct tag
 // `android:"path"` so that dependencies on other modules will have already been handled by the
 // path_properties mutator.
+//
+// With expanded globs, we can catch package boundaries problem instead of
+// silently failing to potentially missing files from Bazel's globs.
 func BazelLabelForModuleSrcExcludes(ctx BazelConversionPathContext, paths, excludes []string) bazel.LabelList {
 	excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil))
 	excluded := make([]string, 0, len(excludeLabels.Includes))
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 99cd75e..9fc701d 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -284,7 +284,7 @@
 					// To install companion files (init_rc, vintf_fragments)
 					// Copy some common properties of apexBundle to apex_manifest
 					commonProperties := []string{
-						"LOCAL_INIT_RC", "LOCAL_VINTF_FRAGMENTS",
+						"LOCAL_FULL_INIT_RC", "LOCAL_VINTF_FRAGMENTS",
 					}
 					for _, name := range commonProperties {
 						if value, ok := apexAndroidMkData.Entries.EntryMap[name]; ok {
@@ -394,7 +394,7 @@
 				// Because apex writes .mk with Custom(), we need to write manually some common properties
 				// which are available via data.Entries
 				commonProperties := []string{
-					"LOCAL_INIT_RC", "LOCAL_VINTF_FRAGMENTS",
+					"LOCAL_FULL_INIT_RC", "LOCAL_VINTF_FRAGMENTS",
 					"LOCAL_PROPRIETARY_MODULE", "LOCAL_VENDOR_MODULE", "LOCAL_ODM_MODULE", "LOCAL_PRODUCT_MODULE", "LOCAL_SYSTEM_EXT_MODULE",
 					"LOCAL_MODULE_OWNER",
 				}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 5439265..ee4255e 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -2756,7 +2756,7 @@
 	data.Custom(&builder, name, prefix, "", data)
 	androidMk := builder.String()
 	ensureContains(t, androidMk, "LOCAL_VINTF_FRAGMENTS := fragment.xml\n")
-	ensureContains(t, androidMk, "LOCAL_INIT_RC := init.rc\n")
+	ensureContains(t, androidMk, "LOCAL_FULL_INIT_RC := init.rc\n")
 }
 
 func TestStaticLinking(t *testing.T) {
diff --git a/bazel/properties.go b/bazel/properties.go
index 148386f..4bb2391 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"path/filepath"
 	"regexp"
 	"sort"
 )
@@ -47,6 +48,57 @@
 	Excludes []Label
 }
 
+// GlobsInDir returns a list of glob expressions for a list of extensions
+// (optionally recursive) within a directory.
+func GlobsInDir(dir string, recursive bool, extensions []string) []string {
+	globs := []string{}
+
+	globInfix := ""
+	if dir == "." {
+		if recursive {
+			// e.g "**/*.h"
+			globInfix = "**/"
+		} // else e.g. "*.h"
+		for _, ext := range extensions {
+			globs = append(globs, globInfix+"*"+ext)
+		}
+	} else {
+		if recursive {
+			// e.g. "foo/bar/**/*.h"
+			dir += "/**"
+		} // else e.g. "foo/bar/*.h"
+		for _, ext := range extensions {
+			globs = append(globs, dir+"/*"+ext)
+		}
+	}
+	return globs
+}
+
+// LooseHdrsGlobs returns the list of non-recursive header globs for each parent directory of
+// each source file in this LabelList's Includes.
+func (ll *LabelList) LooseHdrsGlobs(exts []string) []string {
+	var globs []string
+	for _, parentDir := range ll.uniqueParentDirectories() {
+		globs = append(globs,
+			GlobsInDir(parentDir, false, exts)...)
+	}
+	return globs
+}
+
+// uniqueParentDirectories returns a list of the unique parent directories for
+// all files in ll.Includes.
+func (ll *LabelList) uniqueParentDirectories() []string {
+	dirMap := map[string]bool{}
+	for _, label := range ll.Includes {
+		dirMap[filepath.Dir(label.Label)] = true
+	}
+	dirs := []string{}
+	for dir := range dirMap {
+		dirs = append(dirs, dir)
+	}
+	return dirs
+}
+
 // Append appends the fields of other labelList to the corresponding fields of ll.
 func (ll *LabelList) Append(other LabelList) {
 	if len(ll.Includes) > 0 || len(other.Includes) > 0 {
@@ -224,6 +276,26 @@
 	return LabelListAttribute{Value: UniqueBazelLabelList(value)}
 }
 
+// Append appends all values, including os and arch specific ones, from another
+// LabelListAttribute to this LabelListAttribute.
+func (attrs *LabelListAttribute) Append(other LabelListAttribute) {
+	for arch := range PlatformArchMap {
+		this := attrs.GetValueForArch(arch)
+		that := other.GetValueForArch(arch)
+		this.Append(that)
+		attrs.SetValueForArch(arch, this)
+	}
+
+	for os := range PlatformOsMap {
+		this := attrs.GetValueForOS(os)
+		that := other.GetValueForOS(os)
+		this.Append(that)
+		attrs.SetValueForOS(os, this)
+	}
+
+	attrs.Value.Append(other.Value)
+}
+
 // HasArchSpecificValues returns true if the attribute contains
 // architecture-specific label_list values.
 func (attrs LabelListAttribute) HasConfigurableValues() bool {
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index cc616f2..d2a8729 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -26,6 +26,7 @@
     testSrcs: [
         "build_conversion_test.go",
         "bzl_conversion_test.go",
+        "cc_library_conversion_test.go",
         "cc_library_headers_conversion_test.go",
         "cc_library_static_conversion_test.go",
         "cc_object_conversion_test.go",
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index dd14c7d..b7a2810 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -374,16 +374,9 @@
 		// value>)" to set the default value of unset attributes. In the cases
 		// where the bp2build converter didn't set the default value within the
 		// mutator when creating the BazelTargetModule, this would be a zero
-		// value. For those cases, we return a non-surprising default value so
-		// generated BUILD files are syntactically correct.
-		switch propertyValue.Kind() {
-		case reflect.Slice:
-			return "[]", nil
-		case reflect.Map:
-			return "{}", nil
-		default:
-			return "", nil
-		}
+		// value. For those cases, we return an empty string so we don't
+		// unnecessarily generate empty values.
+		return "", nil
 	}
 
 	var ret string
@@ -397,21 +390,38 @@
 	case reflect.Ptr:
 		return prettyPrint(propertyValue.Elem(), indent)
 	case reflect.Slice:
-		ret = "[\n"
-		for i := 0; i < propertyValue.Len(); i++ {
-			indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1)
+		if propertyValue.Len() == 0 {
+			return "", nil
+		}
+
+		if propertyValue.Len() == 1 {
+			// Single-line list for list with only 1 element
+			ret += "["
+			indexedValue, err := prettyPrint(propertyValue.Index(0), indent)
 			if err != nil {
 				return "", err
 			}
+			ret += indexedValue
+			ret += "]"
+		} else {
+			// otherwise, use a multiline list.
+			ret += "[\n"
+			for i := 0; i < propertyValue.Len(); i++ {
+				indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1)
+				if err != nil {
+					return "", err
+				}
 
-			if indexedValue != "" {
-				ret += makeIndent(indent + 1)
-				ret += indexedValue
-				ret += ",\n"
+				if indexedValue != "" {
+					ret += makeIndent(indent + 1)
+					ret += indexedValue
+					ret += ",\n"
+				}
 			}
+			ret += makeIndent(indent)
+			ret += "]"
 		}
-		ret += makeIndent(indent)
-		ret += "]"
+
 	case reflect.Struct:
 		// Special cases where the bp2build sends additional information to the codegenerator
 		// by wrapping the attributes in a custom struct type.
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 49897b3..1ede442 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -27,9 +27,7 @@
 		expectedBazelTarget string
 	}{
 		{
-			bp: `custom {
-	name: "foo",
-}
+			bp: `custom { name: "foo" }
 		`,
 			expectedBazelTarget: `soong_module(
     name = "foo",
@@ -85,9 +83,7 @@
     soong_module_variant = "",
     soong_module_deps = [
     ],
-    required = [
-        "bar",
-    ],
+    required = ["bar"],
 )`,
 		},
 		{
@@ -116,12 +112,10 @@
 		targets: ["goal_foo"],
 		tag: ".foo",
 	},
-	dists: [
-		{
-			targets: ["goal_bar"],
-			tag: ".bar",
-		},
-	],
+	dists: [{
+		targets: ["goal_bar"],
+		tag: ".bar",
+	}],
 }
 		`,
 			expectedBazelTarget: `soong_module(
@@ -133,18 +127,12 @@
     ],
     dist = {
         "tag": ".foo",
-        "targets": [
-            "goal_foo",
-        ],
+        "targets": ["goal_foo"],
     },
-    dists = [
-        {
-            "tag": ".bar",
-            "targets": [
-                "goal_bar",
-            ],
-        },
-    ],
+    dists = [{
+        "tag": ".bar",
+        "targets": ["goal_bar"],
+    }],
 )`,
 		},
 		{
@@ -169,19 +157,13 @@
     soong_module_variant = "",
     soong_module_deps = [
     ],
-    dists = [
-        {
-            "tag": ".tag",
-            "targets": [
-                "my_goal",
-            ],
-        },
-    ],
+    dists = [{
+        "tag": ".tag",
+        "targets": ["my_goal"],
+    }],
     owner = "custom_owner",
     ramdisk = True,
-    required = [
-        "bar",
-    ],
+    required = ["bar"],
     target_required = [
         "qux",
         "bazqux",
@@ -553,9 +535,7 @@
 }`,
 			expectedBazelTargets: []string{`filegroup(
     name = "fg_foo",
-    srcs = [
-        "b",
-    ],
+    srcs = ["b"],
 )`,
 			},
 		},
@@ -625,7 +605,7 @@
 			bp: `filegroup {
     name: "foobar",
     srcs: [
-      ":foo",
+        ":foo",
         "c",
     ],
     bazel_module: { bp2build_available: true },
@@ -671,25 +651,15 @@
 				`genrule(
     name = "foo",
     cmd = "$(location :foo.tool) --genDir=$(GENDIR) arg $(SRCS) $(OUTS)",
-    outs = [
-        "foo.out",
-    ],
-    srcs = [
-        "foo.in",
-    ],
-    tools = [
-        ":foo.tool",
-    ],
+    outs = ["foo.out"],
+    srcs = ["foo.in"],
+    tools = [":foo.tool"],
 )`,
 				`genrule(
     name = "foo.tool",
     cmd = "cp $(SRCS) $(OUTS)",
-    outs = [
-        "foo_tool.out",
-    ],
-    srcs = [
-        "foo_tool.in",
-    ],
+    outs = ["foo_tool.out"],
+    srcs = ["foo_tool.in"],
 )`,
 			},
 		},
@@ -718,15 +688,9 @@
 			expectedBazelTargets: []string{`genrule(
     name = "foo",
     cmd = "$(locations :foo.tools) -s $(OUTS) $(SRCS)",
-    outs = [
-        "foo.out",
-    ],
-    srcs = [
-        "foo.in",
-    ],
-    tools = [
-        ":foo.tools",
-    ],
+    outs = ["foo.out"],
+    srcs = ["foo.in"],
+    tools = [":foo.tools"],
 )`,
 				`genrule(
     name = "foo.tools",
@@ -735,9 +699,7 @@
         "foo_tool.out",
         "foo_tool2.out",
     ],
-    srcs = [
-        "foo_tool.in",
-    ],
+    srcs = ["foo_tool.in"],
 )`,
 			},
 		},
@@ -758,15 +720,9 @@
 			expectedBazelTargets: []string{`genrule(
     name = "foo",
     cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
-    outs = [
-        "foo.out",
-    ],
-    srcs = [
-        "foo.in",
-    ],
-    tools = [
-        "//other:foo.tool",
-    ],
+    outs = ["foo.out"],
+    srcs = ["foo.in"],
+    tools = ["//other:foo.tool"],
 )`,
 			},
 			fs: otherGenruleBp,
@@ -788,15 +744,9 @@
 			expectedBazelTargets: []string{`genrule(
     name = "foo",
     cmd = "$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)",
-    outs = [
-        "foo.out",
-    ],
-    srcs = [
-        "//other:other.tool",
-    ],
-    tools = [
-        "//other:foo.tool",
-    ],
+    outs = ["foo.out"],
+    srcs = ["//other:other.tool"],
+    tools = ["//other:foo.tool"],
 )`,
 			},
 			fs: otherGenruleBp,
@@ -818,12 +768,8 @@
 			expectedBazelTargets: []string{`genrule(
     name = "foo",
     cmd = "$(location //other:foo.tool) -s $(OUTS) $(SRCS)",
-    outs = [
-        "foo.out",
-    ],
-    srcs = [
-        "foo.in",
-    ],
+    outs = ["foo.out"],
+    srcs = ["foo.in"],
     tools = [
         "//other:foo.tool",
         "//other:other.tool",
@@ -849,12 +795,8 @@
 			expectedBazelTargets: []string{`genrule(
     name = "foo",
     cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
-    outs = [
-        "foo.out",
-    ],
-    srcs = [
-        "foo.in",
-    ],
+    outs = ["foo.out"],
+    srcs = ["foo.in"],
     tools = [
         "//other:foo.tool",
         "//other:other.tool",
@@ -879,12 +821,8 @@
 			expectedBazelTargets: []string{`genrule(
     name = "foo",
     cmd = "cp $(SRCS) $(OUTS)",
-    outs = [
-        "foo.out",
-    ],
-    srcs = [
-        "foo.in",
-    ],
+    outs = ["foo.out"],
+    srcs = ["foo.in"],
 )`,
 			},
 		},
@@ -988,12 +926,8 @@
 			expectedBazelTarget: `genrule(
     name = "gen",
     cmd = "do-something $(SRCS) $(OUTS)",
-    outs = [
-        "out",
-    ],
-    srcs = [
-        "in1",
-    ],
+    outs = ["out"],
+    srcs = ["in1"],
 )`,
 			description: "genrule applies properties from a genrule_defaults dependency if not specified",
 		},
@@ -1062,12 +996,8 @@
 			expectedBazelTarget: `genrule(
     name = "gen",
     cmd = "cp $(SRCS) $(OUTS)",
-    outs = [
-        "out",
-    ],
-    srcs = [
-        "in1",
-    ],
+    outs = ["out"],
+    srcs = ["in1"],
 )`,
 			description: "genrule applies properties from list of genrule_defaults",
 		},
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
new file mode 100644
index 0000000..783af2e
--- /dev/null
+++ b/bp2build/cc_library_conversion_test.go
@@ -0,0 +1,271 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bp2build
+
+import (
+	"android/soong/android"
+	"android/soong/cc"
+	"strings"
+	"testing"
+)
+
+const (
+	// See cc/testing.go for more context
+	soongCcLibraryPreamble = `
+cc_defaults {
+	name: "linux_bionic_supported",
+}
+
+toolchain_library {
+	name: "libclang_rt.builtins-x86_64-android",
+	defaults: ["linux_bionic_supported"],
+	vendor_available: true,
+	vendor_ramdisk_available: true,
+	product_available: true,
+	recovery_available: true,
+	native_bridge_supported: true,
+	src: "",
+}`
+)
+
+func TestCcLibraryBp2Build(t *testing.T) {
+	testCases := []struct {
+		description                        string
+		moduleTypeUnderTest                string
+		moduleTypeUnderTestFactory         android.ModuleFactory
+		moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
+		bp                                 string
+		expectedBazelTargets               []string
+		filesystem                         map[string]string
+		dir                                string
+	}{
+		{
+			description:                        "cc_library - simple example",
+			moduleTypeUnderTest:                "cc_library",
+			moduleTypeUnderTestFactory:         cc.LibraryFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+			filesystem: map[string]string{
+				"android.cpp": "",
+				"darwin.cpp":  "",
+				// Refer to cc.headerExts for the supported header extensions in Soong.
+				"header.h":         "",
+				"header.hh":        "",
+				"header.hpp":       "",
+				"header.hxx":       "",
+				"header.h++":       "",
+				"header.inl":       "",
+				"header.inc":       "",
+				"header.ipp":       "",
+				"header.h.generic": "",
+				"impl.cpp":         "",
+				"linux.cpp":        "",
+				"x86.cpp":          "",
+				"x86_64.cpp":       "",
+				"foo-dir/a.h":      "",
+			},
+			bp: soongCcLibraryPreamble + `
+cc_library_headers { name: "some-headers" }
+cc_library {
+    name: "foo-lib",
+    srcs: ["impl.cpp"],
+    cflags: ["-Wall"],
+    header_libs: ["some-headers"],
+    export_include_dirs: ["foo-dir"],
+    ldflags: ["-Wl,--exclude-libs=bar.a"],
+    arch: {
+        x86: {
+            ldflags: ["-Wl,--exclude-libs=baz.a"],
+            srcs: ["x86.cpp"],
+        },
+        x86_64: {
+            ldflags: ["-Wl,--exclude-libs=qux.a"],
+            srcs: ["x86_64.cpp"],
+        },
+    },
+    target: {
+        android: {
+            srcs: ["android.cpp"],
+        },
+        linux_glibc: {
+            srcs: ["linux.cpp"],
+        },
+        darwin: {
+            srcs: ["darwin.cpp"],
+        },
+    },
+}
+`,
+			expectedBazelTargets: []string{`cc_library(
+    name = "foo-lib",
+    copts = ["-Wall"],
+    deps = [":some-headers"],
+    hdrs = [
+        "header.h",
+        "header.hh",
+        "header.hpp",
+        "header.hxx",
+        "header.h++",
+        "header.inl",
+        "header.inc",
+        "header.ipp",
+        "header.h.generic",
+        "foo-dir/a.h",
+    ],
+    includes = ["foo-dir"],
+    linkopts = ["-Wl,--exclude-libs=bar.a"] + select({
+        "//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=baz.a"],
+        "//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=qux.a"],
+        "//conditions:default": [],
+    }),
+    srcs = ["impl.cpp"] + select({
+        "//build/bazel/platforms/arch:x86": ["x86.cpp"],
+        "//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"],
+        "//conditions:default": [],
+    }) + select({
+        "//build/bazel/platforms/os:android": ["android.cpp"],
+        "//build/bazel/platforms/os:darwin": ["darwin.cpp"],
+        "//build/bazel/platforms/os:linux": ["linux.cpp"],
+        "//conditions:default": [],
+    }),
+)`},
+		},
+		{
+			description:                        "cc_library - trimmed example of //bionic/linker:ld-android",
+			moduleTypeUnderTest:                "cc_library",
+			moduleTypeUnderTestFactory:         cc.LibraryFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+			filesystem: map[string]string{
+				"ld-android.cpp":           "",
+				"linked_list.h":            "",
+				"linker.h":                 "",
+				"linker_block_allocator.h": "",
+				"linker_cfi.h":             "",
+			},
+			bp: soongCcLibraryPreamble + `
+cc_library_headers { name: "libc_headers" }
+cc_library {
+    name: "fake-ld-android",
+    srcs: ["ld_android.cpp"],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Wunused",
+        "-Werror",
+    ],
+    header_libs: ["libc_headers"],
+    ldflags: [
+        "-Wl,--exclude-libs=libgcc.a",
+        "-Wl,--exclude-libs=libgcc_stripped.a",
+        "-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
+        "-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a",
+        "-Wl,--exclude-libs=libclang_rt.builtins-i686-android.a",
+        "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a",
+    ],
+    arch: {
+        x86: {
+            ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
+        },
+        x86_64: {
+            ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
+        },
+    },
+}
+`,
+			expectedBazelTargets: []string{`cc_library(
+    name = "fake-ld-android",
+    copts = [
+        "-Wall",
+        "-Wextra",
+        "-Wunused",
+        "-Werror",
+    ],
+    deps = [":libc_headers"],
+    hdrs = [
+        "linked_list.h",
+        "linker.h",
+        "linker_block_allocator.h",
+        "linker_cfi.h",
+    ],
+    linkopts = [
+        "-Wl,--exclude-libs=libgcc.a",
+        "-Wl,--exclude-libs=libgcc_stripped.a",
+        "-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
+        "-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a",
+        "-Wl,--exclude-libs=libclang_rt.builtins-i686-android.a",
+        "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a",
+    ] + select({
+        "//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=libgcc_eh.a"],
+        "//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=libgcc_eh.a"],
+        "//conditions:default": [],
+    }),
+    srcs = ["ld_android.cpp"],
+)`},
+		},
+	}
+
+	dir := "."
+	for _, testCase := range testCases {
+		filesystem := make(map[string][]byte)
+		toParse := []string{
+			"Android.bp",
+		}
+		for f, content := range testCase.filesystem {
+			if strings.HasSuffix(f, "Android.bp") {
+				toParse = append(toParse, f)
+			}
+			filesystem[f] = []byte(content)
+		}
+		config := android.TestConfig(buildDir, nil, testCase.bp, filesystem)
+		ctx := android.NewTestContext(config)
+
+		cc.RegisterCCBuildComponents(ctx)
+		ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
+		ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
+		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+		ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
+		ctx.RegisterBp2BuildConfig(bp2buildConfig) // TODO(jingwen): make this the default for all tests
+		ctx.RegisterForBazelConversion()
+
+		_, errs := ctx.ParseFileList(dir, toParse)
+		if Errored(t, testCase.description, errs) {
+			continue
+		}
+		_, errs = ctx.ResolveDependencies(config)
+		if Errored(t, testCase.description, errs) {
+			continue
+		}
+
+		checkDir := dir
+		if testCase.dir != "" {
+			checkDir = testCase.dir
+		}
+		codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+		bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir)
+		if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
+			t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
+		} else {
+			for i, target := range bazelTargets {
+				if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
+					t.Errorf(
+						"%s: Expected generated Bazel target to be '%s', got '%s'",
+						testCase.description,
+						w,
+						g,
+					)
+				}
+			}
+		}
+	}
+}
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index 74226ae..c59241f 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -23,7 +23,7 @@
 
 const (
 	// See cc/testing.go for more context
-	soongCcLibraryPreamble = `
+	soongCcLibraryHeadersPreamble = `
 cc_defaults {
 	name: "linux_bionic_supported",
 }
@@ -98,7 +98,7 @@
 				"arch_x86_exported_include_dir/b.h":    "",
 				"arch_x86_64_exported_include_dir/c.h": "",
 			},
-			bp: soongCcLibraryPreamble + `
+			bp: soongCcLibraryHeadersPreamble + `
 cc_library_headers {
     name: "lib-1",
     export_include_dirs: ["lib-1"],
@@ -141,30 +141,18 @@
         "dir-2/dir2a.h",
         "dir-2/dir2b.h",
     ] + select({
-        "//build/bazel/platforms/arch:arm64": [
-            "arch_arm64_exported_include_dir/a.h",
-        ],
-        "//build/bazel/platforms/arch:x86": [
-            "arch_x86_exported_include_dir/b.h",
-        ],
-        "//build/bazel/platforms/arch:x86_64": [
-            "arch_x86_64_exported_include_dir/c.h",
-        ],
+        "//build/bazel/platforms/arch:arm64": ["arch_arm64_exported_include_dir/a.h"],
+        "//build/bazel/platforms/arch:x86": ["arch_x86_exported_include_dir/b.h"],
+        "//build/bazel/platforms/arch:x86_64": ["arch_x86_64_exported_include_dir/c.h"],
         "//conditions:default": [],
     }),
     includes = [
         "dir-1",
         "dir-2",
     ] + select({
-        "//build/bazel/platforms/arch:arm64": [
-            "arch_arm64_exported_include_dir",
-        ],
-        "//build/bazel/platforms/arch:x86": [
-            "arch_x86_exported_include_dir",
-        ],
-        "//build/bazel/platforms/arch:x86_64": [
-            "arch_x86_64_exported_include_dir",
-        ],
+        "//build/bazel/platforms/arch:arm64": ["arch_arm64_exported_include_dir"],
+        "//build/bazel/platforms/arch:x86": ["arch_x86_exported_include_dir"],
+        "//build/bazel/platforms/arch:x86_64": ["arch_x86_64_exported_include_dir"],
         "//conditions:default": [],
     }),
 )`, `cc_library_headers(
@@ -173,18 +161,14 @@
         "lib-1/lib1a.h",
         "lib-1/lib1b.h",
     ],
-    includes = [
-        "lib-1",
-    ],
+    includes = ["lib-1"],
 )`, `cc_library_headers(
     name = "lib-2",
     hdrs = [
         "lib-2/lib2a.h",
         "lib-2/lib2b.h",
     ],
-    includes = [
-        "lib-2",
-    ],
+    includes = ["lib-2"],
 )`},
 		},
 		{
@@ -223,27 +207,13 @@
     name = "darwin-lib",
 )`, `cc_library_headers(
     name = "foo_headers",
-    deps = [
-        ":base-lib",
-    ] + select({
-        "//build/bazel/platforms/os:android": [
-            ":android-lib",
-        ],
-        "//build/bazel/platforms/os:darwin": [
-            ":darwin-lib",
-        ],
-        "//build/bazel/platforms/os:fuchsia": [
-            ":fuchsia-lib",
-        ],
-        "//build/bazel/platforms/os:linux": [
-            ":linux-lib",
-        ],
-        "//build/bazel/platforms/os:linux_bionic": [
-            ":linux_bionic-lib",
-        ],
-        "//build/bazel/platforms/os:windows": [
-            ":windows-lib",
-        ],
+    deps = [":base-lib"] + select({
+        "//build/bazel/platforms/os:android": [":android-lib"],
+        "//build/bazel/platforms/os:darwin": [":darwin-lib"],
+        "//build/bazel/platforms/os:fuchsia": [":fuchsia-lib"],
+        "//build/bazel/platforms/os:linux": [":linux-lib"],
+        "//build/bazel/platforms/os:linux_bionic": [":linux_bionic-lib"],
+        "//build/bazel/platforms/os:windows": [":windows-lib"],
         "//conditions:default": [],
     }),
 )`, `cc_library_headers(
@@ -278,7 +248,7 @@
     name = "exported-lib",
 )`, `cc_library_headers(
     name = "foo_headers",
-    deps = [] + select({
+    deps = select({
         "//build/bazel/platforms/os:android": [
             ":android-lib",
             ":exported-lib",
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index ef528e9..427aed3 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -194,6 +194,8 @@
         ":whole_static_lib_2",
     ],
     hdrs = [
+        "implicit_include_1.h",
+        "implicit_include_2.h",
         "export_include_dir_1/export_include_dir_1_a.h",
         "export_include_dir_1/export_include_dir_1_b.h",
         "export_include_dir_2/export_include_dir_2_a.h",
@@ -212,8 +214,6 @@
     srcs = [
         "foo_static1.cc",
         "foo_static2.cc",
-        "implicit_include_1.h",
-        "implicit_include_2.h",
         "include_dir_1/include_dir_1_a.h",
         "include_dir_1/include_dir_1_b.h",
         "include_dir_2/include_dir_2_a.h",
@@ -222,50 +222,60 @@
         "local_include_dir_1/local_include_dir_1_b.h",
         "local_include_dir_2/local_include_dir_2_a.h",
         "local_include_dir_2/local_include_dir_2_b.h",
+        "implicit_include_1.h",
+        "implicit_include_2.h",
     ],
 )`, `cc_library_static(
     name = "static_lib_1",
-    includes = [
-        ".",
-    ],
-    linkstatic = True,
-    srcs = [
+    hdrs = [
         "implicit_include_1.h",
         "implicit_include_2.h",
+    ],
+    includes = ["."],
+    linkstatic = True,
+    srcs = [
         "static_lib_1.cc",
+        "implicit_include_1.h",
+        "implicit_include_2.h",
     ],
 )`, `cc_library_static(
     name = "static_lib_2",
-    includes = [
-        ".",
-    ],
-    linkstatic = True,
-    srcs = [
+    hdrs = [
         "implicit_include_1.h",
         "implicit_include_2.h",
+    ],
+    includes = ["."],
+    linkstatic = True,
+    srcs = [
         "static_lib_2.cc",
+        "implicit_include_1.h",
+        "implicit_include_2.h",
     ],
 )`, `cc_library_static(
     name = "whole_static_lib_1",
-    includes = [
-        ".",
-    ],
-    linkstatic = True,
-    srcs = [
+    hdrs = [
         "implicit_include_1.h",
         "implicit_include_2.h",
+    ],
+    includes = ["."],
+    linkstatic = True,
+    srcs = [
         "whole_static_lib_1.cc",
+        "implicit_include_1.h",
+        "implicit_include_2.h",
     ],
 )`, `cc_library_static(
     name = "whole_static_lib_2",
-    includes = [
-        ".",
-    ],
-    linkstatic = True,
-    srcs = [
+    hdrs = [
         "implicit_include_1.h",
         "implicit_include_2.h",
+    ],
+    includes = ["."],
+    linkstatic = True,
+    srcs = [
         "whole_static_lib_2.cc",
+        "implicit_include_1.h",
+        "implicit_include_2.h",
     ],
 )`},
 		},
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index 4f3babe..a9d24ac 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -52,7 +52,6 @@
         "-Werror",
     ],
     srcs: [
-        "a/b/*.h",
         "a/b/*.c"
     ],
     exclude_srcs: ["a/b/exclude.c"],
@@ -68,15 +67,15 @@
         "-Wall",
         "-Werror",
     ],
+    hdrs = [
+        "a/b/bar.h",
+        "a/b/foo.h",
+    ],
     local_include_dirs = [
         "include",
         ".",
     ],
-    srcs = [
-        "a/b/bar.h",
-        "a/b/c.c",
-        "a/b/foo.h",
-    ],
+    srcs = ["a/b/c.c"],
 )`,
 			},
 		},
@@ -123,9 +122,7 @@
         "include",
         ".",
     ],
-    srcs = [
-        "a/b/c.c",
-    ],
+    srcs = ["a/b/c.c"],
 )`,
 			},
 		},
@@ -155,29 +152,15 @@
 `,
 			expectedBazelTargets: []string{`cc_object(
     name = "bar",
-    copts = [
-        "-fno-addrsig",
-    ],
-    local_include_dirs = [
-        ".",
-    ],
-    srcs = [
-        "x/y/z.c",
-    ],
+    copts = ["-fno-addrsig"],
+    local_include_dirs = ["."],
+    srcs = ["x/y/z.c"],
 )`, `cc_object(
     name = "foo",
-    copts = [
-        "-fno-addrsig",
-    ],
-    deps = [
-        ":bar",
-    ],
-    local_include_dirs = [
-        ".",
-    ],
-    srcs = [
-        "a/b/c.c",
-    ],
+    copts = ["-fno-addrsig"],
+    deps = [":bar"],
+    local_include_dirs = ["."],
+    srcs = ["a/b/c.c"],
 )`,
 			},
 		},
@@ -200,12 +183,8 @@
 `,
 			expectedBazelTargets: []string{`cc_object(
     name = "foo",
-    copts = [
-        "-fno-addrsig",
-    ],
-    srcs = [
-        "a/b/c.c",
-    ],
+    copts = ["-fno-addrsig"],
+    srcs = ["a/b/c.c"],
 )`,
 			},
 		},
@@ -228,12 +207,8 @@
 `,
 			expectedBazelTargets: []string{`cc_object(
     name = "foo",
-    asflags = [
-        "-DPLATFORM_SDK_VERSION={Platform_sdk_version}",
-    ],
-    copts = [
-        "-fno-addrsig",
-    ],
+    asflags = ["-DPLATFORM_SDK_VERSION={Platform_sdk_version}"],
+    copts = ["-fno-addrsig"],
 )`,
 			},
 		},
@@ -321,23 +296,13 @@
 			expectedBazelTargets: []string{
 				`cc_object(
     name = "foo",
-    copts = [
-        "-fno-addrsig",
-    ] + select({
-        "//build/bazel/platforms/arch:x86": [
-            "-fPIC",
-        ],
+    copts = ["-fno-addrsig"] + select({
+        "//build/bazel/platforms/arch:x86": ["-fPIC"],
         "//conditions:default": [],
     }),
-    local_include_dirs = [
-        ".",
-    ],
-    srcs = [
-        "a.cpp",
-    ] + select({
-        "//build/bazel/platforms/arch:arm": [
-            "arch/arm/file.S",
-        ],
+    local_include_dirs = ["."],
+    srcs = ["a.cpp"] + select({
+        "//build/bazel/platforms/arch:arm": ["arch/arm/file.S"],
         "//conditions:default": [],
     }),
 )`,
@@ -375,41 +340,19 @@
 			expectedBazelTargets: []string{
 				`cc_object(
     name = "foo",
-    copts = [
-        "-fno-addrsig",
-    ] + select({
-        "//build/bazel/platforms/arch:arm": [
-            "-Wall",
-        ],
-        "//build/bazel/platforms/arch:arm64": [
-            "-Wall",
-        ],
-        "//build/bazel/platforms/arch:x86": [
-            "-fPIC",
-        ],
-        "//build/bazel/platforms/arch:x86_64": [
-            "-fPIC",
-        ],
+    copts = ["-fno-addrsig"] + select({
+        "//build/bazel/platforms/arch:arm": ["-Wall"],
+        "//build/bazel/platforms/arch:arm64": ["-Wall"],
+        "//build/bazel/platforms/arch:x86": ["-fPIC"],
+        "//build/bazel/platforms/arch:x86_64": ["-fPIC"],
         "//conditions:default": [],
     }),
-    local_include_dirs = [
-        ".",
-    ],
-    srcs = [
-        "base.cpp",
-    ] + select({
-        "//build/bazel/platforms/arch:arm": [
-            "arm.cpp",
-        ],
-        "//build/bazel/platforms/arch:arm64": [
-            "arm64.cpp",
-        ],
-        "//build/bazel/platforms/arch:x86": [
-            "x86.cpp",
-        ],
-        "//build/bazel/platforms/arch:x86_64": [
-            "x86_64.cpp",
-        ],
+    local_include_dirs = ["."],
+    srcs = ["base.cpp"] + select({
+        "//build/bazel/platforms/arch:arm": ["arm.cpp"],
+        "//build/bazel/platforms/arch:arm64": ["arm64.cpp"],
+        "//build/bazel/platforms/arch:x86": ["x86.cpp"],
+        "//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"],
         "//conditions:default": [],
     }),
 )`,
@@ -440,26 +383,14 @@
 			expectedBazelTargets: []string{
 				`cc_object(
     name = "foo",
-    copts = [
-        "-fno-addrsig",
-    ] + select({
-        "//build/bazel/platforms/os:android": [
-            "-fPIC",
-        ],
-        "//build/bazel/platforms/os:darwin": [
-            "-Wall",
-        ],
-        "//build/bazel/platforms/os:windows": [
-            "-fPIC",
-        ],
+    copts = ["-fno-addrsig"] + select({
+        "//build/bazel/platforms/os:android": ["-fPIC"],
+        "//build/bazel/platforms/os:darwin": ["-Wall"],
+        "//build/bazel/platforms/os:windows": ["-fPIC"],
         "//conditions:default": [],
     }),
-    local_include_dirs = [
-        ".",
-    ],
-    srcs = [
-        "base.cpp",
-    ],
+    local_include_dirs = ["."],
+    srcs = ["base.cpp"],
 )`,
 			},
 		},
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index b2b3379..97729df 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -69,20 +69,26 @@
 		return ret, err
 	}
 
-	// Create the selects for arch specific values.
-	selectMap, err := prettyPrintSelectMap(archSelects, "[]", indent)
+	// Convenience function to append selects components to an attribute value.
+	appendSelects := func(selectsData selects, defaultValue, s string) (string, error) {
+		selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent)
+		if err != nil {
+			return "", err
+		}
+		if s != "" && selectMap != "" {
+			s += " + "
+		}
+		s += selectMap
+
+		return s, nil
+	}
+
+	ret, err = appendSelects(archSelects, "[]", ret)
 	if err != nil {
 		return "", err
 	}
-	ret += selectMap
 
-	// Create the selects for target os specific values.
-	selectMap, err = prettyPrintSelectMap(osSelects, "[]", indent)
-	if err != nil {
-		return "", err
-	}
-	ret += selectMap
-
+	ret, err = appendSelects(osSelects, "[]", ret)
 	return ret, err
 }
 
@@ -113,7 +119,7 @@
 	}
 
 	// Create the map.
-	ret := " + select({\n"
+	ret := "select({\n"
 	ret += selects
 	// default condition comes last.
 	ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), "//conditions:default", defaultValue)
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index 7600e36..2054e06 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -33,24 +33,15 @@
 			blueprint: `python_binary_host {
     name: "foo",
     main: "a.py",
-    srcs: [
-        "**/*.py"
-    ],
-    exclude_srcs: [
-        "b/e.py"
-    ],
-    data: [
-        "files/data.txt",
-    ],
-
+    srcs: ["**/*.py"],
+    exclude_srcs: ["b/e.py"],
+    data: ["files/data.txt",],
     bazel_module: { bp2build_available: true },
 }
 `,
 			expectedBazelTargets: []string{`py_binary(
     name = "foo",
-    data = [
-        "files/data.txt",
-    ],
+    data = ["files/data.txt"],
     main = "a.py",
     srcs = [
         "a.py",
@@ -83,9 +74,7 @@
 			expectedBazelTargets: []string{`py_binary(
     name = "foo",
     python_version = "PY2",
-    srcs = [
-        "a.py",
-    ],
+    srcs = ["a.py"],
 )`,
 			},
 		},
@@ -113,9 +102,7 @@
 				// python_version is PY3 by default.
 				`py_binary(
     name = "foo",
-    srcs = [
-        "a.py",
-    ],
+    srcs = ["a.py"],
 )`,
 			},
 		},
diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go
index 2aa373c..37f542e 100644
--- a/bp2build/sh_conversion_test.go
+++ b/bp2build/sh_conversion_test.go
@@ -74,9 +74,7 @@
 }`,
 			expectedBazelTargets: []string{`sh_binary(
     name = "foo",
-    srcs = [
-        "foo.sh",
-    ],
+    srcs = ["foo.sh"],
 )`},
 		},
 	}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index cffeb24..0bca30a 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -59,72 +59,111 @@
 	ctx.AddDependency(module, nil, android.SortedUniqueStrings(allDeps)...)
 }
 
-// bp2buildParseCflags creates a label list attribute containing the cflags of a module, including
-func bp2BuildParseCflags(ctx android.TopDownMutatorContext, module *Module) bazel.StringListAttribute {
-	var ret bazel.StringListAttribute
+// Convenience struct to hold all attributes parsed from compiler properties.
+type compilerAttributes struct {
+	copts bazel.StringListAttribute
+	srcs  bazel.LabelListAttribute
+	hdrs  bazel.LabelListAttribute
+}
+
+// bp2BuildParseCompilerProps returns copts, srcs and hdrs and other attributes.
+func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Module) compilerAttributes {
+	var hdrs, srcs bazel.LabelListAttribute
+	var copts bazel.StringListAttribute
+
+	hdrsAndSrcs := func(baseCompilerProps *BaseCompilerProperties) (bazel.LabelList, bazel.LabelList) {
+		srcsList := android.BazelLabelForModuleSrcExcludes(
+			ctx, baseCompilerProps.Srcs, baseCompilerProps.Exclude_srcs)
+		hdrsList := android.BazelLabelForModuleSrc(ctx, srcsList.LooseHdrsGlobs(headerExts))
+		return hdrsList, srcsList
+	}
+
 	for _, props := range module.compiler.compilerProps() {
 		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
-			ret.Value = baseCompilerProps.Cflags
+			hdrs.Value, srcs.Value = hdrsAndSrcs(baseCompilerProps)
+			copts.Value = baseCompilerProps.Cflags
 			break
 		}
 	}
 
 	for arch, props := range module.GetArchProperties(&BaseCompilerProperties{}) {
 		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
-			ret.SetValueForArch(arch.Name, baseCompilerProps.Cflags)
+			hdrsList, srcsList := hdrsAndSrcs(baseCompilerProps)
+			hdrs.SetValueForArch(arch.Name, bazel.SubtractBazelLabelList(hdrsList, hdrs.Value))
+			srcs.SetValueForArch(arch.Name, srcsList)
+			copts.SetValueForArch(arch.Name, baseCompilerProps.Cflags)
 		}
 	}
 
 	for os, props := range module.GetTargetProperties(&BaseCompilerProperties{}) {
 		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
-			ret.SetValueForOS(os.Name, baseCompilerProps.Cflags)
+			hdrsList, srcsList := hdrsAndSrcs(baseCompilerProps)
+			hdrs.SetValueForOS(os.Name, bazel.SubtractBazelLabelList(hdrsList, hdrs.Value))
+			srcs.SetValueForOS(os.Name, srcsList)
+			copts.SetValueForOS(os.Name, baseCompilerProps.Cflags)
 		}
 	}
 
-	return ret
+	return compilerAttributes{
+		hdrs:  hdrs,
+		srcs:  srcs,
+		copts: copts,
+	}
 }
 
-// bp2BuildParseHeaderLibs creates a label list attribute containing the header library deps of a module, including
+// Convenience struct to hold all attributes parsed from linker properties.
+type linkerAttributes struct {
+	deps     bazel.LabelListAttribute
+	linkopts bazel.StringListAttribute
+}
+
+// bp2BuildParseLinkerProps creates a label list attribute containing the header library deps of a module, including
 // configurable attribute values.
-func bp2BuildParseHeaderLibs(ctx android.TopDownMutatorContext, module *Module) bazel.LabelListAttribute {
-	var ret bazel.LabelListAttribute
+func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) linkerAttributes {
+
+	var deps bazel.LabelListAttribute
+	var linkopts bazel.StringListAttribute
+
 	for _, linkerProps := range module.linker.linkerProps() {
 		if baseLinkerProps, ok := linkerProps.(*BaseLinkerProperties); ok {
 			libs := baseLinkerProps.Header_libs
 			libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
-			ret = bazel.MakeLabelListAttribute(
+			deps = bazel.MakeLabelListAttribute(
 				android.BazelLabelForModuleDeps(ctx, android.SortedUniqueStrings(libs)))
+			linkopts.Value = baseLinkerProps.Ldflags
 			break
 		}
 	}
 
+	for arch, p := range module.GetArchProperties(&BaseLinkerProperties{}) {
+		if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
+			libs := baseLinkerProps.Header_libs
+			libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
+			libs = android.SortedUniqueStrings(libs)
+			deps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, libs))
+			linkopts.SetValueForArch(arch.Name, baseLinkerProps.Ldflags)
+		}
+	}
+
 	for os, p := range module.GetTargetProperties(&BaseLinkerProperties{}) {
 		if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
 			libs := baseLinkerProps.Header_libs
 			libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
 			libs = android.SortedUniqueStrings(libs)
-			ret.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, libs))
+			deps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, libs))
+			linkopts.SetValueForOS(os.Name, baseLinkerProps.Ldflags)
 		}
 	}
 
-	return ret
+	return linkerAttributes{
+		deps:     deps,
+		linkopts: linkopts,
+	}
 }
 
 func bp2BuildListHeadersInDir(ctx android.TopDownMutatorContext, includeDir string) bazel.LabelList {
-	var globInfix string
-
-	if includeDir == "." {
-		globInfix = ""
-	} else {
-		globInfix = "/**"
-	}
-
-	var includeDirGlobs []string
-	includeDirGlobs = append(includeDirGlobs, includeDir+globInfix+"/*.h")
-	includeDirGlobs = append(includeDirGlobs, includeDir+globInfix+"/*.inc")
-	includeDirGlobs = append(includeDirGlobs, includeDir+globInfix+"/*.hpp")
-
-	return android.BazelLabelForModuleSrc(ctx, includeDirGlobs)
+	globs := bazel.GlobsInDir(includeDir, includeDir != ".", headerExts)
+	return android.BazelLabelForModuleSrc(ctx, globs)
 }
 
 // Bazel wants include paths to be relative to the module
diff --git a/cc/gen.go b/cc/gen.go
index 83c019c..b152e02 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -111,9 +111,7 @@
 	return ret
 }
 
-func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile android.Path,
-	outFile, depFile android.ModuleGenPath, aidlFlags string) android.Paths {
-
+func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile android.Path, aidlFlags string) (cppFile android.OutputPath, headerFiles android.Paths) {
 	aidlPackage := strings.TrimSuffix(aidlFile.Rel(), aidlFile.Base())
 	baseName := strings.TrimSuffix(aidlFile.Base(), aidlFile.Ext())
 	shortName := baseName
@@ -126,6 +124,8 @@
 	}
 
 	outDir := android.PathForModuleGen(ctx, "aidl")
+	cppFile = outDir.Join(ctx, aidlPackage, baseName+".cpp")
+	depFile := outDir.Join(ctx, aidlPackage, baseName+".cpp.d")
 	headerI := outDir.Join(ctx, aidlPackage, baseName+".h")
 	headerBn := outDir.Join(ctx, aidlPackage, "Bn"+shortName+".h")
 	headerBp := outDir.Join(ctx, aidlPackage, "Bp"+shortName+".h")
@@ -142,14 +142,14 @@
 		Flag(aidlFlags).
 		Input(aidlFile).
 		OutputDir().
-		Output(outFile).
+		Output(cppFile).
 		ImplicitOutputs(android.WritablePaths{
 			headerI,
 			headerBn,
 			headerBp,
 		})
 
-	return android.Paths{
+	return cppFile, android.Paths{
 		headerI,
 		headerBn,
 		headerBp,
@@ -293,10 +293,9 @@
 				aidlRule = android.NewRuleBuilder(pctx, ctx).Sbox(android.PathForModuleGen(ctx, "aidl"),
 					android.PathForModuleGen(ctx, "aidl.sbox.textproto"))
 			}
-			cppFile := android.GenPathWithExt(ctx, "aidl", srcFile, "cpp")
-			depFile := android.GenPathWithExt(ctx, "aidl", srcFile, "cpp.d")
+			cppFile, aidlHeaders := genAidl(ctx, aidlRule, srcFile, buildFlags.aidlFlags)
 			srcFiles[i] = cppFile
-			aidlHeaders := genAidl(ctx, aidlRule, srcFile, cppFile, depFile, buildFlags.aidlFlags)
+
 			info.aidlHeaders = append(info.aidlHeaders, aidlHeaders...)
 			// Use the generated headers as order only deps to ensure that they are up to date when
 			// needed.
diff --git a/cc/library.go b/cc/library.go
index 18f9fae..738b45f 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -206,6 +206,7 @@
 	RegisterLibraryBuildComponents(android.InitRegistrationContext)
 
 	android.RegisterBp2BuildMutator("cc_library_static", CcLibraryStaticBp2Build)
+	android.RegisterBp2BuildMutator("cc_library", CcLibraryBp2Build)
 }
 
 func RegisterLibraryBuildComponents(ctx android.RegistrationContext) {
@@ -216,6 +217,67 @@
 	ctx.RegisterModuleType("cc_library_host_shared", LibraryHostSharedFactory)
 }
 
+// For bp2build conversion.
+type bazelCcLibraryAttributes struct {
+	Srcs            bazel.LabelListAttribute
+	Hdrs            bazel.LabelListAttribute
+	Copts           bazel.StringListAttribute
+	Linkopts        bazel.StringListAttribute
+	Deps            bazel.LabelListAttribute
+	User_link_flags bazel.StringListAttribute
+	Includes        bazel.StringListAttribute
+}
+
+type bazelCcLibrary struct {
+	android.BazelTargetModuleBase
+	bazelCcLibraryAttributes
+}
+
+func (m *bazelCcLibrary) Name() string {
+	return m.BaseModuleName()
+}
+
+func (m *bazelCcLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
+
+func BazelCcLibraryFactory() android.Module {
+	module := &bazelCcLibrary{}
+	module.AddProperties(&module.bazelCcLibraryAttributes)
+	android.InitBazelTargetModule(module)
+	return module
+}
+
+func CcLibraryBp2Build(ctx android.TopDownMutatorContext) {
+	m, ok := ctx.Module().(*Module)
+	if !ok || !m.ConvertWithBp2build(ctx) {
+		return
+	}
+
+	if ctx.ModuleType() != "cc_library" {
+		return
+	}
+
+	compilerAttrs := bp2BuildParseCompilerProps(ctx, m)
+	linkerAttrs := bp2BuildParseLinkerProps(ctx, m)
+	exportedIncludes, exportedIncludesHeaders := bp2BuildParseExportedIncludes(ctx, m)
+	compilerAttrs.hdrs.Append(exportedIncludesHeaders)
+
+	attrs := &bazelCcLibraryAttributes{
+		Srcs:     compilerAttrs.srcs,
+		Hdrs:     compilerAttrs.hdrs,
+		Copts:    compilerAttrs.copts,
+		Linkopts: linkerAttrs.linkopts,
+		Deps:     linkerAttrs.deps,
+		Includes: exportedIncludes,
+	}
+
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "cc_library",
+		Bzl_load_location: "//build/bazel/rules:full_cc_library.bzl",
+	}
+
+	ctx.CreateBazelTargetModule(BazelCcLibraryFactory, m.Name(), props, attrs)
+}
+
 // cc_library creates both static and/or shared libraries for a device and/or
 // host. By default, a cc_library has a single variant that targets the device.
 // Specifying `host_supported: true` also creates a library that targets the
@@ -2058,9 +2120,10 @@
 }
 
 type bazelCcLibraryStaticAttributes struct {
-	Copts      []string
+	Copts      bazel.StringListAttribute
 	Srcs       bazel.LabelListAttribute
 	Deps       bazel.LabelListAttribute
+	Linkopts   bazel.StringListAttribute
 	Linkstatic bool
 	Includes   bazel.StringListAttribute
 	Hdrs       bazel.LabelListAttribute
@@ -2091,14 +2154,13 @@
 		return
 	}
 
-	var copts []string
-	var srcs []string
+	compilerAttrs := bp2BuildParseCompilerProps(ctx, module)
+
 	var includeDirs []string
 	var localIncludeDirs []string
 	for _, props := range module.compiler.compilerProps() {
 		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
-			copts = baseCompilerProps.Cflags
-			srcs = baseCompilerProps.Srcs
+			// TODO: these should be arch and os specific.
 			includeDirs = bp2BuildMakePathsRelativeToModule(ctx, baseCompilerProps.Include_dirs)
 			localIncludeDirs = bp2BuildMakePathsRelativeToModule(ctx, baseCompilerProps.Local_include_dirs)
 			break
@@ -2111,19 +2173,18 @@
 		localIncludeDirs = append(localIncludeDirs, ".")
 	}
 
-	srcsLabels := android.BazelLabelForModuleSrc(ctx, srcs)
-
 	// For Bazel, be more explicit about headers - list all header files in include dirs as srcs
 	for _, includeDir := range includeDirs {
-		srcsLabels.Append(bp2BuildListHeadersInDir(ctx, includeDir))
+		compilerAttrs.srcs.Value.Append(bp2BuildListHeadersInDir(ctx, includeDir))
 	}
 	for _, localIncludeDir := range localIncludeDirs {
-		srcsLabels.Append(bp2BuildListHeadersInDir(ctx, localIncludeDir))
+		compilerAttrs.srcs.Value.Append(bp2BuildListHeadersInDir(ctx, localIncludeDir))
 	}
 
 	var staticLibs []string
 	var wholeStaticLibs []string
 	for _, props := range module.linker.linkerProps() {
+		// TODO: move this into bp2buildParseLinkerProps
 		if baseLinkerProperties, ok := props.(*BaseLinkerProperties); ok {
 			staticLibs = baseLinkerProperties.Static_libs
 			wholeStaticLibs = baseLinkerProperties.Whole_static_libs
@@ -2145,16 +2206,18 @@
 	allIncludes.Value = append(allIncludes.Value, includeDirs...)
 	allIncludes.Value = append(allIncludes.Value, localIncludeDirs...)
 
-	headerLibsLabels := bp2BuildParseHeaderLibs(ctx, module)
-	depsLabels.Append(headerLibsLabels.Value)
+	compilerAttrs.hdrs.Append(exportedIncludesHeaders)
+
+	linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
+	depsLabels.Append(linkerAttrs.deps.Value)
 
 	attrs := &bazelCcLibraryStaticAttributes{
-		Copts:      copts,
-		Srcs:       bazel.MakeLabelListAttribute(srcsLabels),
+		Copts:      compilerAttrs.copts,
+		Srcs:       compilerAttrs.srcs,
 		Deps:       bazel.MakeLabelListAttribute(depsLabels),
 		Linkstatic: true,
 		Includes:   allIncludes,
-		Hdrs:       exportedIncludesHeaders,
+		Hdrs:       compilerAttrs.hdrs,
 	}
 
 	props := bazel.BazelTargetModuleProperties{
diff --git a/cc/library_headers.go b/cc/library_headers.go
index d35748b..076ce80 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -96,14 +96,14 @@
 	}
 
 	exportedIncludes, exportedIncludesHeaders := bp2BuildParseExportedIncludes(ctx, module)
-
-	headerLibs := bp2BuildParseHeaderLibs(ctx, module)
+	compilerAttrs := bp2BuildParseCompilerProps(ctx, module)
+	linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
 
 	attrs := &bazelCcLibraryHeadersAttributes{
-		Copts:    bp2BuildParseCflags(ctx, module),
+		Copts:    compilerAttrs.copts,
 		Includes: exportedIncludes,
 		Hdrs:     exportedIncludesHeaders,
-		Deps:     headerLibs,
+		Deps:     linkerAttrs.deps,
 	}
 
 	props := bazel.BazelTargetModuleProperties{
diff --git a/cc/object.go b/cc/object.go
index 4f8797d..9bb279a 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -113,6 +113,7 @@
 // For bp2build conversion.
 type bazelObjectAttributes struct {
 	Srcs               bazel.LabelListAttribute
+	Hdrs               bazel.LabelListAttribute
 	Deps               bazel.LabelListAttribute
 	Copts              bazel.StringListAttribute
 	Asflags            []string
@@ -156,16 +157,11 @@
 	}
 
 	// Set arch-specific configurable attributes
-	var srcs bazel.LabelListAttribute
+	compilerAttrs := bp2BuildParseCompilerProps(ctx, m)
 	var localIncludeDirs []string
 	var asFlags []string
 	for _, props := range m.compiler.compilerProps() {
 		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
-			srcs = bazel.MakeLabelListAttribute(
-				android.BazelLabelForModuleSrcExcludes(
-					ctx,
-					baseCompilerProps.Srcs,
-					baseCompilerProps.Exclude_srcs))
 			localIncludeDirs = baseCompilerProps.Local_include_dirs
 			break
 		}
@@ -200,16 +196,11 @@
 	}
 	// TODO(b/183595872) warn/error if we're not handling product variables
 
-	for arch, p := range m.GetArchProperties(&BaseCompilerProperties{}) {
-		if cProps, ok := p.(*BaseCompilerProperties); ok {
-			srcs.SetValueForArch(arch.Name, android.BazelLabelForModuleSrcExcludes(ctx, cProps.Srcs, cProps.Exclude_srcs))
-		}
-	}
-
 	attrs := &bazelObjectAttributes{
-		Srcs:               srcs,
+		Srcs:               compilerAttrs.srcs,
+		Hdrs:               compilerAttrs.hdrs,
 		Deps:               deps,
-		Copts:              bp2BuildParseCflags(ctx, m),
+		Copts:              compilerAttrs.copts,
 		Asflags:            asFlags,
 		Local_include_dirs: localIncludeDirs,
 	}
diff --git a/cc/object_test.go b/cc/object_test.go
index 6ff8a00..f82d544 100644
--- a/cc/object_test.go
+++ b/cc/object_test.go
@@ -15,6 +15,7 @@
 package cc
 
 import (
+	"android/soong/android"
 	"testing"
 )
 
@@ -27,5 +28,28 @@
 			linker_script: "foo.lds",
 		}`)
 	})
+}
 
+func TestCcObjectWithBazel(t *testing.T) {
+	bp := `
+cc_object {
+	name: "foo",
+	srcs: ["baz.o"],
+	bazel_module: { label: "//foo/bar:bar" },
+}`
+	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
+	config.BazelContext = android.MockBazelContext{
+		OutputBaseDir: "outputbase",
+		LabelToOutputFiles: map[string][]string{
+			"//foo/bar:bar": []string{"bazel_out.o"}}}
+	ctx := testCcWithConfig(t, config)
+
+	module := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon").Module()
+	outputFiles, err := module.(android.OutputFileProducer).OutputFiles("")
+	if err != nil {
+		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+	}
+
+	expectedOutputFiles := []string{"outputbase/execroot/__main__/bazel_out.o"}
+	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
 }
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 3f1e9f3..3ce4f85 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -696,7 +696,8 @@
 	result := android.GroupFixturePreparers(
 		prepareForGenRuleTest, android.FixtureModifyConfig(func(config android.Config) {
 			config.BazelContext = android.MockBazelContext{
-				AllFiles: map[string][]string{
+				OutputBaseDir: "outputbase",
+				LabelToOutputFiles: map[string][]string{
 					"//foo/bar:bar": []string{"bazelone.txt", "bazeltwo.txt"}}}
 		})).RunTestWithBp(t, testGenruleBp()+bp)
 
diff --git a/java/Android.bp b/java/Android.bp
index 8334b85..f8ba1b6 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -42,6 +42,7 @@
         "gen.go",
         "genrule.go",
         "hiddenapi.go",
+        "hiddenapi_modular.go",
         "hiddenapi_singleton.go",
         "jacoco.go",
         "java.go",
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
new file mode 100644
index 0000000..bed11fe
--- /dev/null
+++ b/java/hiddenapi_modular.go
@@ -0,0 +1,172 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"android/soong/android"
+)
+
+// Contains support for processing hiddenAPI in a modular fashion.
+
+// HiddenAPIAugmentationProperties contains paths to the files that can be used to augment the information
+// obtained from annotations within the source code in order to create the complete set of flags
+// that should be applied to the dex implementation jars on the bootclasspath.
+//
+// Each property contains a list of paths. With the exception of the Unsupported_packages the paths
+// of each property reference a plain text file that contains a java signature per line. The flags
+// for each of those signatures will be updated in a property specific way.
+//
+// The Unsupported_packages property contains a list of paths, each of which is a plain text file
+// with one Java package per line. All members of all classes within that package (but not nested
+// packages) will be updated in a property specific way.
+type HiddenAPIAugmentationProperties struct {
+	// Marks each signature in the referenced files as being unsupported.
+	Unsupported []string `android:"path"`
+
+	// Marks each signature in the referenced files as being unsupported because it has been removed.
+	// Any conflicts with other flags are ignored.
+	Removed []string `android:"path"`
+
+	// Marks each signature in the referenced files as being supported only for targetSdkVersion <= R
+	// and low priority.
+	Max_target_r_low_priority []string `android:"path"`
+
+	// Marks each signature in the referenced files as being supported only for targetSdkVersion <= Q.
+	Max_target_q []string `android:"path"`
+
+	// Marks each signature in the referenced files as being supported only for targetSdkVersion <= P.
+	Max_target_p []string `android:"path"`
+
+	// Marks each signature in the referenced files as being supported only for targetSdkVersion <= O
+	// and low priority. Any conflicts with other flags are ignored.
+	Max_target_o_low_priority []string `android:"path"`
+
+	// Marks each signature in the referenced files as being blocked.
+	Blocked []string `android:"path"`
+
+	// Marks each signature in every package in the referenced files as being unsupported.
+	Unsupported_packages []string `android:"path"`
+}
+
+func (p *HiddenAPIAugmentationProperties) hiddenAPIAugmentationInfo(ctx android.ModuleContext) hiddenAPIAugmentationInfo {
+	paths := func(paths []string) android.Paths { return android.PathsForModuleSrc(ctx, paths) }
+	return hiddenAPIAugmentationInfo{
+		Unsupported:               paths(p.Unsupported),
+		Removed:                   paths(p.Removed),
+		Max_target_r_low_priority: paths(p.Max_target_r_low_priority),
+		Max_target_q:              paths(p.Max_target_q),
+		Max_target_p:              paths(p.Max_target_p),
+		Max_target_o_low_priority: paths(p.Max_target_o_low_priority),
+		Blocked:                   paths(p.Blocked),
+		Unsupported_packages:      paths(p.Unsupported_packages),
+	}
+}
+
+// hiddenAPIAugmentationInfo contains paths resolved from HiddenAPIAugmentationProperties
+type hiddenAPIAugmentationInfo struct {
+	// See HiddenAPIAugmentationProperties.Unsupported
+	Unsupported android.Paths
+
+	// See HiddenAPIAugmentationProperties.Removed
+	Removed android.Paths
+
+	// See HiddenAPIAugmentationProperties.Max_target_r_low_priority
+	Max_target_r_low_priority android.Paths
+
+	// See HiddenAPIAugmentationProperties.Max_target_q
+	Max_target_q android.Paths
+
+	// See HiddenAPIAugmentationProperties.Max_target_p
+	Max_target_p android.Paths
+
+	// See HiddenAPIAugmentationProperties.Max_target_o_low_priority
+	Max_target_o_low_priority android.Paths
+
+	// See HiddenAPIAugmentationProperties.Blocked
+	Blocked android.Paths
+
+	// See HiddenAPIAugmentationProperties.Unsupported_packages
+	Unsupported_packages android.Paths
+}
+
+// ruleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from the
+// flags from all the modules, the stub flags, augmented with some additional configuration files.
+//
+// baseFlagsPath is the path to the flags file containing all the information from the stubs plus
+// an entry for every single member in the dex implementation jars of the individual modules. Every
+// signature in any of the other files MUST be included in this file.
+//
+// moduleSpecificFlagsPaths are the paths to the flags files generated by each module using
+// information from the baseFlagsPath as well as from annotations within the source.
+//
+// augmentationInfo is a struct containing paths to files that augment the information provided by
+// the moduleSpecificFlagsPaths.
+// ruleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from the
+// flags from all the modules, the stub flags, augmented with some additional configuration files.
+//
+// baseFlagsPath is the path to the flags file containing all the information from the stubs plus
+// an entry for every single member in the dex implementation jars of the individual modules. Every
+// signature in any of the other files MUST be included in this file.
+//
+// moduleSpecificFlagsPaths are the paths to the flags files generated by each module using
+// information from the baseFlagsPath as well as from annotations within the source.
+//
+// augmentationInfo is a struct containing paths to files that augment the information provided by
+// the moduleSpecificFlagsPaths.
+func ruleToGenerateHiddenApiFlags(ctx android.BuilderContext, outputPath android.WritablePath, baseFlagsPath android.Path, moduleSpecificFlagsPaths android.Paths, augmentationInfo hiddenAPIAugmentationInfo) {
+	tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp")
+	rule := android.NewRuleBuilder(pctx, ctx)
+	command := rule.Command().
+		BuiltTool("generate_hiddenapi_lists").
+		FlagWithInput("--csv ", baseFlagsPath).
+		Inputs(moduleSpecificFlagsPaths).
+		FlagWithOutput("--output ", tempPath)
+
+	for _, path := range augmentationInfo.Unsupported {
+		command.FlagWithInput("--unsupported ", path)
+	}
+
+	for _, path := range augmentationInfo.Removed {
+		command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
+	}
+
+	for _, path := range augmentationInfo.Max_target_r_low_priority {
+		command.FlagWithInput("--max-target-r ", path).FlagWithArg("--tag ", "lo-prio")
+	}
+
+	for _, path := range augmentationInfo.Max_target_q {
+		command.FlagWithInput("--max-target-q ", path)
+	}
+
+	for _, path := range augmentationInfo.Max_target_p {
+		command.FlagWithInput("--max-target-p ", path)
+	}
+
+	for _, path := range augmentationInfo.Max_target_o_low_priority {
+		command.FlagWithInput("--max-target-o ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio")
+	}
+
+	for _, path := range augmentationInfo.Blocked {
+		command.FlagWithInput("--blocked ", path)
+	}
+
+	for _, path := range augmentationInfo.Unsupported_packages {
+		command.FlagWithInput("--unsupported ", path).Flag("--packages ")
+	}
+
+	commitChangeForRestat(rule, tempPath, outputPath)
+
+	rule.Build("hiddenAPIFlagsFile", "hiddenapi flags")
+}
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 7e9477b..641e19f 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -18,7 +18,6 @@
 	"fmt"
 
 	"android/soong/android"
-	"android/soong/genrule"
 )
 
 func init() {
@@ -321,63 +320,10 @@
 	return outputPath
 }
 
-// flagsRule creates a rule to build hiddenapi-flags.csv out of flags.csv files generated for boot image modules and
-// the unsupported API.
+// flagsRule is a placeholder that simply returns the location of the file, the generation of the
+// ninja rules is done in generateHiddenAPIBuildActions.
 func flagsRule(ctx android.SingletonContext) android.Path {
-	var flagsCSV android.Paths
-	var combinedRemovedApis android.Path
-
-	ctx.VisitAllModules(func(module android.Module) {
-		if h, ok := module.(hiddenAPIIntf); ok {
-			if csv := h.flagsCSV(); csv != nil {
-				flagsCSV = append(flagsCSV, csv)
-			}
-		} else if g, ok := module.(*genrule.Module); ok {
-			if ctx.ModuleName(module) == "combined-removed-dex" {
-				if len(g.GeneratedSourceFiles()) != 1 || combinedRemovedApis != nil {
-					ctx.Errorf("Expected 1 combined-removed-dex module that generates 1 output file.")
-				}
-				combinedRemovedApis = g.GeneratedSourceFiles()[0]
-			}
-		}
-	})
-
-	if combinedRemovedApis == nil {
-		ctx.Errorf("Failed to find combined-removed-dex.")
-	}
-
-	rule := android.NewRuleBuilder(pctx, ctx)
-
 	outputPath := hiddenAPISingletonPaths(ctx).flags
-	tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp")
-
-	stubFlags := hiddenAPISingletonPaths(ctx).stubFlags
-
-	rule.Command().
-		BuiltTool("generate_hiddenapi_lists").
-		FlagWithInput("--csv ", stubFlags).
-		Inputs(flagsCSV).
-		FlagWithInput("--unsupported ",
-			android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-unsupported.txt")).
-		FlagWithInput("--unsupported ", combinedRemovedApis).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed").
-		FlagWithInput("--max-target-r ",
-			android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt")).FlagWithArg("--tag ", "lo-prio").
-		FlagWithInput("--max-target-q ",
-			android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-max-target-q.txt")).
-		FlagWithInput("--max-target-p ",
-			android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-max-target-p.txt")).
-		FlagWithInput("--max-target-o ", android.PathForSource(
-			ctx, "frameworks/base/boot/hiddenapi/hiddenapi-max-target-o.txt")).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio").
-		FlagWithInput("--blocked ",
-			android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-force-blocked.txt")).
-		FlagWithInput("--unsupported ", android.PathForSource(
-			ctx, "frameworks/base/boot/hiddenapi/hiddenapi-unsupported-packages.txt")).Flag("--packages ").
-		FlagWithOutput("--output ", tempPath)
-
-	commitChangeForRestat(rule, tempPath, outputPath)
-
-	rule.Build("hiddenAPIFlagsFile", "hiddenapi flags")
-
 	return outputPath
 }
 
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 95d19b9..e292d80 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -84,10 +84,11 @@
 }
 
 type platformBootclasspathProperties struct {
-
 	// The names of the bootclasspath_fragment modules that form part of this
 	// platform_bootclasspath.
 	Fragments []ApexVariantReference
+
+	Hidden_api HiddenAPIAugmentationProperties
 }
 
 func platformBootclasspathFactory() android.Module {
@@ -191,6 +192,8 @@
 		}
 	})
 
+	b.generateHiddenAPIBuildActions(ctx, b.configuredModules)
+
 	// Nothing to do if skipping the dexpreopt of boot image jars.
 	if SkipDexpreoptBootJars(ctx) {
 		return
@@ -215,3 +218,24 @@
 func (b *platformBootclasspathModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
 	return defaultBootImageConfig(ctx)
 }
+
+// generateHiddenAPIBuildActions generates all the hidden API related build rules.
+func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module) {
+
+	moduleSpecificFlagsPaths := android.Paths{}
+	for _, module := range modules {
+		if h, ok := module.(hiddenAPIIntf); ok {
+			if csv := h.flagsCSV(); csv != nil {
+				moduleSpecificFlagsPaths = append(moduleSpecificFlagsPaths, csv)
+			}
+		} else {
+			ctx.ModuleErrorf("module %s of type %s does not implement hiddenAPIIntf", module, ctx.OtherModuleType(module))
+		}
+	}
+
+	augmentationInfo := b.properties.Hidden_api.hiddenAPIAugmentationInfo(ctx)
+
+	outputPath := hiddenAPISingletonPaths(ctx).flags
+	baseFlagsPath := hiddenAPISingletonPaths(ctx).stubFlags
+	ruleToGenerateHiddenApiFlags(ctx, outputPath, baseFlagsPath, moduleSpecificFlagsPaths, augmentationInfo)
+}
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index b2f7b2b..5271f8d 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -295,6 +295,118 @@
   grep -q "Make it so" out/soong/build.ninja || fail "New action not present"
 }
 
+# Tests a glob in a build= statement in an Android.bp file, which is interpreted
+# during bootstrapping.
+function test_glob_during_bootstrapping() {
+  setup
+
+  mkdir -p a
+  cat > a/Android.bp <<'EOF'
+build=["foo*.bp"]
+EOF
+  cat > a/fooa.bp <<'EOF'
+bootstrap_go_package {
+  name: "picard-soong-rules",
+  pkgPath: "android/soong/picard",
+  deps: [
+    "blueprint",
+    "soong",
+    "soong-android",
+  ],
+  srcs: [
+    "picard.go",
+  ],
+  pluginFor: ["soong_build"],
+}
+EOF
+
+  cat > a/picard.go <<'EOF'
+package picard
+
+import (
+  "android/soong/android"
+  "github.com/google/blueprint"
+)
+
+var (
+  pctx = android.NewPackageContext("picard")
+)
+
+func init() {
+  android.RegisterSingletonType("picard", PicardSingleton)
+}
+
+func PicardSingleton() android.Singleton {
+  return &picardSingleton{}
+}
+
+type picardSingleton struct{}
+
+var Message = "Make it so."
+
+func (p *picardSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+  picardRule := ctx.Rule(pctx, "picard",
+    blueprint.RuleParams{
+      Command: "echo " + Message + " > ${out}",
+      CommandDeps: []string{},
+      Description: "Something quotable",
+    })
+
+  outputFile := android.PathForOutput(ctx, "picard", "picard.txt")
+  var deps android.Paths
+
+  ctx.Build(pctx, android.BuildParams{
+    Rule: picardRule,
+    Output: outputFile,
+    Inputs: deps,
+  })
+}
+
+EOF
+
+  run_soong
+  local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+  grep -q "Make it so" out/soong/build.ninja || fail "Original action not present"
+
+  cat > a/foob.bp <<'EOF'
+bootstrap_go_package {
+  name: "worf-soong-rules",
+  pkgPath: "android/soong/worf",
+  deps: [
+    "blueprint",
+    "soong",
+    "soong-android",
+    "picard-soong-rules",
+  ],
+  srcs: [
+    "worf.go",
+  ],
+  pluginFor: ["soong_build"],
+}
+EOF
+
+  cat > a/worf.go <<'EOF'
+package worf
+
+import "android/soong/picard"
+
+func init() {
+   picard.Message = "Engage."
+}
+EOF
+
+  run_soong
+  local mtime2=$(stat -c "%y" out/soong/build.ninja)
+  if [[ "$mtime1" == "$mtime2" ]]; then
+    fail "Output Ninja file did not change"
+  fi
+
+  grep -q "Engage" out/soong/build.ninja || fail "New action not present"
+
+  grep -q "Make it so" out/soong/build.ninja && fail "Original action still present"
+}
+
 function test_null_build_after_docs {
   setup
   run_soong
@@ -326,5 +438,6 @@
 test_change_android_bp
 test_delete_android_bp
 test_add_file_to_soong_build
+test_glob_during_bootstrapping
 test_soong_build_rerun_iff_environment_changes
 test_dump_json_module_graph