Merge "Add unconverted reason for jarjar incompatibility." into main
diff --git a/android/filegroup.go b/android/filegroup.go
index 3b86655..6cc9232 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -24,6 +24,7 @@
 	"android/soong/ui/metrics/bp2build_metrics_proto"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 )
 
 func init() {
@@ -141,8 +142,14 @@
 			attrs)
 	} else {
 		if fg.ShouldConvertToProtoLibrary(ctx) {
+			pkgToSrcs := partitionSrcsByPackage(ctx.ModuleDir(), bazel.MakeLabelList(srcs.Value.Includes))
+			if len(pkgToSrcs) > 1 {
+				ctx.ModuleErrorf("TODO: Add bp2build support for multiple package .protosrcs in filegroup")
+				return
+			}
+			pkg := SortedKeys(pkgToSrcs)[0]
 			attrs := &ProtoAttrs{
-				Srcs:                srcs,
+				Srcs:                bazel.MakeLabelListAttribute(pkgToSrcs[pkg]),
 				Strip_import_prefix: fg.properties.Path,
 			}
 
@@ -151,13 +158,39 @@
 				// TODO(b/246997908): we can remove this tag if we could figure out a solution for this bug.
 				"manual",
 			}
+			if pkg != ctx.ModuleDir() {
+				// Since we are creating the proto_library in a subpackage, create an import_prefix relative to the current package
+				if rel, err := filepath.Rel(ctx.ModuleDir(), pkg); err != nil {
+					ctx.ModuleErrorf("Could not get relative path for %v %v", pkg, err)
+				} else if rel != "." {
+					attrs.Import_prefix = &rel
+					// Strip the package prefix
+					attrs.Strip_import_prefix = proptools.StringPtr("")
+				}
+			}
+
 			ctx.CreateBazelTargetModule(
 				bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
 				CommonAttributes{
-					Name: fg.Name() + convertedProtoLibrarySuffix,
+					Name: fg.Name() + "_proto",
+					Dir:  proptools.StringPtr(pkg),
 					Tags: bazel.MakeStringListAttribute(tags),
 				},
 				attrs)
+
+			// Create an alias in the current dir. The actual target might exist in a different package, but rdeps
+			// can reliabily use this alias
+			ctx.CreateBazelTargetModule(
+				bazel.BazelTargetModuleProperties{Rule_class: "alias"},
+				CommonAttributes{
+					Name: fg.Name() + convertedProtoLibrarySuffix,
+					// TODO(b/246997908): we can remove this tag if we could figure out a solution for this bug.
+					Tags: bazel.MakeStringListAttribute(tags),
+				},
+				&bazelAliasAttributes{
+					Actual: bazel.MakeLabelAttribute("//" + pkg + ":" + fg.Name() + "_proto"),
+				},
+			)
 		}
 
 		// TODO(b/242847534): Still convert to a filegroup because other unconverted
diff --git a/android/module.go b/android/module.go
index b982019..0120a54 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1021,6 +1021,11 @@
 	Applicable_licenses bazel.LabelListAttribute
 
 	Testonly *bool
+
+	// Dir is neither a Soong nor Bazel target attribute
+	// If set, the bazel target will be created in this directory
+	// If unset, the bazel target will default to be created in the directory of the visited soong module
+	Dir *string
 }
 
 // constraintAttributes represents Bazel attributes pertaining to build constraints,
diff --git a/android/mutator.go b/android/mutator.go
index 2ec051e..6bcac93 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -17,6 +17,7 @@
 import (
 	"android/soong/bazel"
 	"android/soong/ui/metrics/bp2build_metrics_proto"
+	"path/filepath"
 
 	"github.com/google/blueprint"
 )
@@ -757,6 +758,27 @@
 	mod.base().addBp2buildInfo(info)
 }
 
+// Returns the directory in which the bazel target will be generated
+// If ca.Dir is not nil, use that
+// Otherwise default to the directory of the soong module
+func dirForBazelTargetGeneration(t *topDownMutatorContext, ca *CommonAttributes) string {
+	dir := t.OtherModuleDir(t.Module())
+	if ca.Dir != nil {
+		dir = *ca.Dir
+		// Restrict its use to dirs that contain an Android.bp file.
+		// There are several places in bp2build where we use the existence of Android.bp/BUILD on the filesystem
+		// to curate a compatible label for src files (e.g. headers for cc).
+		// If we arbritrarily create BUILD files, then it might render those curated labels incompatible.
+		if exists, _, _ := t.Config().fs.Exists(filepath.Join(dir, "Android.bp")); !exists {
+			t.ModuleErrorf("Cannot use ca.Dir to create a BazelTarget in dir: %v since it does not contain an Android.bp file", dir)
+		}
+
+		// Set ca.Dir to nil so that it does not get emitted to the BUILD files
+		ca.Dir = nil
+	}
+	return dir
+}
+
 func (t *topDownMutatorContext) CreateBazelConfigSetting(
 	csa bazel.ConfigSettingAttributes,
 	ca CommonAttributes,
@@ -851,7 +873,7 @@
 	constraintAttributes := commonAttrs.fillCommonBp2BuildModuleAttrs(t, enabledProperty)
 	mod := t.Module()
 	info := bp2buildInfo{
-		Dir:             t.OtherModuleDir(mod),
+		Dir:             dirForBazelTargetGeneration(t, &commonAttrs),
 		BazelProps:      bazelProps,
 		CommonAttrs:     commonAttrs,
 		ConstraintAttrs: constraintAttributes,
diff --git a/android/proto.go b/android/proto.go
index cebbd59..aad521b 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"path/filepath"
 	"strings"
 
 	"android/soong/bazel"
@@ -156,12 +157,12 @@
 // Bp2buildProtoInfo contains information necessary to pass on to language specific conversion.
 type Bp2buildProtoInfo struct {
 	Type       *string
-	Name       string
 	Proto_libs bazel.LabelList
 }
 
 type ProtoAttrs struct {
 	Srcs                bazel.LabelListAttribute
+	Import_prefix       *string
 	Strip_import_prefix *string
 	Deps                bazel.LabelListAttribute
 }
@@ -172,6 +173,35 @@
 	"external/protobuf/src": "//external/protobuf:libprotobuf-proto",
 }
 
+// Partitions srcs by the pkg it is in
+// srcs has been created using `TransformSubpackagePaths`
+// This function uses existence of Android.bp/BUILD files to create a label that is compatible with the package structure of bp2build workspace
+func partitionSrcsByPackage(currentDir string, srcs bazel.LabelList) map[string]bazel.LabelList {
+	getPackageFromLabel := func(label string) string {
+		// Remove any preceding //
+		label = strings.TrimPrefix(label, "//")
+		split := strings.Split(label, ":")
+		if len(split) == 1 {
+			// e.g. foo.proto
+			return currentDir
+		} else if split[0] == "" {
+			// e.g. :foo.proto
+			return currentDir
+		} else {
+			return split[0]
+		}
+	}
+
+	pkgToSrcs := map[string]bazel.LabelList{}
+	for _, src := range srcs.Includes {
+		pkg := getPackageFromLabel(src.Label)
+		list := pkgToSrcs[pkg]
+		list.Add(&src)
+		pkgToSrcs[pkg] = list
+	}
+	return pkgToSrcs
+}
+
 // Bp2buildProtoProperties converts proto properties, creating a proto_library and returning the
 // information necessary for language-specific handling.
 func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs bazel.LabelListAttribute) (Bp2buildProtoInfo, bool) {
@@ -197,54 +227,73 @@
 		}
 	}
 
-	info.Name = m.Name() + "_proto"
+	name := m.Name() + "_proto"
+
+	depsFromFilegroup := protoLibraries
 
 	if len(directProtoSrcs.Includes) > 0 {
-		attrs := ProtoAttrs{
-			Srcs: bazel.MakeLabelListAttribute(directProtoSrcs),
-		}
-		attrs.Deps.Append(bazel.MakeLabelListAttribute(protoLibraries))
+		pkgToSrcs := partitionSrcsByPackage(ctx.ModuleDir(), directProtoSrcs)
+		for _, pkg := range SortedStringKeys(pkgToSrcs) {
+			srcs := pkgToSrcs[pkg]
+			attrs := ProtoAttrs{
+				Srcs: bazel.MakeLabelListAttribute(srcs),
+			}
+			attrs.Deps.Append(bazel.MakeLabelListAttribute(depsFromFilegroup))
 
-		for axis, configToProps := range m.GetArchVariantProperties(ctx, &ProtoProperties{}) {
-			for _, rawProps := range configToProps {
-				var props *ProtoProperties
-				var ok bool
-				if props, ok = rawProps.(*ProtoProperties); !ok {
-					ctx.ModuleErrorf("Could not cast ProtoProperties to expected type")
-				}
-				if axis == bazel.NoConfigAxis {
-					info.Type = props.Proto.Type
-
-					if !proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault) {
-						// an empty string indicates to strips the package path
-						path := ""
-						attrs.Strip_import_prefix = &path
+			for axis, configToProps := range m.GetArchVariantProperties(ctx, &ProtoProperties{}) {
+				for _, rawProps := range configToProps {
+					var props *ProtoProperties
+					var ok bool
+					if props, ok = rawProps.(*ProtoProperties); !ok {
+						ctx.ModuleErrorf("Could not cast ProtoProperties to expected type")
 					}
+					if axis == bazel.NoConfigAxis {
+						info.Type = props.Proto.Type
 
-					for _, dir := range props.Proto.Include_dirs {
-						if dep, ok := includeDirsToProtoDeps[dir]; ok {
-							attrs.Deps.Add(bazel.MakeLabelAttribute(dep))
-						} else {
-							ctx.PropertyErrorf("Could not find the proto_library target for include dir", dir)
+						if !proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault) {
+							// an empty string indicates to strips the package path
+							path := ""
+							attrs.Strip_import_prefix = &path
 						}
+
+						for _, dir := range props.Proto.Include_dirs {
+							if dep, ok := includeDirsToProtoDeps[dir]; ok {
+								attrs.Deps.Add(bazel.MakeLabelAttribute(dep))
+							} else {
+								ctx.PropertyErrorf("Could not find the proto_library target for include dir", dir)
+							}
+						}
+					} else if props.Proto.Type != info.Type && props.Proto.Type != nil {
+						ctx.ModuleErrorf("Cannot handle arch-variant types for protos at this time.")
 					}
-				} else if props.Proto.Type != info.Type && props.Proto.Type != nil {
-					ctx.ModuleErrorf("Cannot handle arch-variant types for protos at this time.")
 				}
 			}
+
+			tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module())
+
+			// Since we are creating the proto_library in a subpackage, create an import_prefix relative to the current package
+			if rel, err := filepath.Rel(ctx.ModuleDir(), pkg); err != nil {
+				ctx.ModuleErrorf("Could not get relative path for %v %v", pkg, err)
+			} else if rel != "." {
+				attrs.Import_prefix = &rel
+			}
+
+			ctx.CreateBazelTargetModule(
+				bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
+				CommonAttributes{Name: name, Dir: proptools.StringPtr(pkg), Tags: tags},
+				&attrs,
+			)
+
+			l := ""
+			if pkg == ctx.ModuleDir() { // same package that the original module lives in
+				l = ":" + name
+			} else {
+				l = "//" + pkg + ":" + name
+			}
+			protoLibraries.Add(&bazel.Label{
+				Label: l,
+			})
 		}
-
-		tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module())
-
-		ctx.CreateBazelTargetModule(
-			bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
-			CommonAttributes{Name: info.Name, Tags: tags},
-			&attrs,
-		)
-
-		protoLibraries.Add(&bazel.Label{
-			Label: ":" + info.Name,
-		})
 	}
 
 	info.Proto_libs = protoLibraries
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index cfe52db..5f7b382 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -15,7 +15,6 @@
 package bp2build
 
 import (
-	"android/soong/starlark_import"
 	"fmt"
 	"os"
 	"path/filepath"
@@ -24,6 +23,7 @@
 	"android/soong/android"
 	"android/soong/bazel"
 	"android/soong/shared"
+	"android/soong/starlark_import"
 )
 
 func deleteFilesExcept(ctx *CodegenContext, rootOutputPath android.OutputPath, except []BazelFile) {
@@ -67,6 +67,8 @@
 // writing .bzl files that are equivalent to Android.bp files that are capable
 // of being built with Bazel.
 func Codegen(ctx *CodegenContext) *CodegenMetrics {
+	ctx.Context().BeginEvent("Codegen")
+	defer ctx.Context().EndEvent("Codegen")
 	// This directory stores BUILD files that could be eventually checked-in.
 	bp2buildDir := android.PathForOutput(ctx, "bp2build")
 
@@ -79,7 +81,10 @@
 		fmt.Printf("ERROR: Encountered %d error(s): \nERROR: %s", len(errs), strings.Join(errMsgs, "\n"))
 		os.Exit(1)
 	}
-	bp2buildFiles := CreateBazelFiles(ctx.Config(), nil, res.buildFileToTargets, ctx.mode)
+	var bp2buildFiles []BazelFile
+	ctx.Context().EventHandler.Do("CreateBazelFile", func() {
+		bp2buildFiles = CreateBazelFiles(nil, res.buildFileToTargets, ctx.mode)
+	})
 	injectionFiles, additionalBp2buildFiles, err := CreateSoongInjectionDirFiles(ctx, res.metrics)
 	if err != nil {
 		fmt.Printf("%s\n", err.Error())
@@ -111,7 +116,7 @@
 func CreateSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, []BazelFile, error) {
 	var ret []BazelFile
 
-	productConfigInjectionFiles, productConfigBp2BuildDirFiles, err := CreateProductConfigFiles(ctx)
+	productConfigInjectionFiles, productConfigBp2BuildDirFiles, err := CreateProductConfigFiles(ctx, metrics)
 	if err != nil {
 		return nil, nil, err
 	}
diff --git a/bp2build/bp2build_product_config.go b/bp2build/bp2build_product_config.go
index 2549f11..12a9b15 100644
--- a/bp2build/bp2build_product_config.go
+++ b/bp2build/bp2build_product_config.go
@@ -16,7 +16,8 @@
 )
 
 func CreateProductConfigFiles(
-	ctx *CodegenContext) ([]BazelFile, []BazelFile, error) {
+	ctx *CodegenContext,
+	metrics CodegenMetrics) ([]BazelFile, []BazelFile, error) {
 	cfg := &ctx.config
 	targetProduct := "unknown"
 	if cfg.HasDeviceProduct() {
@@ -52,11 +53,24 @@
 		"{VARIANT}", targetBuildVariant,
 		"{PRODUCT_FOLDER}", currentProductFolder)
 
-	platformMappingContent, err := platformMappingContent(productReplacer.Replace("@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"), &productVariables, ctx.Config().Bp2buildSoongConfigDefinitions)
+	platformMappingContent, err := platformMappingContent(
+		productReplacer.Replace("@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"),
+		&productVariables,
+		ctx.Config().Bp2buildSoongConfigDefinitions,
+		metrics.convertedModulePathMap)
 	if err != nil {
 		return nil, nil, err
 	}
 
+	productsForTestingMap, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing")
+	if err != nil {
+		return nil, nil, err
+	}
+	productsForTesting := android.SortedKeys(productsForTestingMap)
+	for i := range productsForTesting {
+		productsForTesting[i] = fmt.Sprintf("  \"@//build/bazel/tests/products:%s\",", productsForTesting[i])
+	}
+
 	injectionDirFiles := []BazelFile{
 		newFile(
 			currentProductFolder,
@@ -111,9 +125,8 @@
 # currently lunched product, they should all be listed here
 product_labels = [
   "@soong_injection//product_config_platforms:mixed_builds_product-{VARIANT}",
-  "@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"
-]
-`)),
+  "@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}",
+`)+strings.Join(productsForTesting, "\n")+"\n]\n"),
 		newFile(
 			"product_config_platforms",
 			"common.bazelrc",
@@ -150,20 +163,37 @@
 	return injectionDirFiles, bp2buildDirFiles, nil
 }
 
-func platformMappingContent(mainProductLabel string, mainProductVariables *android.ProductVariables, soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions) (string, error) {
+func platformMappingContent(
+	mainProductLabel string,
+	mainProductVariables *android.ProductVariables,
+	soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions,
+	convertedModulePathMap map[string]string) (string, error) {
 	productsForTesting, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing")
 	if err != nil {
 		return "", err
 	}
 	var result strings.Builder
+
+	mergedConvertedModulePathMap := make(map[string]string)
+	for k, v := range convertedModulePathMap {
+		mergedConvertedModulePathMap[k] = v
+	}
+	additionalModuleNamesToPackages, err := starlark_import.GetStarlarkValue[map[string]string]("additional_module_names_to_packages")
+	if err != nil {
+		return "", err
+	}
+	for k, v := range additionalModuleNamesToPackages {
+		mergedConvertedModulePathMap[k] = v
+	}
+
 	result.WriteString("platforms:\n")
-	platformMappingSingleProduct(mainProductLabel, mainProductVariables, soongConfigDefinitions, &result)
+	platformMappingSingleProduct(mainProductLabel, mainProductVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &result)
 	for product, productVariablesStarlark := range productsForTesting {
 		productVariables, err := starlarkMapToProductVariables(productVariablesStarlark)
 		if err != nil {
 			return "", err
 		}
-		platformMappingSingleProduct("@//build/bazel/tests/products:"+product, &productVariables, soongConfigDefinitions, &result)
+		platformMappingSingleProduct("@//build/bazel/tests/products:"+product, &productVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &result)
 	}
 	return result.String(), nil
 }
@@ -182,7 +212,12 @@
 	"_windows_x86_64",
 }
 
-func platformMappingSingleProduct(label string, productVariables *android.ProductVariables, soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions, result *strings.Builder) {
+func platformMappingSingleProduct(
+	label string,
+	productVariables *android.ProductVariables,
+	soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions,
+	convertedModulePathMap map[string]string,
+	result *strings.Builder) {
 	targetBuildVariant := "user"
 	if proptools.Bool(productVariables.Eng) {
 		targetBuildVariant = "eng"
@@ -195,6 +230,11 @@
 		platform_sdk_version = *productVariables.Platform_sdk_version
 	}
 
+	defaultAppCertificateFilegroup := "//build/bazel/utils:empty_filegroup"
+	if proptools.String(productVariables.DefaultAppCertificate) != "" {
+		defaultAppCertificateFilegroup = "@//" + filepath.Dir(proptools.String(productVariables.DefaultAppCertificate)) + ":android_certificate_directory"
+	}
+
 	for _, suffix := range bazelPlatformSuffixes {
 		result.WriteString("  ")
 		result.WriteString(label)
@@ -207,12 +247,12 @@
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:build_from_text_stub=%t\n", proptools.Bool(productVariables.Build_from_text_stub)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:build_id=%s\n", proptools.String(productVariables.BuildId)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:build_version_tags=%s\n", strings.Join(productVariables.BuildVersionTags, ",")))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:certificate_overrides=%s\n", strings.Join(productVariables.CertificateOverrides, ",")))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:cfi_exclude_paths=%s\n", strings.Join(productVariables.CFIExcludePaths, ",")))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:cfi_include_paths=%s\n", strings.Join(productVariables.CFIIncludePaths, ",")))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:compressed_apex=%t\n", proptools.Bool(productVariables.CompressedApex)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:debuggable=%t\n", proptools.Bool(productVariables.Debuggable)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:default_app_certificate=%s\n", proptools.String(productVariables.DefaultAppCertificate)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:default_app_certificate_filegroup=%s\n", defaultAppCertificateFilegroup))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_abi=%s\n", strings.Join(productVariables.DeviceAbi, ",")))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_max_page_size_supported=%s\n", proptools.String(productVariables.DeviceMaxPageSizeSupported)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_name=%s\n", proptools.String(productVariables.DeviceName)))
@@ -237,6 +277,16 @@
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:uml=%t\n", proptools.Bool(productVariables.Uml)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:unbundled_build=%t\n", proptools.Bool(productVariables.Unbundled_build)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:unbundled_build_apps=%s\n", strings.Join(productVariables.Unbundled_build_apps, ",")))
+
+		for _, override := range productVariables.CertificateOverrides {
+			parts := strings.SplitN(override, ":", 2)
+			if apexPath, ok := convertedModulePathMap[parts[0]]; ok {
+				if overrideCertPath, ok := convertedModulePathMap[parts[1]]; ok {
+					result.WriteString(fmt.Sprintf("    --%s:%s_certificate_override=%s:%s\n", apexPath, parts[0], overrideCertPath, parts[1]))
+				}
+			}
+		}
+
 		for namespace, namespaceContents := range productVariables.VendorVars {
 			for variable, value := range namespaceContents {
 				key := namespace + "__" + variable
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 09a9d04..6ca4bb4 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -29,6 +29,7 @@
 	"android/soong/bazel"
 	"android/soong/starlark_fmt"
 	"android/soong/ui/metrics/bp2build_metrics_proto"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/proptools"
@@ -94,16 +95,16 @@
 // statements (use LoadStatements for that), since the targets are usually not
 // adjacent to the load statements at the top of the BUILD file.
 func (targets BazelTargets) String() string {
-	var res string
+	var res strings.Builder
 	for i, target := range targets {
 		if target.ruleClass != "package" {
-			res += target.content
+			res.WriteString(target.content)
 		}
 		if i != len(targets)-1 {
-			res += "\n\n"
+			res.WriteString("\n\n")
 		}
 	}
-	return res
+	return res.String()
 }
 
 // LoadStatements return the string representation of the sorted and deduplicated
@@ -653,6 +654,8 @@
 }
 
 func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (conversionResults, []error) {
+	ctx.Context().BeginEvent("GenerateBazelTargets")
+	defer ctx.Context().EndEvent("GenerateBazelTargets")
 	buildFileToTargets := make(map[string]BazelTargets)
 
 	// Simple metrics tracking for bp2build
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 4d1d171..8ee0439 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -1949,3 +1949,46 @@
 	actual, _ := prettyPrintAttribute(lla, 0)
 	android.AssertStringEquals(t, "Print the common value if all keys in an axis have the same value", `[":libfoo.impl"]`, actual)
 }
+
+// If CommonAttributes.Dir is set, the bazel target should be created in that dir
+func TestCreateBazelTargetInDifferentDir(t *testing.T) {
+	t.Parallel()
+	bp := `
+	custom {
+		name: "foo",
+		dir: "subdir",
+	}
+	`
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	// Check that foo is not created in root dir
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Description: "foo is not created in root dir because it sets dir explicitly",
+		Blueprint:   bp,
+		Filesystem: map[string]string{
+			"subdir/Android.bp": "",
+		},
+		ExpectedBazelTargets: []string{},
+	})
+	// Check that foo is created in `subdir`
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Description: "foo is created in `subdir` because it sets dir explicitly",
+		Blueprint:   bp,
+		Filesystem: map[string]string{
+			"subdir/Android.bp": "",
+		},
+		Dir: "subdir",
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("custom", "foo", AttrNameToString{}),
+		},
+	})
+	// Check that we cannot create target in different dir if it is does not an Android.bp
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Description: "foo cannot be created in `subdir` because it does not contain an Android.bp file",
+		Blueprint:   bp,
+		Dir:         "subdir",
+		ExpectedErr: fmt.Errorf("Cannot use ca.Dir to create a BazelTarget in dir: subdir since it does not contain an Android.bp file"),
+	})
+
+}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index fa1bf8a..402d4b0 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -94,6 +94,7 @@
         # bazel_module end
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
+        "dir": attr.string(),
         "embedded_prop": attr.string(),
         "int64_ptr_prop": attr.int(),
         # nested_props start
@@ -126,6 +127,7 @@
         "arch_paths_exclude": attr.string_list(),
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
+        "dir": attr.string(),
         "embedded_prop": attr.string(),
         "int64_ptr_prop": attr.int(),
         # nested_props start
@@ -158,6 +160,7 @@
         "arch_paths_exclude": attr.string_list(),
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
+        "dir": attr.string(),
         "embedded_prop": attr.string(),
         "int64_ptr_prop": attr.int(),
         # nested_props start
@@ -199,7 +202,7 @@
 			content: "irrelevant",
 		},
 	}
-	files := CreateBazelFiles(android.NullConfig("out", "out/soong"), ruleShims, make(map[string]BazelTargets), QueryView)
+	files := CreateBazelFiles(ruleShims, make(map[string]BazelTargets), QueryView)
 
 	var actualSoongModuleBzl BazelFile
 	for _, f := range files {
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 6b17fc4..e425b36 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -2434,12 +2434,18 @@
 			}), MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
 				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":a_cc_proto_lite"]`,
-			}), MakeBazelTargetNoRestrictions("proto_library", "a_fg_proto_bp2build_converted", AttrNameToString{
+			}), MakeBazelTargetNoRestrictions("proto_library", "a_fg_proto_proto", AttrNameToString{
 				"srcs": `["a_fg.proto"]`,
 				"tags": `[
         "apex_available=//apex_available:anyapex",
         "manual",
     ]`,
+			}), MakeBazelTargetNoRestrictions("alias", "a_fg_proto_bp2build_converted", AttrNameToString{
+				"actual": `"//.:a_fg_proto_proto"`,
+				"tags": `[
+        "apex_available=//apex_available:anyapex",
+        "manual",
+    ]`,
 			}), MakeBazelTargetNoRestrictions("filegroup", "a_fg_proto", AttrNameToString{
 				"srcs": `["a_fg.proto"]`,
 			}),
@@ -2476,12 +2482,18 @@
 			}), MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
 				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":a_cc_proto_lite"]`,
-			}), MakeBazelTargetNoRestrictions("proto_library", "a_fg_proto_bp2build_converted", AttrNameToString{
+			}), MakeBazelTargetNoRestrictions("proto_library", "a_fg_proto_proto", AttrNameToString{
 				"srcs": `["a_fg.proto"]`,
 				"tags": `[
         "apex_available=//apex_available:anyapex",
         "manual",
     ]`,
+			}), MakeBazelTargetNoRestrictions("alias", "a_fg_proto_bp2build_converted", AttrNameToString{
+				"actual": `"//.:a_fg_proto_proto"`,
+				"tags": `[
+        "apex_available=//apex_available:anyapex",
+        "manual",
+    ]`,
 			}), MakeBazelTargetNoRestrictions("filegroup", "a_fg_proto", AttrNameToString{
 				"srcs": `["a_fg.proto"]`,
 			}),
@@ -4903,3 +4915,67 @@
 		},
 	})
 }
+
+// Bazel enforces that proto_library and the .proto file are in the same bazel package
+func TestGenerateProtoLibraryInSamePackage(t *testing.T) {
+	tc := Bp2buildTestCase{
+		Description:                "cc_library depends on .proto files from multiple packages",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library_static {
+	name: "foo",
+	srcs: [
+	   "foo.proto",
+	   "bar/bar.proto", // Different package because there is a bar/Android.bp
+	   "baz/subbaz/baz.proto", // Different package because there is baz/subbaz/Android.bp
+	],
+}
+` + simpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"),
+		Filesystem: map[string]string{
+			"bar/Android.bp":        "",
+			"baz/subbaz/Android.bp": "",
+		},
+	}
+
+	// We will run the test 3 times and check in the root, bar and baz/subbaz directories
+	// Root dir
+	tc.ExpectedBazelTargets = []string{
+		MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+			"local_includes":                    `["."]`,
+			"deps":                              `[":libprotobuf-cpp-lite"]`,
+			"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
+		}),
+		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
+			"srcs": `["foo.proto"]`,
+		}),
+		MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
+			"deps": `[
+        ":foo_proto",
+        "//bar:foo_proto",
+        "//baz/subbaz:foo_proto",
+    ]`,
+		}),
+	}
+	runCcLibraryTestCase(t, tc)
+
+	// bar dir
+	tc.Dir = "bar"
+	tc.ExpectedBazelTargets = []string{
+		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
+			"srcs":          `["//bar:bar.proto"]`,
+			"import_prefix": `"bar"`,
+		}),
+	}
+	runCcLibraryTestCase(t, tc)
+
+	// baz/subbaz dir
+	tc.Dir = "baz/subbaz"
+	tc.ExpectedBazelTargets = []string{
+		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
+			"srcs":          `["//baz/subbaz:baz.proto"]`,
+			"import_prefix": `"baz/subbaz"`,
+		}),
+	}
+	runCcLibraryTestCase(t, tc)
+}
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index d5f2386..f280924 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -1,7 +1,6 @@
 package bp2build
 
 import (
-	"android/soong/starlark_fmt"
 	"encoding/json"
 	"fmt"
 	"reflect"
@@ -9,11 +8,11 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/apex"
 	"android/soong/cc"
 	cc_config "android/soong/cc/config"
 	java_config "android/soong/java/config"
-
-	"android/soong/apex"
+	"android/soong/starlark_fmt"
 
 	"github.com/google/blueprint/proptools"
 )
@@ -105,12 +104,7 @@
 `, starlark_fmt.PrintBool(cfg.PlatformSdkFinal()), platformSdkVersion, cfg.PlatformSdkCodename(), strings.Join(platformVersionActiveCodenames, ", "))
 }
 
-func CreateBazelFiles(
-	cfg android.Config,
-	ruleShims map[string]RuleShim,
-	buildToTargets map[string]BazelTargets,
-	mode CodegenMode) []BazelFile {
-
+func CreateBazelFiles(ruleShims map[string]RuleShim, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
 	var files []BazelFile
 
 	if mode == QueryView {
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index 00ffd79..15284ce 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -27,8 +27,7 @@
 }
 
 func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) {
-	files := CreateBazelFiles(android.NullConfig("out", "out/soong"),
-		map[string]RuleShim{}, map[string]BazelTargets{}, QueryView)
+	files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, QueryView)
 	expectedFilePaths := []bazelFilepath{
 		{
 			dir:      "",
diff --git a/bp2build/filegroup_conversion_test.go b/bp2build/filegroup_conversion_test.go
index 7ce559d..cb2e207 100644
--- a/bp2build/filegroup_conversion_test.go
+++ b/bp2build/filegroup_conversion_test.go
@@ -137,7 +137,7 @@
 		path: "proto",
 }`,
 		ExpectedBazelTargets: []string{
-			MakeBazelTargetNoRestrictions("proto_library", "foo_bp2build_converted", AttrNameToString{
+			MakeBazelTargetNoRestrictions("proto_library", "foo_proto", AttrNameToString{
 				"srcs":                `["proto/foo.proto"]`,
 				"strip_import_prefix": `"proto"`,
 				"tags": `[
@@ -145,6 +145,13 @@
         "manual",
     ]`,
 			}),
+			MakeBazelTargetNoRestrictions("alias", "foo_bp2build_converted", AttrNameToString{
+				"actual": `"//.:foo_proto"`,
+				"tags": `[
+        "apex_available=//apex_available:anyapex",
+        "manual",
+    ]`,
+			}),
 			MakeBazelTargetNoRestrictions("filegroup", "foo", AttrNameToString{
 				"srcs": `["proto/foo.proto"]`}),
 		}})
@@ -170,3 +177,27 @@
     ]`}),
 		}})
 }
+
+func TestFilegroupWithProtoInDifferentPackage(t *testing.T) {
+	runFilegroupTestCase(t, Bp2buildTestCase{
+		Description: "filegroup with .proto in different package",
+		Filesystem: map[string]string{
+			"subdir/Android.bp": "",
+		},
+		Blueprint: `
+filegroup {
+    name: "foo",
+    srcs: ["subdir/foo.proto"],
+}`,
+		Dir: "subdir", // check in subdir
+		ExpectedBazelTargets: []string{
+			MakeBazelTargetNoRestrictions("proto_library", "foo_proto", AttrNameToString{
+				"srcs":                `["//subdir:foo.proto"]`,
+				"import_prefix":       `"subdir"`,
+				"strip_import_prefix": `""`,
+				"tags": `[
+        "apex_available=//apex_available:anyapex",
+        "manual",
+    ]`}),
+		}})
+}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 140b214..18ae82d 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -336,6 +336,8 @@
 	Api *string // File describing the APIs of this module
 
 	Test_config_setting *bool // Used to test generation of config_setting targets
+
+	Dir *string // Dir in which the Bazel Target will be created
 }
 
 type customModule struct {
@@ -461,6 +463,10 @@
 	Api                 bazel.LabelAttribute
 }
 
+func (m *customModule) dir() *string {
+	return m.props.Dir
+}
+
 func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
 	if p := m.props.One_to_many_prop; p != nil && *p {
 		customBp2buildOneToMany(ctx, m)
@@ -508,7 +514,7 @@
 		Rule_class: "custom",
 	}
 
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name(), Dir: m.dir()}, attrs)
 
 	if proptools.Bool(m.props.Test_config_setting) {
 		m.createConfigSetting(ctx)
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index f9b3eac..dd612ce 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -21,7 +21,6 @@
 var VndkMustUseVendorVariantList = []string{
 	"android.hardware.nfc@1.2",
 	"libbinder",
-	"libdumpstateutil",
 	"libcrypto",
 	"libexpat",
 	"libgatekeeper",
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 62b3333..20e366e 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -814,9 +814,7 @@
 		// Run the code-generation phase to convert BazelTargetModules to BUILD files
 		// and print conversion codegenMetrics to the user.
 		codegenContext := bp2build.NewCodegenContext(ctx.Config(), ctx, bp2build.Bp2Build, topDir)
-		ctx.EventHandler.Do("codegen", func() {
-			codegenMetrics = bp2build.Codegen(codegenContext)
-		})
+		codegenMetrics = bp2build.Codegen(codegenContext)
 
 		ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
 
diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go
index 67cb6cf..5c2316a 100644
--- a/cmd/soong_build/queryview.go
+++ b/cmd/soong_build/queryview.go
@@ -15,7 +15,6 @@
 package main
 
 import (
-	"android/soong/starlark_import"
 	"io/fs"
 	"io/ioutil"
 	"os"
@@ -23,6 +22,7 @@
 
 	"android/soong/android"
 	"android/soong/bp2build"
+	"android/soong/starlark_import"
 )
 
 // A helper function to generate a Read-only Bazel workspace in outDir
@@ -35,8 +35,7 @@
 		panic(err)
 	}
 
-	filesToWrite := bp2build.CreateBazelFiles(ctx.Config(), ruleShims, res.BuildDirToTargets(),
-		ctx.Mode())
+	filesToWrite := bp2build.CreateBazelFiles(ruleShims, res.BuildDirToTargets(), ctx.Mode())
 	bazelRcFiles, err2 := CopyBazelRcFiles()
 	if err2 != nil {
 		return err2
diff --git a/python/bp2build.go b/python/bp2build.go
index 60cabc4..41e9f49 100644
--- a/python/bp2build.go
+++ b/python/bp2build.go
@@ -73,7 +73,6 @@
 
 	if !partitionedSrcs["proto"].IsEmpty() {
 		protoInfo, _ := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, partitionedSrcs["proto"])
-		protoLabel := bazel.Label{Label: ":" + protoInfo.Name}
 
 		pyProtoLibraryName := m.Name() + "_py_proto"
 		ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{
@@ -82,7 +81,7 @@
 		}, android.CommonAttributes{
 			Name: pyProtoLibraryName,
 		}, &bazelPythonProtoLibraryAttributes{
-			Deps: bazel.MakeSingleLabelListAttribute(protoLabel),
+			Deps: bazel.MakeLabelListAttribute(protoInfo.Proto_libs),
 		})
 
 		attrs.Deps.Add(bazel.MakeLabelAttribute(":" + pyProtoLibraryName))
diff --git a/tests/lib.sh b/tests/lib.sh
index f337c74..f3db76f 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -154,6 +154,7 @@
   symlink_directory external/bazelbuild-rules_go
   symlink_directory external/bazelbuild-rules_license
   symlink_directory external/bazelbuild-kotlin-rules
+  symlink_directory external/bazelbuild-rules_python
   symlink_directory external/bazelbuild-rules_java
 
   symlink_file WORKSPACE
diff --git a/ui/build/config.go b/ui/build/config.go
index e5c9a50..cecc8fa 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -15,7 +15,6 @@
 package build
 
 import (
-	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -40,9 +39,6 @@
 const (
 	envConfigDir = "vendor/google/tools/soong_config"
 	jsonSuffix   = "json"
-
-	configFetcher         = "vendor/google/tools/soong/expconfigfetcher"
-	envConfigFetchTimeout = 20 * time.Second
 )
 
 var (
@@ -174,87 +170,6 @@
 	}
 }
 
-// fetchEnvConfig optionally fetches a configuration file that can then subsequently be
-// loaded into Soong environment to control certain aspects of build behavior (e.g., enabling RBE).
-// If a configuration file already exists on disk, the fetch is run in the background
-// so as to NOT block the rest of the build execution.
-func fetchEnvConfig(ctx Context, config *configImpl, envConfigName string) error {
-	configName := envConfigName + "." + jsonSuffix
-	expConfigFetcher := &smpb.ExpConfigFetcher{Filename: &configName}
-	defer func() {
-		ctx.Metrics.ExpConfigFetcher(expConfigFetcher)
-	}()
-	if !config.GoogleProdCredsExist() {
-		status := smpb.ExpConfigFetcher_MISSING_GCERT
-		expConfigFetcher.Status = &status
-		return nil
-	}
-
-	s, err := os.Stat(configFetcher)
-	if err != nil {
-		if os.IsNotExist(err) {
-			return nil
-		}
-		return err
-	}
-	if s.Mode()&0111 == 0 {
-		status := smpb.ExpConfigFetcher_ERROR
-		expConfigFetcher.Status = &status
-		return fmt.Errorf("configuration fetcher binary %v is not executable: %v", configFetcher, s.Mode())
-	}
-
-	configExists := false
-	outConfigFilePath := filepath.Join(config.OutDir(), configName)
-	if _, err := os.Stat(outConfigFilePath); err == nil {
-		configExists = true
-	}
-
-	tCtx, cancel := context.WithTimeout(ctx, envConfigFetchTimeout)
-	fetchStart := time.Now()
-	cmd := exec.CommandContext(tCtx, configFetcher, "-output_config_dir", config.OutDir(),
-		"-output_config_name", configName)
-	if err := cmd.Start(); err != nil {
-		status := smpb.ExpConfigFetcher_ERROR
-		expConfigFetcher.Status = &status
-		return err
-	}
-
-	fetchCfg := func() error {
-		if err := cmd.Wait(); err != nil {
-			status := smpb.ExpConfigFetcher_ERROR
-			expConfigFetcher.Status = &status
-			return err
-		}
-		fetchEnd := time.Now()
-		expConfigFetcher.Micros = proto.Uint64(uint64(fetchEnd.Sub(fetchStart).Microseconds()))
-		expConfigFetcher.Filename = proto.String(outConfigFilePath)
-
-		if _, err := os.Stat(outConfigFilePath); err != nil {
-			status := smpb.ExpConfigFetcher_NO_CONFIG
-			expConfigFetcher.Status = &status
-			return err
-		}
-		status := smpb.ExpConfigFetcher_CONFIG
-		expConfigFetcher.Status = &status
-		return nil
-	}
-
-	// If a config file does not exist, wait for the config file to be fetched. Otherwise
-	// fetch the config file in the background and return immediately.
-	if !configExists {
-		defer cancel()
-		return fetchCfg()
-	}
-
-	go func() {
-		defer cancel()
-		if err := fetchCfg(); err != nil {
-			ctx.Verbosef("Failed to fetch config file %v: %v\n", configName, err)
-		}
-	}()
-	return nil
-}
-
 func loadEnvConfig(ctx Context, config *configImpl, bc string) error {
 	if bc == "" {
 		return nil
@@ -368,9 +283,6 @@
 	bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG")
 
 	if bc != "" {
-		if err := fetchEnvConfig(ctx, ret, bc); err != nil {
-			ctx.Verbosef("Failed to fetch config file: %v\n", err)
-		}
 		if err := loadEnvConfig(ctx, ret, bc); err != nil {
 			ctx.Fatalln("Failed to parse env config files: %v", err)
 		}