Merge "Disallow using error-prone merge strategies"
diff --git a/android/config.go b/android/config.go
index 9162eaa..c6885dd 100644
--- a/android/config.go
+++ b/android/config.go
@@ -128,7 +128,7 @@
 
 	// If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error
 	// in tests when a path doesn't exist.
-	testAllowNonExistentPaths bool
+	TestAllowNonExistentPaths bool
 
 	// The list of files that when changed, must invalidate soong_build to
 	// regenerate build.ninja.
@@ -256,7 +256,7 @@
 
 		// Set testAllowNonExistentPaths so that test contexts don't need to specify every path
 		// passed to PathForSource or PathForModuleSrc.
-		testAllowNonExistentPaths: true,
+		TestAllowNonExistentPaths: true,
 
 		BazelContext: noopBazelContext{},
 	}
diff --git a/android/paths.go b/android/paths.go
index 58e1f74..ada4da6 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -586,7 +586,7 @@
 		p := pathForModuleSrc(ctx, sPath)
 		if exists, _, err := ctx.Config().fs.Exists(p.String()); err != nil {
 			ReportPathErrorf(ctx, "%s: %s", p, err.Error())
-		} else if !exists && !ctx.Config().testAllowNonExistentPaths {
+		} else if !exists && !ctx.Config().TestAllowNonExistentPaths {
 			ReportPathErrorf(ctx, "module source path %q does not exist", p)
 		}
 
@@ -1022,7 +1022,7 @@
 		}
 	} else if exists, _, err := ctx.Config().fs.Exists(path.String()); err != nil {
 		ReportPathErrorf(ctx, "%s: %s", path, err.Error())
-	} else if !exists && !ctx.Config().testAllowNonExistentPaths {
+	} else if !exists && !ctx.Config().TestAllowNonExistentPaths {
 		ReportPathErrorf(ctx, "source path %q does not exist", path)
 	}
 	return path
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index add0e1e..4e7039c 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -176,6 +176,8 @@
 ExtServices-core(minSdkVersion:current)
 flatbuffer_headers(minSdkVersion:(no version))
 fmtlib(minSdkVersion:29)
+fmtlib_ndk(minSdkVersion:29)
+framework-mediaprovider(minSdkVersion:30)
 framework-permission(minSdkVersion:30)
 framework-permission(minSdkVersion:current)
 framework-permission-s(minSdkVersion:30)
@@ -240,6 +242,7 @@
 libbacktrace_sys.rust_sysroot(minSdkVersion:29)
 libbase(minSdkVersion:29)
 libbase_headers(minSdkVersion:29)
+libbase_ndk(minSdkVersion:29)
 libbinder_headers(minSdkVersion:29)
 libbinder_headers_platform_shared(minSdkVersion:29)
 libbinderthreadstateutils(minSdkVersion:29)
@@ -315,6 +318,8 @@
 libfmq(minSdkVersion:29)
 libfmq-base(minSdkVersion:29)
 libFraunhoferAAC(minSdkVersion:29)
+libfuse(minSdkVersion:30)
+libfuse_jni(minSdkVersion:30)
 libgav1(minSdkVersion:29)
 libgcc(minSdkVersion:(no version))
 libgcc_stripped(minSdkVersion:(no version))
@@ -468,6 +473,7 @@
 libzstd(minSdkVersion:(no version))
 media_ndk_headers(minSdkVersion:29)
 media_plugin_headers(minSdkVersion:29)
+MediaProvider(minSdkVersion:30)
 mediaswcodec(minSdkVersion:29)
 metrics-constants-protos(minSdkVersion:29)
 modules-utils-build(minSdkVersion:29)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 181946b..bbc4b93 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -2039,7 +2039,7 @@
 		},
 		{
 			name:          "Updatable apex with non-stable transitive dep",
-			expectedError: "compiles against Android API, but dependency \"transitive-jar\" is compiling against non-public Android API.",
+			expectedError: "compiles against Android API, but dependency \"transitive-jar\" is compiling against private API.",
 			bp: `
 				apex {
 					name: "myapex",
diff --git a/bloaty/Android.bp b/bloaty/Android.bp
new file mode 100644
index 0000000..b1f1e39
--- /dev/null
+++ b/bloaty/Android.bp
@@ -0,0 +1,40 @@
+bootstrap_go_package {
+    name: "soong-bloaty",
+    pkgPath: "android/soong/bloaty",
+    deps: [
+        "blueprint",
+        "soong-android",
+    ],
+    srcs: [
+        "bloaty.go",
+    ],
+    pluginFor: ["soong_build"],
+}
+
+python_test_host {
+    name: "bloaty_merger_test",
+    srcs: [
+        "bloaty_merger_test.py",
+        "bloaty_merger.py",
+        "file_sections.proto",
+    ],
+    proto: {
+        canonical_path_from_root: false,
+    },
+    libs: [
+        "pyfakefs",
+        "ninja_rsp",
+    ],
+}
+
+python_binary_host {
+    name: "bloaty_merger",
+    srcs: [
+        "bloaty_merger.py",
+        "file_sections.proto",
+    ],
+    proto: {
+        canonical_path_from_root: false,
+    },
+    libs: ["ninja_rsp"],
+}
diff --git a/bloaty/bloaty.go b/bloaty/bloaty.go
new file mode 100644
index 0000000..0bff8aa
--- /dev/null
+++ b/bloaty/bloaty.go
@@ -0,0 +1,92 @@
+// 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 bloaty implements a singleton that measures binary (e.g. ELF
+// executable, shared library or Rust rlib) section sizes at build time.
+package bloaty
+
+import (
+	"android/soong/android"
+
+	"github.com/google/blueprint"
+)
+
+const bloatyDescriptorExt = "bloaty.csv"
+
+var (
+	fileSizeMeasurerKey blueprint.ProviderKey
+	pctx                = android.NewPackageContext("android/soong/bloaty")
+
+	// bloaty is used to measure a binary section sizes.
+	bloaty = pctx.AndroidStaticRule("bloaty",
+		blueprint.RuleParams{
+			Command:     "${bloaty} -n 0 --csv ${in} > ${out}",
+			CommandDeps: []string{"${bloaty}"},
+		})
+
+	// The bloaty merger script is used to combine the outputs from bloaty
+	// into a single protobuf.
+	bloatyMerger = pctx.AndroidStaticRule("bloatyMerger",
+		blueprint.RuleParams{
+			Command:        "${bloatyMerger} ${out}.lst ${out}",
+			CommandDeps:    []string{"${bloatyMerger}"},
+			Rspfile:        "${out}.lst",
+			RspfileContent: "${in}",
+		})
+)
+
+func init() {
+	pctx.VariableConfigMethod("hostPrebuiltTag", android.Config.PrebuiltOS)
+	pctx.SourcePathVariable("bloaty", "prebuilts/build-tools/${hostPrebuiltTag}/bin/bloaty")
+	pctx.HostBinToolVariable("bloatyMerger", "bloaty_merger")
+	android.RegisterSingletonType("file_metrics", fileSizesSingleton)
+	fileSizeMeasurerKey = blueprint.NewProvider(android.ModuleOutPath{})
+}
+
+// MeasureSizeForPath should be called by binary producers (e.g. in builder.go).
+func MeasureSizeForPath(ctx android.ModuleContext, filePath android.WritablePath) {
+	ctx.SetProvider(fileSizeMeasurerKey, filePath)
+}
+
+type sizesSingleton struct{}
+
+func fileSizesSingleton() android.Singleton {
+	return &sizesSingleton{}
+}
+
+func (singleton *sizesSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	var deps android.Paths
+	// Visit all modules. If the size provider give us a binary path to measure,
+	// create the rule to measure it.
+	ctx.VisitAllModules(func(m android.Module) {
+		if !ctx.ModuleHasProvider(m, fileSizeMeasurerKey) {
+			return
+		}
+		filePath := ctx.ModuleProvider(m, fileSizeMeasurerKey).(android.ModuleOutPath)
+		sizeFile := filePath.ReplaceExtension(ctx, bloatyDescriptorExt)
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        bloaty,
+			Description: "bloaty " + filePath.Rel(),
+			Input:       filePath,
+			Output:      sizeFile,
+		})
+		deps = append(deps, sizeFile)
+	})
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   bloatyMerger,
+		Inputs: android.SortedUniquePaths(deps),
+		Output: android.PathForOutput(ctx, "binary_sizes.pb"),
+	})
+}
diff --git a/bloaty/bloaty_merger.py b/bloaty/bloaty_merger.py
new file mode 100644
index 0000000..c873fb8
--- /dev/null
+++ b/bloaty/bloaty_merger.py
@@ -0,0 +1,79 @@
+# 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.
+"""Bloaty CSV Merger
+
+Merges a list of .csv files from Bloaty into a protobuf.  It takes the list as
+a first argument and the output as second. For instance:
+
+    $ bloaty_merger binary_sizes.lst binary_sizes.pb
+
+"""
+
+import argparse
+import csv
+
+import ninja_rsp
+
+import file_sections_pb2
+
+BLOATY_EXTENSION = ".bloaty.csv"
+
+def parse_csv(path):
+  """Parses a Bloaty-generated CSV file into a protobuf.
+
+  Args:
+    path: The filepath to the CSV file, relative to $ANDROID_TOP.
+
+  Returns:
+    A file_sections_pb2.File if the file was found; None otherwise.
+  """
+  file_proto = None
+  with open(path, newline='') as csv_file:
+    file_proto = file_sections_pb2.File()
+    if path.endswith(BLOATY_EXTENSION):
+      file_proto.path = path[:-len(BLOATY_EXTENSION)]
+    section_reader = csv.DictReader(csv_file)
+    for row in section_reader:
+      section = file_proto.sections.add()
+      section.name = row["sections"]
+      section.vm_size = int(row["vmsize"])
+      section.file_size = int(row["filesize"])
+  return file_proto
+
+def create_file_size_metrics(input_list, output_proto):
+  """Creates a FileSizeMetrics proto from a list of CSV files.
+
+  Args:
+    input_list: The path to the file which contains the list of CSV files. Each
+        filepath is separated by a space.
+    output_proto: The path for the output protobuf.
+  """
+  metrics = file_sections_pb2.FileSizeMetrics()
+  reader = ninja_rsp.NinjaRspFileReader(input_list)
+  for csv_path in reader:
+    file_proto = parse_csv(csv_path)
+    if file_proto:
+      metrics.files.append(file_proto)
+  with open(output_proto, "wb") as output:
+    output.write(metrics.SerializeToString())
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument("input_list_file", help="List of bloaty csv files.")
+  parser.add_argument("output_proto", help="Output proto.")
+  args = parser.parse_args()
+  create_file_size_metrics(args.input_list_file, args.output_proto)
+
+if __name__ == '__main__':
+  main()
diff --git a/bloaty/bloaty_merger_test.py b/bloaty/bloaty_merger_test.py
new file mode 100644
index 0000000..0e3641d
--- /dev/null
+++ b/bloaty/bloaty_merger_test.py
@@ -0,0 +1,65 @@
+# 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.
+import unittest
+
+from pyfakefs import fake_filesystem_unittest
+
+import bloaty_merger
+import file_sections_pb2
+
+
+class BloatyMergerTestCase(fake_filesystem_unittest.TestCase):
+  def setUp(self):
+    self.setUpPyfakefs()
+
+  def test_parse_csv(self):
+    csv_content = "sections,vmsize,filesize\nsection1,2,3\n"
+    self.fs.create_file("file1.bloaty.csv", contents=csv_content)
+    pb = bloaty_merger.parse_csv("file1.bloaty.csv")
+    self.assertEqual(pb.path, "file1")
+    self.assertEqual(len(pb.sections), 1)
+    s = pb.sections[0]
+    self.assertEqual(s.name, "section1")
+    self.assertEqual(s.vm_size, 2)
+    self.assertEqual(s.file_size, 3)
+
+  def test_missing_file(self):
+    with self.assertRaises(FileNotFoundError):
+      bloaty_merger.parse_csv("missing.bloaty.csv")
+
+  def test_malformed_csv(self):
+    csv_content = "header1,heaVder2,header3\n4,5,6\n"
+    self.fs.create_file("file1.bloaty.csv", contents=csv_content)
+    with self.assertRaises(KeyError):
+      bloaty_merger.parse_csv("file1.bloaty.csv")
+
+  def test_create_file_metrics(self):
+    file_list = "file1.bloaty.csv file2.bloaty.csv"
+    file1_content = "sections,vmsize,filesize\nsection1,2,3\nsection2,7,8"
+    file2_content = "sections,vmsize,filesize\nsection1,4,5\n"
+
+    self.fs.create_file("files.lst", contents=file_list)
+    self.fs.create_file("file1.bloaty.csv", contents=file1_content)
+    self.fs.create_file("file2.bloaty.csv", contents=file2_content)
+
+    bloaty_merger.create_file_size_metrics("files.lst", "output.pb")
+
+    metrics = file_sections_pb2.FileSizeMetrics()
+    with open("output.pb", "rb") as output:
+      metrics.ParseFromString(output.read())
+
+
+if __name__ == '__main__':
+  suite = unittest.TestLoader().loadTestsFromTestCase(BloatyMergerTestCase)
+  unittest.TextTestRunner(verbosity=2).run(suite)
diff --git a/bloaty/file_sections.proto b/bloaty/file_sections.proto
new file mode 100644
index 0000000..34a32db
--- /dev/null
+++ b/bloaty/file_sections.proto
@@ -0,0 +1,39 @@
+// 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.
+syntax = "proto2";
+
+package file_sections;
+
+message SectionDescriptior {
+  // Name of the section (e.g. .rodata)
+  optional string name = 1;
+
+  // Size of that section as part of the file.
+  optional uint64 file_size = 2;
+
+  // Size of that section when loaded in memory.
+  optional uint64 vm_size = 3;
+}
+
+message File {
+  // Relative path from $OUT_DIR.
+  optional string path = 1;
+
+  // File sections.
+  repeated SectionDescriptior sections = 2;
+}
+
+message FileSizeMetrics {
+  repeated File files = 1;
+}
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index ddde1b7..521bb06 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -22,7 +22,8 @@
     testSrcs: [
         "build_conversion_test.go",
         "bzl_conversion_test.go",
-        "cc_conversion_test.go",
+        "cc_library_headers_conversion_test.go",
+        "cc_object_conversion_test.go",
         "conversion_test.go",
         "sh_conversion_test.go",
         "testing.go",
diff --git a/bp2build/cc_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
similarity index 100%
rename from bp2build/cc_conversion_test.go
rename to bp2build/cc_library_headers_conversion_test.go
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
new file mode 100644
index 0000000..e4ffe16
--- /dev/null
+++ b/bp2build/cc_object_conversion_test.go
@@ -0,0 +1,186 @@
+// 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"
+	"fmt"
+	"strings"
+	"testing"
+)
+
+func TestCcObjectBp2Build(t *testing.T) {
+	testCases := []struct {
+		description                        string
+		moduleTypeUnderTest                string
+		moduleTypeUnderTestFactory         android.ModuleFactory
+		moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
+		blueprint                          string
+		expectedBazelTargets               []string
+		filesystem                         map[string]string
+	}{
+		{
+			description:                        "simple cc_object generates cc_object with include header dep",
+			moduleTypeUnderTest:                "cc_object",
+			moduleTypeUnderTestFactory:         cc.ObjectFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+			filesystem: map[string]string{
+				"a/b/foo.h": "",
+				"a/b/bar.h": "",
+				"a/b/c.c":   "",
+			},
+			blueprint: `cc_object {
+    name: "foo",
+    local_include_dirs: ["include"],
+    cflags: [
+        "-Wno-gcc-compat",
+        "-Wall",
+        "-Werror",
+    ],
+    srcs: [
+        "a/b/*.h",
+        "a/b/c.c"
+    ],
+
+    bazel_module: { bp2build_available: true },
+}
+`,
+			expectedBazelTargets: []string{`cc_object(
+    name = "foo",
+    copts = [
+        "-fno-addrsig",
+        "-Wno-gcc-compat",
+        "-Wall",
+        "-Werror",
+    ],
+    local_include_dirs = [
+        "include",
+    ],
+    srcs = [
+        "a/b/bar.h",
+        "a/b/foo.h",
+        "a/b/c.c",
+    ],
+)`,
+			},
+		},
+		{
+			description:                        "simple cc_object with defaults",
+			moduleTypeUnderTest:                "cc_object",
+			moduleTypeUnderTestFactory:         cc.ObjectFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+			blueprint: `cc_object {
+    name: "foo",
+    local_include_dirs: ["include"],
+    srcs: [
+        "a/b/*.h",
+        "a/b/c.c"
+    ],
+
+    defaults: ["foo_defaults"],
+    bazel_module: { bp2build_available: true },
+}
+
+cc_defaults {
+    name: "foo_defaults",
+    defaults: ["foo_bar_defaults"],
+	// TODO(b/178130668): handle configurable attributes that depend on the platform
+    arch: {
+        x86: {
+            cflags: ["-fPIC"],
+        },
+        x86_64: {
+            cflags: ["-fPIC"],
+        },
+    },
+}
+
+cc_defaults {
+    name: "foo_bar_defaults",
+    cflags: [
+        "-Wno-gcc-compat",
+        "-Wall",
+        "-Werror",
+    ],
+}
+`,
+			expectedBazelTargets: []string{`cc_object(
+    name = "foo",
+    copts = [
+        "-Wno-gcc-compat",
+        "-Wall",
+        "-Werror",
+        "-fno-addrsig",
+    ],
+    local_include_dirs = [
+        "include",
+    ],
+    srcs = [
+        "a/b/c.c",
+    ],
+)`,
+			},
+		},
+	}
+
+	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.blueprint, filesystem)
+		ctx := android.NewTestContext(config)
+		// Always register cc_defaults module factory
+		ctx.RegisterModuleType("cc_defaults", func() android.Module { return cc.DefaultsFactory() })
+
+		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+		ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
+		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
+		}
+
+		bazelTargets := GenerateBazelTargets(ctx.Context.Context, Bp2Build)[dir]
+		if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
+			fmt.Println(bazelTargets)
+			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/cc/cc.go b/cc/cc.go
index 7f59158..6c1469f 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -28,6 +28,7 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/bazel"
 	"android/soong/cc/config"
 	"android/soong/genrule"
 )
@@ -364,6 +365,8 @@
 	// can depend on libraries that are not exported by the APEXes and use private symbols
 	// from the exported libraries.
 	Test_for []string
+
+	bazel.Properties
 }
 
 type VendorProperties struct {
diff --git a/cc/library.go b/cc/library.go
index bdcb8ae..65533bc 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -27,7 +27,6 @@
 	"github.com/google/blueprint/pathtools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/cc/config"
 )
 
@@ -121,9 +120,6 @@
 	// If this is an LLNDK library, properties to describe the LLNDK stubs.  Will be copied from
 	// the module pointed to by llndk_stubs if it is set.
 	Llndk llndkLibraryProperties
-
-	// Properties for Bazel migration purposes.
-	bazel.Properties
 }
 
 // StaticProperties is a properties stanza to affect only attributes of the "static" variants of a
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 448e144..e5a5557 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -86,6 +86,10 @@
 		return
 	}
 
+	if !module.Properties.Bazel_module.Bp2build_available {
+		return
+	}
+
 	lib, ok := module.linker.(*libraryDecorator)
 	if !ok {
 		// Not a cc_library module
@@ -96,10 +100,6 @@
 		return
 	}
 
-	if !lib.Properties.Bazel_module.Bp2build_available {
-		return
-	}
-
 	// list of directories that will be added to the include path (using -I) for this
 	// module and any module that links against this module.
 	includeDirs := lib.flagExporter.Properties.Export_system_include_dirs
diff --git a/cc/object.go b/cc/object.go
index 3ce7676..d92e110 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -18,6 +18,7 @@
 	"fmt"
 
 	"android/soong/android"
+	"android/soong/bazel"
 )
 
 //
@@ -27,6 +28,8 @@
 func init() {
 	android.RegisterModuleType("cc_object", ObjectFactory)
 	android.RegisterSdkMemberType(ccObjectSdkMemberType)
+
+	android.RegisterBp2BuildMutator("cc_object", ObjectBp2Build)
 }
 
 var ccObjectSdkMemberType = &librarySdkMemberType{
@@ -82,9 +85,80 @@
 	module.compiler.appendCflags([]string{"-fno-addrsig"})
 
 	module.sdkMemberTypes = []android.SdkMemberType{ccObjectSdkMemberType}
+
 	return module.Init()
 }
 
+// For bp2build conversion.
+type bazelObjectAttributes struct {
+	Srcs               bazel.LabelList
+	Copts              []string
+	Local_include_dirs []string
+}
+
+type bazelObject struct {
+	android.BazelTargetModuleBase
+	bazelObjectAttributes
+}
+
+func (m *bazelObject) Name() string {
+	return m.BaseModuleName()
+}
+
+func (m *bazelObject) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
+
+func BazelObjectFactory() android.Module {
+	module := &bazelObject{}
+	module.AddProperties(&module.bazelObjectAttributes)
+	android.InitBazelTargetModule(module)
+	return module
+}
+
+// ObjectBp2Build is the bp2build converter from cc_object modules to the
+// Bazel equivalent target, plus any necessary include deps for the cc_object.
+func ObjectBp2Build(ctx android.TopDownMutatorContext) {
+	m, ok := ctx.Module().(*Module)
+	if !ok || !m.Properties.Bazel_module.Bp2build_available {
+		return
+	}
+
+	// a Module can be something other than a cc_object.
+	if ctx.ModuleType() != "cc_object" {
+		return
+	}
+
+	if m.compiler == nil {
+		// a cc_object must have access to the compiler decorator for its props.
+		ctx.ModuleErrorf("compiler must not be nil for a cc_object module")
+	}
+
+	var copts []string
+	var srcs []string
+	var localIncludeDirs []string
+	for _, props := range m.compiler.compilerProps() {
+		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
+			copts = baseCompilerProps.Cflags
+			srcs = baseCompilerProps.Srcs
+			localIncludeDirs = baseCompilerProps.Local_include_dirs
+			break
+		}
+	}
+
+	attrs := &bazelObjectAttributes{
+		Srcs:               android.BazelLabelForModuleSrc(ctx, srcs),
+		Copts:              copts,
+		Local_include_dirs: localIncludeDirs,
+	}
+
+	props := bazel.NewBazelTargetModuleProperties(
+		m.Name(),
+		"cc_object",
+		"//build/bazel/rules:cc_object.bzl",
+	)
+
+	ctx.CreateBazelTargetModule(BazelObjectFactory, props, attrs)
+}
+
 func (object *objectLinker) appendLdflags(flags []string) {
 	panic(fmt.Errorf("appendLdflags on objectLinker not supported"))
 }
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 57563eb..e15324b 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -282,11 +282,14 @@
 		Input:  p.sourceFilePath,
 	})
 
-	if p.Installable() {
-		installPath := ctx.InstallFile(p.installDirPath, p.outputFilePath.Base(), p.outputFilePath)
-		for _, sl := range p.properties.Symlinks {
-			ctx.InstallSymlink(p.installDirPath, sl, installPath)
-		}
+	if !p.Installable() {
+		p.SkipInstall()
+	}
+
+	// Call InstallFile even when uninstallable to make the module included in the package
+	installPath := ctx.InstallFile(p.installDirPath, p.outputFilePath.Base(), p.outputFilePath)
+	for _, sl := range p.properties.Symlinks {
+		ctx.InstallSymlink(p.installDirPath, sl, installPath)
 	}
 }
 
diff --git a/java/java.go b/java/java.go
index 69ec2a4..dbfad02 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1014,6 +1014,7 @@
 const (
 	// TODO(jiyong) rename these for better readability. Make the allowed
 	// and disallowed link types explicit
+	// order is important here. See rank()
 	javaCore linkType = iota
 	javaSdk
 	javaSystem
@@ -1022,6 +1023,31 @@
 	javaPlatform
 )
 
+func (lt linkType) String() string {
+	switch lt {
+	case javaCore:
+		return "core Java API"
+	case javaSdk:
+		return "Android API"
+	case javaSystem:
+		return "system API"
+	case javaModule:
+		return "module API"
+	case javaSystemServer:
+		return "system server API"
+	case javaPlatform:
+		return "private API"
+	default:
+		panic(fmt.Errorf("unrecognized linktype: %v", lt))
+	}
+}
+
+// rank determins the total order among linkTypes. A link type of rank A can link to another link
+// type of rank B only when B <= A
+func (lt linkType) rank() int {
+	return int(lt)
+}
+
 type linkTypeContext interface {
 	android.Module
 	getLinkType(name string) (ret linkType, stubs bool)
@@ -1081,44 +1107,13 @@
 		return
 	}
 	otherLinkType, _ := to.getLinkType(ctx.OtherModuleName(to))
-	commonMessage := " In order to fix this, consider adjusting sdk_version: OR platform_apis: " +
-		"property of the source or target module so that target module is built with the same " +
-		"or smaller API set when compared to the source."
 
-	switch myLinkType {
-	case javaCore:
-		if otherLinkType != javaCore {
-			ctx.ModuleErrorf("compiles against core Java API, but dependency %q is compiling against non-core Java APIs."+commonMessage,
-				ctx.OtherModuleName(to))
-		}
-		break
-	case javaSdk:
-		if otherLinkType != javaCore && otherLinkType != javaSdk {
-			ctx.ModuleErrorf("compiles against Android API, but dependency %q is compiling against non-public Android API."+commonMessage,
-				ctx.OtherModuleName(to))
-		}
-		break
-	case javaSystem:
-		if otherLinkType == javaPlatform || otherLinkType == javaModule || otherLinkType == javaSystemServer {
-			ctx.ModuleErrorf("compiles against system API, but dependency %q is compiling against private API."+commonMessage,
-				ctx.OtherModuleName(to))
-		}
-		break
-	case javaModule:
-		if otherLinkType == javaPlatform || otherLinkType == javaSystemServer {
-			ctx.ModuleErrorf("compiles against module API, but dependency %q is compiling against private API."+commonMessage,
-				ctx.OtherModuleName(to))
-		}
-		break
-	case javaSystemServer:
-		if otherLinkType == javaPlatform {
-			ctx.ModuleErrorf("compiles against system server API, but dependency %q is compiling against private API."+commonMessage,
-				ctx.OtherModuleName(to))
-		}
-		break
-	case javaPlatform:
-		// no restriction on link-type
-		break
+	if myLinkType.rank() < otherLinkType.rank() {
+		ctx.ModuleErrorf("compiles against %v, but dependency %q is compiling against %v. "+
+			"In order to fix this, consider adjusting sdk_version: OR platform_apis: "+
+			"property of the source or target module so that target module is built "+
+			"with the same or smaller API set when compared to the source.",
+			myLinkType, ctx.OtherModuleName(to), otherLinkType)
 	}
 }
 
diff --git a/java/java_test.go b/java/java_test.go
index e7776c3..0ef4db6 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -127,7 +127,6 @@
 	}
 
 	t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
-
 	return ctx, config
 }
 
@@ -1179,6 +1178,110 @@
 	}
 }
 
+func TestJavaLint(t *testing.T) {
+	ctx, _ := testJavaWithFS(t, `
+		java_library {
+			name: "foo",
+			srcs: [
+				"a.java",
+				"b.java",
+				"c.java",
+			],
+			min_sdk_version: "29",
+			sdk_version: "system_current",
+		}
+       `, map[string][]byte{
+		"lint-baseline.xml": nil,
+	})
+
+	foo := ctx.ModuleForTests("foo", "android_common")
+	rule := foo.Rule("lint")
+
+	if !strings.Contains(rule.RuleParams.Command, "--baseline lint-baseline.xml") {
+		t.Error("did not pass --baseline flag")
+	}
+}
+
+func TestJavaLintWithoutBaseline(t *testing.T) {
+	ctx, _ := testJavaWithFS(t, `
+		java_library {
+			name: "foo",
+			srcs: [
+				"a.java",
+				"b.java",
+				"c.java",
+			],
+			min_sdk_version: "29",
+			sdk_version: "system_current",
+		}
+       `, map[string][]byte{})
+
+	foo := ctx.ModuleForTests("foo", "android_common")
+	rule := foo.Rule("lint")
+
+	if strings.Contains(rule.RuleParams.Command, "--baseline") {
+		t.Error("passed --baseline flag for non existent file")
+	}
+}
+
+func TestJavaLintRequiresCustomLintFileToExist(t *testing.T) {
+	config := testConfig(
+		nil,
+		`
+		java_library {
+			name: "foo",
+			srcs: [
+			],
+			min_sdk_version: "29",
+			sdk_version: "system_current",
+			lint: {
+				baseline_filename: "mybaseline.xml",
+			},
+		}
+     `, map[string][]byte{
+			"build/soong/java/lint_defaults.txt":                   nil,
+			"prebuilts/cmdline-tools/tools/bin/lint":               nil,
+			"prebuilts/cmdline-tools/tools/lib/lint-classpath.jar": nil,
+			"framework/aidl":                     nil,
+			"a.java":                             nil,
+			"AndroidManifest.xml":                nil,
+			"build/make/target/product/security": nil,
+		})
+	config.TestAllowNonExistentPaths = false
+	testJavaErrorWithConfig(t,
+		"source path \"mybaseline.xml\" does not exist",
+		config,
+	)
+}
+
+func TestJavaLintUsesCorrectBpConfig(t *testing.T) {
+	ctx, _ := testJavaWithFS(t, `
+		java_library {
+			name: "foo",
+			srcs: [
+				"a.java",
+				"b.java",
+				"c.java",
+			],
+			min_sdk_version: "29",
+			sdk_version: "system_current",
+			lint: {
+				error_checks: ["SomeCheck"],
+				baseline_filename: "mybaseline.xml",
+			},
+		}
+       `, map[string][]byte{
+		"mybaseline.xml": nil,
+	})
+
+	foo := ctx.ModuleForTests("foo", "android_common")
+	rule := foo.Rule("lint")
+
+	if !strings.Contains(rule.RuleParams.Command, "--baseline mybaseline.xml") {
+		t.Error("did not use the correct file for baseline")
+	}
+}
+
 func TestGeneratedSources(t *testing.T) {
 	ctx, _ := testJavaWithFS(t, `
 		java_library {
diff --git a/java/lint.go b/java/lint.go
index c9e0cdd..8272595 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -19,6 +19,8 @@
 	"sort"
 	"strings"
 
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
 )
 
@@ -46,6 +48,9 @@
 
 		// Modules that provide extra lint checks
 		Extra_check_modules []string
+
+		// Name of the file that lint uses as the baseline. Defaults to "lint-baseline.xml".
+		Baseline_filename *string
 	}
 }
 
@@ -344,6 +349,19 @@
 		cmd.FlagWithArg("--check ", checkOnly)
 	}
 
+	if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
+		var lintBaseline android.OptionalPath
+		if String(l.properties.Lint.Baseline_filename) != "" {
+			// if manually specified, we require the file to exist
+			lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
+		} else {
+			lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
+		}
+		if lintBaseline.Valid() {
+			cmd.FlagWithInput("--baseline ", lintBaseline.Path())
+		}
+	}
+
 	cmd.Text("|| (").Text("cat").Input(text).Text("; exit 7)").Text(")")
 
 	rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String())
diff --git a/rust/Android.bp b/rust/Android.bp
index 8b2aa30..a29c474 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -8,6 +8,7 @@
     deps: [
         "soong",
         "soong-android",
+        "soong-bloaty",
         "soong-cc",
         "soong-rust-config",
     ],
diff --git a/rust/builder.go b/rust/builder.go
index 56fe031..547d705 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -21,6 +21,7 @@
 	"github.com/google/blueprint"
 
 	"android/soong/android"
+	"android/soong/bloaty"
 	"android/soong/rust/config"
 )
 
@@ -249,6 +250,8 @@
 		implicits = append(implicits, clippyFile)
 	}
 
+	bloaty.MeasureSizeForPath(ctx, outputFile)
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:            rustc,
 		Description:     "rustc " + main.Rel(),
diff --git a/scripts/Android.bp b/scripts/Android.bp
index b9163cc..310c959 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -209,13 +209,18 @@
     test_suites: ["general-tests"],
 }
 
+python_library_host {
+    name: "ninja_rsp",
+    srcs: ["ninja_rsp.py"],
+}
+
 python_binary_host {
     name: "lint-project-xml",
     main: "lint-project-xml.py",
     srcs: [
         "lint-project-xml.py",
-        "ninja_rsp.py",
     ],
+    libs: ["ninja_rsp"],
 }
 
 python_binary_host {
@@ -223,8 +228,8 @@
     main: "gen-kotlin-build-file.py",
     srcs: [
         "gen-kotlin-build-file.py",
-        "ninja_rsp.py",
     ],
+    libs: ["ninja_rsp"],
 }
 
 python_binary_host {
diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh
index ac67438..b93c883 100755
--- a/scripts/build-mainline-modules.sh
+++ b/scripts/build-mainline-modules.sh
@@ -8,6 +8,7 @@
   com.android.art.testing
   com.android.conscrypt
   com.android.i18n
+  com.android.os.statsd
   com.android.runtime
   com.android.tzdata
 )