Merge "Add use_platform_libs to fuzz config"
diff --git a/OWNERS b/OWNERS
index 0234f27..9221d3e 100644
--- a/OWNERS
+++ b/OWNERS
@@ -10,10 +10,12 @@
delmerico@google.com
dwillemsen@google.com
eakammer@google.com
+jihoonkang@google.com
jobredeaux@google.com
joeo@google.com
juu@google.com
lamontjones@google.com
+mrziwang@google.com
spandandas@google.com
tradical@google.com
usta@google.com
diff --git a/README.md b/README.md
index 70311cb..2d8f0af 100644
--- a/README.md
+++ b/README.md
@@ -565,6 +565,12 @@
by all of the vendor's other modules using the normal namespace and visibility
rules.
+`soongConfigTraceMutator` enables modules affected by soong config variables to
+write outputs into a hashed directory path. It does this by recording accesses
+to soong config variables on each module, and then accumulating records of each
+module's all dependencies. `m soong_config_trace` builds information about
+hashes to `$OUT_DIR/soong/soong_config_trace.json`.
+
## Build logic
The build logic is written in Go using the
diff --git a/aidl_library/aidl_library.go b/aidl_library/aidl_library.go
index 8a84e6b..5985103 100644
--- a/aidl_library/aidl_library.go
+++ b/aidl_library/aidl_library.go
@@ -107,8 +107,10 @@
type AidlLibraryInfo struct {
// The direct aidl files of the module
Srcs android.Paths
- // The include dirs to the direct aidl files and those provided from aidl_library deps
+ // The include dirs to the direct aidl files and those provided from transitive aidl_library deps
IncludeDirs android.DepSet
+ // The direct hdrs and hdrs from transitive deps
+ Hdrs android.DepSet
}
// AidlLibraryProvider provides the srcs and the transitive include dirs
@@ -116,37 +118,48 @@
func (lib *AidlLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
includeDirsDepSetBuilder := android.NewDepSetBuilder(android.PREORDER)
+ hdrsDepSetBuilder := android.NewDepSetBuilder(android.PREORDER)
if len(lib.properties.Srcs) == 0 && len(lib.properties.Hdrs) == 0 {
ctx.ModuleErrorf("at least srcs or hdrs prop must be non-empty")
}
srcs := android.PathsForModuleSrc(ctx, lib.properties.Srcs)
+ hdrs := android.PathsForModuleSrc(ctx, lib.properties.Hdrs)
+
if lib.properties.Strip_import_prefix != nil {
srcs = android.PathsWithModuleSrcSubDir(
ctx,
srcs,
- android.String(lib.properties.Strip_import_prefix))
+ android.String(lib.properties.Strip_import_prefix),
+ )
+
+ hdrs = android.PathsWithModuleSrcSubDir(
+ ctx,
+ hdrs,
+ android.String(lib.properties.Strip_import_prefix),
+ )
}
+ hdrsDepSetBuilder.Direct(hdrs...)
includeDir := android.PathForModuleSrc(
ctx,
proptools.StringDefault(lib.properties.Strip_import_prefix, ""),
)
-
includeDirsDepSetBuilder.Direct(includeDir)
for _, dep := range ctx.GetDirectDepsWithTag(aidlLibraryTag) {
if ctx.OtherModuleHasProvider(dep, AidlLibraryProvider) {
info := ctx.OtherModuleProvider(dep, AidlLibraryProvider).(AidlLibraryInfo)
includeDirsDepSetBuilder.Transitive(&info.IncludeDirs)
+ hdrsDepSetBuilder.Transitive(&info.Hdrs)
}
}
- // TODO(b/279960133) Propagate direct and transitive headers/srcs when aidl action sandboxes inputs
ctx.SetProvider(AidlLibraryProvider, AidlLibraryInfo{
Srcs: srcs,
IncludeDirs: *includeDirsDepSetBuilder.Build(),
+ Hdrs: *hdrsDepSetBuilder.Build(),
})
}
diff --git a/aidl_library/aidl_library_test.go b/aidl_library/aidl_library_test.go
index d9b410a..d9dd245 100644
--- a/aidl_library/aidl_library_test.go
+++ b/aidl_library/aidl_library_test.go
@@ -37,7 +37,7 @@
aidl_library {
name: "foo",
srcs: ["a/b/Foo.aidl"],
- hdrs: ["Header.aidl"],
+ hdrs: ["a/Header.aidl"],
strip_import_prefix: "a",
deps: ["bar"],
}
@@ -61,6 +61,13 @@
[]string{"package_foo/a/b/Foo.aidl"},
actualInfo.Srcs,
)
+
+ android.AssertPathsRelativeToTopEquals(
+ t,
+ "aidl hdrs paths",
+ []string{"package_foo/a/Header.aidl"},
+ actualInfo.Hdrs.ToList(),
+ )
}
func TestAidlLibraryWithoutStripImportPrefix(t *testing.T) {
@@ -72,6 +79,7 @@
aidl_library {
name: "bar",
srcs: ["x/y/Bar.aidl"],
+ hdrs: ["BarHeader.aidl"],
}
`),
}.AddToFixture(),
@@ -80,7 +88,6 @@
aidl_library {
name: "foo",
srcs: ["a/b/Foo.aidl"],
- hdrs: ["Header.aidl"],
deps: ["bar"],
}
`),
@@ -103,6 +110,13 @@
[]string{"package_foo/a/b/Foo.aidl"},
actualInfo.Srcs,
)
+
+ android.AssertPathsRelativeToTopEquals(
+ t,
+ "aidl hdrs paths",
+ []string{"package_bar/BarHeader.aidl"},
+ actualInfo.Hdrs.ToList(),
+ )
}
func TestAidlLibraryWithNoSrcsHdrsDeps(t *testing.T) {
diff --git a/android/Android.bp b/android/Android.bp
index 118087d..94d2c04 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -77,6 +77,7 @@
"path_properties.go",
"paths.go",
"phony.go",
+ "plugin.go",
"prebuilt.go",
"prebuilt_build_tool.go",
"proto.go",
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 9700f8b..adbed00 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -223,6 +223,7 @@
"frameworks/base/tools/streaming_proto": Bp2BuildDefaultTrueRecursively,
"frameworks/hardware/interfaces/stats/aidl": Bp2BuildDefaultTrue,
"frameworks/libs/modules-utils/build": Bp2BuildDefaultTrueRecursively,
+ "frameworks/libs/net/common/native": Bp2BuildDefaultTrueRecursively,
"frameworks/native/libs/adbd_auth": Bp2BuildDefaultTrueRecursively,
"frameworks/native/libs/arect": Bp2BuildDefaultTrueRecursively,
"frameworks/native/libs/gui": Bp2BuildDefaultTrue,
@@ -476,6 +477,7 @@
"code_coverage.policy",
"code_coverage.policy.other",
"codec2_soft_exports",
+ "compatibility_matrix_schema",
"flatbuffer_headers",
"framework-connectivity-protos",
"gemmlowp_headers",
@@ -760,6 +762,14 @@
// aidl
"aidl",
"libaidl-common",
+
+ // java_resources containing only a single filegroup
+ "libauto_value_plugin",
+ "auto_value_plugin_resources",
+ "auto_value_extension",
+
+ // Used by xsd_config
+ "xsdc",
}
Bp2buildModuleTypeAlwaysConvertList = []string{
@@ -772,6 +782,7 @@
"java_import_host",
"java_sdk_library",
"sysprop_library",
+ "xsd_config",
}
// Add the names of modules that bp2build should never convert, if it is
@@ -834,7 +845,6 @@
"libprotobuf-internal-python-srcs", // TODO(b/210751803), we don't handle path property for filegroups
"libprotobuf-java-full", // TODO(b/210751803), we don't handle path property for filegroups
"libprotobuf-java-util-full", // TODO(b/210751803), we don't handle path property for filegroups
- "auto_value_plugin_resources", // TODO(b/210751803), we don't handle path property for filegroups
// go deps:
"analyze_bcpf", // depends on bpmodify a blueprint_go_binary.
@@ -1462,6 +1472,13 @@
// python_test_host with test data
"sbom_writers_test",
+
+ // TODO(B/283193845): tradefed and its java_test_host dependents
+ "tradefed",
+ "permissive_mte_test",
+ "ICU4CTestRunner",
+
+ "HelloWorldHostTest", // TODO(b/280452825): Convert HelloWorldHostTest to b test
}
MixedBuildsDisabledList = []string{
@@ -1565,10 +1582,10 @@
// also be built - do not add them to this list.
StagingMixedBuildsEnabledList = []string{
// M13: media.swcodec launch
- // TODO(b/282042844): reenable
- // "com.android.media.swcodec",
- // "test_com.android.media.swcodec",
- // "libstagefright_foundation",
+ "com.android.media.swcodec",
+ "test_com.android.media.swcodec",
+ "libstagefright_foundation",
+ "libcodec2_hidl@1.0",
}
// These should be the libs that are included by the apexes in the ProdMixedBuildsEnabledList
diff --git a/android/androidmk.go b/android/androidmk.go
index aa411d1..62f82f2 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -42,7 +42,7 @@
}
func RegisterAndroidMkBuildComponents(ctx RegistrationContext) {
- ctx.RegisterSingletonType("androidmk", AndroidMkSingleton)
+ ctx.RegisterParallelSingletonType("androidmk", AndroidMkSingleton)
}
// Enable androidmk support.
diff --git a/android/api_levels.go b/android/api_levels.go
index fa919fd..2391e6c 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -22,7 +22,7 @@
)
func init() {
- RegisterSingletonType("api_levels", ApiLevelsSingleton)
+ RegisterParallelSingletonType("api_levels", ApiLevelsSingleton)
}
const previewAPILevelBase = 9000
diff --git a/android/bazel.go b/android/bazel.go
index 114b1f5..d326634 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -46,6 +46,10 @@
// that is not a platform incompatibility. Example: the module-type is not
// enabled, or is not bp2build-converted.
ModuleIncompatibility
+
+ // Missing dependencies. We can't query Bazel for modules if it has missing dependencies, there
+ // will be failures.
+ ModuleMissingDeps
)
// FileGroupAsLibrary describes a filegroup module that is converted to some library
@@ -367,16 +371,26 @@
// As a side effect, calling this method will also log whether this module is
// mixed build enabled for metrics reporting.
func MixedBuildsEnabled(ctx BaseModuleContext) MixedBuildEnabledStatus {
- module := ctx.Module()
- apexInfo := ctx.Provider(ApexInfoProvider).(ApexInfo)
- withinApex := !apexInfo.IsForPlatform()
-
platformIncompatible := isPlatformIncompatible(ctx.Os(), ctx.Arch().ArchType)
if platformIncompatible {
ctx.Config().LogMixedBuild(ctx, false)
return TechnicalIncompatibility
}
+ if ctx.Config().AllowMissingDependencies() {
+ missingDeps := ctx.getMissingDependencies()
+ // If there are missing dependencies, querying Bazel will fail. Soong instead fails at execution
+ // time, not loading/analysis. disable mixed builds and fall back to Soong to maintain that
+ // behavior.
+ if len(missingDeps) > 0 {
+ ctx.Config().LogMixedBuild(ctx, false)
+ return ModuleMissingDeps
+ }
+ }
+
+ module := ctx.Module()
+ apexInfo := ctx.Provider(ApexInfoProvider).(ApexInfo)
+ withinApex := !apexInfo.IsForPlatform()
mixedBuildEnabled := ctx.Config().IsMixedBuildsEnabled() &&
module.Enabled() &&
convertedToBazel(ctx, module) &&
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 10cf60a..d71eca2 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -74,14 +74,12 @@
}
)
-func init() {
- RegisterMixedBuildsMutator(InitRegistrationContext)
+func registerMixedBuildsMutator(ctx RegisterMutatorsContext) {
+ ctx.BottomUp("mixed_builds_prep", mixedBuildsPrepareMutator).Parallel()
}
func RegisterMixedBuildsMutator(ctx RegistrationContext) {
- ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) {
- ctx.BottomUp("mixed_builds_prep", mixedBuildsPrepareMutator).Parallel()
- })
+ ctx.FinalDepsMutators(registerMixedBuildsMutator)
}
func mixedBuildsPrepareMutator(ctx BottomUpMutatorContext) {
@@ -183,10 +181,6 @@
// Returns the results of GetOutputFiles and GetCcObjectFiles in a single query (in that order).
GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, error)
- // Returns the executable binary resultant from building together the python sources
- // TODO(b/232976601): Remove.
- GetPythonBinary(label string, cfgKey configKey) (string, error)
-
// Returns the results of the GetApexInfo query (including output files)
GetApexInfo(label string, cfgkey configKey) (cquery.ApexInfo, error)
@@ -315,14 +309,6 @@
return result, nil
}
-func (m MockBazelContext) GetPythonBinary(label string, _ configKey) (string, error) {
- result, ok := m.LabelToPythonBinary[label]
- if !ok {
- return "", fmt.Errorf("no target with label %q in LabelToPythonBinary", label)
- }
- return result, nil
-}
-
func (m MockBazelContext) GetApexInfo(label string, _ configKey) (cquery.ApexInfo, error) {
result, ok := m.LabelToApexInfo[label]
if !ok {
@@ -431,15 +417,6 @@
return cquery.CcInfo{}, fmt.Errorf("no bazel response found for %v", key)
}
-func (bazelCtx *mixedBuildBazelContext) GetPythonBinary(label string, cfgKey configKey) (string, error) {
- key := makeCqueryKey(label, cquery.GetPythonBinary, cfgKey)
- if rawString, ok := bazelCtx.results[key]; ok {
- bazelOutput := strings.TrimSpace(rawString)
- return cquery.GetPythonBinary.ParseResult(bazelOutput), nil
- }
- return "", fmt.Errorf("no bazel response found for %v", key)
-}
-
func (bazelCtx *mixedBuildBazelContext) GetApexInfo(label string, cfgKey configKey) (cquery.ApexInfo, error) {
key := makeCqueryKey(label, cquery.GetApexInfo, cfgKey)
if rawString, ok := bazelCtx.results[key]; ok {
@@ -468,10 +445,6 @@
panic("unimplemented")
}
-func (n noopBazelContext) GetPythonBinary(_ string, _ configKey) (string, error) {
- panic("unimplemented")
-}
-
func (n noopBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexInfo, error) {
panic("unimplemented")
}
@@ -505,7 +478,7 @@
return []bazel.AqueryDepset{}
}
-func addToStringSet(set map[string]bool, items []string) {
+func AddToStringSet(set map[string]bool, items []string) {
for _, item := range items {
set[item] = true
}
@@ -517,19 +490,19 @@
switch buildMode {
case BazelProdMode:
- addToStringSet(enabledModules, allowlists.ProdMixedBuildsEnabledList)
+ AddToStringSet(enabledModules, allowlists.ProdMixedBuildsEnabledList)
for enabledAdHocModule := range forceEnabled {
enabledModules[enabledAdHocModule] = true
}
case BazelStagingMode:
// Staging mode includes all prod modules plus all staging modules.
- addToStringSet(enabledModules, allowlists.ProdMixedBuildsEnabledList)
- addToStringSet(enabledModules, allowlists.StagingMixedBuildsEnabledList)
+ AddToStringSet(enabledModules, allowlists.ProdMixedBuildsEnabledList)
+ AddToStringSet(enabledModules, allowlists.StagingMixedBuildsEnabledList)
for enabledAdHocModule := range forceEnabled {
enabledModules[enabledAdHocModule] = true
}
case BazelDevMode:
- addToStringSet(disabledModules, allowlists.MixedBuildsDisabledList)
+ AddToStringSet(disabledModules, allowlists.MixedBuildsDisabledList)
default:
panic("Expected BazelProdMode, BazelStagingMode, or BazelDevMode")
}
@@ -609,7 +582,7 @@
allowlists.StagingDclaMixedBuildsEnabledList...)
}
dclaEnabledModules := map[string]bool{}
- addToStringSet(dclaEnabledModules, dclaMixedBuildsEnabledList)
+ AddToStringSet(dclaEnabledModules, dclaMixedBuildsEnabledList)
return &mixedBuildBazelContext{
bazelRunner: &builtinBazelRunner{c.UseBazelProxy, absolutePath(c.outDir)},
paths: &paths,
@@ -701,6 +674,18 @@
// We don't need to set --host_platforms because it's set in bazelrc files
// that the bazel shell script wrapper passes
+ // Optimize Ninja rebuilds by ensuring Bazel write into product-agnostic
+ // output paths for the configured targets that shouldn't be affected by
+ // TARGET_PRODUCT. Otherwise product agnostic modules will be rebuilt by
+ // Ninja when the product changes, unconditionally.
+ //
+ // For example, Mainline APEXes should be identical regardless of the
+ // product (modulo arch/cpu).
+ //
+ // This flag forcibly disables the platform prefix in the intermediate
+ // outputs during a mixed build.
+ "--noexperimental_platform_in_output_dir",
+
// Suppress noise
"--ui_event_filters=-INFO",
"--noshow_progress",
@@ -746,9 +731,9 @@
#####################################################
def _config_node_transition_impl(settings, attr):
if attr.os == "android" and attr.arch == "target":
- target = "{PRODUCT}-{VARIANT}"
+ target = "current_product-{VARIANT}"
else:
- target = "{PRODUCT}-{VARIANT}_%s_%s" % (attr.os, attr.arch)
+ target = "current_product-{VARIANT}_%s_%s" % (attr.os, attr.arch)
apex_name = ""
if attr.within_apex:
# //build/bazel/rules/apex:apex_name has to be set to a non_empty value,
@@ -759,7 +744,7 @@
# value here.
apex_name = "dcla_apex"
outputs = {
- "//command_line_option:platforms": "@soong_injection//product_config_platforms/products/{PRODUCT}-{VARIANT}:%s" % target,
+ "//command_line_option:platforms": "@soong_injection//product_config_platforms:%s" % target,
"@//build/bazel/rules/apex:within_apex": attr.within_apex,
"@//build/bazel/rules/apex:min_sdk_version": attr.apex_sdk_version,
"@//build/bazel/rules/apex:apex_name": apex_name,
@@ -985,9 +970,9 @@
platform_name = platforms[0].name
if platform_name == "host":
return "HOST"
- if not platform_name.startswith("{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}"):
- fail("expected platform name of the form '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_android_<arch>' or '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_linux_<arch>', but was " + str(platforms))
- platform_name = platform_name.removeprefix("{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}").removeprefix("_")
+ if not platform_name.startswith("current_product-{TARGET_BUILD_VARIANT}"):
+ fail("expected platform name of the form 'current_product-{TARGET_BUILD_VARIANT}_android_<arch>' or 'current_product-{TARGET_BUILD_VARIANT}_linux_<arch>', but was " + str(platforms))
+ platform_name = platform_name.removeprefix("current_product-{TARGET_BUILD_VARIANT}").removeprefix("_")
config_key = ""
if not platform_name:
config_key = "target|android"
@@ -996,7 +981,7 @@
elif platform_name.startswith("linux_"):
config_key = platform_name.removeprefix("linux_") + "|linux"
else:
- fail("expected platform name of the form '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_android_<arch>' or '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_linux_<arch>', but was " + str(platforms))
+ fail("expected platform name of the form 'current_product-{TARGET_BUILD_VARIANT}_android_<arch>' or 'current_product-{TARGET_BUILD_VARIANT}_linux_<arch>', but was " + str(platforms))
within_apex = buildoptions.get("//build/bazel/rules/apex:within_apex")
apex_sdk_version = buildoptions.get("//build/bazel/rules/apex:min_sdk_version")
diff --git a/android/bazel_test.go b/android/bazel_test.go
index 77e2515..13fd408 100644
--- a/android/bazel_test.go
+++ b/android/bazel_test.go
@@ -436,3 +436,150 @@
}
}
}
+
+type mixedBuildModule struct {
+ ModuleBase
+ BazelModuleBase
+ props struct {
+ Deps []string
+ Mixed_build_incompatible *bool
+ QueuedBazelCall bool `blueprint:"mutated"`
+ }
+}
+
+type mixedBuildModuleInfo struct {
+ QueuedBazelCall bool
+}
+
+var mixedBuildModuleProvider = blueprint.NewProvider(mixedBuildModuleInfo{})
+
+func mixedBuildModuleFactory() Module {
+ m := &mixedBuildModule{}
+ m.AddProperties(&m.props)
+ InitAndroidArchModule(m, HostAndDeviceDefault, MultilibBoth)
+ InitBazelModule(m)
+
+ return m
+}
+
+func (m *mixedBuildModule) ConvertWithBp2build(ctx TopDownMutatorContext) {
+}
+
+func (m *mixedBuildModule) DepsMutator(ctx BottomUpMutatorContext) {
+ ctx.AddDependency(ctx.Module(), installDepTag{}, m.props.Deps...)
+}
+
+func (m *mixedBuildModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+func (m *mixedBuildModule) IsMixedBuildSupported(ctx BaseModuleContext) bool {
+ return !proptools.Bool(m.props.Mixed_build_incompatible)
+}
+
+func (m *mixedBuildModule) QueueBazelCall(ctx BaseModuleContext) {
+ m.props.QueuedBazelCall = true
+}
+
+func (m *mixedBuildModule) ProcessBazelQueryResponse(ctx ModuleContext) {
+ ctx.SetProvider(mixedBuildModuleProvider, mixedBuildModuleInfo{
+ QueuedBazelCall: m.props.QueuedBazelCall,
+ })
+}
+
+var prepareForMixedBuildTests = FixtureRegisterWithContext(func(ctx RegistrationContext) {
+ ctx.RegisterModuleType("deps", mixedBuildModuleFactory)
+ RegisterMixedBuildsMutator(ctx)
+})
+
+func TestMixedBuildsEnabledForType(t *testing.T) {
+ baseBp := `
+ deps {
+ name: "foo",
+ deps: ["bar"],
+ target: { windows: { enabled: true } },
+ %s
+ }
+`
+ depBp := `
+ deps {
+ name: "bar",
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }
+`
+ testCases := []struct {
+ desc string
+ variant *string
+ missingDeps bool
+ extraBpInfo string
+ mixedBuildsEnabled bool
+ }{
+ {
+ desc: "mixed builds works",
+ mixedBuildsEnabled: true,
+ extraBpInfo: `bazel_module: { bp2build_available: true },`,
+ },
+ {
+ desc: "missing deps",
+ missingDeps: true,
+ mixedBuildsEnabled: false,
+ extraBpInfo: `bazel_module: { bp2build_available: true },`,
+ },
+ {
+ desc: "windows no mixed builds",
+ mixedBuildsEnabled: false,
+ variant: proptools.StringPtr("windows_x86"),
+ extraBpInfo: `bazel_module: { bp2build_available: true },`,
+ },
+ {
+ desc: "mixed builds disabled by type",
+ mixedBuildsEnabled: false,
+ extraBpInfo: `mixed_build_incompatible: true,
+ bazel_module: { bp2build_available: true },`,
+ },
+ {
+ desc: "mixed builds not bp2build available",
+ mixedBuildsEnabled: false,
+ extraBpInfo: `bazel_module: { bp2build_available: false },`,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ handlers := GroupFixturePreparers(
+ prepareForMixedBuildTests,
+ PrepareForTestWithArchMutator,
+ FixtureModifyConfig(func(config Config) {
+ config.BazelContext = MockBazelContext{
+ OutputBaseDir: "base",
+ }
+ config.Targets[Windows] = []Target{
+ {Windows, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", true},
+ {Windows, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", true},
+ }
+ }),
+ )
+ bp := fmt.Sprintf(baseBp, tc.extraBpInfo)
+ if tc.missingDeps {
+ handlers = GroupFixturePreparers(
+ handlers,
+ PrepareForTestWithAllowMissingDependencies,
+ )
+ } else {
+ bp += depBp
+ }
+ result := handlers.RunTestWithBp(t, bp)
+
+ variant := proptools.StringDefault(tc.variant, "android_arm64_armv8-a")
+
+ m := result.ModuleForTests("foo", variant)
+ mixedBuildModuleInfo := result.TestContext.ModuleProvider(m.Module(), mixedBuildModuleProvider).(mixedBuildModuleInfo)
+ if w, g := tc.mixedBuildsEnabled, mixedBuildModuleInfo.QueuedBazelCall; w != g {
+ t.Errorf("Expected mixed builds enabled %t, got mixed builds enabled %t", w, g)
+ }
+ })
+ }
+}
diff --git a/android/buildinfo_prop.go b/android/buildinfo_prop.go
index 46f6488..8e19ad5 100644
--- a/android/buildinfo_prop.go
+++ b/android/buildinfo_prop.go
@@ -23,7 +23,7 @@
func init() {
ctx := InitRegistrationContext
- ctx.RegisterSingletonModuleType("buildinfo_prop", buildinfoPropFactory)
+ ctx.RegisterParallelSingletonModuleType("buildinfo_prop", buildinfoPropFactory)
}
type buildinfoPropProperties struct {
diff --git a/android/config.go b/android/config.go
index acadb3f..236d1c1 100644
--- a/android/config.go
+++ b/android/config.go
@@ -80,9 +80,10 @@
type CmdArgs struct {
bootstrap.Args
- RunGoTests bool
- OutDir string
- SoongOutDir string
+ RunGoTests bool
+ OutDir string
+ SoongOutDir string
+ SoongVariables string
SymlinkForestMarker string
Bp2buildMarker string
@@ -302,6 +303,9 @@
// modules that aren't mixed-built for at least one variant will cause a build
// failure
ensureAllowlistIntegrity bool
+
+ // List of Api libraries that contribute to Api surfaces.
+ apiLibraries map[string]struct{}
}
type deviceConfig struct {
@@ -488,7 +492,7 @@
func NewConfig(cmdArgs CmdArgs, availableEnv map[string]string) (Config, error) {
// Make a config with default options.
config := &config{
- ProductVariablesFileName: filepath.Join(cmdArgs.SoongOutDir, productVariablesFileName),
+ ProductVariablesFileName: cmdArgs.SoongVariables,
env: availableEnv,
@@ -622,6 +626,33 @@
config.BazelContext, err = NewBazelContext(config)
config.Bp2buildPackageConfig = GetBp2BuildAllowList()
+ // TODO(b/276958307): Replace the hardcoded list to a sdk_library local prop.
+ config.apiLibraries = map[string]struct{}{
+ "android.net.ipsec.ike": {},
+ "art.module.public.api": {},
+ "conscrypt.module.public.api": {},
+ "framework-adservices": {},
+ "framework-appsearch": {},
+ "framework-bluetooth": {},
+ "framework-connectivity": {},
+ "framework-connectivity-t": {},
+ "framework-graphics": {},
+ "framework-media": {},
+ "framework-mediaprovider": {},
+ "framework-ondevicepersonalization": {},
+ "framework-permission": {},
+ "framework-permission-s": {},
+ "framework-scheduling": {},
+ "framework-sdkextensions": {},
+ "framework-statsd": {},
+ "framework-sdksandbox": {},
+ "framework-tethering": {},
+ "framework-uwb": {},
+ "framework-virtualization": {},
+ "framework-wifi": {},
+ "i18n.module.public.api": {},
+ }
+
return Config{config}, err
}
@@ -726,6 +757,14 @@
return path
}
+func (c *config) HostCcSharedLibPath(ctx PathContext, lib string) Path {
+ libDir := "lib"
+ if ctx.Config().BuildArch.Multilib == "lib64" {
+ libDir = "lib64"
+ }
+ return pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, libDir, false, lib+".so")
+}
+
// PrebuiltOS returns the name of the host OS used in prebuilts directories.
func (c *config) PrebuiltOS() string {
switch runtime.GOOS {
@@ -1671,10 +1710,6 @@
return c.productVariables.ProductPrivateSepolicyDirs
}
-func (c *config) MissingUsesLibraries() []string {
- return c.productVariables.MissingUsesLibraries
-}
-
func (c *config) TargetMultitreeUpdateMeta() bool {
return c.productVariables.MultitreeUpdateMeta
}
@@ -1850,6 +1885,10 @@
return uncheckedFinalApiLevel(apiLevel)
}
+func (c *deviceConfig) BuildBrokenPluginValidation() []string {
+ return c.config.productVariables.BuildBrokenPluginValidation
+}
+
func (c *deviceConfig) BuildBrokenClangAsFlags() bool {
return c.config.productVariables.BuildBrokenClangAsFlags
}
@@ -1886,8 +1925,12 @@
return InList(name, c.config.productVariables.BuildBrokenInputDirModules)
}
-func (c *deviceConfig) BuildBrokenDepfile() bool {
- return Bool(c.config.productVariables.BuildBrokenDepfile)
+func (c *config) BuildWarningBadOptionalUsesLibsAllowlist() []string {
+ return c.productVariables.BuildWarningBadOptionalUsesLibsAllowlist
+}
+
+func (c *deviceConfig) GenruleSandboxing() bool {
+ return Bool(c.config.productVariables.GenruleSandboxing)
}
func (c *deviceConfig) RequiresInsecureExecmemForSwiftshader() bool {
@@ -1979,8 +2022,20 @@
func (c *config) SetBuildFromTextStub(b bool) {
c.buildFromTextStub = b
}
+
func (c *config) AddForceEnabledModules(forceEnabled []string) {
for _, forceEnabledModule := range forceEnabled {
c.bazelForceEnabledModules[forceEnabledModule] = struct{}{}
}
}
+
+func (c *config) SetApiLibraries(libs []string) {
+ c.apiLibraries = make(map[string]struct{})
+ for _, lib := range libs {
+ c.apiLibraries[lib] = struct{}{}
+ }
+}
+
+func (c *config) GetApiLibraries() map[string]struct{} {
+ return c.apiLibraries
+}
diff --git a/android/filegroup.go b/android/filegroup.go
index f30ee51..c042ff1 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -177,6 +177,17 @@
}
}
+type FileGroupPath interface {
+ GetPath(ctx TopDownMutatorContext) string
+}
+
+func (fg *fileGroup) GetPath(ctx TopDownMutatorContext) string {
+ if fg.properties.Path != nil {
+ return *fg.properties.Path
+ }
+ return ""
+}
+
type fileGroupProperties struct {
// srcs lists files that will be included in this filegroup
Srcs []string `android:"path"`
@@ -207,6 +218,7 @@
BazelModuleBase
DefaultableModuleBase
FileGroupAsLibrary
+ FileGroupPath
properties fileGroupProperties
srcs Paths
}
@@ -214,6 +226,7 @@
var _ MixedBuildBuildable = (*fileGroup)(nil)
var _ SourceFileProducer = (*fileGroup)(nil)
var _ FileGroupAsLibrary = (*fileGroup)(nil)
+var _ FileGroupPath = (*fileGroup)(nil)
// filegroup contains a list of files that are referenced by other modules
// properties (such as "srcs") using the syntax ":<name>". filegroup are
diff --git a/android/gen_notice.go b/android/gen_notice.go
index 091345b..1acc638 100644
--- a/android/gen_notice.go
+++ b/android/gen_notice.go
@@ -28,7 +28,7 @@
// Register the gen_notice module type.
func RegisterGenNoticeBuildComponents(ctx RegistrationContext) {
- ctx.RegisterSingletonType("gen_notice_build_rules", GenNoticeBuildRulesFactory)
+ ctx.RegisterParallelSingletonType("gen_notice_build_rules", GenNoticeBuildRulesFactory)
ctx.RegisterModuleType("gen_notice", GenNoticeFactory)
}
diff --git a/android/metrics.go b/android/metrics.go
index 3d41a1d..63c72cd 100644
--- a/android/metrics.go
+++ b/android/metrics.go
@@ -42,7 +42,7 @@
}
func init() {
- RegisterSingletonType("soong_metrics", soongMetricsSingletonFactory)
+ RegisterParallelSingletonType("soong_metrics", soongMetricsSingletonFactory)
}
func soongMetricsSingletonFactory() Singleton { return soongMetricsSingleton{} }
diff --git a/android/module.go b/android/module.go
index db602a0..98084f3 100644
--- a/android/module.go
+++ b/android/module.go
@@ -15,6 +15,9 @@
package android
import (
+ "crypto/md5"
+ "encoding/hex"
+ "encoding/json"
"fmt"
"net/url"
"os"
@@ -354,6 +357,10 @@
AddMissingDependencies(missingDeps []string)
+ // getMissingDependencies returns the list of missing dependencies.
+ // Calling this function prevents adding new dependencies.
+ getMissingDependencies() []string
+
// AddUnconvertedBp2buildDep stores module name of a direct dependency that was not converted via bp2build
AddUnconvertedBp2buildDep(dep string)
@@ -710,6 +717,31 @@
return l[:k+1]
}
+// soongConfigTrace holds all references to VendorVars. Uses []string for blueprint:"mutated"
+type soongConfigTrace struct {
+ Bools []string `json:",omitempty"`
+ Strings []string `json:",omitempty"`
+ IsSets []string `json:",omitempty"`
+}
+
+func (c *soongConfigTrace) isEmpty() bool {
+ return len(c.Bools) == 0 && len(c.Strings) == 0 && len(c.IsSets) == 0
+}
+
+// Returns hash of serialized trace records (empty string if there's no trace recorded)
+func (c *soongConfigTrace) hash() string {
+ // Use MD5 for speed. We don't care collision or preimage attack
+ if c.isEmpty() {
+ return ""
+ }
+ j, err := json.Marshal(c)
+ if err != nil {
+ panic(fmt.Errorf("json marshal of %#v failed: %#v", *c, err))
+ }
+ hash := md5.Sum(j)
+ return hex.EncodeToString(hash[:])
+}
+
type nameProperties struct {
// The name of the module. Must be unique across all modules.
Name *string
@@ -939,7 +971,8 @@
NamespaceExportedToMake bool `blueprint:"mutated"`
- MissingDeps []string `blueprint:"mutated"`
+ MissingDeps []string `blueprint:"mutated"`
+ CheckedMissingDeps bool `blueprint:"mutated"`
// Name and variant strings stored by mutators to enable Module.String()
DebugName string `blueprint:"mutated"`
@@ -953,6 +986,10 @@
// Bazel conversion status
BazelConversionStatus BazelConversionStatus `blueprint:"mutated"`
+
+ // SoongConfigTrace records accesses to VendorVars (soong_config)
+ SoongConfigTrace soongConfigTrace `blueprint:"mutated"`
+ SoongConfigTraceHash string `blueprint:"mutated"`
}
// CommonAttributes represents the common Bazel attributes from which properties
@@ -2862,6 +2899,20 @@
}
}
+func (b *baseModuleContext) checkedMissingDeps() bool {
+ return b.Module().base().commonProperties.CheckedMissingDeps
+}
+
+func (b *baseModuleContext) getMissingDependencies() []string {
+ checked := &b.Module().base().commonProperties.CheckedMissingDeps
+ *checked = true
+ var missingDeps []string
+ missingDeps = append(missingDeps, b.Module().base().commonProperties.MissingDeps...)
+ missingDeps = append(missingDeps, b.bp.EarlyGetMissingDependencies()...)
+ missingDeps = FirstUniqueStrings(missingDeps)
+ return missingDeps
+}
+
type AllowDisabledModuleDependency interface {
blueprint.DependencyTag
AllowDisabledModuleDependency(target Module) bool
@@ -3141,6 +3192,10 @@
return m.bp.ModuleSubDir()
}
+func (m *moduleContext) ModuleSoongConfigHash() string {
+ return m.module.base().commonProperties.SoongConfigTraceHash
+}
+
func (b *baseModuleContext) Target() Target {
return b.target
}
@@ -3724,7 +3779,9 @@
}
func init() {
- RegisterSingletonType("buildtarget", BuildTargetSingleton)
+ RegisterParallelSingletonType("buildtarget", BuildTargetSingleton)
+ RegisterParallelSingletonType("soongconfigtrace", soongConfigTraceSingletonFunc)
+ FinalDepsMutators(registerSoongConfigTraceMutator)
}
func BuildTargetSingleton() Singleton {
@@ -3906,3 +3963,54 @@
}
return d.depSet.ToList().(InstallPaths)
}
+
+func registerSoongConfigTraceMutator(ctx RegisterMutatorsContext) {
+ ctx.BottomUp("soongconfigtrace", soongConfigTraceMutator).Parallel()
+}
+
+// soongConfigTraceMutator accumulates recorded soong_config trace from children. Also it normalizes
+// SoongConfigTrace to make it consistent.
+func soongConfigTraceMutator(ctx BottomUpMutatorContext) {
+ trace := &ctx.Module().base().commonProperties.SoongConfigTrace
+ ctx.VisitDirectDeps(func(m Module) {
+ childTrace := &m.base().commonProperties.SoongConfigTrace
+ trace.Bools = append(trace.Bools, childTrace.Bools...)
+ trace.Strings = append(trace.Strings, childTrace.Strings...)
+ trace.IsSets = append(trace.IsSets, childTrace.IsSets...)
+ })
+ trace.Bools = SortedUniqueStrings(trace.Bools)
+ trace.Strings = SortedUniqueStrings(trace.Strings)
+ trace.IsSets = SortedUniqueStrings(trace.IsSets)
+
+ ctx.Module().base().commonProperties.SoongConfigTraceHash = trace.hash()
+}
+
+// soongConfigTraceSingleton writes a map from each module's config hash value to trace data.
+func soongConfigTraceSingletonFunc() Singleton {
+ return &soongConfigTraceSingleton{}
+}
+
+type soongConfigTraceSingleton struct {
+}
+
+func (s *soongConfigTraceSingleton) GenerateBuildActions(ctx SingletonContext) {
+ outFile := PathForOutput(ctx, "soong_config_trace.json")
+
+ traces := make(map[string]*soongConfigTrace)
+ ctx.VisitAllModules(func(module Module) {
+ trace := &module.base().commonProperties.SoongConfigTrace
+ if !trace.isEmpty() {
+ hash := module.base().commonProperties.SoongConfigTraceHash
+ traces[hash] = trace
+ }
+ })
+
+ j, err := json.Marshal(traces)
+ if err != nil {
+ ctx.Errorf("json marshal to %q failed: %#v", outFile, err)
+ return
+ }
+
+ WriteFileRule(ctx, outFile, string(j))
+ ctx.Phony("soong_config_trace", outFile)
+}
diff --git a/android/mutator.go b/android/mutator.go
index 0a091eb..4185315 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -67,6 +67,8 @@
// collateGloballyRegisteredMutators constructs the list of mutators that have been registered
// with the InitRegistrationContext and will be used at runtime.
func collateGloballyRegisteredMutators() sortableComponents {
+ // ensure mixed builds mutator is the last mutator
+ finalDeps = append(finalDeps, registerMixedBuildsMutator)
return collateRegisteredMutators(preArch, preDeps, postDeps, finalDeps)
}
@@ -885,10 +887,16 @@
}
func (b *bottomUpMutatorContext) AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []blueprint.Module {
+ if b.baseModuleContext.checkedMissingDeps() {
+ panic("Adding deps not allowed after checking for missing deps")
+ }
return b.bp.AddDependency(module, tag, name...)
}
func (b *bottomUpMutatorContext) AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string) {
+ if b.baseModuleContext.checkedMissingDeps() {
+ panic("Adding deps not allowed after checking for missing deps")
+ }
b.bp.AddReverseDependency(module, tag, name)
}
@@ -938,11 +946,17 @@
func (b *bottomUpMutatorContext) AddVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag,
names ...string) []blueprint.Module {
+ if b.baseModuleContext.checkedMissingDeps() {
+ panic("Adding deps not allowed after checking for missing deps")
+ }
return b.bp.AddVariationDependencies(variations, tag, names...)
}
func (b *bottomUpMutatorContext) AddFarVariationDependencies(variations []blueprint.Variation,
tag blueprint.DependencyTag, names ...string) []blueprint.Module {
+ if b.baseModuleContext.checkedMissingDeps() {
+ panic("Adding deps not allowed after checking for missing deps")
+ }
return b.bp.AddFarVariationDependencies(variations, tag, names...)
}
@@ -952,10 +966,16 @@
}
func (b *bottomUpMutatorContext) ReplaceDependencies(name string) {
+ if b.baseModuleContext.checkedMissingDeps() {
+ panic("Adding deps not allowed after checking for missing deps")
+ }
b.bp.ReplaceDependencies(name)
}
func (b *bottomUpMutatorContext) ReplaceDependenciesIf(name string, predicate blueprint.ReplaceDependencyPredicate) {
+ if b.baseModuleContext.checkedMissingDeps() {
+ panic("Adding deps not allowed after checking for missing deps")
+ }
b.bp.ReplaceDependenciesIf(name, predicate)
}
diff --git a/android/paths.go b/android/paths.go
index eaa6a8d..0f3d972 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1475,7 +1475,11 @@
}
func pathForModuleOut(ctx ModuleOutPathContext) OutputPath {
- return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir())
+ soongConfigHash := ""
+ if i, ok := ctx.(interface{ ModuleSoongConfigHash() string }); ok {
+ soongConfigHash = i.ModuleSoongConfigHash()
+ }
+ return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir(), soongConfigHash)
}
// PathForModuleOut returns a Path representing the paths... under the module's
diff --git a/android/plugin.go b/android/plugin.go
new file mode 100644
index 0000000..4672453
--- /dev/null
+++ b/android/plugin.go
@@ -0,0 +1,140 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "strings"
+
+ "github.com/google/blueprint"
+)
+
+func init() {
+ RegisterPluginSingletonBuildComponents(InitRegistrationContext)
+}
+
+func RegisterPluginSingletonBuildComponents(ctx RegistrationContext) {
+ ctx.RegisterParallelSingletonType("plugins", pluginSingletonFactory)
+}
+
+// pluginSingleton is a singleton to handle allowlisting of the final Android-<product_name>.mk file
+// output.
+func pluginSingletonFactory() Singleton {
+ return &pluginSingleton{}
+}
+
+type pluginSingleton struct{}
+
+var allowedPluginsByName = map[string]bool{
+ "aidl-soong-rules": true,
+ "arm_compute_library_nn_driver": true,
+ "cuttlefish-soong-rules": true,
+ "gki-soong-rules": true,
+ "hidl-soong-rules": true,
+ "kernel-config-soong-rules": true,
+ "soong-angle-codegen": true,
+ "soong-api": true,
+ "soong-art": true,
+ "soong-ca-certificates": true,
+ "soong-ca-certificates-apex": true,
+ "soong-clang": true,
+ "soong-clang-prebuilts": true,
+ "soong-csuite": true,
+ "soong-fluoride": true,
+ "soong-fs_config": true,
+ "soong-icu": true,
+ "soong-java-config-error_prone": true,
+ "soong-libchrome": true,
+ "soong-llvm": true,
+ "soong-robolectric": true,
+ "soong-rust-prebuilts": true,
+ "soong-selinux": true,
+ "soong-wayland-protocol-codegen": true,
+ "treble_report_app": true,
+ "treble_report_local": true,
+ "treble_report_module": true,
+ "vintf-compatibility-matrix-soong-rules": true,
+ "xsdc-soong-rules": true,
+}
+
+const (
+ internalPluginsPath = "vendor/google/build/soong/internal_plugins.json"
+)
+
+type pluginProvider interface {
+ IsPluginFor(string) bool
+}
+
+func maybeAddInternalPluginsToAllowlist(ctx SingletonContext) {
+ if path := ExistentPathForSource(ctx, internalPluginsPath); path.Valid() {
+ ctx.AddNinjaFileDeps(path.String())
+ absPath := absolutePath(path.String())
+ var moreAllowed map[string]bool
+ data, err := ioutil.ReadFile(absPath)
+ if err != nil {
+ ctx.Errorf("Failed to open internal plugins path %q %q", internalPluginsPath, err)
+ }
+ if err := json.Unmarshal(data, &moreAllowed); err != nil {
+ fmt.Fprintf(os.Stderr, "Internal plugins file %q did not parse correctly: %q", data, err)
+ }
+ for k, v := range moreAllowed {
+ allowedPluginsByName[k] = v
+ }
+ }
+}
+
+func (p *pluginSingleton) GenerateBuildActions(ctx SingletonContext) {
+ for _, p := range ctx.DeviceConfig().BuildBrokenPluginValidation() {
+ allowedPluginsByName[p] = true
+ }
+ maybeAddInternalPluginsToAllowlist(ctx)
+
+ disallowedPlugins := map[string]bool{}
+ ctx.VisitAllModulesBlueprint(func(module blueprint.Module) {
+ if ctx.ModuleType(module) != "bootstrap_go_package" {
+ return
+ }
+
+ p, ok := module.(pluginProvider)
+ if !ok || !p.IsPluginFor("soong_build") {
+ return
+ }
+
+ name := ctx.ModuleName(module)
+ if _, ok := allowedPluginsByName[name]; ok {
+ return
+ }
+
+ dir := ctx.ModuleDir(module)
+
+ // allow use of plugins within Soong to not allowlist everything
+ if strings.HasPrefix(dir, "build/soong") {
+ return
+ }
+
+ // allow third party users outside of external to create new plugins, i.e. non-google paths
+ // under vendor or hardware
+ if !strings.HasPrefix(dir, "external/") && IsThirdPartyPath(dir) {
+ return
+ }
+ disallowedPlugins[name] = true
+ })
+ if len(disallowedPlugins) > 0 {
+ ctx.Errorf("New plugins are not supported; however %q were found. Please reach out to the build team or use BUILD_BROKEN_PLUGIN_VALIDATION (see Changes.md for more info).", SortedStringKeys(disallowedPlugins))
+ }
+}
diff --git a/android/register.go b/android/register.go
index 1a3db9d..64b0207 100644
--- a/android/register.go
+++ b/android/register.go
@@ -65,16 +65,19 @@
// True if this should be registered as a pre-singleton, false otherwise.
pre bool
+ // True if this should be registered as a parallel singleton.
+ parallel bool
+
name string
factory SingletonFactory
}
-func newSingleton(name string, factory SingletonFactory) singleton {
- return singleton{false, name, factory}
+func newSingleton(name string, factory SingletonFactory, parallel bool) singleton {
+ return singleton{pre: false, parallel: parallel, name: name, factory: factory}
}
func newPreSingleton(name string, factory SingletonFactory) singleton {
- return singleton{true, name, factory}
+ return singleton{pre: true, parallel: false, name: name, factory: factory}
}
func (s singleton) componentName() string {
@@ -86,7 +89,7 @@
if s.pre {
ctx.RegisterPreSingletonType(s.name, adaptor)
} else {
- ctx.RegisterSingletonType(s.name, adaptor)
+ ctx.RegisterSingletonType(s.name, adaptor, s.parallel)
}
}
@@ -145,8 +148,16 @@
moduleTypeByFactory[factory] = name
}
+func registerSingletonType(name string, factory SingletonFactory, parallel bool) {
+ singletons = append(singletons, newSingleton(name, factory, parallel))
+}
+
func RegisterSingletonType(name string, factory SingletonFactory) {
- singletons = append(singletons, newSingleton(name, factory))
+ registerSingletonType(name, factory, false)
+}
+
+func RegisterParallelSingletonType(name string, factory SingletonFactory) {
+ registerSingletonType(name, factory, true)
}
func RegisterPreSingletonType(name string, factory SingletonFactory) {
@@ -220,17 +231,17 @@
func collateGloballyRegisteredSingletons() sortableComponents {
allSingletons := append(sortableComponents(nil), singletons...)
allSingletons = append(allSingletons,
- singleton{false, "bazeldeps", BazelSingleton},
+ singleton{pre: false, parallel: true, name: "bazeldeps", factory: BazelSingleton},
// Register phony just before makevars so it can write out its phony rules as Make rules
- singleton{false, "phony", phonySingletonFactory},
+ singleton{pre: false, parallel: false, name: "phony", factory: phonySingletonFactory},
// Register makevars after other singletons so they can export values through makevars
- singleton{false, "makevars", makeVarsSingletonFunc},
+ singleton{pre: false, parallel: false, name: "makevars", factory: makeVarsSingletonFunc},
// Register env and ninjadeps last so that they can track all used environment variables and
// Ninja file dependencies stored in the config.
- singleton{false, "ninjadeps", ninjaDepsSingletonFactory},
+ singleton{pre: false, parallel: false, name: "ninjadeps", factory: ninjaDepsSingletonFactory},
)
return allSingletons
@@ -259,7 +270,9 @@
type RegistrationContext interface {
RegisterModuleType(name string, factory ModuleFactory)
RegisterSingletonModuleType(name string, factory SingletonModuleFactory)
+ RegisterParallelSingletonModuleType(name string, factory SingletonModuleFactory)
RegisterPreSingletonType(name string, factory SingletonFactory)
+ RegisterParallelSingletonType(name string, factory SingletonFactory)
RegisterSingletonType(name string, factory SingletonFactory)
PreArchMutators(f RegisterMutatorFunc)
@@ -315,8 +328,15 @@
}
func (ctx *initRegistrationContext) RegisterSingletonModuleType(name string, factory SingletonModuleFactory) {
+ ctx.registerSingletonModuleType(name, factory, false)
+}
+func (ctx *initRegistrationContext) RegisterParallelSingletonModuleType(name string, factory SingletonModuleFactory) {
+ ctx.registerSingletonModuleType(name, factory, true)
+}
+
+func (ctx *initRegistrationContext) registerSingletonModuleType(name string, factory SingletonModuleFactory, parallel bool) {
s, m := SingletonModuleFactoryAdaptor(name, factory)
- ctx.RegisterSingletonType(name, s)
+ ctx.registerSingletonType(name, s, parallel)
ctx.RegisterModuleType(name, m)
// Overwrite moduleTypesForDocs with the original factory instead of the lambda returned by
// SingletonModuleFactoryAdaptor so that docs can find the module type documentation on the
@@ -324,12 +344,20 @@
RegisterModuleTypeForDocs(name, reflect.ValueOf(factory))
}
-func (ctx *initRegistrationContext) RegisterSingletonType(name string, factory SingletonFactory) {
+func (ctx *initRegistrationContext) registerSingletonType(name string, factory SingletonFactory, parallel bool) {
if _, present := ctx.singletonTypes[name]; present {
panic(fmt.Sprintf("singleton type %q is already registered", name))
}
ctx.singletonTypes[name] = factory
- RegisterSingletonType(name, factory)
+ registerSingletonType(name, factory, parallel)
+}
+
+func (ctx *initRegistrationContext) RegisterSingletonType(name string, factory SingletonFactory) {
+ ctx.registerSingletonType(name, factory, false)
+}
+
+func (ctx *initRegistrationContext) RegisterParallelSingletonType(name string, factory SingletonFactory) {
+ ctx.registerSingletonType(name, factory, true)
}
func (ctx *initRegistrationContext) RegisterPreSingletonType(name string, factory SingletonFactory) {
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index 5fa6012..0246a08 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -421,6 +421,57 @@
}).(map[string]blueprint.ModuleFactory)
}
+// tracingConfig is a wrapper to soongconfig.SoongConfig which records all accesses to SoongConfig.
+type tracingConfig struct {
+ config soongconfig.SoongConfig
+ boolSet map[string]bool
+ stringSet map[string]string
+ isSetSet map[string]bool
+}
+
+func (c *tracingConfig) Bool(name string) bool {
+ c.boolSet[name] = c.config.Bool(name)
+ return c.boolSet[name]
+}
+
+func (c *tracingConfig) String(name string) string {
+ c.stringSet[name] = c.config.String(name)
+ return c.stringSet[name]
+}
+
+func (c *tracingConfig) IsSet(name string) bool {
+ c.isSetSet[name] = c.config.IsSet(name)
+ return c.isSetSet[name]
+}
+
+func (c *tracingConfig) getTrace() soongConfigTrace {
+ ret := soongConfigTrace{}
+
+ for k, v := range c.boolSet {
+ ret.Bools = append(ret.Bools, fmt.Sprintf("%q:%t", k, v))
+ }
+ for k, v := range c.stringSet {
+ ret.Strings = append(ret.Strings, fmt.Sprintf("%q:%q", k, v))
+ }
+ for k, v := range c.isSetSet {
+ ret.IsSets = append(ret.IsSets, fmt.Sprintf("%q:%t", k, v))
+ }
+
+ return ret
+}
+
+func newTracingConfig(config soongconfig.SoongConfig) *tracingConfig {
+ c := tracingConfig{
+ config: config,
+ boolSet: make(map[string]bool),
+ stringSet: make(map[string]string),
+ isSetSet: make(map[string]bool),
+ }
+ return &c
+}
+
+var _ soongconfig.SoongConfig = (*tracingConfig)(nil)
+
// configModuleFactory takes an existing soongConfigModuleFactory and a
// ModuleType to create a new ModuleFactory that uses a custom loadhook.
func configModuleFactory(factory blueprint.ModuleFactory, moduleType *soongconfig.ModuleType, bp2build bool) blueprint.ModuleFactory {
@@ -485,8 +536,8 @@
// conditional on Soong config variables by reading the product
// config variables from Make.
AddLoadHook(module, func(ctx LoadHookContext) {
- config := ctx.Config().VendorConfig(moduleType.ConfigNamespace)
- newProps, err := soongconfig.PropertiesToApply(moduleType, conditionalProps, config)
+ tracingConfig := newTracingConfig(ctx.Config().VendorConfig(moduleType.ConfigNamespace))
+ newProps, err := soongconfig.PropertiesToApply(moduleType, conditionalProps, tracingConfig)
if err != nil {
ctx.ModuleErrorf("%s", err)
return
@@ -494,6 +545,8 @@
for _, ps := range newProps {
ctx.AppendProperties(ps)
}
+
+ module.(Module).base().commonProperties.SoongConfigTrace = tracingConfig.getTrace()
})
}
return module, props
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
index cab3e2d..79bdeb8 100644
--- a/android/soong_config_modules_test.go
+++ b/android/soong_config_modules_test.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "path/filepath"
"testing"
)
@@ -34,7 +35,8 @@
type soongConfigTestModule struct {
ModuleBase
DefaultableModuleBase
- props soongConfigTestModuleProperties
+ props soongConfigTestModuleProperties
+ outputPath ModuleOutPath
}
type soongConfigTestModuleProperties struct {
@@ -49,7 +51,9 @@
return m
}
-func (t soongConfigTestModule) GenerateAndroidBuildActions(ModuleContext) {}
+func (t *soongConfigTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ t.outputPath = PathForModuleOut(ctx, "test")
+}
var prepareForSoongConfigTestModule = FixtureRegisterWithContext(func(ctx RegistrationContext) {
ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory)
@@ -503,3 +507,197 @@
})
}
}
+
+func TestSoongConfigModuleTrace(t *testing.T) {
+ bp := `
+ soong_config_module_type {
+ name: "acme_test",
+ module_type: "test",
+ config_namespace: "acme",
+ variables: ["board", "feature1", "FEATURE3", "unused_string_var"],
+ bool_variables: ["feature2", "unused_feature", "always_true"],
+ value_variables: ["size", "unused_size"],
+ properties: ["cflags", "srcs", "defaults"],
+ }
+
+ soong_config_module_type {
+ name: "acme_test_defaults",
+ module_type: "test_defaults",
+ config_namespace: "acme",
+ variables: ["board", "feature1", "FEATURE3", "unused_string_var"],
+ bool_variables: ["feature2", "unused_feature", "always_true"],
+ value_variables: ["size", "unused_size"],
+ properties: ["cflags", "srcs", "defaults"],
+ }
+
+ soong_config_string_variable {
+ name: "board",
+ values: ["soc_a", "soc_b", "soc_c"],
+ }
+
+ soong_config_string_variable {
+ name: "unused_string_var",
+ values: ["a", "b"],
+ }
+
+ soong_config_bool_variable {
+ name: "feature1",
+ }
+
+ soong_config_bool_variable {
+ name: "FEATURE3",
+ }
+
+ test_defaults {
+ name: "test_defaults",
+ cflags: ["DEFAULT"],
+ }
+
+ test {
+ name: "normal",
+ defaults: ["test_defaults"],
+ }
+
+ acme_test {
+ name: "board_1",
+ defaults: ["test_defaults"],
+ soong_config_variables: {
+ board: {
+ soc_a: {
+ cflags: ["-DSOC_A"],
+ },
+ },
+ },
+ }
+
+ acme_test {
+ name: "board_2",
+ defaults: ["test_defaults"],
+ soong_config_variables: {
+ board: {
+ soc_a: {
+ cflags: ["-DSOC_A"],
+ },
+ },
+ },
+ }
+
+ acme_test {
+ name: "size",
+ defaults: ["test_defaults"],
+ soong_config_variables: {
+ size: {
+ cflags: ["-DSIZE=%s"],
+ },
+ },
+ }
+
+ acme_test {
+ name: "board_and_size",
+ defaults: ["test_defaults"],
+ soong_config_variables: {
+ board: {
+ soc_a: {
+ cflags: ["-DSOC_A"],
+ },
+ },
+ size: {
+ cflags: ["-DSIZE=%s"],
+ },
+ },
+ }
+
+ acme_test_defaults {
+ name: "board_defaults",
+ soong_config_variables: {
+ board: {
+ soc_a: {
+ cflags: ["-DSOC_A"],
+ },
+ },
+ },
+ }
+
+ acme_test_defaults {
+ name: "size_defaults",
+ soong_config_variables: {
+ size: {
+ cflags: ["-DSIZE=%s"],
+ },
+ },
+ }
+
+ test {
+ name: "board_and_size_with_defaults",
+ defaults: ["board_defaults", "size_defaults"],
+ }
+ `
+
+ fixtureForVendorVars := func(vars map[string]map[string]string) FixturePreparer {
+ return FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+ variables.VendorVars = vars
+ })
+ }
+
+ preparer := fixtureForVendorVars(map[string]map[string]string{
+ "acme": {
+ "board": "soc_a",
+ "size": "42",
+ "feature1": "true",
+ "feature2": "false",
+ // FEATURE3 unset
+ "unused_feature": "true", // unused
+ "unused_size": "1", // unused
+ "unused_string_var": "a", // unused
+ "always_true": "true",
+ },
+ })
+
+ t.Run("soong config trace hash", func(t *testing.T) {
+ result := GroupFixturePreparers(
+ preparer,
+ PrepareForTestWithDefaults,
+ PrepareForTestWithSoongConfigModuleBuildComponents,
+ prepareForSoongConfigTestModule,
+ FixtureRegisterWithContext(func(ctx RegistrationContext) {
+ ctx.FinalDepsMutators(registerSoongConfigTraceMutator)
+ }),
+ FixtureWithRootAndroidBp(bp),
+ ).RunTest(t)
+
+ // Hashes of modules not using soong config should be empty
+ normal := result.ModuleForTests("normal", "").Module().(*soongConfigTestModule)
+ AssertDeepEquals(t, "normal hash", normal.base().commonProperties.SoongConfigTraceHash, "")
+ AssertDeepEquals(t, "normal hash out", normal.outputPath.RelativeToTop().String(), "out/soong/.intermediates/normal/test")
+
+ board1 := result.ModuleForTests("board_1", "").Module().(*soongConfigTestModule)
+ board2 := result.ModuleForTests("board_2", "").Module().(*soongConfigTestModule)
+ size := result.ModuleForTests("size", "").Module().(*soongConfigTestModule)
+
+ // Trace mutator sets soong config trace hash correctly
+ board1Hash := board1.base().commonProperties.SoongConfigTrace.hash()
+ board1Output := board1.outputPath.RelativeToTop().String()
+ AssertDeepEquals(t, "board hash calc", board1Hash, board1.base().commonProperties.SoongConfigTraceHash)
+ AssertDeepEquals(t, "board hash path", board1Output, filepath.Join("out/soong/.intermediates/board_1", board1Hash, "test"))
+
+ sizeHash := size.base().commonProperties.SoongConfigTrace.hash()
+ sizeOutput := size.outputPath.RelativeToTop().String()
+ AssertDeepEquals(t, "size hash calc", sizeHash, size.base().commonProperties.SoongConfigTraceHash)
+ AssertDeepEquals(t, "size hash path", sizeOutput, filepath.Join("out/soong/.intermediates/size", sizeHash, "test"))
+
+ // Trace should be identical for modules using the same set of variables
+ AssertDeepEquals(t, "board trace", board1.base().commonProperties.SoongConfigTrace, board2.base().commonProperties.SoongConfigTrace)
+ AssertDeepEquals(t, "board hash", board1.base().commonProperties.SoongConfigTraceHash, board2.base().commonProperties.SoongConfigTraceHash)
+
+ // Trace hash should be different for different sets of soong variables
+ AssertBoolEquals(t, "board hash not equal to size hash", board1.base().commonProperties.SoongConfigTraceHash == size.commonProperties.SoongConfigTraceHash, false)
+
+ boardSize := result.ModuleForTests("board_and_size", "").Module().(*soongConfigTestModule)
+ boardSizeDefaults := result.ModuleForTests("board_and_size_with_defaults", "").Module()
+
+ // Trace should propagate
+ AssertDeepEquals(t, "board_size hash calc", boardSize.base().commonProperties.SoongConfigTrace.hash(), boardSize.base().commonProperties.SoongConfigTraceHash)
+ AssertDeepEquals(t, "board_size trace", boardSize.base().commonProperties.SoongConfigTrace, boardSizeDefaults.base().commonProperties.SoongConfigTrace)
+ AssertDeepEquals(t, "board_size hash", boardSize.base().commonProperties.SoongConfigTraceHash, boardSizeDefaults.base().commonProperties.SoongConfigTraceHash)
+ })
+}
diff --git a/android/test_asserts.go b/android/test_asserts.go
index 4143f15..5cc7e4a 100644
--- a/android/test_asserts.go
+++ b/android/test_asserts.go
@@ -17,6 +17,7 @@
import (
"fmt"
"reflect"
+ "regexp"
"strings"
"testing"
)
@@ -137,6 +138,20 @@
}
}
+// AssertStringMatches checks if the string matches the given regular expression. If it does not match,
+// then an error is reported with the supplied message including a reason for why it failed.
+func AssertStringMatches(t *testing.T, message, s, expectedRex string) {
+ t.Helper()
+ ok, err := regexp.MatchString(expectedRex, s)
+ if err != nil {
+ t.Fatalf("regexp failure trying to match %s against `%s` expression: %s", s, expectedRex, err)
+ return
+ }
+ if !ok {
+ t.Errorf("%s does not match regular expression %s", s, expectedRex)
+ }
+}
+
// AssertStringListContains checks if the list of strings contains the expected string. If it does
// not then it reports an error prefixed with the supplied message and including a reason for why it
// failed.
diff --git a/android/test_suites.go b/android/test_suites.go
index b570b23..b48d71a 100644
--- a/android/test_suites.go
+++ b/android/test_suites.go
@@ -15,7 +15,7 @@
package android
func init() {
- RegisterSingletonType("testsuites", testSuiteFilesFactory)
+ RegisterParallelSingletonType("testsuites", testSuiteFilesFactory)
}
func testSuiteFilesFactory() Singleton {
diff --git a/android/testing.go b/android/testing.go
index 2a9c658..5ad7ad0 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -495,8 +495,18 @@
ctx.RegisterModuleType(name, m)
}
+func (ctx *TestContext) RegisterParallelSingletonModuleType(name string, factory SingletonModuleFactory) {
+ s, m := SingletonModuleFactoryAdaptor(name, factory)
+ ctx.RegisterParallelSingletonType(name, s)
+ ctx.RegisterModuleType(name, m)
+}
+
func (ctx *TestContext) RegisterSingletonType(name string, factory SingletonFactory) {
- ctx.singletons = append(ctx.singletons, newSingleton(name, factory))
+ ctx.singletons = append(ctx.singletons, newSingleton(name, factory, false))
+}
+
+func (ctx *TestContext) RegisterParallelSingletonType(name string, factory SingletonFactory) {
+ ctx.singletons = append(ctx.singletons, newSingleton(name, factory, true))
}
func (ctx *TestContext) RegisterPreSingletonType(name string, factory SingletonFactory) {
diff --git a/android/variable.go b/android/variable.go
index 97171e7..9fb2537 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -420,8 +420,6 @@
TargetFSConfigGen []string `json:",omitempty"`
- MissingUsesLibraries []string `json:",omitempty"`
-
EnforceProductPartitionInterface *bool `json:",omitempty"`
EnforceInterPartitionJavaSdkLibrary *bool `json:",omitempty"`
@@ -440,16 +438,19 @@
ShippingApiLevel *string `json:",omitempty"`
+ BuildBrokenPluginValidation []string `json:",omitempty"`
BuildBrokenClangAsFlags bool `json:",omitempty"`
BuildBrokenClangCFlags bool `json:",omitempty"`
BuildBrokenClangProperty bool `json:",omitempty"`
- BuildBrokenDepfile *bool `json:",omitempty"`
+ GenruleSandboxing *bool `json:",omitempty"`
BuildBrokenEnforceSyspropOwner bool `json:",omitempty"`
BuildBrokenTrebleSyspropNeverallow bool `json:",omitempty"`
BuildBrokenUsesSoongPython2Modules bool `json:",omitempty"`
BuildBrokenVendorPropertyNamespace bool `json:",omitempty"`
BuildBrokenInputDirModules []string `json:",omitempty"`
+ BuildWarningBadOptionalUsesLibsAllowlist []string `json:",omitempty"`
+
BuildDebugfsRestrictionsEnabled bool `json:",omitempty"`
RequiresInsecureExecmemForSwiftshader bool `json:",omitempty"`
@@ -847,6 +848,9 @@
// indirections to extract the struct from the reflect.Value.
if v, ok := maybeExtractConfigVarProp(variableStruct); ok {
variableStruct = v
+ } else if !v.IsValid() {
+ // Skip invalid variables which may not used, else leads to panic
+ continue
}
for j := 0; j < variableStruct.NumField(); j++ {
diff --git a/android_sdk/sdk_repo_host.go b/android_sdk/sdk_repo_host.go
index 61058df..9623a8b 100644
--- a/android_sdk/sdk_repo_host.go
+++ b/android_sdk/sdk_repo_host.go
@@ -242,7 +242,7 @@
fmt.Fprintln(w, ".PHONY:", name, "sdk_repo", "sdk-repo-"+name)
fmt.Fprintln(w, "sdk_repo", "sdk-repo-"+name+":", strings.Join(s.FilesToInstall().Strings(), " "))
- fmt.Fprintf(w, "$(call dist-for-goals,sdk_repo sdk-repo-%s,%s:%s-$(FILE_NAME_TAG).zip)\n\n", s.BaseModuleName(), s.outputFile.String(), s.outputBaseName)
+ fmt.Fprintf(w, "$(call dist-for-goals,sdk_repo sdk-repo-%s,%s:%s-FILE_NAME_TAG_PLACEHOLDER.zip)\n\n", s.BaseModuleName(), s.outputFile.String(), s.outputBaseName)
},
}
}
diff --git a/apex/apex.go b/apex/apex.go
index 1c79463..f49492e 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1871,14 +1871,17 @@
}); ok {
af.overriddenPackageName = app.OverriddenManifestPackageName()
}
- apexFiles := []apexFile{af}
+
+ apexFiles := []apexFile{}
if allowlist := aapp.PrivAppAllowlist(); allowlist.Valid() {
dirInApex := filepath.Join("etc", "permissions")
- privAppAllowlist := newApexFile(ctx, allowlist.Path(), aapp.BaseModuleName()+"privapp", dirInApex, etc, aapp)
+ privAppAllowlist := newApexFile(ctx, allowlist.Path(), aapp.BaseModuleName()+"_privapp", dirInApex, etc, aapp)
apexFiles = append(apexFiles, privAppAllowlist)
}
+ apexFiles = append(apexFiles, af)
+
return apexFiles
}
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index ebc35cf..a63344f 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -27,7 +27,7 @@
}
func registerApexDepsInfoComponents(ctx android.RegistrationContext) {
- ctx.RegisterSingletonType("apex_depsinfo_singleton", apexDepsInfoSingletonFactory)
+ ctx.RegisterParallelSingletonType("apex_depsinfo_singleton", apexDepsInfoSingletonFactory)
}
type apexDepsInfoSingleton struct {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index c1d80a3..38e24e8 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -6260,8 +6260,7 @@
sdk_version: "current",
system_modules: "none",
privileged: true,
- privapp_allowlist: "perms.xml",
- package_name: "com.android.AppFooPriv",
+ privapp_allowlist: "privapp_allowlist_com.android.AppFooPriv.xml",
stl: "none",
apex_available: [ "myapex" ],
}
@@ -6306,6 +6305,18 @@
// ... and not directly inside the APEX
ensureNotContains(t, copyCmds, "image.apex/lib64/"+jni+".so")
}
+
+ apexBundle := module.Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, ctx, apexBundle)
+ var builder strings.Builder
+ data.Custom(&builder, apexBundle.Name(), "TARGET_", "", data)
+ androidMk := builder.String()
+ ensureContains(t, androidMk, "LOCAL_MODULE := AppFooPriv.myapex")
+ ensureContains(t, androidMk, "LOCAL_MODULE := AppFoo.myapex")
+ ensureMatches(t, androidMk, "LOCAL_SOONG_INSTALLED_MODULE := \\S+AppFooPriv.apk")
+ ensureMatches(t, androidMk, "LOCAL_SOONG_INSTALLED_MODULE := \\S+AppFoo.apk")
+ ensureMatches(t, androidMk, "LOCAL_SOONG_INSTALL_PAIRS := \\S+AppFooPriv.apk")
+ ensureContains(t, androidMk, "LOCAL_SOONG_INSTALL_PAIRS := privapp_allowlist_com.android.AppFooPriv.xml:$(PRODUCT_OUT)/apex/myapex/etc/permissions/privapp_allowlist_com.android.AppFooPriv.xml")
}
func TestApexWithAppImportBuildId(t *testing.T) {
diff --git a/apex/key.go b/apex/key.go
index 0a7e80f..3010d76 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -33,7 +33,7 @@
func registerApexKeyBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("apex_key", ApexKeyFactory)
- ctx.RegisterSingletonType("apex_keys_text", apexKeysTextFactory)
+ ctx.RegisterParallelSingletonType("apex_keys_text", apexKeysTextFactory)
}
type apexKey struct {
diff --git a/bazel/bazel_proxy.go b/bazel/bazel_proxy.go
index 2940b99..229818d 100644
--- a/bazel/bazel_proxy.go
+++ b/bazel/bazel_proxy.go
@@ -26,10 +26,11 @@
"time"
)
-// Logs fatal events of ProxyServer.
+// Logs events of ProxyServer.
type ServerLogger interface {
Fatal(v ...interface{})
Fatalf(format string, v ...interface{})
+ Println(v ...interface{})
}
// CmdRequest is a request to the Bazel Proxy server.
@@ -71,9 +72,10 @@
// The ProxyServer will only live as long as soong_ui does; the
// underlying Bazel server will live past the duration of the build.
type ProxyServer struct {
- logger ServerLogger
- outDir string
- workspaceDir string
+ logger ServerLogger
+ outDir string
+ workspaceDir string
+ bazeliskVersion string
// The server goroutine will listen on this channel and stop handling requests
// once it is written to.
done chan struct{}
@@ -119,12 +121,17 @@
}
// NewProxyServer is a constructor for a ProxyServer.
-func NewProxyServer(logger ServerLogger, outDir string, workspaceDir string) *ProxyServer {
+func NewProxyServer(logger ServerLogger, outDir string, workspaceDir string, bazeliskVersion string) *ProxyServer {
+ if len(bazeliskVersion) > 0 {
+ logger.Println("** Using Bazelisk for this build, due to env var USE_BAZEL_VERSION=" + bazeliskVersion + " **")
+ }
+
return &ProxyServer{
- logger: logger,
- outDir: outDir,
- workspaceDir: workspaceDir,
- done: make(chan struct{}),
+ logger: logger,
+ outDir: outDir,
+ workspaceDir: workspaceDir,
+ done: make(chan struct{}),
+ bazeliskVersion: bazeliskVersion,
}
}
@@ -155,6 +162,9 @@
return fmt.Errorf("Error decoding request: %s", err)
}
+ if len(b.bazeliskVersion) > 0 {
+ req.Env = append(req.Env, "USE_BAZEL_VERSION="+b.bazeliskVersion)
+ }
stdout, stderr, cmdErr := ExecBazel("./build/bazel/bin/bazel", b.workspaceDir, req)
errorString := ""
if cmdErr != nil {
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index 6a3b3c8..ca96f23 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -8,7 +8,6 @@
var (
GetOutputFiles = &getOutputFilesRequestType{}
- GetPythonBinary = &getPythonBinaryRequestType{}
GetCcInfo = &getCcInfoType{}
GetApexInfo = &getApexInfoType{}
GetCcUnstrippedInfo = &getCcUnstrippedInfoType{}
@@ -45,8 +44,6 @@
type getOutputFilesRequestType struct{}
-type getPythonBinaryRequestType struct{}
-
// Name returns a string name for this request type. Such request type names must be unique,
// and must only consist of alphanumeric characters.
func (g getOutputFilesRequestType) Name() string {
@@ -72,31 +69,6 @@
return splitOrEmpty(rawString, ", ")
}
-// Name returns a string name for this request type. Such request type names must be unique,
-// and must only consist of alphanumeric characters.
-func (g getPythonBinaryRequestType) Name() string {
- return "getPythonBinary"
-}
-
-// StarlarkFunctionBody returns a starlark function body to process this request type.
-// The returned string is the body of a Starlark function which obtains
-// all request-relevant information about a target and returns a string containing
-// this information.
-// The function should have the following properties:
-// - The arguments are `target` (a configured target) and `id_string` (the label + configuration).
-// - The return value must be a string.
-// - The function body should not be indented outside of its own scope.
-func (g getPythonBinaryRequestType) StarlarkFunctionBody() string {
- return "return providers(target)['FilesToRunProvider'].executable.path"
-}
-
-// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
-// The given rawString must correspond to the string output which was created by evaluating the
-// Starlark given in StarlarkFunctionBody.
-func (g getPythonBinaryRequestType) ParseResult(rawString string) string {
- return rawString
-}
-
type getCcInfoType struct{}
// Name returns a string name for this request type. Such request type names must be unique,
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
index 7003ce1..e772bb7 100644
--- a/bazel/cquery/request_type_test.go
+++ b/bazel/cquery/request_type_test.go
@@ -40,34 +40,6 @@
}
}
-func TestGetPythonBinaryParseResults(t *testing.T) {
- t.Parallel()
- testCases := []struct {
- description string
- input string
- expectedOutput string
- }{
- {
- description: "no result",
- input: "",
- expectedOutput: "",
- },
- {
- description: "one result",
- input: "test",
- expectedOutput: "test",
- },
- }
- for _, tc := range testCases {
- t.Run(tc.description, func(t *testing.T) {
- actualOutput := GetPythonBinary.ParseResult(tc.input)
- if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
- t.Errorf("expected %#v != actual %#v", tc.expectedOutput, actualOutput)
- }
- })
- }
-}
-
func TestGetCcInfoParseResults(t *testing.T) {
t.Parallel()
testCases := []struct {
diff --git a/bloaty/bloaty.go b/bloaty/bloaty.go
index 50f241f..3cff60f 100644
--- a/bloaty/bloaty.go
+++ b/bloaty/bloaty.go
@@ -51,7 +51,7 @@
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)
+ android.RegisterParallelSingletonType("file_metrics", fileSizesSingleton)
fileSizeMeasurerKey = blueprint.NewProvider(measuredFiles{})
}
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 9ec3a40..4ecd05d 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -72,7 +72,6 @@
"license_conversion_test.go",
"license_kind_conversion_test.go",
"linker_config_conversion_test.go",
- "ndk_headers_conversion_test.go",
"package_conversion_test.go",
"performance_test.go",
"prebuilt_etc_conversion_test.go",
diff --git a/bp2build/bp2build_product_config.go b/bp2build/bp2build_product_config.go
index 3abef9d..66d0cc5 100644
--- a/bp2build/bp2build_product_config.go
+++ b/bp2build/bp2build_product_config.go
@@ -68,6 +68,14 @@
"@//build/bazel/product_config:__subpackages__",
"@soong_injection//product_config_platforms:__subpackages__",
])
+
+load("//{PRODUCT_FOLDER}:soong.variables.bzl", _soong_variables = "variables")
+load("@//build/bazel/product_config:android_product.bzl", "android_product")
+
+android_product(
+ name = "current_product-{VARIANT}",
+ soong_variables = _soong_variables,
+)
`)),
newFile(
"product_config_platforms",
@@ -78,6 +86,7 @@
# TODO: When we start generating the platforms for more than just the
# currently lunched product, they should all be listed here
product_labels = [
+ "@soong_injection//product_config_platforms:current_product-{VARIANT}",
"@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"
]
`)),
@@ -85,25 +94,30 @@
"product_config_platforms",
"common.bazelrc",
productReplacer.Replace(`
-build --platforms @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
+# current_product refers to the current TARGET_PRODUCT set, usually through
+# 'lunch' or 'banchan'. Every build will have a primary TARGET_PRODUCT, but
+# bazel supports using other products in tests or configuration transitions. The
+# other products can be found in
+# @soong_injection//product_config_platforms/products/...
+build --platforms @soong_injection//product_config_platforms:current_product-{VARIANT}_linux_x86_64
-build:android --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}
-build:linux_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
-build:linux_bionic_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_bionic_x86_64
-build:linux_musl_x86 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86
-build:linux_musl_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86_64
+build:android --platforms=@soong_injection//product_config_platforms:current_product-{VARIANT}
+build:linux_x86_64 --platforms=@soong_injection//product_config_platforms:current_product-{VARIANT}_linux_x86_64
+build:linux_bionic_x86_64 --platforms=@soong_injection//product_config_platforms:current_product-{VARIANT}_linux_bionic_x86_64
+build:linux_musl_x86 --platforms=@soong_injection//product_config_platforms:current_product-{VARIANT}_linux_musl_x86
+build:linux_musl_x86_64 --platforms=@soong_injection//product_config_platforms:current_product-{VARIANT}_linux_musl_x86_64
`)),
newFile(
"product_config_platforms",
"linux.bazelrc",
productReplacer.Replace(`
-build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
+build --host_platform @soong_injection//product_config_platforms:current_product-{VARIANT}_linux_x86_64
`)),
newFile(
"product_config_platforms",
"darwin.bazelrc",
productReplacer.Replace(`
-build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_darwin_x86_64
+build --host_platform product_config_platforms:current_product-{VARIANT}_darwin_x86_64
`)),
newFile(
"product_config_platforms",
@@ -111,7 +125,7 @@
productReplacer.Replace(`
flags:
--cpu=k8
- @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}
+ @soong_injection//product_config_platforms:current_product-{VARIANT}
`)),
}
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index 6ec3703..8a83cc0 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -222,6 +222,7 @@
"-Wl,--version-script,$(location vs)",
"-Wl,--dynamic-list,$(location dynamic.list)",
]`,
+ "features": `["android_cfi_exports_map"]`,
},
},
},
@@ -249,6 +250,7 @@
"version_script",
"dynamic.list",
]`,
+ "features": `["android_cfi_exports_map"]`,
"linkopts": `[
"--nospace_flag",
"-z",
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 0e8705b..3dd9373 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -900,7 +900,8 @@
"-Wl,--version-script,$(location v.map)",
"-Wl,--dynamic-list,$(location dynamic.list)",
]`,
- "srcs": `["a.cpp"]`,
+ "srcs": `["a.cpp"]`,
+ "features": `["android_cfi_exports_map"]`,
}),
},
)
@@ -958,6 +959,11 @@
"//conditions:default": [],
})`,
"srcs": `["a.cpp"]`,
+ "features": `select({
+ "//build/bazel/platforms/arch:arm": ["android_cfi_exports_map"],
+ "//build/bazel/platforms/arch:arm64": ["android_cfi_exports_map"],
+ "//conditions:default": [],
+ })`,
}),
},
)
@@ -985,12 +991,15 @@
}
`,
ExpectedBazelTargets: []string{
- MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{}),
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "features": `["android_cfi_exports_map"]`,
+ }),
MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
"additional_linker_inputs": `[
"version_script",
"dynamic.list",
]`,
+ "features": `["android_cfi_exports_map"]`,
"linkopts": `[
"--nospace_flag",
"-z",
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index 2ee9c99..6c9f9a1 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -362,6 +362,7 @@
"-Wl,--version-script,$(location version_script)",
"-Wl,--dynamic-list,$(location dynamic.list)",
]`,
+ "features": `["android_cfi_exports_map"]`,
}),
},
})
@@ -398,6 +399,7 @@
"-Wl,--version-script,$(location version_script)",
"-Wl,--dynamic-list,$(location dynamic.list)",
]`,
+ "features": `["android_cfi_exports_map"]`,
}),
},
})
@@ -913,6 +915,7 @@
"header.h",
]`,
"linkopts": `["-Wl,--version-script,$(location version_script)"]`,
+ "features": `["android_cfi_exports_map"]`,
}),
},
})
diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go
index 60766f4..fd92e95 100644
--- a/bp2build/java_library_conversion_test.go
+++ b/bp2build/java_library_conversion_test.go
@@ -826,3 +826,43 @@
},
})
}
+
+func TestJavaLibraryJavaResourcesSingleFilegroup(t *testing.T) {
+ runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
+ Filesystem: map[string]string{
+ "res/a.res": "",
+ "res/b.res": "",
+ "res/dir1/b.res": "",
+ },
+ Description: "java_library",
+ Blueprint: `java_library {
+ name: "java-lib-1",
+ srcs: ["a.java"],
+ java_resources: [":filegroup1"],
+ bazel_module: { bp2build_available: true },
+}
+
+filegroup {
+ name: "filegroup1",
+ path: "foo",
+ srcs: ["foo/a", "foo/b"],
+}
+
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
+ "srcs": `["a.java"]`,
+ "resources": `[":filegroup1"]`,
+ "resource_strip_prefix": `"foo"`,
+ }),
+ MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
+ MakeBazelTargetNoRestrictions("filegroup", "filegroup1", AttrNameToString{
+ "srcs": `[
+ "foo/a",
+ "foo/b",
+ ]`}),
+ },
+ }, func(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+ })
+}
diff --git a/bp2build/java_test_host_conversion_test.go b/bp2build/java_test_host_conversion_test.go
new file mode 100644
index 0000000..f411ffb
--- /dev/null
+++ b/bp2build/java_test_host_conversion_test.go
@@ -0,0 +1,149 @@
+// Copyright 2023 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 (
+ "testing"
+
+ "android/soong/android"
+ "android/soong/java"
+)
+
+func runJavaTestHostTestCase(t *testing.T, tc Bp2buildTestCase) {
+ t.Helper()
+ (&tc).ModuleTypeUnderTest = "java_test_host"
+ (&tc).ModuleTypeUnderTestFactory = java.TestHostFactory
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("java_library", java.LibraryFactory)
+ }, tc)
+}
+
+func TestJavaTestHostGeneral(t *testing.T) {
+ runJavaTestHostTestCase(t, Bp2buildTestCase{
+ Description: "java_test_host general",
+ Filesystem: map[string]string{},
+ Blueprint: `
+java_test_host {
+ name: "java_test_host-1",
+ srcs: ["a.java", "b.java"],
+ libs: ["lib_a"],
+ static_libs: ["static_libs_a"],
+ exclude_srcs: ["b.java"],
+ javacflags: ["-Xdoclint:all/protected"],
+ java_version: "8",
+}
+
+java_library {
+ name: "lib_a",
+ bazel_module: { bp2build_available: false },
+}
+
+java_library {
+ name: "static_libs_a",
+ bazel_module: { bp2build_available: false },
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("java_library", "java_test_host-1_lib", AttrNameToString{
+ "deps": `[
+ ":lib_a-neverlink",
+ ":static_libs_a",
+ ]`,
+ "java_version": `"8"`,
+ "javacopts": `["-Xdoclint:all/protected"]`,
+ "srcs": `["a.java"]`,
+ "target_compatible_with": `select({
+ "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ })`,
+ }),
+ MakeBazelTarget("java_test", "java_test_host-1", AttrNameToString{
+ "runtime_deps": `[":java_test_host-1_lib"]`,
+ "target_compatible_with": `select({
+ "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ })`,
+ }),
+ },
+ })
+}
+
+func TestJavaTestHostNoSrcs(t *testing.T) {
+ runJavaTestHostTestCase(t, Bp2buildTestCase{
+ Description: "java_test_host without srcs",
+ Filesystem: map[string]string{},
+ Blueprint: `
+java_test_host {
+ name: "java_test_host-1",
+ libs: ["lib_a"],
+ static_libs: ["static_libs_a"],
+}
+
+java_library {
+ name: "lib_a",
+ bazel_module: { bp2build_available: false },
+}
+
+java_library {
+ name: "static_libs_a",
+ bazel_module: { bp2build_available: false },
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("java_test", "java_test_host-1", AttrNameToString{
+ "runtime_deps": `[
+ ":lib_a-neverlink",
+ ":static_libs_a",
+ ]`,
+ "target_compatible_with": `select({
+ "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ })`,
+ }),
+ },
+ })
+}
+
+func TestJavaTestHostKotlinSrcs(t *testing.T) {
+ runJavaTestHostTestCase(t, Bp2buildTestCase{
+ Description: "java_test_host with .kt in srcs",
+ Filesystem: map[string]string{},
+ Blueprint: `
+java_test_host {
+ name: "java_test_host-1",
+ srcs: ["a.java", "b.kt"],
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("java_test", "java_test_host-1", AttrNameToString{
+ "runtime_deps": `[":java_test_host-1_lib"]`,
+ "target_compatible_with": `select({
+ "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ })`,
+ }),
+ MakeBazelTarget("kt_jvm_library", "java_test_host-1_lib", AttrNameToString{
+ "srcs": `[
+ "a.java",
+ "b.kt",
+ ]`,
+ "target_compatible_with": `select({
+ "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ })`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/ndk_headers_conversion_test.go b/bp2build/ndk_headers_conversion_test.go
deleted file mode 100644
index 9d0f1f2..0000000
--- a/bp2build/ndk_headers_conversion_test.go
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
- "fmt"
- "testing"
-
- "android/soong/cc"
-)
-
-func TestNdkHeaderFilepaths(t *testing.T) {
- bpTemplate := `
- ndk_headers {
- name: "foo",
- srcs: %v,
- exclude_srcs: %v,
- }
- `
- testCases := []struct {
- desc string
- srcs string
- excludeSrcs string
- expectedHdrs string
- }{
- {
- desc: "Single header file",
- srcs: `["foo.h"]`,
- excludeSrcs: `[]`,
- expectedHdrs: `["foo.h"]`,
- },
- {
- desc: "Multiple header files",
- srcs: `["foo.h", "foo_other.h"]`,
- excludeSrcs: `[]`,
- expectedHdrs: `[
- "foo.h",
- "foo_other.h",
- ]`,
- },
- {
- desc: "Multiple header files with excludes",
- srcs: `["foo.h", "foo_other.h"]`,
- excludeSrcs: `["foo_other.h"]`,
- expectedHdrs: `["foo.h"]`,
- },
- {
- desc: "Multiple header files via Soong-supported globs",
- srcs: `["*.h"]`,
- excludeSrcs: `[]`,
- expectedHdrs: `[
- "foo.h",
- "foo_other.h",
- ]`,
- },
- }
- for _, testCase := range testCases {
- fs := map[string]string{
- "foo.h": "",
- "foo_other.h": "",
- }
- expectedApiContributionTargetName := "foo.contribution"
- expectedBazelTarget := MakeBazelTargetNoRestrictions(
- "cc_api_headers",
- expectedApiContributionTargetName,
- AttrNameToString{
- "hdrs": testCase.expectedHdrs,
- },
- )
- RunApiBp2BuildTestCase(t, cc.RegisterNdkModuleTypes, Bp2buildTestCase{
- Description: testCase.desc,
- Blueprint: fmt.Sprintf(bpTemplate, testCase.srcs, testCase.excludeSrcs),
- ExpectedBazelTargets: []string{expectedBazelTarget},
- Filesystem: fs,
- })
- }
-}
-
-func TestNdkHeaderIncludeDir(t *testing.T) {
- bpTemplate := `
- ndk_headers {
- name: "foo",
- from: %v,
- to: "this/value/is/ignored",
- }
- `
- testCases := []struct {
- desc string
- from string
- expectedIncludeDir string
- }{
- {
- desc: "Empty `from` value",
- from: `""`,
- expectedIncludeDir: `""`,
- },
- {
- desc: "Non-Empty `from` value",
- from: `"include"`,
- expectedIncludeDir: `"include"`,
- },
- }
- for _, testCase := range testCases {
- expectedApiContributionTargetName := "foo.contribution"
- expectedBazelTarget := MakeBazelTargetNoRestrictions(
- "cc_api_headers",
- expectedApiContributionTargetName,
- AttrNameToString{
- "include_dir": testCase.expectedIncludeDir,
- },
- )
- RunApiBp2BuildTestCase(t, cc.RegisterNdkModuleTypes, Bp2buildTestCase{
- Description: testCase.desc,
- Blueprint: fmt.Sprintf(bpTemplate, testCase.from),
- ExpectedBazelTargets: []string{expectedBazelTarget},
- })
- }
-}
-
-func TestVersionedNdkHeaderFilepaths(t *testing.T) {
- bp := `
- versioned_ndk_headers {
- name: "common_libc",
- from: "include"
- }
- `
- fs := map[string]string{
- "include/math.h": "",
- "include/stdio.h": "",
- "include/arm/arm.h": "",
- "include/x86/x86.h": "",
- }
- expectedApiContributionTargetName := "common_libc.contribution"
- expectedBazelTarget := MakeBazelTargetNoRestrictions(
- "cc_api_headers",
- expectedApiContributionTargetName,
- AttrNameToString{
- "include_dir": `"include"`,
- "hdrs": `[
- "include/math.h",
- "include/stdio.h",
- "include/arm/arm.h",
- "include/x86/x86.h",
- ]`,
- },
- )
- RunApiBp2BuildTestCase(t, cc.RegisterNdkModuleTypes, Bp2buildTestCase{
- Blueprint: bp,
- Filesystem: fs,
- ExpectedBazelTargets: []string{expectedBazelTarget},
- })
-}
diff --git a/bp2build/ndk_library_conversion_test.go b/bp2build/ndk_library_conversion_test.go
deleted file mode 100644
index 819ab25..0000000
--- a/bp2build/ndk_library_conversion_test.go
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
- "testing"
-
- "android/soong/cc"
-)
-
-func TestNdkLibraryContributionSymbolFile(t *testing.T) {
- bp := `
- ndk_library {
- name: "libfoo",
- symbol_file: "libfoo.map.txt",
- }
- `
- expectedBazelTarget := MakeBazelTargetNoRestrictions(
- "cc_api_contribution",
- "libfoo.ndk.contribution",
- AttrNameToString{
- "api": `"libfoo.map.txt"`,
- "api_surfaces": `["publicapi"]`,
- "library_name": `"libfoo"`,
- "target_compatible_with": `["//build/bazel/platforms/os:android"]`,
- },
- )
- RunApiBp2BuildTestCase(t, cc.RegisterNdkModuleTypes, Bp2buildTestCase{
- Blueprint: bp,
- ExpectedBazelTargets: []string{expectedBazelTarget},
- })
-}
-
-func TestNdkLibraryContributionHeaders(t *testing.T) {
- bp := `
- ndk_library {
- name: "libfoo",
- symbol_file: "libfoo.map.txt",
- export_header_libs: ["libfoo_headers"],
- }
- `
- fs := map[string]string{
- "header_directory/Android.bp": `
- ndk_headers {
- name: "libfoo_headers",
- }
- `,
- }
- expectedBazelTarget := MakeBazelTargetNoRestrictions(
- "cc_api_contribution",
- "libfoo.ndk.contribution",
- AttrNameToString{
- "api": `"libfoo.map.txt"`,
- "api_surfaces": `["publicapi"]`,
- "library_name": `"libfoo"`,
- "hdrs": `["//header_directory:libfoo_headers.contribution"]`,
- "target_compatible_with": `["//build/bazel/platforms/os:android"]`,
- },
- )
- RunApiBp2BuildTestCase(t, cc.RegisterNdkModuleTypes, Bp2buildTestCase{
- Blueprint: bp,
- Filesystem: fs,
- ExpectedBazelTargets: []string{expectedBazelTarget},
- })
-}
diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go
index ad07f68..813773d 100644
--- a/bp2build/soong_config_module_type_conversion_test.go
+++ b/bp2build/soong_config_module_type_conversion_test.go
@@ -200,6 +200,53 @@
)`}})
}
+func TestSoongConfigModuleType_MultipleBoolVar_PartialUseNotPanic(t *testing.T) {
+ bp := `
+soong_config_bool_variable {
+ name: "feature1",
+}
+
+soong_config_bool_variable {
+ name: "feature2",
+}
+
+soong_config_module_type {
+ name: "custom_cc_library_static",
+ module_type: "cc_library_static",
+ config_namespace: "acme",
+ variables: ["feature1", "feature2",],
+ properties: ["cflags"],
+}
+
+custom_cc_library_static {
+ name: "foo",
+ bazel_module: { bp2build_available: true },
+ host_supported: true,
+ soong_config_variables: {
+ feature1: {
+ conditions_default: {
+ cflags: ["-DDEFAULT1"],
+ },
+ cflags: ["-DFEATURE1"],
+ },
+ },
+}`
+
+ runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+ Description: "soong config variables - used part of multiple bool variable do not panic",
+ ModuleTypeUnderTest: "cc_library_static",
+ ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ Blueprint: bp,
+ ExpectedBazelTargets: []string{`cc_library_static(
+ name = "foo",
+ copts = select({
+ "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
+ "//conditions:default": ["-DDEFAULT1"],
+ }),
+ local_includes = ["."],
+)`}})
+}
+
func TestSoongConfigModuleType_StringAndBoolVar(t *testing.T) {
bp := `
soong_config_bool_variable {
diff --git a/cc/bp2build.go b/cc/bp2build.go
index fa98df4..259ba39 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -1257,6 +1257,7 @@
label := android.BazelLabelForModuleSrcSingle(ctx, *props.Version_script)
additionalLinkerInputs.Add(&label)
linkerFlags = append(linkerFlags, fmt.Sprintf("-Wl,--version-script,$(location %s)", label.Label))
+ axisFeatures = append(axisFeatures, "android_cfi_exports_map")
}
if props.Dynamic_list != nil {
diff --git a/cc/cc.go b/cc/cc.go
index f4b5655..c9f00e2 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -83,7 +83,7 @@
ctx.TopDown("sabi_deps", sabiDepsMutator)
})
- ctx.RegisterSingletonType("kythe_extract_all", kytheExtractAllFactory)
+ ctx.RegisterParallelSingletonType("kythe_extract_all", kytheExtractAllFactory)
}
// Deps is a struct containing module names of dependencies, separated by the kind of dependency.
@@ -4100,8 +4100,6 @@
// Aggressively generate api targets for all header modules
// This is necessary since the header module does not know if it is a dep of API surface stub library
apiLibraryHeadersBp2Build(ctx, c)
- case ndkLibrary:
- ndkLibraryBp2build(ctx, c)
}
}
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 422df73..173911b 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -39,7 +39,6 @@
var prepareForCcTest = android.GroupFixturePreparers(
PrepareForTestWithCcIncludeVndk,
- aidl_library.PrepareForTestWithAidlLibrary,
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.DeviceVndkVersion = StringPtr("current")
variables.ProductVndkVersion = StringPtr("current")
@@ -4420,7 +4419,7 @@
}
}
-func TestAidlLibraryWithHeader(t *testing.T) {
+func TestAidlLibraryWithHeaders(t *testing.T) {
t.Parallel()
ctx := android.GroupFixturePreparers(
prepareForCcTest,
@@ -4430,6 +4429,7 @@
aidl_library {
name: "bar",
srcs: ["x/y/Bar.aidl"],
+ hdrs: ["x/HeaderBar.aidl"],
strip_import_prefix: "x",
}
`)}.AddToFixture(),
@@ -4438,6 +4438,7 @@
aidl_library {
name: "foo",
srcs: ["a/b/Foo.aidl"],
+ hdrs: ["a/HeaderFoo.aidl"],
strip_import_prefix: "a",
deps: ["bar"],
}
@@ -4452,7 +4453,20 @@
).RunTest(t).TestContext
libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static")
- manifest := android.RuleBuilderSboxProtoForTests(t, libfoo.Output("aidl.sbox.textproto"))
+
+ android.AssertPathsRelativeToTopEquals(
+ t,
+ "aidl headers",
+ []string{
+ "package_bar/x/HeaderBar.aidl",
+ "package_foo/a/HeaderFoo.aidl",
+ "package_foo/a/b/Foo.aidl",
+ "out/soong/.intermediates/package_foo/libfoo/android_arm64_armv8-a_static/gen/aidl_library.sbox.textproto",
+ },
+ libfoo.Rule("aidl_library").Implicits,
+ )
+
+ manifest := android.RuleBuilderSboxProtoForTests(t, libfoo.Output("aidl_library.sbox.textproto"))
aidlCommand := manifest.Commands[0].GetCommand()
expectedAidlFlags := "-Ipackage_foo/a -Ipackage_bar/x"
@@ -4462,14 +4476,14 @@
outputs := strings.Join(libfoo.AllOutputs(), " ")
- android.AssertStringDoesContain(t, "aidl-generated header", outputs, "gen/aidl/b/BpFoo.h")
- android.AssertStringDoesContain(t, "aidl-generated header", outputs, "gen/aidl/b/BnFoo.h")
- android.AssertStringDoesContain(t, "aidl-generated header", outputs, "gen/aidl/b/Foo.h")
+ android.AssertStringDoesContain(t, "aidl-generated header", outputs, "gen/aidl_library/b/BpFoo.h")
+ android.AssertStringDoesContain(t, "aidl-generated header", outputs, "gen/aidl_library/b/BnFoo.h")
+ android.AssertStringDoesContain(t, "aidl-generated header", outputs, "gen/aidl_library/b/Foo.h")
android.AssertStringDoesContain(t, "aidl-generated cpp", outputs, "b/Foo.cpp")
// Confirm that the aidl header doesn't get compiled to cpp and h files
- android.AssertStringDoesNotContain(t, "aidl-generated header", outputs, "gen/aidl/y/BpBar.h")
- android.AssertStringDoesNotContain(t, "aidl-generated header", outputs, "gen/aidl/y/BnBar.h")
- android.AssertStringDoesNotContain(t, "aidl-generated header", outputs, "gen/aidl/y/Bar.h")
+ android.AssertStringDoesNotContain(t, "aidl-generated header", outputs, "gen/aidl_library/y/BpBar.h")
+ android.AssertStringDoesNotContain(t, "aidl-generated header", outputs, "gen/aidl_library/y/BnBar.h")
+ android.AssertStringDoesNotContain(t, "aidl-generated header", outputs, "gen/aidl_library/y/Bar.h")
android.AssertStringDoesNotContain(t, "aidl-generated cpp", outputs, "y/Bar.cpp")
}
@@ -4548,6 +4562,55 @@
}
}
+func TestInvalidAidlProp(t *testing.T) {
+ t.Parallel()
+
+ testCases := []struct {
+ description string
+ bp string
+ }{
+ {
+ description: "Invalid use of aidl.libs and aidl.include_dirs",
+ bp: `
+ cc_library {
+ name: "foo",
+ aidl: {
+ libs: ["foo_aidl"],
+ include_dirs: ["bar/include"],
+ }
+ }
+ `,
+ },
+ {
+ description: "Invalid use of aidl.libs and aidl.local_include_dirs",
+ bp: `
+ cc_library {
+ name: "foo",
+ aidl: {
+ libs: ["foo_aidl"],
+ local_include_dirs: ["include"],
+ }
+ }
+ `,
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.description, func(t *testing.T) {
+ bp := `
+ aidl_library {
+ name: "foo_aidl",
+ srcs: ["Foo.aidl"],
+ } ` + testCase.bp
+ android.GroupFixturePreparers(
+ prepareForCcTest,
+ aidl_library.PrepareForTestWithAidlLibrary.
+ ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("For aidl headers, please only use aidl.libs prop")),
+ ).RunTestWithBp(t, bp)
+ })
+ }
+}
+
func TestMinSdkVersionInClangTriple(t *testing.T) {
t.Parallel()
ctx := testCc(t, `
@@ -4789,23 +4852,24 @@
checkIncludeDirs(t, ctx, foo,
expectedIncludeDirs(`
.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl
+ .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl_library
`),
expectedSystemIncludeDirs(``),
expectedGeneratedHeaders(`
.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/b.h
.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bnb.h
.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bpb.h
- .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/y/Bar.h
- .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/y/BnBar.h
- .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/y/BpBar.h
+ .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl_library/y/Bar.h
+ .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl_library/y/BnBar.h
+ .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl_library/y/BpBar.h
`),
expectedOrderOnlyDeps(`
.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/b.h
.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bnb.h
.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bpb.h
- .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/y/Bar.h
- .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/y/BnBar.h
- .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/y/BpBar.h
+ .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl_library/y/Bar.h
+ .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl_library/y/BnBar.h
+ .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl_library/y/BpBar.h
`),
)
})
diff --git a/cc/ccdeps.go b/cc/ccdeps.go
index 75e1faf..d30abba 100644
--- a/cc/ccdeps.go
+++ b/cc/ccdeps.go
@@ -30,7 +30,7 @@
// The info file is generated in $OUT/module_bp_cc_depend.json.
func init() {
- android.RegisterSingletonType("ccdeps_generator", ccDepsGeneratorSingleton)
+ android.RegisterParallelSingletonType("ccdeps_generator", ccDepsGeneratorSingleton)
}
func ccDepsGeneratorSingleton() android.Singleton {
diff --git a/cc/cmakelists.go b/cc/cmakelists.go
index ad130ba..0f3f02d 100644
--- a/cc/cmakelists.go
+++ b/cc/cmakelists.go
@@ -29,7 +29,7 @@
// structure (see variable CLionOutputProjectsDirectory for root).
func init() {
- android.RegisterSingletonType("cmakelists_generator", cMakeListsGeneratorSingleton)
+ android.RegisterParallelSingletonType("cmakelists_generator", cMakeListsGeneratorSingleton)
}
func cMakeListsGeneratorSingleton() android.Singleton {
diff --git a/cc/compdb.go b/cc/compdb.go
index ea12443..617be1a 100644
--- a/cc/compdb.go
+++ b/cc/compdb.go
@@ -32,7 +32,7 @@
// make SOONG_GEN_COMPDB=1 nothing to get all targets.
func init() {
- android.RegisterSingletonType("compdb_generator", compDBGeneratorSingleton)
+ android.RegisterParallelSingletonType("compdb_generator", compDBGeneratorSingleton)
}
func compDBGeneratorSingleton() android.Singleton {
diff --git a/cc/compiler.go b/cc/compiler.go
index 5da745e..16f4a6e 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -565,6 +565,11 @@
"-I"+android.PathForModuleGen(ctx, "yacc", ctx.ModuleDir()).String())
}
+ if len(compiler.Properties.Aidl.Libs) > 0 &&
+ (len(compiler.Properties.Aidl.Include_dirs) > 0 || len(compiler.Properties.Aidl.Local_include_dirs) > 0) {
+ ctx.ModuleErrorf("aidl.libs and (aidl.include_dirs or aidl.local_include_dirs) can't be set at the same time. For aidl headers, please only use aidl.libs prop")
+ }
+
if compiler.hasAidl(deps) {
flags.aidlFlags = append(flags.aidlFlags, compiler.Properties.Aidl.Flags...)
if len(compiler.Properties.Aidl.Local_include_dirs) > 0 {
@@ -594,8 +599,14 @@
}
flags.aidlFlags = append(flags.aidlFlags, "--min_sdk_version="+aidlMinSdkVersion)
- flags.Local.CommonFlags = append(flags.Local.CommonFlags,
- "-I"+android.PathForModuleGen(ctx, "aidl").String())
+ if compiler.hasSrcExt(".aidl") {
+ flags.Local.CommonFlags = append(flags.Local.CommonFlags,
+ "-I"+android.PathForModuleGen(ctx, "aidl").String())
+ }
+ if len(deps.AidlLibraryInfos) > 0 {
+ flags.Local.CommonFlags = append(flags.Local.CommonFlags,
+ "-I"+android.PathForModuleGen(ctx, "aidl_library").String())
+ }
}
if compiler.hasSrcExt(".rscript") || compiler.hasSrcExt(".fs") {
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index d55a13d..efa4549 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -42,6 +42,8 @@
"-bugprone-unchecked-optional-access",
// http://b/265438407
"-misc-use-anonymous-namespace",
+ // http://b/285005947
+ "-performance-avoid-endl",
}
// Some clang-tidy checks are included in some tidy_checks_as_errors lists,
@@ -56,6 +58,14 @@
"-bugprone-signed-char-misuse",
// http://b/241819232
"-misc-const-correctness",
+ // http://b/285356805
+ "-bugprone-unsafe-functions",
+ "-cert-msc24-c",
+ "-cert-msc33-c",
+ // http://b/285356799
+ "-modernize-type-traits",
+ // http://b/285361108
+ "-readability-avoid-unconditional-preprocessor-if",
}
extraArgFlags = []string{
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index 6a10e14..a0ef575 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -20,6 +20,12 @@
"android/soong/android"
)
+func init() {
+ exportedVars.ExportStringListStaticVariable("DarwinAvailableLibraries", darwinAvailableLibraries)
+ exportedVars.ExportStringListStaticVariable("LinuxAvailableLibraries", linuxAvailableLibraries)
+ exportedVars.ExportStringListStaticVariable("WindowsAvailableLibraries", windowsAvailableLibraries)
+}
+
type toolchainFactory func(arch android.Arch) Toolchain
var toolchainFactories = make(map[android.OsType]map[android.ArchType]toolchainFactory)
diff --git a/cc/fuzz.go b/cc/fuzz.go
index dfefc11..c897501 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -28,7 +28,7 @@
func init() {
android.RegisterModuleType("cc_fuzz", LibFuzzFactory)
- android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory)
+ android.RegisterParallelSingletonType("cc_fuzz_packaging", fuzzPackagingFactory)
}
type FuzzProperties struct {
@@ -398,7 +398,9 @@
}
hostOrTargetString := "target"
- if ccModule.Host() {
+ if ccModule.Target().HostCross {
+ hostOrTargetString = "host_cross"
+ } else if ccModule.Host() {
hostOrTargetString = "host"
}
diff --git a/cc/gen.go b/cc/gen.go
index dbb9560..b15f164 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -107,7 +107,14 @@
return ret
}
-func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile android.Path, aidlFlags string) (cppFile android.OutputPath, headerFiles android.Paths) {
+func genAidl(
+ ctx android.ModuleContext,
+ rule *android.RuleBuilder,
+ outDirBase string,
+ aidlFile android.Path,
+ aidlHdrs android.Paths,
+ aidlFlags string,
+) (cppFile android.OutputPath, headerFiles android.Paths) {
aidlPackage := strings.TrimSuffix(aidlFile.Rel(), aidlFile.Base())
baseName := strings.TrimSuffix(aidlFile.Base(), aidlFile.Ext())
shortName := baseName
@@ -119,7 +126,7 @@
shortName = strings.TrimPrefix(baseName, "I")
}
- outDir := android.PathForModuleGen(ctx, "aidl")
+ outDir := android.PathForModuleGen(ctx, outDirBase)
cppFile = outDir.Join(ctx, aidlPackage, baseName+".cpp")
depFile := outDir.Join(ctx, aidlPackage, baseName+".cpp.d")
headerI := outDir.Join(ctx, aidlPackage, baseName+".h")
@@ -128,6 +135,8 @@
cmd := rule.Command()
cmd.BuiltTool("aidl-cpp").
+ // libc++ is default stl for aidl-cpp (a cc_binary_host module)
+ ImplicitTool(ctx.Config().HostCcSharedLibPath(ctx, "libc++")).
FlagWithDepFile("-d", depFile).
Flag("--ninja").
Flag(aidlFlags).
@@ -140,6 +149,10 @@
headerBp,
})
+ if aidlHdrs != nil {
+ cmd.Implicits(aidlHdrs)
+ }
+
return cppFile, android.Paths{
headerI,
headerBn,
@@ -283,14 +296,19 @@
ctx android.ModuleContext,
aidlLibraryInfos []aidl_library.AidlLibraryInfo,
srcFiles android.Paths,
- buildFlags builderFlags) (android.Paths, android.Paths, generatedSourceInfo) {
+ buildFlags builderFlags,
+) (android.Paths, android.Paths, generatedSourceInfo) {
var info generatedSourceInfo
var deps android.Paths
var rsFiles android.Paths
+ // aidlRule supports compiling aidl files from srcs prop while aidlLibraryRule supports
+ // compiling aidl files from aidl_library modules specified in aidl.libs prop.
+ // The rules are separated so that they don't wipe out the other's outputDir
var aidlRule *android.RuleBuilder
+ var aidlLibraryRule *android.RuleBuilder
var yaccRule_ *android.RuleBuilder
yaccRule := func() *android.RuleBuilder {
@@ -331,7 +349,14 @@
android.PathForModuleGen(ctx, "aidl.sbox.textproto"))
}
baseDir := strings.TrimSuffix(srcFile.String(), srcFile.Rel())
- cppFile, aidlHeaders := genAidl(ctx, aidlRule, srcFile, buildFlags.aidlFlags+" -I"+baseDir)
+ cppFile, aidlHeaders := genAidl(
+ ctx,
+ aidlRule,
+ "aidl",
+ srcFile,
+ nil,
+ buildFlags.aidlFlags+" -I"+baseDir,
+ )
srcFiles[i] = cppFile
info.aidlHeaders = append(info.aidlHeaders, aidlHeaders...)
@@ -354,13 +379,21 @@
}
for _, aidlLibraryInfo := range aidlLibraryInfos {
+ if aidlLibraryRule == nil {
+ aidlLibraryRule = android.NewRuleBuilder(pctx, ctx).Sbox(
+ android.PathForModuleGen(ctx, "aidl_library"),
+ android.PathForModuleGen(ctx, "aidl_library.sbox.textproto"),
+ ).SandboxInputs()
+ }
for _, aidlSrc := range aidlLibraryInfo.Srcs {
- if aidlRule == nil {
- // TODO(b/279960133): Sandbox inputs to ensure aidl headers are explicitly specified
- aidlRule = android.NewRuleBuilder(pctx, ctx).Sbox(android.PathForModuleGen(ctx, "aidl"),
- android.PathForModuleGen(ctx, "aidl.sbox.textproto"))
- }
- cppFile, aidlHeaders := genAidl(ctx, aidlRule, aidlSrc, buildFlags.aidlFlags)
+ cppFile, aidlHeaders := genAidl(
+ ctx,
+ aidlLibraryRule,
+ "aidl_library",
+ aidlSrc,
+ aidlLibraryInfo.Hdrs.ToList(),
+ buildFlags.aidlFlags,
+ )
srcFiles = append(srcFiles, cppFile)
info.aidlHeaders = append(info.aidlHeaders, aidlHeaders...)
@@ -375,6 +408,10 @@
aidlRule.Build("aidl", "gen aidl")
}
+ if aidlLibraryRule != nil {
+ aidlLibraryRule.Build("aidl_library", "gen aidl_library")
+ }
+
if yaccRule_ != nil {
yaccRule_.Build("yacc", "gen yacc")
}
diff --git a/cc/library.go b/cc/library.go
index 09a7253..98096a8 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -2118,8 +2118,14 @@
// Optionally export aidl headers.
if Bool(library.Properties.Aidl.Export_aidl_headers) {
if library.baseCompiler.hasAidl(deps) {
- dir := android.PathForModuleGen(ctx, "aidl")
- library.reexportDirs(dir)
+ if library.baseCompiler.hasSrcExt(".aidl") {
+ dir := android.PathForModuleGen(ctx, "aidl")
+ library.reexportDirs(dir)
+ }
+ if len(deps.AidlLibraryInfos) > 0 {
+ dir := android.PathForModuleGen(ctx, "aidl_library")
+ library.reexportDirs(dir)
+ }
library.reexportDeps(library.baseCompiler.aidlOrderOnlyDeps...)
library.addExportedGeneratedHeaders(library.baseCompiler.aidlHeaders...)
diff --git a/cc/lto.go b/cc/lto.go
index 1afa1dd..a8bed23 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -43,22 +43,16 @@
// referred to in blueprint files as "lto"
Lto struct {
Never *bool `android:"arch_variant"`
- Full *bool `android:"arch_variant"`
Thin *bool `android:"arch_variant"`
} `android:"arch_variant"`
// Dep properties indicate that this module needs to be built with LTO
// since it is an object dependency of an LTO module.
- FullEnabled bool `blueprint:"mutated"`
ThinEnabled bool `blueprint:"mutated"`
NoLtoEnabled bool `blueprint:"mutated"`
- FullDep bool `blueprint:"mutated"`
ThinDep bool `blueprint:"mutated"`
NoLtoDep bool `blueprint:"mutated"`
- // Use clang lld instead of gnu ld.
- Use_clang_lld *bool
-
// Use -fwhole-program-vtables cflag.
Whole_program_vtables *bool
}
@@ -77,13 +71,6 @@
}
}
-func (lto *lto) useClangLld(ctx BaseModuleContext) bool {
- if lto.Properties.Use_clang_lld != nil {
- return Bool(lto.Properties.Use_clang_lld)
- }
- return true
-}
-
func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
// TODO(b/131771163): Disable LTO when using explicit fuzzing configurations.
// LTO breaks fuzzer builds.
@@ -91,18 +78,11 @@
return flags
}
- // TODO(b/254713216): LTO doesn't work on riscv64 yet.
- if ctx.Arch().ArchType == android.Riscv64 {
- return flags
- }
-
if lto.LTO(ctx) {
var ltoCFlag string
var ltoLdFlag string
if lto.ThinLTO() {
ltoCFlag = "-flto=thin -fsplit-lto-unit"
- } else if lto.FullLTO() {
- ltoCFlag = "-flto"
} else {
ltoCFlag = "-flto=thin -fsplit-lto-unit"
ltoLdFlag = "-Wl,--lto-O0"
@@ -117,7 +97,7 @@
flags.Local.CFlags = append(flags.Local.CFlags, "-fwhole-program-vtables")
}
- if (lto.DefaultThinLTO(ctx) || lto.ThinLTO()) && ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") && lto.useClangLld(ctx) {
+ if (lto.DefaultThinLTO(ctx) || lto.ThinLTO()) && ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") {
// Set appropriate ThinLTO cache policy
cacheDirFormat := "-Wl,--thinlto-cache-dir="
cacheDir := android.PathForOutput(ctx, "thinlto-cache").String()
@@ -141,13 +121,13 @@
}
func (lto *lto) LTO(ctx BaseModuleContext) bool {
- return lto.ThinLTO() || lto.FullLTO() || lto.DefaultThinLTO(ctx)
+ return lto.ThinLTO() || lto.DefaultThinLTO(ctx)
}
func (lto *lto) DefaultThinLTO(ctx BaseModuleContext) bool {
// LP32 has many subtle issues and less test coverage.
lib32 := ctx.Arch().ArchType.Multilib == "lib32"
- // CFI enables full LTO.
+ // CFI adds LTO flags by itself.
cfi := ctx.isCfi()
// Performance and binary size are less important for host binaries and tests.
host := ctx.Host()
@@ -158,10 +138,6 @@
return GlobalThinLTO(ctx) && !lto.Never() && !lib32 && !cfi && !host && !test && !vndk
}
-func (lto *lto) FullLTO() bool {
- return lto != nil && (proptools.Bool(lto.Properties.Lto.Full) || lto.Properties.FullEnabled)
-}
-
func (lto *lto) ThinLTO() bool {
return lto != nil && (proptools.Bool(lto.Properties.Lto.Thin) || lto.Properties.ThinEnabled)
}
@@ -179,12 +155,8 @@
globalThinLTO := GlobalThinLTO(mctx)
if m, ok := mctx.Module().(*Module); ok {
- full := m.lto.FullLTO()
thin := m.lto.ThinLTO()
never := m.lto.Never()
- if full && thin {
- mctx.PropertyErrorf("LTO", "FullLTO and ThinLTO are mutually exclusive")
- }
mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
tag := mctx.OtherModuleDependencyTag(dep)
@@ -202,9 +174,6 @@
}
if dep, ok := dep.(*Module); ok {
- if full && !dep.lto.FullLTO() {
- dep.lto.Properties.FullDep = true
- }
if !globalThinLTO && thin && !dep.lto.ThinLTO() {
dep.lto.Properties.ThinDep = true
}
@@ -227,9 +196,6 @@
// Create variations for LTO types required as static
// dependencies
variationNames := []string{""}
- if m.lto.Properties.FullDep && !m.lto.FullLTO() {
- variationNames = append(variationNames, "lto-full")
- }
if !globalThinLTO && m.lto.Properties.ThinDep && !m.lto.ThinLTO() {
variationNames = append(variationNames, "lto-thin")
}
@@ -239,13 +205,10 @@
// Use correct dependencies if LTO property is explicitly set
// (mutually exclusive)
- if m.lto.FullLTO() {
- mctx.SetDependencyVariation("lto-full")
- }
if !globalThinLTO && m.lto.ThinLTO() {
mctx.SetDependencyVariation("lto-thin")
}
- // Never must be the last, it overrides Thin or Full.
+ // Never must be the last, it overrides Thin.
if globalThinLTO && m.lto.Never() {
mctx.SetDependencyVariation("lto-none")
}
@@ -262,9 +225,6 @@
}
// LTO properties for dependencies
- if name == "lto-full" {
- variation.lto.Properties.FullEnabled = true
- }
if name == "lto-thin" {
variation.lto.Properties.ThinEnabled = true
}
@@ -273,7 +233,6 @@
}
variation.Properties.PreventInstall = true
variation.Properties.HideFromMake = true
- variation.lto.Properties.FullDep = false
variation.lto.Properties.ThinDep = false
variation.lto.Properties.NoLtoDep = false
}
diff --git a/cc/ndk_abi.go b/cc/ndk_abi.go
index 3456c32..86166dc 100644
--- a/cc/ndk_abi.go
+++ b/cc/ndk_abi.go
@@ -19,8 +19,8 @@
)
func init() {
- android.RegisterSingletonType("ndk_abi_dump", NdkAbiDumpSingleton)
- android.RegisterSingletonType("ndk_abi_diff", NdkAbiDiffSingleton)
+ android.RegisterParallelSingletonType("ndk_abi_dump", NdkAbiDumpSingleton)
+ android.RegisterParallelSingletonType("ndk_abi_diff", NdkAbiDiffSingleton)
}
func getNdkAbiDumpInstallBase(ctx android.PathContext) android.OutputPath {
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 7354be9..d0ae4a5 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -19,10 +19,8 @@
"path/filepath"
"github.com/google/blueprint"
- "github.com/google/blueprint/proptools"
"android/soong/android"
- "android/soong/bazel"
)
var (
@@ -81,7 +79,6 @@
type headerModule struct {
android.ModuleBase
- android.BazelModuleBase
properties headerProperties
@@ -147,39 +144,6 @@
}
}
-// TODO(b/243196151): Populate `system` and `arch` metadata
-type bazelCcApiHeadersAttributes struct {
- Hdrs bazel.LabelListAttribute
- Include_dir *string
-}
-
-func createCcApiHeadersTarget(ctx android.TopDownMutatorContext, includes []string, excludes []string, include_dir *string) {
- props := bazel.BazelTargetModuleProperties{
- Rule_class: "cc_api_headers",
- Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl",
- }
- attrs := &bazelCcApiHeadersAttributes{
- Hdrs: bazel.MakeLabelListAttribute(
- android.BazelLabelForModuleSrcExcludes(
- ctx,
- includes,
- excludes,
- ),
- ),
- Include_dir: include_dir,
- }
- ctx.CreateBazelTargetModule(props, android.CommonAttributes{
- Name: android.ApiContributionTargetName(ctx.ModuleName()),
- }, attrs)
-}
-
-var _ android.ApiProvider = (*headerModule)(nil)
-
-func (h *headerModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
- // Generate `cc_api_headers` target for Multi-tree API export
- createCcApiHeadersTarget(ctx, h.properties.Srcs, h.properties.Exclude_srcs, h.properties.From)
-}
-
// ndk_headers installs the sets of ndk headers defined in the srcs property
// to the sysroot base + "usr/include" + to directory + directory component.
// ndk_headers requires the license file to be specified. Example:
@@ -226,7 +190,6 @@
// Note that this is really only built to handle bionic/libc/include.
type versionedHeaderModule struct {
android.ModuleBase
- android.BazelModuleBase
properties versionedHeaderProperties
@@ -264,15 +227,6 @@
processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, srcFiles, installPaths)
}
-var _ android.ApiProvider = (*versionedHeaderModule)(nil)
-
-func (h *versionedHeaderModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
- // Glob all .h files under `From`
- includePattern := headerGlobPattern(proptools.String(h.properties.From))
- // Generate `cc_api_headers` target for Multi-tree API export
- createCcApiHeadersTarget(ctx, []string{includePattern}, []string{}, h.properties.From)
-}
-
func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path,
srcFiles android.Paths, installPaths []android.WritablePath) android.Path {
// The versioner depends on a dependencies directory to simplify determining include paths
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index f8a3559..f0b7cc5 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -599,24 +599,3 @@
}
return android.BazelLabelForModuleDepsWithFn(ctx, hdrLibs, addSuffix)
}
-
-func ndkLibraryBp2build(ctx android.TopDownMutatorContext, m *Module) {
- props := bazel.BazelTargetModuleProperties{
- Rule_class: "cc_api_contribution",
- Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl",
- }
- stubLibrary := m.compiler.(*stubDecorator)
- attrs := &bazelCcApiContributionAttributes{
- Library_name: stubLibrary.implementationModuleName(m.Name()),
- Api_surfaces: bazel.MakeStringListAttribute(
- []string{android.PublicApi.String()}),
- }
- if symbolFile := stubLibrary.properties.Symbol_file; symbolFile != nil {
- apiLabel := android.BazelLabelForModuleSrcSingle(ctx, proptools.String(symbolFile)).Label
- attrs.Api = *bazel.MakeLabelAttribute(apiLabel)
- }
- apiHeaders := apiHeaderLabels(ctx, stubLibrary.properties.Export_header_libs)
- attrs.Hdrs = bazel.MakeLabelListAttribute(apiHeaders)
- apiContributionTargetName := android.ApiContributionTargetName(ctx.ModuleName())
- ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: apiContributionTargetName}, attrs)
-}
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index dffc6c6..0cf21b6 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -66,7 +66,7 @@
ctx.RegisterModuleType("ndk_library", NdkLibraryFactory)
ctx.RegisterModuleType("versioned_ndk_headers", versionedNdkHeadersFactory)
ctx.RegisterModuleType("preprocessed_ndk_headers", preprocessedNdkHeadersFactory)
- ctx.RegisterSingletonType("ndk", NdkSingleton)
+ ctx.RegisterParallelSingletonType("ndk", NdkSingleton)
}
func getNdkInstallBase(ctx android.PathContext) android.InstallPath {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 7fddc1b..6e732b6 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -665,6 +665,21 @@
s.Diag.Cfi = nil
}
+ // TODO(b/280478629): runtimes don't exist for musl arm64 yet.
+ if ctx.toolchain().Musl() && ctx.Arch().ArchType == android.Arm64 {
+ s.Address = nil
+ s.Hwaddress = nil
+ s.Thread = nil
+ s.Scudo = nil
+ s.Fuzzer = nil
+ s.Cfi = nil
+ s.Diag.Cfi = nil
+ s.Misc_undefined = nil
+ s.Undefined = nil
+ s.All_undefined = nil
+ s.Integer_overflow = nil
+ }
+
// Also disable CFI for VNDK variants of components
if ctx.isVndk() && ctx.useVndk() {
s.Cfi = nil
diff --git a/cc/stub_library.go b/cc/stub_library.go
index f324dcc..3a6d0ae 100644
--- a/cc/stub_library.go
+++ b/cc/stub_library.go
@@ -23,7 +23,7 @@
func init() {
// Use singleton type to gather all generated soong modules.
- android.RegisterSingletonType("stublibraries", stubLibrariesSingleton)
+ android.RegisterParallelSingletonType("stublibraries", stubLibrariesSingleton)
}
type stubLibraries struct {
diff --git a/cc/test.go b/cc/test.go
index 27de06b..3f5f710 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -70,6 +70,10 @@
// Add MinApiLevelModuleController with ro.vndk.version property. If ro.vndk.version has an
// integer value and the value is less than the min_vndk_version, skip this module.
Min_vndk_version *int64
+
+ // Extra <option> tags to add to the auto generated test xml file under the test runner, e.g., GTest.
+ // The "key" is optional in each of these.
+ Test_runner_options []tradefed.Option
}
type TestBinaryProperties struct {
@@ -398,6 +402,7 @@
TestConfigTemplateProp: test.Properties.Test_config_template,
TestSuites: test.testDecorator.InstallerProperties.Test_suites,
Config: configs,
+ TestRunnerOptions: test.Properties.Test_options.Test_runner_options,
AutoGenConfig: test.Properties.Auto_gen_config,
TestInstallBase: testInstallBase,
DeviceTemplate: "${NativeTestConfigTemplate}",
diff --git a/cc/tidy.go b/cc/tidy.go
index bbcaece..7b123cb 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -201,7 +201,7 @@
}
func init() {
- android.RegisterSingletonType("tidy_phony_targets", TidyPhonySingleton)
+ android.RegisterParallelSingletonType("tidy_phony_targets", TidyPhonySingleton)
}
// This TidyPhonySingleton generates both tidy-* and obj-* phony targets for C/C++ files.
diff --git a/cc/vndk.go b/cc/vndk.go
index 9b70004..7a2286e 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -417,16 +417,16 @@
func init() {
RegisterVndkLibraryTxtTypes(android.InitRegistrationContext)
- android.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
+ android.RegisterParallelSingletonType("vndk-snapshot", VndkSnapshotSingleton)
}
func RegisterVndkLibraryTxtTypes(ctx android.RegistrationContext) {
- ctx.RegisterSingletonModuleType("llndk_libraries_txt", llndkLibrariesTxtFactory)
- ctx.RegisterSingletonModuleType("vndksp_libraries_txt", vndkSPLibrariesTxtFactory)
- ctx.RegisterSingletonModuleType("vndkcore_libraries_txt", vndkCoreLibrariesTxtFactory)
- ctx.RegisterSingletonModuleType("vndkprivate_libraries_txt", vndkPrivateLibrariesTxtFactory)
- ctx.RegisterSingletonModuleType("vndkproduct_libraries_txt", vndkProductLibrariesTxtFactory)
- ctx.RegisterSingletonModuleType("vndkcorevariant_libraries_txt", vndkUsingCoreVariantLibrariesTxtFactory)
+ ctx.RegisterParallelSingletonModuleType("llndk_libraries_txt", llndkLibrariesTxtFactory)
+ ctx.RegisterParallelSingletonModuleType("vndksp_libraries_txt", vndkSPLibrariesTxtFactory)
+ ctx.RegisterParallelSingletonModuleType("vndkcore_libraries_txt", vndkCoreLibrariesTxtFactory)
+ ctx.RegisterParallelSingletonModuleType("vndkprivate_libraries_txt", vndkPrivateLibrariesTxtFactory)
+ ctx.RegisterParallelSingletonModuleType("vndkproduct_libraries_txt", vndkProductLibrariesTxtFactory)
+ ctx.RegisterParallelSingletonModuleType("vndkcorevariant_libraries_txt", vndkUsingCoreVariantLibrariesTxtFactory)
}
type vndkLibrariesTxt struct {
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index cf6c1c7..d589925 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -78,6 +78,7 @@
flag.StringVar(&cmdlineArgs.Bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit")
flag.StringVar(&cmdlineArgs.SymlinkForestMarker, "symlink_forest_marker", "", "If set, create the bp2build symlink forest, touch the specified marker file, then exit")
flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output")
+ flag.StringVar(&cmdlineArgs.SoongVariables, "soong_variables", "soong.variables", "the file contains all build variables")
flag.StringVar(&cmdlineArgs.BazelForceEnabledModules, "bazel-force-enabled-modules", "", "additional modules to build with Bazel. Comma-delimited")
flag.BoolVar(&cmdlineArgs.EmptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file")
flag.BoolVar(&cmdlineArgs.MultitreeBuild, "multitree-build", false, "this is a multitree build")
@@ -517,6 +518,8 @@
var finalOutputFile string
+ writeSymlink := false
+
// Run Soong for a specific activity, like bp2build, queryview
// or the actual Soong build for the build.ninja file.
switch configuration.BuildMode {
@@ -539,11 +542,22 @@
maybeQuit(err, "")
}
}
+ writeSymlink = true
} else {
finalOutputFile = runSoongOnlyBuild(ctx, extraNinjaDeps)
+
+ if configuration.BuildMode == android.AnalysisNoBazel {
+ writeSymlink = true
+ }
}
writeMetrics(configuration, ctx.EventHandler, metricsDir)
}
+
+ // Register this environment variablesas being an implicit dependencies of
+ // soong_build. Changes to this environment variable will result in
+ // retriggering soong_build.
+ configuration.Getenv("USE_BAZEL_VERSION")
+
writeUsedEnvironmentFile(configuration)
// Touch the output file so that it's the newest file created by soong_build.
@@ -551,6 +565,24 @@
// are ninja inputs to the main output file, then ninja would superfluously
// rebuild this output file on the next build invocation.
touch(shared.JoinPath(topDir, finalOutputFile))
+
+ // TODO(b/277029044): Remove this function once build.<product>.ninja lands
+ if writeSymlink {
+ writeBuildNinjaSymlink(configuration, finalOutputFile)
+ }
+}
+
+// TODO(b/277029044): Remove this function once build.<product>.ninja lands
+func writeBuildNinjaSymlink(config android.Config, source string) {
+ targetPath := shared.JoinPath(topDir, config.SoongOutDir(), "build.ninja")
+ sourcePath := shared.JoinPath(topDir, source)
+
+ if targetPath == sourcePath {
+ return
+ }
+
+ os.Remove(targetPath)
+ os.Symlink(sourcePath, targetPath)
}
func writeUsedEnvironmentFile(configuration android.Config) {
diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go
index afb3de3..6ead589 100644
--- a/dexpreopt/class_loader_context.go
+++ b/dexpreopt/class_loader_context.go
@@ -17,11 +17,11 @@
import (
"encoding/json"
"fmt"
- "sort"
"strconv"
- "strings"
"android/soong/android"
+
+ "github.com/google/blueprint/proptools"
)
// This comment describes the following:
@@ -310,8 +310,8 @@
// Nested class loader context shouldn't have conditional part (it is allowed only at the top level).
for ver, _ := range nestedClcMap {
if ver != AnySdkVersion {
- clcStr, _ := ComputeClassLoaderContext(nestedClcMap)
- return fmt.Errorf("nested class loader context shouldn't have conditional part: %s", clcStr)
+ clcPaths := ComputeClassLoaderContextDependencies(nestedClcMap)
+ return fmt.Errorf("nested class loader context shouldn't have conditional part: %+v", clcPaths)
}
}
subcontexts := nestedClcMap[AnySdkVersion]
@@ -418,6 +418,15 @@
return string(bytes)
}
+func (clcMap ClassLoaderContextMap) DumpForFlag() string {
+ jsonCLC := toJsonClassLoaderContext(clcMap)
+ bytes, err := json.Marshal(jsonCLC)
+ if err != nil {
+ panic(err)
+ }
+ return proptools.ShellEscapeIncludingSpaces(string(bytes))
+}
+
// excludeLibsFromCLCList excludes the libraries from the ClassLoaderContext in this list.
//
// This treats the supplied list as being immutable (as it may come from a dependency). So, it
@@ -544,67 +553,27 @@
return true, nil
}
-// Return the class loader context as a string, and a slice of build paths for all dependencies.
+// Returns a slice of build paths for all possible dependencies that the class loader context may
+// refer to.
// Perform a depth-first preorder traversal of the class loader context tree for each SDK version.
-// Return the resulting string and a slice of on-host build paths to all library dependencies.
-func ComputeClassLoaderContext(clcMap ClassLoaderContextMap) (clcStr string, paths android.Paths) {
- // CLC for different SDK versions should come in specific order that agrees with PackageManager.
- // Since PackageManager processes SDK versions in ascending order and prepends compatibility
- // libraries at the front, the required order is descending, except for AnySdkVersion that has
- // numerically the largest order, but must be the last one. Example of correct order: [30, 29,
- // 28, AnySdkVersion]. There are Soong tests to ensure that someone doesn't change this by
- // accident, but there is no way to guard against changes in the PackageManager, except for
- // grepping logcat on the first boot for absence of the following messages:
- //
- // `logcat | grep -E 'ClassLoaderContext [a-z ]+ mismatch`
- //
- versions := make([]int, 0, len(clcMap))
- for ver, _ := range clcMap {
- if ver != AnySdkVersion {
- versions = append(versions, ver)
- }
- }
- sort.Sort(sort.Reverse(sort.IntSlice(versions))) // descending order
- versions = append(versions, AnySdkVersion)
-
- for _, sdkVer := range versions {
- sdkVerStr := fmt.Sprintf("%d", sdkVer)
- if sdkVer == AnySdkVersion {
- sdkVerStr = "any" // a special keyword that means any SDK version
- }
- hostClc, targetClc, hostPaths := computeClassLoaderContextRec(clcMap[sdkVer])
- if hostPaths != nil {
- clcStr += fmt.Sprintf(" --host-context-for-sdk %s %s", sdkVerStr, hostClc)
- clcStr += fmt.Sprintf(" --target-context-for-sdk %s %s", sdkVerStr, targetClc)
- }
+func ComputeClassLoaderContextDependencies(clcMap ClassLoaderContextMap) android.Paths {
+ var paths android.Paths
+ for _, clcs := range clcMap {
+ hostPaths := ComputeClassLoaderContextDependenciesRec(clcs)
paths = append(paths, hostPaths...)
}
- return clcStr, android.FirstUniquePaths(paths)
+ return android.FirstUniquePaths(paths)
}
-// Helper function for ComputeClassLoaderContext() that handles recursion.
-func computeClassLoaderContextRec(clcs []*ClassLoaderContext) (string, string, android.Paths) {
+// Helper function for ComputeClassLoaderContextDependencies() that handles recursion.
+func ComputeClassLoaderContextDependenciesRec(clcs []*ClassLoaderContext) android.Paths {
var paths android.Paths
- var clcsHost, clcsTarget []string
-
for _, clc := range clcs {
- subClcHost, subClcTarget, subPaths := computeClassLoaderContextRec(clc.Subcontexts)
- if subPaths != nil {
- subClcHost = "{" + subClcHost + "}"
- subClcTarget = "{" + subClcTarget + "}"
- }
-
- clcsHost = append(clcsHost, "PCL["+clc.Host.String()+"]"+subClcHost)
- clcsTarget = append(clcsTarget, "PCL["+clc.Device+"]"+subClcTarget)
-
+ subPaths := ComputeClassLoaderContextDependenciesRec(clc.Subcontexts)
paths = append(paths, clc.Host)
paths = append(paths, subPaths...)
}
-
- clcHost := strings.Join(clcsHost, "#")
- clcTarget := strings.Join(clcsTarget, "#")
-
- return clcHost, clcTarget, paths
+ return paths
}
// Class loader contexts that come from Make via JSON dexpreopt.config. JSON CLC representation is
diff --git a/dexpreopt/class_loader_context_test.go b/dexpreopt/class_loader_context_test.go
index 8b3c013..39b4652 100644
--- a/dexpreopt/class_loader_context_test.go
+++ b/dexpreopt/class_loader_context_test.go
@@ -20,6 +20,7 @@
import (
"fmt"
"reflect"
+ "sort"
"strings"
"testing"
@@ -34,7 +35,7 @@
// │ └── android.hidl.base
// │
// └── any
- // ├── a
+ // ├── a' (a single quotation mark (') is there to test escaping)
// ├── b
// ├── c
// ├── d
@@ -53,7 +54,7 @@
m := make(ClassLoaderContextMap)
- m.AddContext(ctx, AnySdkVersion, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
+ m.AddContext(ctx, AnySdkVersion, "a'", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
m.AddContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
m.AddContext(ctx, AnySdkVersion, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
@@ -96,11 +97,10 @@
fixClassLoaderContext(m)
- var haveStr string
var havePaths android.Paths
var haveUsesLibsReq, haveUsesLibsOpt []string
if valid && validationError == nil {
- haveStr, havePaths = ComputeClassLoaderContext(m)
+ havePaths = ComputeClassLoaderContextDependencies(m)
haveUsesLibsReq, haveUsesLibsOpt = m.UsesLibs()
}
@@ -111,29 +111,6 @@
}
})
- // Test that class loader context structure is correct.
- t.Run("string", func(t *testing.T) {
- wantStr := " --host-context-for-sdk 29 " +
- "PCL[out/soong/" + AndroidHidlManager + ".jar]#" +
- "PCL[out/soong/" + AndroidHidlBase + ".jar]" +
- " --target-context-for-sdk 29 " +
- "PCL[/system/framework/" + AndroidHidlManager + ".jar]#" +
- "PCL[/system/framework/" + AndroidHidlBase + ".jar]" +
- " --host-context-for-sdk any " +
- "PCL[out/soong/a.jar]#PCL[out/soong/b.jar]#PCL[out/soong/c.jar]#PCL[out/soong/d.jar]" +
- "{PCL[out/soong/a2.jar]#PCL[out/soong/b2.jar]#PCL[out/soong/c2.jar]" +
- "{PCL[out/soong/a1.jar]#PCL[out/soong/b1.jar]}}#" +
- "PCL[out/soong/f.jar]#PCL[out/soong/a3.jar]#PCL[out/soong/b3.jar]" +
- " --target-context-for-sdk any " +
- "PCL[/system/a.jar]#PCL[/system/b.jar]#PCL[/system/c.jar]#PCL[/system/d.jar]" +
- "{PCL[/system/a2.jar]#PCL[/system/b2.jar]#PCL[/system/c2.jar]" +
- "{PCL[/system/a1.jar]#PCL[/system/b1.jar]}}#" +
- "PCL[/system/f.jar]#PCL[/system/a3.jar]#PCL[/system/b3.jar]"
- if wantStr != haveStr {
- t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
- }
- })
-
// Test that all expected build paths are gathered.
t.Run("paths", func(t *testing.T) {
wantPaths := []string{
@@ -143,14 +120,28 @@
"out/soong/a1.jar", "out/soong/b1.jar",
"out/soong/f.jar", "out/soong/a3.jar", "out/soong/b3.jar",
}
- if !reflect.DeepEqual(wantPaths, havePaths.Strings()) {
- t.Errorf("\nwant paths: %s\nhave paths: %s", wantPaths, havePaths)
- }
+ actual := havePaths.Strings()
+ // The order does not matter.
+ sort.Strings(wantPaths)
+ sort.Strings(actual)
+ android.AssertArrayString(t, "", wantPaths, actual)
+ })
+
+ // Test the JSON passed to construct_context.py.
+ t.Run("json", func(t *testing.T) {
+ // The tree structure within each SDK version should be kept exactly the same when serialized
+ // to JSON. The order matters because the Python script keeps the order within each SDK version
+ // as is.
+ // The JSON is passed to the Python script as a commandline flag, so quotation ('') and escaping
+ // must be performed.
+ android.AssertStringEquals(t, "", strings.TrimSpace(`
+'{"29":[{"Name":"android.hidl.manager-V1.0-java","Optional":false,"Host":"out/soong/android.hidl.manager-V1.0-java.jar","Device":"/system/framework/android.hidl.manager-V1.0-java.jar","Subcontexts":[]},{"Name":"android.hidl.base-V1.0-java","Optional":false,"Host":"out/soong/android.hidl.base-V1.0-java.jar","Device":"/system/framework/android.hidl.base-V1.0-java.jar","Subcontexts":[]}],"30":[],"42":[],"any":[{"Name":"a'\''","Optional":false,"Host":"out/soong/a.jar","Device":"/system/a.jar","Subcontexts":[]},{"Name":"b","Optional":false,"Host":"out/soong/b.jar","Device":"/system/b.jar","Subcontexts":[]},{"Name":"c","Optional":false,"Host":"out/soong/c.jar","Device":"/system/c.jar","Subcontexts":[]},{"Name":"d","Optional":false,"Host":"out/soong/d.jar","Device":"/system/d.jar","Subcontexts":[{"Name":"a2","Optional":false,"Host":"out/soong/a2.jar","Device":"/system/a2.jar","Subcontexts":[]},{"Name":"b2","Optional":false,"Host":"out/soong/b2.jar","Device":"/system/b2.jar","Subcontexts":[]},{"Name":"c2","Optional":false,"Host":"out/soong/c2.jar","Device":"/system/c2.jar","Subcontexts":[{"Name":"a1","Optional":false,"Host":"out/soong/a1.jar","Device":"/system/a1.jar","Subcontexts":[]},{"Name":"b1","Optional":false,"Host":"out/soong/b1.jar","Device":"/system/b1.jar","Subcontexts":[]}]}]},{"Name":"f","Optional":false,"Host":"out/soong/f.jar","Device":"/system/f.jar","Subcontexts":[]},{"Name":"a3","Optional":false,"Host":"out/soong/a3.jar","Device":"/system/a3.jar","Subcontexts":[]},{"Name":"b3","Optional":false,"Host":"out/soong/b3.jar","Device":"/system/b3.jar","Subcontexts":[]}]}'
+`), m.DumpForFlag())
})
// Test for libraries that are added by the manifest_fixer.
t.Run("uses libs", func(t *testing.T) {
- wantUsesLibsReq := []string{"a", "b", "c", "d", "f", "a3", "b3"}
+ wantUsesLibsReq := []string{"a'", "b", "c", "d", "f", "a3", "b3"}
wantUsesLibsOpt := []string{}
if !reflect.DeepEqual(wantUsesLibsReq, haveUsesLibsReq) {
t.Errorf("\nwant required uses libs: %s\nhave required uses libs: %s", wantUsesLibsReq, haveUsesLibsReq)
@@ -236,49 +227,6 @@
checkError(t, err, "nested class loader context shouldn't have conditional part")
}
-// Test for SDK version order in conditional CLC: no matter in what order the libraries are added,
-// they end up in the order that agrees with PackageManager.
-func TestCLCSdkVersionOrder(t *testing.T) {
- ctx := testContext()
- optional := false
- m := make(ClassLoaderContextMap)
- m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
- m.AddContext(ctx, 29, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
- m.AddContext(ctx, 30, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
- m.AddContext(ctx, AnySdkVersion, "d", optional, buildPath(ctx, "d"), installPath(ctx, "d"), nil)
-
- valid, validationError := validateClassLoaderContext(m)
-
- fixClassLoaderContext(m)
-
- var haveStr string
- if valid && validationError == nil {
- haveStr, _ = ComputeClassLoaderContext(m)
- }
-
- // Test that validation is successful (all paths are known).
- t.Run("validate", func(t *testing.T) {
- if !(valid && validationError == nil) {
- t.Errorf("invalid class loader context")
- }
- })
-
- // Test that class loader context structure is correct.
- t.Run("string", func(t *testing.T) {
- wantStr := " --host-context-for-sdk 30 PCL[out/soong/c.jar]" +
- " --target-context-for-sdk 30 PCL[/system/c.jar]" +
- " --host-context-for-sdk 29 PCL[out/soong/b.jar]" +
- " --target-context-for-sdk 29 PCL[/system/b.jar]" +
- " --host-context-for-sdk 28 PCL[out/soong/a.jar]" +
- " --target-context-for-sdk 28 PCL[/system/a.jar]" +
- " --host-context-for-sdk any PCL[out/soong/d.jar]" +
- " --target-context-for-sdk any PCL[/system/d.jar]"
- if wantStr != haveStr {
- t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
- }
- })
-}
-
func TestCLCMExcludeLibs(t *testing.T) {
ctx := testContext()
const optional = false
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 0cc3bd6..e61ebe6 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -197,7 +197,7 @@
func init() {
pctx.Import("android/soong/android")
- android.RegisterSingletonType("dexpreopt-soong-config", func() android.Singleton {
+ android.RegisterParallelSingletonType("dexpreopt-soong-config", func() android.Singleton {
return &globalSoongConfigSingleton{}
})
}
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 2b38793..20737e3 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -52,7 +52,8 @@
// GenerateDexpreoptRule generates a set of commands that will preopt a module based on a GlobalConfig and a
// ModuleConfig. The produced files and their install locations will be available through rule.Installs().
func GenerateDexpreoptRule(ctx android.BuilderContext, globalSoong *GlobalSoongConfig,
- global *GlobalConfig, module *ModuleConfig) (rule *android.RuleBuilder, err error) {
+ global *GlobalConfig, module *ModuleConfig, productPackages android.Path) (
+ rule *android.RuleBuilder, err error) {
defer func() {
if r := recover(); r != nil {
@@ -92,7 +93,8 @@
generateDM := shouldGenerateDM(module, global)
for archIdx, _ := range module.Archs {
- dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage, generateDM)
+ dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage,
+ generateDM, productPackages)
}
}
}
@@ -232,9 +234,9 @@
pathtools.ReplaceExtension(filepath.Base(path), "odex"))
}
-func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
- module *ModuleConfig, rule *android.RuleBuilder, archIdx int, profile android.WritablePath,
- appImage bool, generateDM bool) {
+func dexpreoptCommand(ctx android.BuilderContext, globalSoong *GlobalSoongConfig,
+ global *GlobalConfig, module *ModuleConfig, rule *android.RuleBuilder, archIdx int,
+ profile android.WritablePath, appImage bool, generateDM bool, productPackages android.Path) {
arch := module.Archs[archIdx]
@@ -351,11 +353,13 @@
}
// Generate command that saves host and target class loader context in shell variables.
- clc, paths := ComputeClassLoaderContext(module.ClassLoaderContexts)
+ paths := ComputeClassLoaderContextDependencies(module.ClassLoaderContexts)
rule.Command().
Text(`eval "$(`).Tool(globalSoong.ConstructContext).
Text(` --target-sdk-version ${target_sdk_version}`).
- Text(clc).Implicits(paths).
+ FlagWithArg("--context-json=", module.ClassLoaderContexts.DumpForFlag()).
+ FlagWithInput("--product-packages=", productPackages).
+ Implicits(paths).
Text(`)"`)
}
diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
index ba05d94..8033b48 100644
--- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
+++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
@@ -42,7 +42,8 @@
// The flag is useful when running dex2oat on system image and vendor image which are built separately.
usesTargetFiles = flag.Bool("uses_target_files", false, "whether or not dexpreopt is running on target_files")
// basePath indicates the path where target_files.zip is extracted.
- basePath = flag.String("base_path", ".", "base path where images and tools are extracted")
+ basePath = flag.String("base_path", ".", "base path where images and tools are extracted")
+ productPackagesPath = flag.String("product_packages", "", "path to product_packages.txt")
)
type builderContext struct {
@@ -87,6 +88,10 @@
usage("--module configuration file is required")
}
+ if *productPackagesPath == "" {
+ usage("--product_packages configuration file is required")
+ }
+
// NOTE: duplicating --out_dir here is incorrect (one should be the another
// plus "/soong" but doing so apparently breaks dexpreopt
ctx := &builderContext{android.NullConfig(*outDir, *outDir)}
@@ -159,11 +164,12 @@
moduleConfig.DexPreoptImageLocationsOnHost[i] = *basePath + location
}
}
- writeScripts(ctx, globalSoongConfig, globalConfig, moduleConfig, *dexpreoptScriptPath)
+ writeScripts(ctx, globalSoongConfig, globalConfig, moduleConfig, *dexpreoptScriptPath, *productPackagesPath)
}
func writeScripts(ctx android.BuilderContext, globalSoong *dexpreopt.GlobalSoongConfig,
- global *dexpreopt.GlobalConfig, module *dexpreopt.ModuleConfig, dexpreoptScriptPath string) {
+ global *dexpreopt.GlobalConfig, module *dexpreopt.ModuleConfig, dexpreoptScriptPath string,
+ productPackagesPath string) {
write := func(rule *android.RuleBuilder, file string) {
script := &bytes.Buffer{}
script.WriteString(scriptHeader)
@@ -199,7 +205,8 @@
panic(err)
}
}
- dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(
+ ctx, globalSoong, global, module, android.PathForTesting(productPackagesPath))
if err != nil {
panic(err)
}
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 429b5ff..2b19c9d 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -100,8 +100,9 @@
globalSoong := globalSoongConfigForTests()
global := GlobalConfigForTests(ctx)
module := testSystemModuleConfig(ctx, "test")
+ productPackages := android.PathForTesting("product_packages.txt")
- rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
if err != nil {
t.Fatal(err)
}
@@ -124,6 +125,7 @@
systemModule := testSystemModuleConfig(ctx, "Stest")
systemProductModule := testSystemProductModuleConfig(ctx, "SPtest")
productModule := testProductModuleConfig(ctx, "Ptest")
+ productPackages := android.PathForTesting("product_packages.txt")
global.HasSystemOther = true
@@ -157,7 +159,7 @@
for _, test := range tests {
global.PatternsOnSystemOther = test.patterns
for _, mt := range test.moduleTests {
- rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, mt.module)
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, mt.module, productPackages)
if err != nil {
t.Fatal(err)
}
@@ -182,11 +184,12 @@
globalSoong := globalSoongConfigForTests()
global := GlobalConfigForTests(ctx)
module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
+ productPackages := android.PathForTesting("product_packages.txt")
global.ApexSystemServerJars = android.CreateTestConfiguredJarList(
[]string{"com.android.apex1:service-A"})
- rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
if err != nil {
t.Fatal(err)
}
@@ -205,11 +208,12 @@
globalSoong := globalSoongConfigForTests()
global := GlobalConfigForTests(ctx)
module := testPlatformSystemServerModuleConfig(ctx, "service-A")
+ productPackages := android.PathForTesting("product_packages.txt")
global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList(
[]string{"platform:service-A"})
- rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
if err != nil {
t.Fatal(err)
}
@@ -228,11 +232,12 @@
globalSoong := globalSoongConfigForTests()
global := GlobalConfigForTests(ctx)
module := testSystemExtSystemServerModuleConfig(ctx, "service-A")
+ productPackages := android.PathForTesting("product_packages.txt")
global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList(
[]string{"system_ext:service-A"})
- rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
if err != nil {
t.Fatal(err)
}
@@ -251,11 +256,12 @@
globalSoong := globalSoongConfigForTests()
global := GlobalConfigForTests(ctx)
module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
+ productPackages := android.PathForTesting("product_packages.txt")
global.ApexStandaloneSystemServerJars = android.CreateTestConfiguredJarList(
[]string{"com.android.apex1:service-A"})
- rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
if err != nil {
t.Fatal(err)
}
@@ -274,10 +280,11 @@
globalSoong := globalSoongConfigForTests()
global := GlobalConfigForTests(ctx)
module := testSystemModuleConfig(ctx, "test")
+ productPackages := android.PathForTesting("product_packages.txt")
module.ProfileClassListing = android.OptionalPathForPath(android.PathForTesting("profile"))
- rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
if err != nil {
t.Fatal(err)
}
diff --git a/genrule/Android.bp b/genrule/Android.bp
index 8fb5c40..b201cae 100644
--- a/genrule/Android.bp
+++ b/genrule/Android.bp
@@ -15,6 +15,7 @@
"soong-shared",
],
srcs: [
+ "allowlists.go",
"genrule.go",
"locations.go",
],
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
new file mode 100644
index 0000000..2954f8b
--- /dev/null
+++ b/genrule/allowlists.go
@@ -0,0 +1,134 @@
+// Copyright 2023 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 genrule
+
+var (
+ DepfileAllowList = []string{
+ "depfile_allowed_for_test",
+ "tflite_support_spm_config",
+ "tflite_support_spm_encoder_config",
+ "gen_uwb_core_proto",
+ "libtextclassifier_fbgen_utils_flatbuffers_flatbuffers_test",
+ "libtextclassifier_fbgen_utils_lua_utils_tests",
+ "libtextclassifier_fbgen_lang_id_common_flatbuffers_model",
+ "libtextclassifier_fbgen_lang_id_common_flatbuffers_embedding-network",
+ "libtextclassifier_fbgen_annotator_datetime_datetime",
+ "libtextclassifier_fbgen_annotator_model",
+ "libtextclassifier_fbgen_annotator_experimental_experimental",
+ "libtextclassifier_fbgen_annotator_entity-data",
+ "libtextclassifier_fbgen_annotator_person_name_person_name_model",
+ "libtextclassifier_fbgen_utils_tflite_text_encoder_config",
+ "libtextclassifier_fbgen_utils_codepoint-range",
+ "libtextclassifier_fbgen_utils_intents_intent-config",
+ "libtextclassifier_fbgen_utils_flatbuffers_flatbuffers",
+ "libtextclassifier_fbgen_utils_zlib_buffer",
+ "libtextclassifier_fbgen_utils_tokenizer",
+ "libtextclassifier_fbgen_utils_grammar_rules",
+ "libtextclassifier_fbgen_utils_grammar_semantics_expression",
+ "libtextclassifier_fbgen_utils_resources",
+ "libtextclassifier_fbgen_utils_i18n_language-tag",
+ "libtextclassifier_fbgen_utils_normalization",
+ "libtextclassifier_fbgen_utils_container_bit-vector",
+ "libtextclassifier_fbgen_actions_actions-entity-data",
+ "libtextclassifier_fbgen_actions_actions_model",
+ "libtextclassifier_fbgen_utils_grammar_testing_value",
+ }
+
+ SandboxingDenyModuleList = []string{
+ "framework-javastream-protos",
+ "RsBalls-rscript",
+ "CtsRsBlasTestCases-rscript",
+ "pvmfw_fdt_template_rs",
+ "RSTest_v14-rscript",
+ "com.android.apex.test.bar_stripped",
+ "com.android.apex.test.sharedlibs_secondary_generated",
+ "ImageProcessingJB-rscript",
+ "RSTest-rscript",
+ "BluetoothGeneratedDumpsysBinarySchema_bfbs",
+ "WmediumdServerProto_h",
+ "TracingVMProtoStub_h",
+ "FrontendStub_h",
+ "VehicleServerProtoStub_cc",
+ "AudioFocusControlProtoStub_cc",
+ "AudioFocusControlProtoStub_h",
+ "TracingVMProtoStub_cc",
+ "VehicleServerProtoStub_h",
+ "hidl2aidl_translate_cpp_test_gen_headers",
+ "hidl2aidl_translate_cpp_test_gen_src",
+ "hidl2aidl_translate_java_test_gen_src",
+ "hidl2aidl_translate_ndk_test_gen_headers",
+ "hidl2aidl_translate_ndk_test_gen_src",
+ "hidl_hash_test_gen",
+ "nos_app_avb_service_genc++",
+ "nos_app_avb_service_genc++_headers",
+ "nos_app_avb_service_genc++_mock",
+ "nos_app_identity_service_genc++",
+ "nos_app_keymaster_service_genc++",
+ "nos_generator_test_service_genc++_headers",
+ "nos_generator_test_service_genc++_mock",
+ "r8retrace-run-retrace",
+ "ltp_config_arm",
+ "ltp_config_arm_64_hwasan",
+ "ltp_config_arm_lowmem",
+ "ltp_config_arm_64",
+ "ltp_config_riscv_64",
+ "ltp_config_x86_64",
+ "vm-tests-tf-lib",
+ "hidl_cpp_impl_test_gen-headers",
+ "pandora_experimental-python-gen-src",
+ "framework-cppstream-protos",
+ "Refocus-rscript",
+ "RSTest_v11-rscript",
+ "RSTest_v16-rscript",
+ "ScriptGroupTest-rscript",
+ "ImageProcessing2-rscript",
+ "ImageProcessing-rscript",
+ "com.android.apex.test.pony_stripped",
+ "com.android.apex.test.baz_stripped",
+ "com.android.apex.test.foo_stripped",
+ "com.android.apex.test.sharedlibs_generated",
+ "CtsRenderscriptTestCases-rscript",
+ "BlueberryFacadeAndCertGeneratedStub_py",
+ "BlueberryFacadeGeneratedStub_cc",
+ "BlueberryFacadeGeneratedStub_h",
+ "BluetoothGeneratedDumpsysDataSchema_h",
+ "FrontendStub_cc",
+ "OpenwrtControlServerProto_cc",
+ "OpenwrtControlServerProto_h",
+ "WmediumdServerProto_cc",
+ "c2hal_test_genc++",
+ "c2hal_test_genc++_headers",
+ "hidl2aidl_test_gen_aidl",
+ "hidl_error_test_gen",
+ "hidl_export_test_gen-headers",
+ "hidl_format_test_diff",
+ "hidl_hash_version_gen",
+ "libbt_topshim_facade_py_proto",
+ "nos_app_identity_service_genc++_headers",
+ "nos_app_identity_service_genc++_mock",
+ "nos_app_keymaster_service_genc++_headers",
+ "nos_app_keymaster_service_genc++_mock",
+ "nos_app_weaver_service_genc++",
+ "nos_app_weaver_service_genc++_headers",
+ "nos_app_weaver_service_genc++_mock",
+ "nos_generator_test_service_genc++",
+ "pandora-python-gen-src",
+ }
+
+ SandboxingDenyPathList = []string{
+ "art/test",
+ "external/perfetto",
+ }
+)
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 00adb70..4992625 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -24,6 +24,7 @@
"path/filepath"
"strconv"
"strings"
+ "sync"
"android/soong/bazel/cquery"
@@ -60,6 +61,12 @@
PrepareForTestWithGenRuleBuildComponents,
)
+var DepfileAllowSet map[string]bool
+var SandboxingDenyModuleSet map[string]bool
+var SandboxingDenyPathSet map[string]bool
+var SandboxingDenyModuleSetLock sync.Mutex
+var DepfileAllowSetLock sync.Mutex
+
func RegisterGenruleBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("genrule_defaults", defaultsFactory)
@@ -452,7 +459,7 @@
manifestPath := android.PathForModuleOut(ctx, manifestName)
// Use a RuleBuilder to create a rule that runs the command inside an sbox sandbox.
- rule := android.NewRuleBuilder(pctx, ctx).Sbox(task.genDir, manifestPath).SandboxTools()
+ rule := getSandboxedRuleBuilder(ctx, android.NewRuleBuilder(pctx, ctx).Sbox(task.genDir, manifestPath))
cmd := rule.Command()
for _, out := range task.out {
@@ -594,14 +601,22 @@
func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// Allowlist genrule to use depfile until we have a solution to remove it.
// TODO(b/235582219): Remove allowlist for genrule
- if ctx.ModuleType() == "gensrcs" &&
- !ctx.DeviceConfig().BuildBrokenDepfile() &&
- Bool(g.properties.Depfile) {
- ctx.PropertyErrorf(
- "depfile",
- "Deprecated to ensure the module type is convertible to Bazel. "+
- "Try specifying the dependencies explicitly so that there is no need to use depfile. "+
- "If not possible, the escape hatch is to use BUILD_BROKEN_DEPFILE to bypass the error.")
+ if Bool(g.properties.Depfile) {
+ if DepfileAllowSet == nil {
+ DepfileAllowSetLock.Lock()
+ defer DepfileAllowSetLock.Unlock()
+ DepfileAllowSet = map[string]bool{}
+ android.AddToStringSet(DepfileAllowSet, DepfileAllowList)
+ }
+ // TODO(b/283852474): Checking the GenruleSandboxing flag is temporary in
+ // order to pass the presubmit before internal master is updated.
+ if ctx.DeviceConfig().GenruleSandboxing() && !DepfileAllowSet[g.Name()] {
+ ctx.PropertyErrorf(
+ "depfile",
+ "Deprecated to ensure the module type is convertible to Bazel. "+
+ "Try specifying the dependencies explicitly so that there is no need to use depfile. "+
+ "If not possible, the escape hatch is to add the module to allowlists.go to bypass the error.")
+ }
}
g.generateCommonBuildActions(ctx)
@@ -737,7 +752,7 @@
// TODO(ccross): this RuleBuilder is a hack to be able to call
// rule.Command().PathForOutput. Replace this with passing the rule into the
// generator.
- rule := android.NewRuleBuilder(pctx, ctx).Sbox(genDir, nil).SandboxTools()
+ rule := getSandboxedRuleBuilder(ctx, android.NewRuleBuilder(pctx, ctx).Sbox(genDir, nil))
for _, in := range shard {
outFile := android.GenPathWithExt(ctx, finalSubDir, in, String(properties.Output_extension))
@@ -1020,3 +1035,22 @@
return module
}
+
+func getSandboxedRuleBuilder(ctx android.ModuleContext, r *android.RuleBuilder) *android.RuleBuilder {
+ if !ctx.DeviceConfig().GenruleSandboxing() {
+ return r.SandboxTools()
+ }
+ if SandboxingDenyModuleSet == nil {
+ SandboxingDenyModuleSetLock.Lock()
+ defer SandboxingDenyModuleSetLock.Unlock()
+ SandboxingDenyModuleSet = map[string]bool{}
+ SandboxingDenyPathSet = map[string]bool{}
+ android.AddToStringSet(SandboxingDenyModuleSet, append(DepfileAllowList, SandboxingDenyModuleList...))
+ android.AddToStringSet(SandboxingDenyPathSet, SandboxingDenyPathList)
+ }
+
+ if SandboxingDenyPathSet[ctx.ModuleDir()] || SandboxingDenyModuleSet[ctx.ModuleName()] {
+ return r.SandboxTools()
+ }
+ return r.SandboxInputs()
+}
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 63f8fa9..370fe3d 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -97,8 +97,9 @@
func TestGenruleCmd(t *testing.T) {
testcases := []struct {
- name string
- prop string
+ name string
+ moduleName string
+ prop string
allowMissingDependencies bool
@@ -285,7 +286,8 @@
expect: "echo foo > __SBOX_SANDBOX_DIR__/out/out2",
},
{
- name: "depfile",
+ name: "depfile",
+ moduleName: "depfile_allowed_for_test",
prop: `
out: ["out"],
depfile: true,
@@ -397,7 +399,8 @@
err: "$(depfile) used without depfile property",
},
{
- name: "error no depfile",
+ name: "error no depfile",
+ moduleName: "depfile_allowed_for_test",
prop: `
out: ["out"],
depfile: true,
@@ -440,11 +443,15 @@
for _, test := range testcases {
t.Run(test.name, func(t *testing.T) {
- bp := "genrule {\n"
- bp += "name: \"gen\",\n"
- bp += test.prop
- bp += "}\n"
-
+ moduleName := "gen"
+ if test.moduleName != "" {
+ moduleName = test.moduleName
+ }
+ bp := fmt.Sprintf(`
+ genrule {
+ name: "%s",
+ %s
+ }`, moduleName, test.prop)
var expectedErrors []string
if test.err != "" {
expectedErrors = append(expectedErrors, regexp.QuoteMeta(test.err))
@@ -455,6 +462,9 @@
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.Allow_missing_dependencies = proptools.BoolPtr(test.allowMissingDependencies)
}),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.GenruleSandboxing = proptools.BoolPtr(true)
+ }),
android.FixtureModifyContext(func(ctx *android.TestContext) {
ctx.SetAllowMissingDependencies(test.allowMissingDependencies)
}),
@@ -466,7 +476,7 @@
return
}
- gen := result.Module("gen", "").(*Module)
+ gen := result.Module(moduleName, "").(*Module)
android.AssertStringEquals(t, "raw commands", test.expect, gen.rawCommands[0])
})
}
@@ -627,53 +637,42 @@
}
}
-func TestGensrcsBuildBrokenDepfile(t *testing.T) {
+func TestGenruleAllowlistingDepfile(t *testing.T) {
tests := []struct {
- name string
- prop string
- BuildBrokenDepfile *bool
- err string
+ name string
+ prop string
+ err string
+ moduleName string
}{
{
- name: `error when BuildBrokenDepfile is set to false`,
+ name: `error when module is not allowlisted`,
prop: `
depfile: true,
cmd: "cat $(in) > $(out) && cat $(depfile)",
`,
- BuildBrokenDepfile: proptools.BoolPtr(false),
- err: "depfile: Deprecated to ensure the module type is convertible to Bazel",
+ err: "depfile: Deprecated to ensure the module type is convertible to Bazel",
},
{
- name: `error when BuildBrokenDepfile is not set`,
+ name: `no error when module is allowlisted`,
prop: `
depfile: true,
cmd: "cat $(in) > $(out) && cat $(depfile)",
`,
- err: "depfile: Deprecated to ensure the module type is convertible to Bazel.",
- },
- {
- name: `no error when BuildBrokenDepfile is explicitly set to true`,
- prop: `
- depfile: true,
- cmd: "cat $(in) > $(out) && cat $(depfile)",
- `,
- BuildBrokenDepfile: proptools.BoolPtr(true),
- },
- {
- name: `no error if depfile is not set`,
- prop: `
- cmd: "cat $(in) > $(out)",
- `,
+ moduleName: `depfile_allowed_for_test`,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
+ moduleName := "foo"
+ if test.moduleName != "" {
+ moduleName = test.moduleName
+ }
bp := fmt.Sprintf(`
gensrcs {
- name: "foo",
+ name: "%s",
srcs: ["data.txt"],
%s
- }`, test.prop)
+ }`, moduleName, test.prop)
var expectedErrors []string
if test.err != "" {
@@ -682,9 +681,7 @@
android.GroupFixturePreparers(
prepareForGenRuleTest,
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- if test.BuildBrokenDepfile != nil {
- variables.BuildBrokenDepfile = test.BuildBrokenDepfile
- }
+ variables.GenruleSandboxing = proptools.BoolPtr(true)
}),
).
ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)).
diff --git a/java/app.go b/java/app.go
index e095092..3e4c8cf 100755
--- a/java/app.go
+++ b/java/app.go
@@ -18,6 +18,7 @@
// related module types, including their override variants.
import (
+ "fmt"
"path/filepath"
"strings"
@@ -613,7 +614,6 @@
}
}
-
return mainCertificate, certificates
}
@@ -621,13 +621,21 @@
return a.installApkName
}
-func (a *AndroidApp) createPrivappAllowlist(ctx android.ModuleContext) *android.OutputPath {
+func (a *AndroidApp) createPrivappAllowlist(ctx android.ModuleContext) android.Path {
if a.appProperties.Privapp_allowlist == nil {
return nil
}
+
+ isOverrideApp := a.GetOverriddenBy() != ""
+ if !isOverrideApp {
+ // if this is not an override, we don't need to rewrite the existing privapp allowlist
+ return android.PathForModuleSrc(ctx, *a.appProperties.Privapp_allowlist)
+ }
+
if a.overridableAppProperties.Package_name == nil {
ctx.PropertyErrorf("privapp_allowlist", "package_name must be set to use privapp_allowlist")
}
+
packageName := *a.overridableAppProperties.Package_name
fileName := "privapp_allowlist_" + packageName + ".xml"
outPath := android.PathForModuleOut(ctx, fileName).OutputPath
@@ -787,17 +795,18 @@
// Install the app package.
shouldInstallAppPackage := (Bool(a.Module.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() && !a.appProperties.PreventInstall
if shouldInstallAppPackage {
+ if a.privAppAllowlist.Valid() {
+ allowlistInstallPath := android.PathForModuleInstall(ctx, "etc", "permissions")
+ allowlistInstallFilename := a.installApkName + ".xml"
+ ctx.InstallFile(allowlistInstallPath, allowlistInstallFilename, a.privAppAllowlist.Path())
+ }
+
var extraInstalledPaths android.Paths
for _, extra := range a.extraOutputFiles {
installed := ctx.InstallFile(a.installDir, extra.Base(), extra)
extraInstalledPaths = append(extraInstalledPaths, installed)
}
ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile, extraInstalledPaths...)
-
- if a.privAppAllowlist.Valid() {
- installPath := android.PathForModuleInstall(ctx, "etc", "permissions")
- ctx.InstallFile(installPath, a.privAppAllowlist.Path().Base(), a.privAppAllowlist.Path())
- }
}
a.buildAppDependencyInfo(ctx)
@@ -977,6 +986,10 @@
// For OutputFileProducer interface
func (a *AndroidApp) OutputFiles(tag string) (android.Paths, error) {
switch tag {
+ // In some instances, it can be useful to reference the aapt-generated flags from another
+ // target, e.g., system server implements services declared in the framework-res manifest.
+ case ".aapt.proguardOptionsFile":
+ return []android.Path{a.proguardOptionsFile}, nil
case ".aapt.srcjar":
return []android.Path{a.aaptSrcJar}, nil
case ".export-package.apk":
@@ -1379,10 +1392,15 @@
}
}
-// presentOptionalUsesLibs returns optional_uses_libs after filtering out MissingUsesLibraries, which don't exist in the
-// build.
+// presentOptionalUsesLibs returns optional_uses_libs after filtering out libraries that don't exist in the source tree.
func (u *usesLibrary) presentOptionalUsesLibs(ctx android.BaseModuleContext) []string {
- optionalUsesLibs, _ := android.FilterList(u.usesLibraryProperties.Optional_uses_libs, ctx.Config().MissingUsesLibraries())
+ optionalUsesLibs := android.FilterListPred(u.usesLibraryProperties.Optional_uses_libs, func(s string) bool {
+ exists := ctx.OtherModuleExists(s)
+ if !exists && !android.InList(ctx.ModuleName(), ctx.Config().BuildWarningBadOptionalUsesLibsAllowlist()) {
+ fmt.Printf("Warning: Module '%s' depends on non-existing optional_uses_libs '%s'\n", ctx.ModuleName(), s)
+ }
+ return exists
+ })
return optionalUsesLibs
}
diff --git a/java/app_test.go b/java/app_test.go
index c485478..cf7d174 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -2645,7 +2645,7 @@
PrepareForTestWithJavaSdkLibraryFiles,
FixtureWithLastReleaseApis("runtime-library", "foo", "quuz", "qux", "bar", "fred"),
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.MissingUsesLibraries = []string{"baz"}
+ variables.BuildWarningBadOptionalUsesLibsAllowlist = []string{"app", "prebuilt"}
}),
).RunTestWithBp(t, bp)
@@ -2693,52 +2693,11 @@
`--optional-uses-library baz `
android.AssertStringDoesContain(t, "verify apk cmd args", verifyApkCmd, verifyApkArgs)
- // Test that all present libraries are preopted, including implicit SDK dependencies, possibly stubs
+ // Test that necessary args are passed for constructing CLC in Ninja phase.
cmd := app.Rule("dexpreopt").RuleParams.Command
- w := `--target-context-for-sdk any ` +
- `PCL[/system/framework/qux.jar]#` +
- `PCL[/system/framework/quuz.jar]#` +
- `PCL[/system/framework/foo.jar]#` +
- `PCL[/system/framework/non-sdk-lib.jar]#` +
- `PCL[/system/framework/bar.jar]#` +
- `PCL[/system/framework/runtime-library.jar]#` +
- `PCL[/system/framework/runtime-required-x.jar]#` +
- `PCL[/system/framework/runtime-optional-x.jar]#` +
- `PCL[/system/framework/runtime-required-y.jar]#` +
- `PCL[/system/framework/runtime-optional-y.jar] `
- android.AssertStringDoesContain(t, "dexpreopt app cmd args", cmd, w)
-
- // Test conditional context for target SDK version 28.
- android.AssertStringDoesContain(t, "dexpreopt app cmd 28", cmd,
- `--target-context-for-sdk 28`+
- ` PCL[/system/framework/org.apache.http.legacy.jar] `)
-
- // Test conditional context for target SDK version 29.
- android.AssertStringDoesContain(t, "dexpreopt app cmd 29", cmd,
- `--target-context-for-sdk 29`+
- ` PCL[/system/framework/android.hidl.manager-V1.0-java.jar]`+
- `#PCL[/system/framework/android.hidl.base-V1.0-java.jar] `)
-
- // Test conditional context for target SDK version 30.
- // "android.test.mock" is absent because "android.test.runner" is not used.
- android.AssertStringDoesContain(t, "dexpreopt app cmd 30", cmd,
- `--target-context-for-sdk 30`+
- ` PCL[/system/framework/android.test.base.jar] `)
-
- cmd = prebuilt.Rule("dexpreopt").RuleParams.Command
- android.AssertStringDoesContain(t, "dexpreopt prebuilt cmd", cmd,
- `--target-context-for-sdk any`+
- ` PCL[/system/framework/foo.jar]`+
- `#PCL[/system/framework/non-sdk-lib.jar]`+
- `#PCL[/system/framework/android.test.runner.jar]`+
- `#PCL[/system/framework/bar.jar] `)
-
- // Test conditional context for target SDK version 30.
- // "android.test.mock" is present because "android.test.runner" is used.
- android.AssertStringDoesContain(t, "dexpreopt prebuilt cmd 30", cmd,
- `--target-context-for-sdk 30`+
- ` PCL[/system/framework/android.test.base.jar]`+
- `#PCL[/system/framework/android.test.mock.jar] `)
+ android.AssertStringDoesContain(t, "dexpreopt app cmd context", cmd, "--context-json=")
+ android.AssertStringDoesContain(t, "dexpreopt app cmd product_packages", cmd,
+ "--product-packages=out/soong/target/product/test_device/product_packages.txt")
}
func TestDexpreoptBcp(t *testing.T) {
@@ -3563,9 +3522,8 @@
android_app {
name: "foo",
srcs: ["a.java"],
- privapp_allowlist: "perms.xml",
+ privapp_allowlist: "privapp_allowlist_com.android.foo.xml",
privileged: true,
- package_name: "com.android.foo",
sdk_version: "current",
}
override_android_app {
@@ -3578,20 +3536,94 @@
app := result.ModuleForTests("foo", "android_common")
overrideApp := result.ModuleForTests("foo", "android_common_bar")
- // verify that privapp allowlist is created
- app.Output("out/soong/.intermediates/foo/android_common/privapp_allowlist_com.android.foo.xml")
+ // verify that privapp allowlist is created for override apps
overrideApp.Output("out/soong/.intermediates/foo/android_common_bar/privapp_allowlist_com.google.android.foo.xml")
- expectedAllowlist := "perms.xml"
- actualAllowlist := app.Rule("modifyAllowlist").Input.String()
- if expectedAllowlist != actualAllowlist {
- t.Errorf("expected allowlist to be %q; got %q", expectedAllowlist, actualAllowlist)
- }
- overrideActualAllowlist := overrideApp.Rule("modifyAllowlist").Input.String()
- if expectedAllowlist != overrideActualAllowlist {
- t.Errorf("expected override allowlist to be %q; got %q", expectedAllowlist, overrideActualAllowlist)
+ expectedAllowlistInput := "privapp_allowlist_com.android.foo.xml"
+ overrideActualAllowlistInput := overrideApp.Rule("modifyAllowlist").Input.String()
+ if expectedAllowlistInput != overrideActualAllowlistInput {
+ t.Errorf("expected override allowlist to be %q; got %q", expectedAllowlistInput, overrideActualAllowlistInput)
}
// verify that permissions are copied to device
- app.Output("out/soong/target/product/test_device/system/etc/permissions/privapp_allowlist_com.android.foo.xml")
- overrideApp.Output("out/soong/target/product/test_device/system/etc/permissions/privapp_allowlist_com.google.android.foo.xml")
+ app.Output("out/soong/target/product/test_device/system/etc/permissions/foo.xml")
+ overrideApp.Output("out/soong/target/product/test_device/system/etc/permissions/bar.xml")
+}
+
+func TestPrivappAllowlistAndroidMk(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ android.PrepareForTestWithAndroidMk,
+ ).RunTestWithBp(
+ t,
+ `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ privapp_allowlist: "privapp_allowlist_com.android.foo.xml",
+ privileged: true,
+ sdk_version: "current",
+ }
+ override_android_app {
+ name: "bar",
+ base: "foo",
+ package_name: "com.google.android.foo",
+ }
+ `,
+ )
+ baseApp := result.ModuleForTests("foo", "android_common")
+ overrideApp := result.ModuleForTests("foo", "android_common_bar")
+
+ baseAndroidApp := baseApp.Module().(*AndroidApp)
+ baseEntries := android.AndroidMkEntriesForTest(t, result.TestContext, baseAndroidApp)[0]
+ android.AssertStringMatches(
+ t,
+ "androidmk has incorrect LOCAL_SOONG_INSTALLED_MODULE; expected to find foo.apk",
+ baseEntries.EntryMap["LOCAL_SOONG_INSTALLED_MODULE"][0],
+ "\\S+foo.apk",
+ )
+ android.AssertStringMatches(
+ t,
+ "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include foo.apk",
+ baseEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0],
+ "\\S+foo.apk",
+ )
+ android.AssertStringMatches(
+ t,
+ "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include app",
+ baseEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0],
+ "\\S+foo.apk:\\S+/target/product/test_device/system/priv-app/foo/foo.apk",
+ )
+ android.AssertStringMatches(
+ t,
+ "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include privapp_allowlist",
+ baseEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0],
+ "privapp_allowlist_com.android.foo.xml:\\S+/target/product/test_device/system/etc/permissions/foo.xml",
+ )
+
+ overrideAndroidApp := overrideApp.Module().(*AndroidApp)
+ overrideEntries := android.AndroidMkEntriesForTest(t, result.TestContext, overrideAndroidApp)[0]
+ android.AssertStringMatches(
+ t,
+ "androidmk has incorrect LOCAL_SOONG_INSTALLED_MODULE; expected to find bar.apk",
+ overrideEntries.EntryMap["LOCAL_SOONG_INSTALLED_MODULE"][0],
+ "\\S+bar.apk",
+ )
+ android.AssertStringMatches(
+ t,
+ "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include bar.apk",
+ overrideEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0],
+ "\\S+bar.apk",
+ )
+ android.AssertStringMatches(
+ t,
+ "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include app",
+ overrideEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0],
+ "\\S+bar.apk:\\S+/target/product/test_device/system/priv-app/bar/bar.apk",
+ )
+ android.AssertStringMatches(
+ t,
+ "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include privapp_allowlist",
+ overrideEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0],
+ "\\S+soong/.intermediates/foo/android_common_bar/privapp_allowlist_com.google.android.foo.xml:\\S+/target/product/test_device/system/etc/permissions/bar.xml",
+ )
}
diff --git a/java/base.go b/java/base.go
index 374138c..dd02ef8 100644
--- a/java/base.go
+++ b/java/base.go
@@ -2188,5 +2188,9 @@
if binary, ok := ctx.Module().(*Binary); ok {
javaBinaryHostBp2Build(ctx, binary)
}
+ case "java_test_host":
+ if testHost, ok := ctx.Module().(*TestHost); ok {
+ javaTestHostBp2Build(ctx, testHost)
+ }
}
}
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index 2541f14..9bdef74 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -432,3 +432,39 @@
fragment = result.Module("a_test_fragment", "android_common").(*BootclasspathFragmentModule)
android.AssertBoolEquals(t, "is a test fragment by type", true, fragment.isTestFragment())
}
+
+func TestBootclassFragment_LinkTextStub(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ prepareForTestWithBootclasspathFragment,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("mysdklibrary"),
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.SetBuildFromTextStub(true)
+ }),
+ ).RunTestWithBp(t, `
+ bootclasspath_fragment {
+ name: "myfragment",
+ contents: ["mysdklibrary"],
+ hidden_api: {split_packages: ["*"]},
+ additional_stubs: [
+ "android-non-updatable",
+ ],
+ }
+ java_sdk_library {
+ name: "mysdklibrary",
+ srcs: ["a.java"],
+ shared_library: false,
+ public: {enabled: true},
+ system: {enabled: true},
+ }
+ `)
+
+ fragment := result.ModuleForTests("myfragment", "android_common")
+ ruleCommand := fragment.Rule("modularHiddenAPIStubFlagsFile").RuleParams.Command
+ android.AssertStringDoesContain(t, "Command expected to contain library as dependency stub dex",
+ ruleCommand, "--dependency-stub-dex=out/soong/.intermediates/default/java/android-non-updatable.stubs.module_lib.from-text/android_common/dex/android-non-updatable.stubs.module_lib.from-text.jar")
+ android.AssertStringDoesNotContain(t,
+ "Command not expected to contain multiple api_library as dependency stub dex", ruleCommand,
+ "--dependency-stub-dex=out/soong/.intermediates/default/java/android-non-updatable.stubs.from-text/android_common/dex/android-non-updatable.stubs.from-text.jar")
+}
diff --git a/java/config/config.go b/java/config/config.go
index b82a137..195dae1 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -98,7 +98,7 @@
"-JDcom.android.tools.r8.emitRecordAnnotationsExInDex",
}, dexerJavaVmFlagsList...))
exportedVars.ExportStringListStaticVariable("R8Flags", append([]string{
- "-JXmx2048M",
+ "-JXmx4096M",
"-JDcom.android.tools.r8.emitRecordAnnotationsInDex",
"-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex",
"-JDcom.android.tools.r8.emitRecordAnnotationsExInDex",
diff --git a/java/core-libraries/TxtStubLibraries.bp b/java/core-libraries/TxtStubLibraries.bp
index 813187e..0cf0f36 100644
--- a/java/core-libraries/TxtStubLibraries.bp
+++ b/java/core-libraries/TxtStubLibraries.bp
@@ -22,8 +22,6 @@
libs: [
"core-current-stubs-for-system-modules-no-annotations.from-text",
],
- // TODO: Enable after stub generation from .txt file is available
- enabled: false,
}
java_library {
@@ -36,8 +34,6 @@
"core.current.stubs.from-text",
"core-lambda-stubs.from-text",
],
- // TODO: Enable after stub generation from .txt file is available
- enabled: false,
}
// Same as core-module-lib-stubs-system-modules, but the stubs are generated from .txt files
@@ -47,8 +43,6 @@
libs: [
"core-module-lib-stubs-for-system-modules-no-annotations.from-text",
],
- // TODO: Enable after stub generation from .txt file is available
- enabled: false,
}
java_library {
@@ -61,8 +55,6 @@
"core.module_lib.stubs.from-text",
"core-lambda-stubs.from-text",
],
- // TODO: Enable after stub generation from .txt file is available
- enabled: false,
}
java_library {
@@ -79,8 +71,6 @@
sdk_version: "none",
system_modules: "none",
visibility: ["//visibility:private"],
- // TODO: Enable after stub generation from .txt file is available
- enabled: false,
}
// Same as legacy-core-platform-api-stubs-system-modules, but the stubs are generated from .txt files
@@ -91,8 +81,6 @@
"legacy.core.platform.api.no.annotations.stubs.from-text",
"core-lambda-stubs.from-text",
],
- // TODO: Enable after stub generation from .txt file is available
- enabled: false,
}
java_library {
@@ -108,8 +96,6 @@
"legacy.core.platform.api.stubs.from-text",
],
patch_module: "java.base",
- // TODO: Enable after stub generation from .txt file is available
- enabled: false,
}
// Same as stable-core-platform-api-stubs-system-modules, but the stubs are generated from .txt files
@@ -120,8 +106,6 @@
"stable.core.platform.api.no.annotations.stubs.from-text",
"core-lambda-stubs.from-text",
],
- // TODO: Enable after stub generation from .txt file is available
- enabled: false,
}
java_library {
@@ -137,8 +121,6 @@
"stable.core.platform.api.stubs.from-text",
],
patch_module: "java.base",
- // TODO: Enable after stub generation from .txt file is available
- enabled: false,
}
java_api_library {
@@ -151,6 +133,4 @@
// LambdaMetaFactory depends on CallSite etc. which is part of the Core API surface
"core.current.stubs.from-text",
],
- // TODO: Enable after stub generation from .txt file is available
- enabled: false,
}
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index a96b312..e588c9a 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -390,7 +390,11 @@
globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
- dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, dexpreoptConfig)
+ // "product_packages.txt" is generated by `build/make/core/Makefile`.
+ productPackages := android.PathForModuleInPartitionInstall(ctx, "", "product_packages.txt")
+
+ dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(
+ ctx, globalSoong, global, dexpreoptConfig, productPackages)
if err != nil {
ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error())
return
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index f477f40..35f6097 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -465,7 +465,7 @@
}
func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) {
- ctx.RegisterSingletonModuleType("dex_bootjars", dexpreoptBootJarsFactory)
+ ctx.RegisterParallelSingletonModuleType("dex_bootjars", dexpreoptBootJarsFactory)
}
func SkipDexpreoptBootJars(ctx android.PathContext) bool {
@@ -816,7 +816,7 @@
cmd.FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch])
}
- if global.EnableUffdGc {
+ if global.EnableUffdGc && image.target.Os == android.Android {
cmd.Flag("--runtime-arg").Flag("-Xgc:CMC")
}
diff --git a/java/dexpreopt_check.go b/java/dexpreopt_check.go
index 83c088c..7499481 100644
--- a/java/dexpreopt_check.go
+++ b/java/dexpreopt_check.go
@@ -28,7 +28,7 @@
}
func RegisterDexpreoptCheckBuildComponents(ctx android.RegistrationContext) {
- ctx.RegisterSingletonModuleType("dexpreopt_systemserver_check", dexpreoptSystemserverCheckFactory)
+ ctx.RegisterParallelSingletonModuleType("dexpreopt_systemserver_check", dexpreoptSystemserverCheckFactory)
}
// A build-time check to verify if all compilation artifacts of system server jars are installed
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 8a521aa..151c94a 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -535,6 +535,14 @@
// b/223382732
FlagWithArg("--hide ", "ChangedDefault")
+ // Force metalava to ignore classes on the classpath when an API file contains missing classes.
+ // See b/285140653 for more information.
+ cmd.FlagWithArg("--api-class-resolution ", "api")
+
+ // Force metalava to sort overloaded methods by their order in the source code.
+ // See b/285312164 for more information.
+ cmd.FlagWithArg("--api-overloaded-method-order ", "source")
+
return cmd
}
diff --git a/java/fuzz.go b/java/fuzz.go
index 770b694..b3c2fd4 100644
--- a/java/fuzz.go
+++ b/java/fuzz.go
@@ -42,7 +42,7 @@
func RegisterJavaFuzzBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("java_fuzz", JavaFuzzFactory)
- ctx.RegisterSingletonType("java_fuzz_packaging", javaFuzzPackagingFactory)
+ ctx.RegisterParallelSingletonType("java_fuzz_packaging", javaFuzzPackagingFactory)
}
type JavaFuzzTest struct {
@@ -165,7 +165,9 @@
}
hostOrTargetString := "target"
- if javaFuzzModule.Host() {
+ if javaFuzzModule.Target().HostCross {
+ hostOrTargetString = "host_cross"
+ } else if javaFuzzModule.Host() {
hostOrTargetString = "host"
}
@@ -190,7 +192,11 @@
files = s.PackageArtifacts(ctx, module, javaFuzzModule.fuzzPackagedModule, archDir, builder)
// Add .jar
- files = append(files, fuzz.FileToZip{SourceFilePath: javaFuzzModule.implementationJarFile})
+ if !javaFuzzModule.Host() {
+ files = append(files, fuzz.FileToZip{SourceFilePath: javaFuzzModule.implementationJarFile, DestinationPathPrefix: "classes"})
+ }
+
+ files = append(files, fuzz.FileToZip{SourceFilePath: javaFuzzModule.outputFile})
// Add jni .so files
for _, fPath := range javaFuzzModule.jniFilePaths {
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 96e084a..e54275b 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -647,7 +647,7 @@
// public version is provided by the art.module.public.api module. In those cases it is necessary
// to treat all those modules as they were the same name, otherwise it will result in multiple
// definitions of a single class being passed to hidden API processing which will cause an error.
- if name == scope.nonUpdatablePrebuiltModule || name == scope.nonUpdatableSourceModule {
+ if name == scope.nonUpdatablePrebuiltModule || name == android.JavaApiLibraryName(ctx.Config(), scope.nonUpdatableSourceModule) {
// Treat all *android-non-updatable* modules as if they were part of an android-non-updatable
// java_sdk_library.
// TODO(b/192067200): Remove once android-non-updatable is a java_sdk_library or equivalent.
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 52934a3..d4ee4fc 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -25,7 +25,7 @@
}
func RegisterHiddenApiSingletonComponents(ctx android.RegistrationContext) {
- ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory)
+ ctx.RegisterParallelSingletonType("hiddenapi", hiddenAPISingletonFactory)
}
var PrepareForTestWithHiddenApiBuildComponents = android.FixtureRegisterWithContext(RegisterHiddenApiSingletonComponents)
diff --git a/java/java.go b/java/java.go
index 65bfce0..4f7b401 100644
--- a/java/java.go
+++ b/java/java.go
@@ -73,8 +73,8 @@
ctx.BottomUp("jacoco_deps", jacocoDepsMutator).Parallel()
})
- ctx.RegisterSingletonType("logtags", LogtagsSingleton)
- ctx.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory)
+ ctx.RegisterParallelSingletonType("logtags", LogtagsSingleton)
+ ctx.RegisterParallelSingletonType("kythe_java_extract", kytheExtractJavaFactory)
}
func RegisterJavaSdkMemberTypes() {
@@ -936,6 +936,10 @@
// Extra <option> tags to add to the auto generated test xml file. The "key"
// is optional in each of these.
Tradefed_options []tradefed.Option
+
+ // Extra <option> tags to add to the auto generated test xml file under the test runner, e.g., AndroidJunitTest.
+ // The "key" is optional in each of these.
+ Test_runner_options []tradefed.Option
}
type testProperties struct {
@@ -1218,6 +1222,7 @@
TestSuites: j.testProperties.Test_suites,
Config: configs,
OptionsForAutogenerated: j.testProperties.Test_options.Tradefed_options,
+ TestRunnerOptions: j.testProperties.Test_options.Test_runner_options,
AutoGenConfig: j.testProperties.Auto_gen_config,
UnitTest: j.testProperties.Test_options.Unit_test,
DeviceTemplate: "${JavaTestConfigTemplate}",
@@ -1416,6 +1421,8 @@
nil,
nil)
+ android.InitBazelModule(module)
+
InitJavaModuleMultiTargets(module, android.HostSupported)
return module
@@ -1650,7 +1657,7 @@
// list of api.txt files relative to this directory that contribute to the
// API surface.
// This is a list of relative paths
- Api_files []string
+ Api_files []string `android:"path"`
// List of flags to be passed to the javac compiler to generate jar file
Javacflags []string
@@ -1728,6 +1735,14 @@
FlagWithArg("--hide ", "InvalidNullabilityOverride").
FlagWithArg("--hide ", "ChangedDefault")
+ // Force metalava to ignore classes on the classpath when an API file contains missing classes.
+ // See b/285140653 for more information.
+ cmd.FlagWithArg("--api-class-resolution ", "api")
+
+ // Force metalava to sort overloaded methods by their order in the source code.
+ // See b/285312164 for more information.
+ cmd.FlagWithArg("--api-overloaded-method-order ", "source")
+
return cmd
}
@@ -1813,7 +1828,7 @@
case javaApiContributionTag:
provider := ctx.OtherModuleProvider(dep, JavaApiImportProvider).(JavaApiImportInfo)
providerApiFile := provider.ApiFile
- if providerApiFile == nil {
+ if providerApiFile == nil && !ctx.Config().AllowMissingDependencies() {
ctx.ModuleErrorf("Error: %s has an empty api file.", dep.Name())
}
srcFiles = append(srcFiles, android.PathForSource(ctx, providerApiFile.String()))
@@ -1832,12 +1847,10 @@
// Add the api_files inputs
for _, api := range al.properties.Api_files {
- // Use MaybeExistentPathForSource since the api file might not exist during analysis.
- // This will be provided by the orchestrator in the combined execution.
- srcFiles = append(srcFiles, android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), api))
+ srcFiles = append(srcFiles, android.PathForModuleSrc(ctx, api))
}
- if srcFiles == nil {
+ if srcFiles == nil && !ctx.Config().AllowMissingDependencies() {
ctx.ModuleErrorf("Error: %s has an empty api file.", ctx.ModuleName())
}
@@ -2608,6 +2621,7 @@
&appProperties{},
&appTestProperties{},
&overridableAppProperties{},
+ &hostTestProperties{},
&testProperties{},
&ImportProperties{},
&AARImportProperties{},
@@ -2705,6 +2719,15 @@
Resource_strip_prefix *string
}
+func (m *Library) javaResourcesGetSingleFilegroupStripPrefix(ctx android.TopDownMutatorContext) (string, bool) {
+ if otherM, ok := ctx.ModuleFromName(m.properties.Java_resources[0]); ok && len(m.properties.Java_resources) == 1 {
+ if fg, isFilegroup := otherM.(android.FileGroupPath); isFilegroup {
+ return filepath.Join(ctx.OtherModuleDir(otherM), fg.GetPath(ctx)), true
+ }
+ }
+ return "", false
+}
+
func (m *Library) convertJavaResourcesAttributes(ctx android.TopDownMutatorContext) *javaResourcesAttributes {
var resources bazel.LabelList
var resourceStripPrefix *string
@@ -2714,8 +2737,12 @@
}
if m.properties.Java_resources != nil {
+ if prefix, ok := m.javaResourcesGetSingleFilegroupStripPrefix(ctx); ok {
+ resourceStripPrefix = proptools.StringPtr(prefix)
+ } else {
+ resourceStripPrefix = proptools.StringPtr(ctx.ModuleDir())
+ }
resources.Append(android.BazelLabelForModuleSrc(ctx, m.properties.Java_resources))
- resourceStripPrefix = proptools.StringPtr(ctx.ModuleDir())
}
//TODO(b/179889880) handle case where glob includes files outside package
@@ -3102,23 +3129,89 @@
return
}
- libName := m.Name() + "_lib"
+ libInfo := libraryCreationInfo{
+ deps: deps,
+ attrs: commonAttrs,
+ baseName: m.Name(),
+ hasKotlin: bp2BuildInfo.hasKotlin,
+ }
+ libName := createLibraryTarget(ctx, libInfo)
+ binAttrs.Runtime_deps.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + libName}})
+
+ // Create the BazelTargetModule.
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, binAttrs)
+}
+
+type javaTestHostAttributes struct {
+ *javaCommonAttributes
+ Deps bazel.LabelListAttribute
+ Runtime_deps bazel.LabelListAttribute
+}
+
+// javaTestHostBp2Build is for java_test_host bp2build.
+func javaTestHostBp2Build(ctx android.TopDownMutatorContext, m *TestHost) {
+ commonAttrs, bp2BuildInfo := m.convertLibraryAttrsBp2Build(ctx)
+ depLabels := bp2BuildInfo.DepLabels
+
+ deps := depLabels.Deps
+ deps.Append(depLabels.StaticDeps)
+
+ var runtimeDeps bazel.LabelListAttribute
+ attrs := &javaTestHostAttributes{
+ Runtime_deps: runtimeDeps,
+ }
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "java_test",
+ Bzl_load_location: "//build/bazel/rules/java:test.bzl",
+ }
+
+ if commonAttrs.Srcs.IsEmpty() {
+ // if there are no sources, then the dependencies can only be used at runtime
+ attrs.Runtime_deps = deps
+ attrs.javaCommonAttributes = commonAttrs
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+ return
+ }
+
+ libInfo := libraryCreationInfo{
+ deps: deps,
+ attrs: commonAttrs,
+ baseName: m.Name(),
+ hasKotlin: bp2BuildInfo.hasKotlin,
+ }
+ libName := createLibraryTarget(ctx, libInfo)
+ attrs.Runtime_deps.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + libName}})
+
+ // Create the BazelTargetModule.
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+}
+
+// libraryCreationInfo encapsulates the info needed to create java_library target from
+// java_binary_host or java_test_host.
+type libraryCreationInfo struct {
+ deps bazel.LabelListAttribute
+ attrs *javaCommonAttributes
+ baseName string
+ hasKotlin bool
+}
+
+// helper function that creates java_library target from java_binary_host or java_test_host,
+// and returns the library target name,
+func createLibraryTarget(ctx android.TopDownMutatorContext, libInfo libraryCreationInfo) string {
+ libName := libInfo.baseName + "_lib"
var libProps bazel.BazelTargetModuleProperties
- if bp2BuildInfo.hasKotlin {
+ if libInfo.hasKotlin {
libProps = ktJvmLibraryBazelTargetModuleProperties()
} else {
libProps = javaLibraryBazelTargetModuleProperties()
}
libAttrs := &javaLibraryAttributes{
- Deps: deps,
- javaCommonAttributes: commonAttrs,
+ Deps: libInfo.deps,
+ javaCommonAttributes: libInfo.attrs,
}
ctx.CreateBazelTargetModule(libProps, android.CommonAttributes{Name: libName}, libAttrs)
- binAttrs.Runtime_deps.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + libName}})
-
- // Create the BazelTargetModule.
- ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, binAttrs)
+ return libName
}
type bazelJavaImportAttributes struct {
diff --git a/java/java_test.go b/java/java_test.go
index 2a4913e..cd5c343 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -2252,6 +2252,29 @@
android.AssertStringDoesContain(t, "Command expected to contain output files list text file flag", manifestCommand, "--out __SBOX_SANDBOX_DIR__/out/sources.txt")
}
+func TestJavaApiLibraryFilegroupInput(t *testing.T) {
+ ctx, _ := testJavaWithFS(t, `
+ filegroup {
+ name: "default_current.txt",
+ srcs: ["current.txt"],
+ }
+
+ java_api_library {
+ name: "foo",
+ api_files: [":default_current.txt"],
+ }
+ `,
+ map[string][]byte{
+ "current.txt": nil,
+ })
+
+ m := ctx.ModuleForTests("foo", "android_common")
+ outputs := fmt.Sprint(m.AllOutputs())
+ if !strings.Contains(outputs, "foo/foo.jar") {
+ t.Errorf("Module output does not contain expected jar %s", "foo/foo.jar")
+ }
+}
+
func TestTradefedOptions(t *testing.T) {
result := PrepareForTestWithJavaBuildComponents.RunTestWithBp(t, `
java_test_host {
@@ -2275,3 +2298,27 @@
t.Errorf("Expected args[\"extraConfigs\"] to equal %q, was %q", expected, args["extraConfigs"])
}
}
+
+func TestTestRunnerOptions(t *testing.T) {
+ result := PrepareForTestWithJavaBuildComponents.RunTestWithBp(t, `
+java_test_host {
+ name: "foo",
+ test_options: {
+ test_runner_options: [
+ {
+ name: "test-timeout",
+ value: "10m"
+ }
+ ]
+ }
+}
+`)
+
+ buildOS := result.Config.BuildOS.String()
+ args := result.ModuleForTests("foo", buildOS+"_common").
+ Output("out/soong/.intermediates/foo/" + buildOS + "_common/foo.config").Args
+ expected := proptools.NinjaAndShellEscape("<option name=\"test-timeout\" value=\"10m\" />\\n ")
+ if args["extraTestRunnerConfigs"] != expected {
+ t.Errorf("Expected args[\"extraTestRunnerConfigs\"] to equal %q, was %q", expected, args["extraTestRunnerConfigs"])
+ }
+}
diff --git a/java/jdeps.go b/java/jdeps.go
index a52b867..4c8c11c 100644
--- a/java/jdeps.go
+++ b/java/jdeps.go
@@ -26,7 +26,7 @@
// called. Dependency info file is generated in $OUT/module_bp_java_depend.json.
func init() {
- android.RegisterSingletonType("jdeps_generator", jDepsGeneratorSingleton)
+ android.RegisterParallelSingletonType("jdeps_generator", jDepsGeneratorSingleton)
}
func jDepsGeneratorSingleton() android.Singleton {
diff --git a/java/lint.go b/java/lint.go
index 40ef484..a0f9970 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -705,7 +705,7 @@
var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
func init() {
- android.RegisterSingletonType("lint",
+ android.RegisterParallelSingletonType("lint",
func() android.Singleton { return &lintSingleton{} })
registerLintBuildComponents(android.InitRegistrationContext)
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 07fb92c..0d4db7c 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -26,7 +26,7 @@
}
func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContext) {
- ctx.RegisterSingletonModuleType("platform_bootclasspath", platformBootclasspathFactory)
+ ctx.RegisterParallelSingletonModuleType("platform_bootclasspath", platformBootclasspathFactory)
}
// The tags used for the dependencies between the platform bootclasspath and any configured boot
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index d417291..2197304 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -36,7 +36,7 @@
}
func registerPlatformCompatConfigBuildComponents(ctx android.RegistrationContext) {
- ctx.RegisterSingletonType("platform_compat_config_singleton", platformCompatConfigSingletonFactory)
+ ctx.RegisterParallelSingletonType("platform_compat_config_singleton", platformCompatConfigSingletonFactory)
ctx.RegisterModuleType("platform_compat_config", PlatformCompatConfigFactory)
ctx.RegisterModuleType("prebuilt_platform_compat_config", prebuiltCompatConfigFactory)
ctx.RegisterModuleType("global_compat_config", globalCompatConfigFactory)
diff --git a/java/robolectric.go b/java/robolectric.go
index 008b8b1..6bbe872 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -144,29 +144,37 @@
roboTestConfig := android.PathForModuleGen(ctx, "robolectric").
Join(ctx, "com/android/tools/test_config.properties")
+ var ok bool
+ var instrumentedApp *AndroidApp
+
// TODO: this inserts paths to built files into the test, it should really be inserting the contents.
instrumented := ctx.GetDirectDepsWithTag(instrumentationForTag)
- if len(instrumented) != 1 {
+ if len(instrumented) == 1 {
+ instrumentedApp, ok = instrumented[0].(*AndroidApp)
+ if !ok {
+ ctx.PropertyErrorf("instrumentation_for", "dependency must be an android_app")
+ }
+ } else if !ctx.Config().AllowMissingDependencies() {
panic(fmt.Errorf("expected exactly 1 instrumented dependency, got %d", len(instrumented)))
}
- instrumentedApp, ok := instrumented[0].(*AndroidApp)
- if !ok {
- ctx.PropertyErrorf("instrumentation_for", "dependency must be an android_app")
+ if instrumentedApp != nil {
+ r.manifest = instrumentedApp.mergedManifestFile
+ r.resourceApk = instrumentedApp.outputFile
+
+ generateRoboTestConfig(ctx, roboTestConfig, instrumentedApp)
+ r.extraResources = android.Paths{roboTestConfig}
}
- r.manifest = instrumentedApp.mergedManifestFile
- r.resourceApk = instrumentedApp.outputFile
-
- generateRoboTestConfig(ctx, roboTestConfig, instrumentedApp)
- r.extraResources = android.Paths{roboTestConfig}
-
r.Library.GenerateAndroidBuildActions(ctx)
roboSrcJar := android.PathForModuleGen(ctx, "robolectric", ctx.ModuleName()+".srcjar")
- r.generateRoboSrcJar(ctx, roboSrcJar, instrumentedApp)
- r.roboSrcJar = roboSrcJar
+
+ if instrumentedApp != nil {
+ r.generateRoboSrcJar(ctx, roboSrcJar, instrumentedApp)
+ r.roboSrcJar = roboSrcJar
+ }
roboTestConfigJar := android.PathForModuleOut(ctx, "robolectric_samedir", "samedir_config.jar")
generateSameDirRoboTestConfigJar(ctx, roboTestConfigJar)
@@ -177,7 +185,10 @@
// once the Make test runner is removed.
roboTestConfigJar,
r.outputFile,
- instrumentedApp.implementationAndResourcesJar,
+ }
+
+ if instrumentedApp != nil {
+ combinedJarJars = append(combinedJarJars, instrumentedApp.implementationAndResourcesJar)
}
handleLibDeps := func(dep android.Module) {
@@ -213,21 +224,28 @@
r.tests = append(r.tests, s)
}
- r.data = append(r.data, r.manifest, r.resourceApk)
+ installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
+ var installDeps android.Paths
+
+ if r.manifest != nil {
+ r.data = append(r.data, r.manifest)
+ installedManifest := ctx.InstallFile(installPath, ctx.ModuleName()+"-AndroidManifest.xml", r.manifest)
+ installDeps = append(installDeps, installedManifest)
+ }
+
+ if r.resourceApk != nil {
+ r.data = append(r.data, r.resourceApk)
+ installedResourceApk := ctx.InstallFile(installPath, ctx.ModuleName()+".apk", r.resourceApk)
+ installDeps = append(installDeps, installedResourceApk)
+ }
runtimes := ctx.GetDirectDepWithTag("robolectric-android-all-prebuilts", roboRuntimesTag)
-
- installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
-
- installedResourceApk := ctx.InstallFile(installPath, ctx.ModuleName()+".apk", r.resourceApk)
- installedManifest := ctx.InstallFile(installPath, ctx.ModuleName()+"-AndroidManifest.xml", r.manifest)
- installedConfig := ctx.InstallFile(installPath, ctx.ModuleName()+".config", r.testConfig)
-
- var installDeps android.Paths
for _, runtime := range runtimes.(*robolectricRuntimes).runtimes {
installDeps = append(installDeps, runtime)
}
- installDeps = append(installDeps, installedResourceApk, installedManifest, installedConfig)
+
+ installedConfig := ctx.InstallFile(installPath, ctx.ModuleName()+".config", r.testConfig)
+ installDeps = append(installDeps, installedConfig)
for _, data := range android.PathsForModuleSrc(ctx, r.testProperties.Data) {
installedData := ctx.InstallFile(installPath, data.Rel(), data)
@@ -340,7 +358,9 @@
fmt.Fprintln(w, "LOCAL_MODULE :=", name)
android.AndroidMkEmitAssignList(w, "LOCAL_JAVA_LIBRARIES", []string{module}, r.libs)
fmt.Fprintln(w, "LOCAL_TEST_PACKAGE :=", String(r.robolectricProperties.Instrumentation_for))
- fmt.Fprintln(w, "LOCAL_INSTRUMENT_SRCJARS :=", r.roboSrcJar.String())
+ if r.roboSrcJar != nil {
+ fmt.Fprintln(w, "LOCAL_INSTRUMENT_SRCJARS :=", r.roboSrcJar.String())
+ }
android.AndroidMkEmitAssignList(w, "LOCAL_ROBOTEST_FILES", tests)
if t := r.robolectricProperties.Test_options.Timeout; t != nil {
fmt.Fprintln(w, "LOCAL_ROBOTEST_TIMEOUT :=", *t)
diff --git a/java/sdk.go b/java/sdk.go
index 8b4918a..7fa604f 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -28,7 +28,7 @@
func init() {
android.RegisterPreSingletonType("sdk_versions", sdkPreSingletonFactory)
- android.RegisterSingletonType("sdk", sdkSingletonFactory)
+ android.RegisterParallelSingletonType("sdk", sdkSingletonFactory)
android.RegisterMakeVarsProvider(pctx, sdkMakeVars)
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 103f1ac..89da19a 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -156,6 +156,9 @@
// Whether the api scope can be treated as unstable, and should skip compat checks.
unstable bool
+
+ // Represents the SDK kind of this scope.
+ kind android.SdkKind
}
// Initialize a scope, creating and adding appropriate dependency tags
@@ -229,6 +232,10 @@
return ".stubs" + scope.moduleSuffix
}
+func (scope *apiScope) apiLibraryModuleName(baseName string) string {
+ return scope.stubsLibraryModuleName(baseName) + ".from-text"
+}
+
func (scope *apiScope) stubsLibraryModuleName(baseName string) string {
return baseName + scope.stubsLibraryModuleNameSuffix()
}
@@ -289,6 +296,7 @@
return &module.sdkLibraryProperties.Public
},
sdkVersion: "current",
+ kind: android.SdkPublic,
})
apiScopeSystem = initApiScope(&apiScope{
name: "system",
@@ -301,6 +309,7 @@
moduleSuffix: ".system",
sdkVersion: "system_current",
annotation: "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS)",
+ kind: android.SdkSystem,
})
apiScopeTest = initApiScope(&apiScope{
name: "test",
@@ -314,6 +323,7 @@
sdkVersion: "test_current",
annotation: "android.annotation.TestApi",
unstable: true,
+ kind: android.SdkTest,
})
apiScopeModuleLib = initApiScope(&apiScope{
name: "module-lib",
@@ -331,6 +341,7 @@
moduleSuffix: ".module_lib",
sdkVersion: "module_current",
annotation: "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES)",
+ kind: android.SdkModule,
})
apiScopeSystemServer = initApiScope(&apiScope{
name: "system-server",
@@ -361,6 +372,7 @@
// com.android.* classes are okay in this interface"
"--hide", "InternalClasses",
},
+ kind: android.SdkSystemServer,
})
allApiScopes = apiScopes{
apiScopePublic,
@@ -842,6 +854,13 @@
return c.namingScheme.stubsSourceModuleName(apiScope, baseName)
}
+// Name of the java_api_library module that generates the from-text stubs source
+// and compiles to a jar file.
+func (c *commonToSdkLibraryAndImport) apiLibraryModuleName(apiScope *apiScope) string {
+ baseName := c.module.BaseModuleName()
+ return c.namingScheme.apiLibraryModuleName(apiScope, baseName)
+}
+
// The component names for different outputs of the java_sdk_library.
//
// They are similar to the names used for the child modules it creates
@@ -1269,7 +1288,9 @@
// Add dependencies to the stubs library
stubModuleName := module.stubsLibraryModuleName(apiScope)
// Use JavaApiLibraryName function to be redirected to stubs generated from .txt if applicable
- stubModuleName = android.JavaApiLibraryName(ctx.Config(), stubModuleName)
+ if module.contributesToApiSurface(ctx.Config()) {
+ stubModuleName = android.JavaApiLibraryName(ctx.Config(), stubModuleName)
+ }
ctx.AddVariationDependencies(nil, apiScope.stubsTag, stubModuleName)
// Add a dependency on the stubs source in order to access both stubs source and api information.
@@ -1477,6 +1498,11 @@
return latestPrebuiltApiModuleName(module.distStem()+"-incompatibilities", apiScope)
}
+func (module *SdkLibrary) contributesToApiSurface(c android.Config) bool {
+ _, exists := c.GetApiLibraries()[module.Name()]
+ return exists
+}
+
func childModuleVisibility(childVisibility []string) []string {
if childVisibility == nil {
// No child visibility set. The child will use the visibility of the sdk_library.
@@ -1758,6 +1784,46 @@
mctx.CreateModule(DroidstubsFactory, &props).(*Droidstubs).CallHookIfAvailable(mctx)
}
+func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
+ props := struct {
+ Name *string
+ Visibility []string
+ Api_contributions []string
+ Libs []string
+ Static_libs []string
+ Dep_api_srcs *string
+ }{}
+
+ props.Name = proptools.StringPtr(module.apiLibraryModuleName(apiScope))
+ props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
+
+ apiContributions := []string{}
+
+ // Api surfaces are not independent of each other, but have subset relationships,
+ // and so does the api files. To generate from-text stubs for api surfaces other than public,
+ // all subset api domains' api_contriubtions must be added as well.
+ scope := apiScope
+ for scope != nil {
+ apiContributions = append(apiContributions, module.stubsSourceModuleName(scope)+".api.contribution")
+ scope = scope.extends
+ }
+
+ props.Api_contributions = apiContributions
+ props.Libs = module.properties.Libs
+ props.Libs = append(props.Libs, module.sdkLibraryProperties.Stub_only_libs...)
+ props.Libs = append(props.Libs, "stub-annotations")
+ props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs
+ props.Dep_api_srcs = proptools.StringPtr(apiScope.kind.DefaultJavaLibraryName() + ".from-text")
+
+ // android_module_lib_stubs_current.from-text only comprises api contributions from art, conscrypt and i18n.
+ // Thus, replace with android_module_lib_stubs_current_full.from-text, which comprises every api domains.
+ if apiScope.kind == android.SdkModule {
+ props.Dep_api_srcs = proptools.StringPtr(apiScope.kind.DefaultJavaLibraryName() + "_full.from-text")
+ }
+
+ mctx.CreateModule(ApiLibraryFactory, &props)
+}
+
func (module *SdkLibrary) compareAgainstLatestApi(apiScope *apiScope) bool {
return !(apiScope.unstable || module.sdkLibraryProperties.Unsafe_ignore_missing_latest_api)
}
@@ -1954,6 +2020,10 @@
module.createStubsSourcesAndApi(mctx, scope, module.stubsSourceModuleName(scope), scope.droidstubsArgs)
module.createStubsLibrary(mctx, scope)
+
+ if module.contributesToApiSurface(mctx.Config()) {
+ module.createApiLibrary(mctx, scope)
+ }
}
if module.requiresRuntimeImplementationLibrary() {
@@ -2006,6 +2076,8 @@
stubsLibraryModuleName(scope *apiScope, baseName string) string
stubsSourceModuleName(scope *apiScope, baseName string) string
+
+ apiLibraryModuleName(scope *apiScope, baseName string) string
}
type defaultNamingScheme struct {
@@ -2019,6 +2091,10 @@
return scope.stubsSourceModuleName(baseName)
}
+func (s *defaultNamingScheme) apiLibraryModuleName(scope *apiScope, baseName string) string {
+ return scope.apiLibraryModuleName(baseName)
+}
+
var _ sdkLibraryComponentNamingScheme = (*defaultNamingScheme)(nil)
func moduleStubLinkType(name string) (stub bool, ret sdkLinkType) {
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 1d0c13d..141e16b 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -35,6 +35,9 @@
"29": {"foo"},
"30": {"bar", "barney", "baz", "betty", "foo", "fred", "quuz", "wilma"},
}),
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.SetApiLibraries([]string{"foo"})
+ }),
).RunTestWithBp(t, `
droiddoc_exported_dir {
name: "droiddoc-templates-sdk",
@@ -121,6 +124,7 @@
result.ModuleForTests(apiScopeSystem.stubsSourceModuleName("foo"), "android_common")
result.ModuleForTests(apiScopeTest.stubsSourceModuleName("foo"), "android_common")
result.ModuleForTests(apiScopePublic.stubsSourceModuleName("foo")+".api.contribution", "")
+ result.ModuleForTests(apiScopePublic.apiLibraryModuleName("foo"), "android_common")
result.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common")
result.ModuleForTests("foo.api.public.28", "")
result.ModuleForTests("foo.api.system.28", "")
@@ -1412,3 +1416,62 @@
fooStubsSources := result.ModuleForTests("foo.stubs.source", "android_common").Module().(*Droidstubs)
android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs, "bar-lib")
}
+
+func TestJavaSdkLibrary_ApiLibrary(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.SetApiLibraries([]string{"foo"})
+ }),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ system: {
+ enabled: true,
+ },
+ module_lib: {
+ enabled: true,
+ },
+ test: {
+ enabled: true,
+ },
+ }
+ `)
+
+ testCases := []struct {
+ scope *apiScope
+ apiContributions []string
+ depApiSrcs string
+ }{
+ {
+ scope: apiScopePublic,
+ apiContributions: []string{"foo.stubs.source.api.contribution"},
+ depApiSrcs: "android_stubs_current.from-text",
+ },
+ {
+ scope: apiScopeSystem,
+ apiContributions: []string{"foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
+ depApiSrcs: "android_system_stubs_current.from-text",
+ },
+ {
+ scope: apiScopeTest,
+ apiContributions: []string{"foo.stubs.source.test.api.contribution", "foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
+ depApiSrcs: "android_test_stubs_current.from-text",
+ },
+ {
+ scope: apiScopeModuleLib,
+ apiContributions: []string{"foo.stubs.source.module_lib.api.contribution", "foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
+ depApiSrcs: "android_module_lib_stubs_current_full.from-text",
+ },
+ }
+
+ for _, c := range testCases {
+ m := result.ModuleForTests(c.scope.apiLibraryModuleName("foo"), "android_common").Module().(*ApiLibrary)
+ android.AssertArrayString(t, "Module expected to contain api contributions", c.apiContributions, m.properties.Api_contributions)
+ android.AssertStringEquals(t, "Module expected to contain full api surface api library", c.depApiSrcs, *m.properties.Dep_api_srcs)
+ }
+}
diff --git a/java/testing.go b/java/testing.go
index 6671bf0..3a238d7 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -71,7 +71,12 @@
// Needed for framework
defaultJavaDir + "/framework/aidl": nil,
// Needed for various deps defined in GatherRequiredDepsForTest()
- defaultJavaDir + "/a.java": nil,
+ defaultJavaDir + "/a.java": nil,
+ defaultJavaDir + "/api/current.txt": nil,
+ defaultJavaDir + "/api/system-current.txt": nil,
+ defaultJavaDir + "/api/test-current.txt": nil,
+ defaultJavaDir + "/api/module-lib-current.txt": nil,
+ defaultJavaDir + "/api/system-server-current.txt": nil,
// Needed for R8 rules on apps
"build/make/core/proguard.flags": nil,
@@ -395,16 +400,20 @@
}
extraApiLibraryModules := map[string]string{
- "android_stubs_current.from-text": "api/current.txt",
- "android_system_stubs_current.from-text": "api/system-current.txt",
- "android_test_stubs_current.from-text": "api/test-current.txt",
- "android_module_lib_stubs_current.from-text": "api/module-lib-current.txt",
- "android_module_lib_stubs_current_full.from-text": "api/module-lib-current.txt",
- "android_system_server_stubs_current.from-text": "api/system-server-current.txt",
- "core.current.stubs.from-text": "api/current.txt",
- "legacy.core.platform.api.stubs.from-text": "api/current.txt",
- "stable.core.platform.api.stubs.from-text": "api/current.txt",
- "core-lambda-stubs.from-text": "api/current.txt",
+ "android_stubs_current.from-text": "api/current.txt",
+ "android_system_stubs_current.from-text": "api/system-current.txt",
+ "android_test_stubs_current.from-text": "api/test-current.txt",
+ "android_module_lib_stubs_current.from-text": "api/module-lib-current.txt",
+ "android_module_lib_stubs_current_full.from-text": "api/module-lib-current.txt",
+ "android_system_server_stubs_current.from-text": "api/system-server-current.txt",
+ "core.current.stubs.from-text": "api/current.txt",
+ "legacy.core.platform.api.stubs.from-text": "api/current.txt",
+ "stable.core.platform.api.stubs.from-text": "api/current.txt",
+ "core-lambda-stubs.from-text": "api/current.txt",
+ "android-non-updatable.stubs.from-text": "api/current.txt",
+ "android-non-updatable.stubs.system.from-text": "api/system-current.txt",
+ "android-non-updatable.stubs.test.from-text": "api/test-current.txt",
+ "android-non-updatable.stubs.module_lib.from-text": "api/module-lib-current.txt",
}
for libName, apiFile := range extraApiLibraryModules {
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 8225df6..c0ae0c0 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -870,7 +870,7 @@
}
// Safeguard against $(call inherit-product,$(PRODUCT_PATH))
- const maxMatchingFiles = 150
+ const maxMatchingFiles = 155 // temporarily increased to 155 for b/284854738
if len(matchingPaths) > maxMatchingFiles {
return []starlarkNode{ctx.newBadNode(v, "there are >%d files matching the pattern, please rewrite it", maxMatchingFiles)}
}
diff --git a/multitree/metadata.go b/multitree/metadata.go
index 3fd7215..0eb0efc 100644
--- a/multitree/metadata.go
+++ b/multitree/metadata.go
@@ -20,7 +20,7 @@
)
func init() {
- android.RegisterSingletonType("update-meta", UpdateMetaSingleton)
+ android.RegisterParallelSingletonType("update-meta", UpdateMetaSingleton)
}
func UpdateMetaSingleton() android.Singleton {
diff --git a/provenance/provenance_singleton.go b/provenance/provenance_singleton.go
index fbb6212..5d27c0c 100644
--- a/provenance/provenance_singleton.go
+++ b/provenance/provenance_singleton.go
@@ -51,7 +51,7 @@
}
func RegisterProvenanceSingleton(ctx android.RegistrationContext) {
- ctx.RegisterSingletonType("provenance_metadata_singleton", provenanceInfoSingletonFactory)
+ ctx.RegisterParallelSingletonType("provenance_metadata_singleton", provenanceInfoSingletonFactory)
}
var PrepareForTestWithProvenanceSingleton = android.FixtureRegisterWithContext(RegisterProvenanceSingleton)
diff --git a/python/test.go b/python/test.go
index 31da17e..6e23a44 100644
--- a/python/test.go
+++ b/python/test.go
@@ -39,7 +39,7 @@
}
func PythonTestHostFactory() android.Module {
- return NewTest(android.HostSupportedNoCross).init()
+ return NewTest(android.HostSupported).init()
}
func PythonTestFactory() android.Module {
@@ -66,6 +66,10 @@
// Test options.
Test_options TestOptions
+
+ // list of device binary modules that should be installed alongside the test
+ // This property adds 64bit AND 32bit variants of the dependency
+ Data_device_bins_both []string `android:"arch_variant"`
}
type TestOptions struct {
@@ -98,12 +102,48 @@
android.InitAndroidArchModule(p, p.hod, p.multilib)
android.InitDefaultableModule(p)
android.InitBazelModule(p)
- if p.hod == android.HostSupportedNoCross && p.testProperties.Test_options.Unit_test == nil {
+ if p.isTestHost() && p.testProperties.Test_options.Unit_test == nil {
p.testProperties.Test_options.Unit_test = proptools.BoolPtr(true)
}
return p
}
+func (p *PythonTestModule) isTestHost() bool {
+ return p.hod == android.HostSupported
+}
+
+var dataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"}
+
+// python_test_host DepsMutator uses this method to add multilib dependencies of
+// data_device_bin_both
+func (p *PythonTestModule) addDataDeviceBinsDeps(ctx android.BottomUpMutatorContext, filter string) {
+ if len(p.testProperties.Data_device_bins_both) < 1 {
+ return
+ }
+
+ var maybeAndroidTarget *android.Target
+ androidTargetList := android.FirstTarget(ctx.Config().Targets[android.Android], filter)
+ if len(androidTargetList) > 0 {
+ maybeAndroidTarget = &androidTargetList[0]
+ }
+
+ if maybeAndroidTarget != nil {
+ ctx.AddFarVariationDependencies(
+ maybeAndroidTarget.Variations(),
+ dataDeviceBinsTag,
+ p.testProperties.Data_device_bins_both...,
+ )
+ }
+}
+
+func (p *PythonTestModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+ p.PythonBinaryModule.DepsMutator(ctx)
+ if p.isTestHost() {
+ p.addDataDeviceBinsDeps(ctx, "lib32")
+ p.addDataDeviceBinsDeps(ctx, "lib64")
+ }
+}
+
func (p *PythonTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// We inherit from only the library's GenerateAndroidBuildActions, and then
// just use buildBinary() so that the binary is not installed into the location
@@ -153,6 +193,12 @@
p.data = append(p.data, android.DataPath{SrcPath: dataSrcPath})
}
+ if p.isTestHost() && len(p.testProperties.Data_device_bins_both) > 0 {
+ ctx.VisitDirectDepsWithTag(dataDeviceBinsTag, func(dep android.Module) {
+ p.data = append(p.data, android.DataPath{SrcPath: android.OutputFileForModule(ctx, dep, "")})
+ })
+ }
+
// Emulate the data property for java_data dependencies.
for _, javaData := range ctx.GetDirectDepsWithTag(javaDataTag) {
for _, javaDataSrcPath := range android.OutputFilesForModule(ctx, javaData, "") {
diff --git a/rust/builder.go b/rust/builder.go
index 0aa2225..0dfaef4 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -261,7 +261,7 @@
// Disallow experimental features
modulePath := android.PathForModuleSrc(ctx).String()
if !(android.IsThirdPartyPath(modulePath) || strings.HasPrefix(modulePath, "prebuilts")) {
- rustcFlags = append(rustcFlags, "-Zallow-features=\"custom_inner_attributes,mixed_integer_ops\"")
+ rustcFlags = append(rustcFlags, "-Zallow-features=\"\"")
}
// Collect linker flags
diff --git a/rust/config/global.go b/rust/config/global.go
index 748bb3d..60acc6e 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -51,9 +51,6 @@
// Use v0 mangling to distinguish from C++ symbols
"-C symbol-mangling-version=v0",
"--color always",
- // TODO (b/267698452): Temporary workaround until the "no unstable
- // features" policy is enforced.
- "-A stable-features",
"-Zdylib-lto",
}
diff --git a/rust/doc.go b/rust/doc.go
index fe3581b..6970d79 100644
--- a/rust/doc.go
+++ b/rust/doc.go
@@ -19,7 +19,7 @@
)
func init() {
- android.RegisterSingletonType("rustdoc", RustdocSingleton)
+ android.RegisterParallelSingletonType("rustdoc", RustdocSingleton)
}
func RustdocSingleton() android.Singleton {
diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go
index 865665e..7fa9f5c 100644
--- a/rust/fuzz_test.go
+++ b/rust/fuzz_test.go
@@ -46,18 +46,16 @@
// Check that compiler flags are set appropriately .
fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Rule("rustc")
- if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-Z sanitizer=hwaddress") ||
- !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov-module'") ||
+ if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov-module'") ||
!strings.Contains(fuzz_libtest.Args["rustcFlags"], "--cfg fuzzing") {
- t.Errorf("rust_fuzz module does not contain the expected flags (sancov-module, cfg fuzzing, hwaddress sanitizer).")
+ t.Errorf("rust_fuzz module does not contain the expected flags (sancov-module, cfg fuzzing).")
}
// Check that dependencies have 'fuzzer' variants produced for them as well.
libtest_fuzzer := ctx.ModuleForTests("libtest_fuzzing", "android_arm64_armv8-a_rlib_rlib-std_fuzzer").Output("libtest_fuzzing.rlib")
- if !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-Z sanitizer=hwaddress") ||
- !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-C passes='sancov-module'") ||
+ if !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-C passes='sancov-module'") ||
!strings.Contains(libtest_fuzzer.Args["rustcFlags"], "--cfg fuzzing") {
- t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov-module, cfg fuzzing, hwaddress sanitizer).")
+ t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov-module, cfg fuzzing).")
}
}
diff --git a/rust/project_json.go b/rust/project_json.go
index fe259d6..40aa7c7 100644
--- a/rust/project_json.go
+++ b/rust/project_json.go
@@ -74,7 +74,7 @@
}
func init() {
- android.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
+ android.RegisterParallelSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
}
// sourceProviderVariantSource returns the path to the source file if this
diff --git a/rust/rust.go b/rust/rust.go
index dc53cc0..4324ecb 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -45,7 +45,7 @@
})
pctx.Import("android/soong/rust/config")
pctx.ImportAs("cc_config", "android/soong/cc/config")
- android.InitRegistrationContext.RegisterSingletonType("kythe_rust_extract", kytheExtractRustFactory)
+ android.InitRegistrationContext.RegisterParallelSingletonType("kythe_rust_extract", kytheExtractRustFactory)
}
type Flags struct {
diff --git a/rust/sanitize.go b/rust/sanitize.go
index c68137e..83cf055 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -226,11 +226,6 @@
}
if Bool(sanitize.Properties.Sanitize.Fuzzer) {
flags.RustFlags = append(flags.RustFlags, fuzzerFlags...)
- if ctx.Arch().ArchType == android.Arm64 && ctx.Os().Bionic() {
- flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
- } else {
- flags.RustFlags = append(flags.RustFlags, asanFlags...)
- }
} else if Bool(sanitize.Properties.Sanitize.Hwaddress) {
flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
} else if Bool(sanitize.Properties.Sanitize.Address) {
@@ -424,14 +419,6 @@
return true
}
- // TODO(b/178365482): Rust/CC interop doesn't work just yet; don't sanitize rust_ffi modules until
- // linkage issues are resolved.
- if lib, ok := mod.compiler.(libraryInterface); ok {
- if lib.shared() || lib.static() {
- return true
- }
- }
-
return mod.sanitize.isSanitizerExplicitlyDisabled(t)
}
diff --git a/rust/testing.go b/rust/testing.go
index 0a6a870..7f30569 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -200,8 +200,8 @@
ctx.BottomUp("rust_stdlinkage", LibstdMutator).Parallel()
ctx.BottomUp("rust_begin", BeginMutator).Parallel()
})
- ctx.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
- ctx.RegisterSingletonType("kythe_rust_extract", kytheExtractRustFactory)
+ ctx.RegisterParallelSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
+ ctx.RegisterParallelSingletonType("kythe_rust_extract", kytheExtractRustFactory)
ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel()
})
diff --git a/scripts/construct_context.py b/scripts/construct_context.py
index 3f601c3..fc3a89e 100755
--- a/scripts/construct_context.py
+++ b/scripts/construct_context.py
@@ -19,6 +19,7 @@
from __future__ import print_function
import argparse
+import json
import sys
from manifest import compare_version_gt
@@ -33,20 +34,14 @@
dest='sdk',
help='specify target SDK version (as it appears in the manifest)')
parser.add_argument(
- '--host-context-for-sdk',
- dest='host_contexts',
- action='append',
- nargs=2,
- metavar=('sdk', 'context'),
- help='specify context on host for a given SDK version or "any" version')
+ '--context-json',
+ default='',
+ dest='context_json',
+ )
parser.add_argument(
- '--target-context-for-sdk',
- dest='target_contexts',
- action='append',
- nargs=2,
- metavar=('sdk', 'context'),
- help='specify context on target for a given SDK version or "any" '
- 'version'
+ '--product-packages',
+ default='',
+ dest='product_packages_file',
)
return parser.parse_args(args)
@@ -55,28 +50,69 @@
# context regardless of the target SDK version.
any_sdk = 'any'
-
-# We assume that the order of context arguments passed to this script is
-# correct (matches the order computed by package manager). It is possible to
-# sort them here, but Soong needs to use deterministic order anyway, so it can
-# as well use the correct order.
-def construct_context(versioned_contexts, target_sdk):
- context = []
- for [sdk, ctx] in versioned_contexts:
- if sdk == any_sdk or compare_version_gt(sdk, target_sdk):
- context.append(ctx)
- return context
+context_sep = '#'
-def construct_contexts(args):
- host_context = construct_context(args.host_contexts, args.sdk)
- target_context = construct_context(args.target_contexts, args.sdk)
- context_sep = '#'
+def encode_class_loader(context, product_packages):
+ host_sub_contexts, target_sub_contexts = encode_class_loaders(
+ context['Subcontexts'], product_packages)
+
+ return ('PCL[%s]%s' % (context['Host'], host_sub_contexts),
+ 'PCL[%s]%s' % (context['Device'], target_sub_contexts))
+
+
+def encode_class_loaders(contexts, product_packages):
+ host_contexts = []
+ target_contexts = []
+
+ for context in contexts:
+ if not context['Optional'] or context['Name'] in product_packages:
+ host_context, target_context = encode_class_loader(
+ context, product_packages)
+ host_contexts.append(host_context)
+ target_contexts.append(target_context)
+
+ if host_contexts:
+ return ('{%s}' % context_sep.join(host_contexts),
+ '{%s}' % context_sep.join(target_contexts))
+ else:
+ return '', ''
+
+
+def construct_context_args(target_sdk, context_json, product_packages):
+ all_contexts = []
+
+ # CLC for different SDK versions should come in specific order that agrees
+ # with PackageManager. Since PackageManager processes SDK versions in
+ # ascending order and prepends compatibility libraries at the front, the
+ # required order is descending, except for any_sdk that has numerically
+ # the largest order, but must be the last one. Example of correct order:
+ # [30, 29, 28, any_sdk]. There are Python tests to ensure that someone
+ # doesn't change this by accident, but there is no way to guard against
+ # changes in the PackageManager, except for grepping logcat on the first
+ # boot for absence of the following messages:
+ #
+ # `logcat | grep -E 'ClassLoaderContext [a-z ]+ mismatch`
+
+ for sdk, contexts in sorted(
+ ((sdk, contexts)
+ for sdk, contexts in context_json.items()
+ if sdk != any_sdk and compare_version_gt(sdk, target_sdk)),
+ key=lambda item: int(item[0]), reverse=True):
+ all_contexts += contexts
+
+ if any_sdk in context_json:
+ all_contexts += context_json[any_sdk]
+
+ host_contexts, target_contexts = encode_class_loaders(
+ all_contexts, product_packages)
+
return (
- 'class_loader_context_arg=--class-loader-context=PCL[]{%s} ; ' %
- context_sep.join(host_context) +
- 'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{%s}' #pylint: disable=line-too-long
- % context_sep.join(target_context))
+ 'class_loader_context_arg=--class-loader-context=PCL[]%s ; ' %
+ host_contexts +
+ 'stored_class_loader_context_arg='
+ '--stored-class-loader-context=PCL[]%s'
+ % target_contexts)
def main():
@@ -85,12 +121,12 @@
args = parse_args(sys.argv[1:])
if not args.sdk:
raise SystemExit('target sdk version is not set')
- if not args.host_contexts:
- args.host_contexts = []
- if not args.target_contexts:
- args.target_contexts = []
- print(construct_contexts(args))
+ context_json = json.loads(args.context_json)
+ with open(args.product_packages_file, 'r') as f:
+ product_packages = set(line.strip() for line in f if line.strip())
+
+ print(construct_context_args(args.sdk, context_json, product_packages))
# pylint: disable=broad-except
except Exception as err:
diff --git a/scripts/construct_context_test.py b/scripts/construct_context_test.py
index 2ff5ac5..34a0e16 100755
--- a/scripts/construct_context_test.py
+++ b/scripts/construct_context_test.py
@@ -24,62 +24,249 @@
sys.dont_write_bytecode = True
-def construct_contexts(arglist):
- args = cc.parse_args(arglist)
- return cc.construct_contexts(args)
+CONTEXT_JSON = {
+ '28': [
+ {
+ 'Name': 'z',
+ 'Optional': False,
+ 'Host': 'out/zdir/z.jar',
+ 'Device': '/system/z.jar',
+ 'Subcontexts': [],
+ },
+ ],
+ '29': [
+ {
+ 'Name': 'x',
+ 'Optional': False,
+ 'Host': 'out/xdir/x.jar',
+ 'Device': '/system/x.jar',
+ 'Subcontexts': [],
+ },
+ {
+ 'Name': 'y',
+ 'Optional': False,
+ 'Host': 'out/ydir/y.jar',
+ 'Device': '/product/y.jar',
+ 'Subcontexts': [],
+ },
+ ],
+ 'any': [
+ {
+ 'Name': 'a',
+ 'Optional': False,
+ 'Host': 'out/adir/a.jar',
+ 'Device': '/system/a.jar',
+ 'Subcontexts': [
+ { # Not installed optional, being the only child.
+ 'Name': 'a1',
+ 'Optional': True,
+ 'Host': 'out/a1dir/a1.jar',
+ 'Device': '/product/a1.jar',
+ 'Subcontexts': [],
+ },
+ ],
+ },
+ {
+ 'Name': 'b',
+ 'Optional': True,
+ 'Host': 'out/bdir/b.jar',
+ 'Device': '/product/b.jar',
+ 'Subcontexts': [
+ { # Not installed but required.
+ 'Name': 'b1',
+ 'Optional': False,
+ 'Host': 'out/b1dir/b1.jar',
+ 'Device': '/product/b1.jar',
+ 'Subcontexts': [],
+ },
+ { # Installed optional.
+ 'Name': 'b2',
+ 'Optional': True,
+ 'Host': 'out/b2dir/b2.jar',
+ 'Device': '/product/b2.jar',
+ 'Subcontexts': [],
+ },
+ { # Not installed optional.
+ 'Name': 'b3',
+ 'Optional': True,
+ 'Host': 'out/b3dir/b3.jar',
+ 'Device': '/product/b3.jar',
+ 'Subcontexts': [],
+ },
+ { # Installed optional with one more level of nested deps.
+ 'Name': 'b4',
+ 'Optional': True,
+ 'Host': 'out/b4dir/b4.jar',
+ 'Device': '/product/b4.jar',
+ 'Subcontexts': [
+ {
+ 'Name': 'b41',
+ 'Optional': True,
+ 'Host': 'out/b41dir/b41.jar',
+ 'Device': '/product/b41.jar',
+ 'Subcontexts': [],
+ },
+ {
+ 'Name': 'b42',
+ 'Optional': True,
+ 'Host': 'out/b42dir/b42.jar',
+ 'Device': '/product/b42.jar',
+ 'Subcontexts': [],
+ },
+ ],
+ },
+ ],
+ },
+ { # Not installed optional, at the top-level.
+ 'Name': 'c',
+ 'Optional': True,
+ 'Host': 'out/cdir/c.jar',
+ 'Device': '/product/c.jar',
+ 'Subcontexts': [],
+ },
+ ],
+}
-contexts = [
- '--host-context-for-sdk',
- '28',
- 'PCL[out/zdir/z.jar]',
- '--target-context-for-sdk',
- '28',
- 'PCL[/system/z.jar]',
- '--host-context-for-sdk',
- '29',
- 'PCL[out/xdir/x.jar]#PCL[out/ydir/y.jar]',
- '--target-context-for-sdk',
- '29',
- 'PCL[/system/x.jar]#PCL[/product/y.jar]',
- '--host-context-for-sdk',
- 'any',
- 'PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]',
- '--target-context-for-sdk',
- 'any',
- 'PCL[/system/a.jar]#PCL[/product/b.jar]',
-]
+PRODUCT_PACKAGES = ['a', 'b', 'b2', 'b4', 'b41', 'b42', 'x', 'y', 'z']
-#pylint: disable=line-too-long
+
+def construct_context_args(target_sdk):
+ return cc.construct_context_args(target_sdk, CONTEXT_JSON, PRODUCT_PACKAGES)
+
+
class ConstructContextTest(unittest.TestCase):
+ def test_construct_context_27(self):
+ actual = construct_context_args('27')
+ # The order matters.
+ expected = (
+ 'class_loader_context_arg='
+ '--class-loader-context=PCL[]{'
+ 'PCL[out/xdir/x.jar]#'
+ 'PCL[out/ydir/y.jar]#'
+ 'PCL[out/zdir/z.jar]#'
+ 'PCL[out/adir/a.jar]#'
+ 'PCL[out/bdir/b.jar]{'
+ 'PCL[out/b1dir/b1.jar]#'
+ 'PCL[out/b2dir/b2.jar]#'
+ 'PCL[out/b4dir/b4.jar]{'
+ 'PCL[out/b41dir/b41.jar]#'
+ 'PCL[out/b42dir/b42.jar]'
+ '}'
+ '}'
+ '}'
+ ' ; '
+ 'stored_class_loader_context_arg='
+ '--stored-class-loader-context=PCL[]{'
+ 'PCL[/system/x.jar]#'
+ 'PCL[/product/y.jar]#'
+ 'PCL[/system/z.jar]#'
+ 'PCL[/system/a.jar]#'
+ 'PCL[/product/b.jar]{'
+ 'PCL[/product/b1.jar]#'
+ 'PCL[/product/b2.jar]#'
+ 'PCL[/product/b4.jar]{'
+ 'PCL[/product/b41.jar]#'
+ 'PCL[/product/b42.jar]'
+ '}'
+ '}'
+ '}')
+ self.assertEqual(actual, expected)
def test_construct_context_28(self):
- args = ['--target-sdk-version', '28'] + contexts
- result = construct_contexts(args)
- expect = (
- 'class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/xdir/x.jar]#PCL[out/ydir/y.jar]#PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]}'
+ actual = construct_context_args('28')
+ expected = (
+ 'class_loader_context_arg='
+ '--class-loader-context=PCL[]{'
+ 'PCL[out/xdir/x.jar]#'
+ 'PCL[out/ydir/y.jar]#'
+ 'PCL[out/adir/a.jar]#'
+ 'PCL[out/bdir/b.jar]{'
+ 'PCL[out/b1dir/b1.jar]#'
+ 'PCL[out/b2dir/b2.jar]#'
+ 'PCL[out/b4dir/b4.jar]{'
+ 'PCL[out/b41dir/b41.jar]#'
+ 'PCL[out/b42dir/b42.jar]'
+ '}'
+ '}'
+ '}'
' ; '
- 'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/x.jar]#PCL[/product/y.jar]#PCL[/system/a.jar]#PCL[/product/b.jar]}')
- self.assertEqual(result, expect)
+ 'stored_class_loader_context_arg='
+ '--stored-class-loader-context=PCL[]{'
+ 'PCL[/system/x.jar]#'
+ 'PCL[/product/y.jar]#'
+ 'PCL[/system/a.jar]#'
+ 'PCL[/product/b.jar]{'
+ 'PCL[/product/b1.jar]#'
+ 'PCL[/product/b2.jar]#'
+ 'PCL[/product/b4.jar]{'
+ 'PCL[/product/b41.jar]#'
+ 'PCL[/product/b42.jar]'
+ '}'
+ '}'
+ '}')
+ self.assertEqual(actual, expected)
def test_construct_context_29(self):
- args = ['--target-sdk-version', '29'] + contexts
- result = construct_contexts(args)
- expect = (
- 'class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]}'
+ actual = construct_context_args('29')
+ expected = (
+ 'class_loader_context_arg='
+ '--class-loader-context=PCL[]{'
+ 'PCL[out/adir/a.jar]#'
+ 'PCL[out/bdir/b.jar]{'
+ 'PCL[out/b1dir/b1.jar]#'
+ 'PCL[out/b2dir/b2.jar]#'
+ 'PCL[out/b4dir/b4.jar]{'
+ 'PCL[out/b41dir/b41.jar]#'
+ 'PCL[out/b42dir/b42.jar]'
+ '}'
+ '}'
+ '}'
' ; '
- 'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/a.jar]#PCL[/product/b.jar]}')
- self.assertEqual(result, expect)
+ 'stored_class_loader_context_arg='
+ '--stored-class-loader-context=PCL[]{'
+ 'PCL[/system/a.jar]#'
+ 'PCL[/product/b.jar]{'
+ 'PCL[/product/b1.jar]#'
+ 'PCL[/product/b2.jar]#'
+ 'PCL[/product/b4.jar]{'
+ 'PCL[/product/b41.jar]#'
+ 'PCL[/product/b42.jar]'
+ '}'
+ '}'
+ '}')
+ self.assertEqual(actual, expected)
def test_construct_context_S(self):
- args = ['--target-sdk-version', 'S'] + contexts
- result = construct_contexts(args)
- expect = (
- 'class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]}'
+ actual = construct_context_args('S')
+ expected = (
+ 'class_loader_context_arg='
+ '--class-loader-context=PCL[]{'
+ 'PCL[out/adir/a.jar]#'
+ 'PCL[out/bdir/b.jar]{'
+ 'PCL[out/b1dir/b1.jar]#'
+ 'PCL[out/b2dir/b2.jar]#'
+ 'PCL[out/b4dir/b4.jar]{'
+ 'PCL[out/b41dir/b41.jar]#'
+ 'PCL[out/b42dir/b42.jar]'
+ '}'
+ '}'
+ '}'
' ; '
- 'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/a.jar]#PCL[/product/b.jar]}')
- self.assertEqual(result, expect)
-#pylint: enable=line-too-long
+ 'stored_class_loader_context_arg='
+ '--stored-class-loader-context=PCL[]{'
+ 'PCL[/system/a.jar]#'
+ 'PCL[/product/b.jar]{'
+ 'PCL[/product/b1.jar]#'
+ 'PCL[/product/b2.jar]#'
+ 'PCL[/product/b4.jar]{'
+ 'PCL[/product/b41.jar]#'
+ 'PCL[/product/b42.jar]'
+ '}'
+ '}'
+ '}')
+ self.assertEqual(actual, expected)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/snapshot/host_fake_snapshot.go b/snapshot/host_fake_snapshot.go
index b04657d..c4cfbb5 100644
--- a/snapshot/host_fake_snapshot.go
+++ b/snapshot/host_fake_snapshot.go
@@ -75,7 +75,7 @@
}
func registerHostSnapshotComponents(ctx android.RegistrationContext) {
- ctx.RegisterSingletonType("host-fake-snapshot", HostToolsFakeAndroidSingleton)
+ ctx.RegisterParallelSingletonType("host-fake-snapshot", HostToolsFakeAndroidSingleton)
}
type hostFakeSingleton struct {
diff --git a/snapshot/recovery_snapshot.go b/snapshot/recovery_snapshot.go
index ac002be..8ff59cb 100644
--- a/snapshot/recovery_snapshot.go
+++ b/snapshot/recovery_snapshot.go
@@ -68,7 +68,7 @@
type RecoverySnapshotImage struct{}
func (RecoverySnapshotImage) Init(ctx android.RegistrationContext) {
- ctx.RegisterSingletonType("recovery-snapshot", RecoverySnapshotSingleton)
+ ctx.RegisterParallelSingletonType("recovery-snapshot", RecoverySnapshotSingleton)
}
func (RecoverySnapshotImage) RegisterAdditionalModule(ctx android.RegistrationContext, name string, factory android.ModuleFactory) {
diff --git a/snapshot/vendor_snapshot.go b/snapshot/vendor_snapshot.go
index 8f7b8c2..4484c85 100644
--- a/snapshot/vendor_snapshot.go
+++ b/snapshot/vendor_snapshot.go
@@ -78,8 +78,8 @@
type VendorSnapshotImage struct{}
func (VendorSnapshotImage) Init(ctx android.RegistrationContext) {
- ctx.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
- ctx.RegisterSingletonType("vendor-fake-snapshot", VendorFakeSnapshotSingleton)
+ ctx.RegisterParallelSingletonType("vendor-snapshot", VendorSnapshotSingleton)
+ ctx.RegisterParallelSingletonType("vendor-fake-snapshot", VendorFakeSnapshotSingleton)
}
func (VendorSnapshotImage) RegisterAdditionalModule(ctx android.RegistrationContext, name string, factory android.ModuleFactory) {
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index 5935247..5fc05f8 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -207,8 +207,8 @@
function test_soong_build_rerun_iff_environment_changes() {
setup
- mkdir -p cherry
- cat > cherry/Android.bp <<'EOF'
+ mkdir -p build/soong/cherry
+ cat > build/soong/cherry/Android.bp <<'EOF'
bootstrap_go_package {
name: "cherry",
pkgPath: "android/soong/cherry",
@@ -224,7 +224,7 @@
}
EOF
- cat > cherry/cherry.go <<'EOF'
+ cat > build/soong/cherry/cherry.go <<'EOF'
package cherry
import (
@@ -317,8 +317,8 @@
run_soong
local -r mtime1=$(stat -c "%y" out/soong/build.ninja)
- mkdir -p a
- cat > a/Android.bp <<'EOF'
+ mkdir -p vendor/foo/picard
+ cat > vendor/foo/picard/Android.bp <<'EOF'
bootstrap_go_package {
name: "picard-soong-rules",
pkgPath: "android/soong/picard",
@@ -334,7 +334,7 @@
}
EOF
- cat > a/picard.go <<'EOF'
+ cat > vendor/foo/picard/picard.go <<'EOF'
package picard
import (
@@ -390,11 +390,11 @@
function test_glob_during_bootstrapping() {
setup
- mkdir -p a
- cat > a/Android.bp <<'EOF'
+ mkdir -p build/soong/picard
+ cat > build/soong/picard/Android.bp <<'EOF'
build=["foo*.bp"]
EOF
- cat > a/fooa.bp <<'EOF'
+ cat > build/soong/picard/fooa.bp <<'EOF'
bootstrap_go_package {
name: "picard-soong-rules",
pkgPath: "android/soong/picard",
@@ -410,7 +410,7 @@
}
EOF
- cat > a/picard.go <<'EOF'
+ cat > build/soong/picard/picard.go <<'EOF'
package picard
import (
@@ -459,7 +459,7 @@
grep -q "Make it so" out/soong/build.ninja || fail "Original action not present"
- cat > a/foob.bp <<'EOF'
+ cat > build/soong/picard/foob.bp <<'EOF'
bootstrap_go_package {
name: "worf-soong-rules",
pkgPath: "android/soong/worf",
@@ -476,7 +476,7 @@
}
EOF
- cat > a/worf.go <<'EOF'
+ cat > build/soong/picard/worf.go <<'EOF'
package worf
import "android/soong/picard"
diff --git a/tests/dcla_apex_comparison_test.sh b/tests/dcla_apex_comparison_test.sh
index 97ae97e..667dde0 100755
--- a/tests/dcla_apex_comparison_test.sh
+++ b/tests/dcla_apex_comparison_test.sh
@@ -45,6 +45,11 @@
com.android.tethering
)
+BAZEL_TARGETS=(
+ //packages/modules/adb/apex:com.android.adbd
+ //frameworks/av/apex:com.android.media.swcodec
+)
+
DCLA_LIBS=(
libbase.so
libc++.so
@@ -76,6 +81,10 @@
############
OUTPUT_DIR="$(mktemp -d tmp.XXXXXX)"
+function call_bazel() {
+ build/bazel/bin/bazel $@
+}
+
function cleanup {
rm -rf "${OUTPUT_DIR}"
}
@@ -87,7 +96,9 @@
function extract_dcla_libs() {
local product=$1; shift
- for module in "${MODULES[@]}"; do
+ local modules=("$@"); shift
+
+ for module in "${modules[@]}"; do
local apex="${OUTPUT_DIR}/${product}/${module}.apex"
local extract_dir="${OUTPUT_DIR}/${product}/${module}/extract"
@@ -97,11 +108,12 @@
function compare_dcla_libs() {
local product=$1; shift
+ local modules=("$@"); shift
for lib in "${DCLA_LIBS[@]}"; do
for arch in lib lib64; do
local prev_sha=""
- for module in "${MODULES[@]}"; do
+ for module in "${modules[@]}"; do
local file="${OUTPUT_DIR}/${product}/${module}/extract/${arch}/${lib}"
if [[ ! -f "${file}" ]]; then
# not all libs are present in a module
@@ -112,7 +124,7 @@
sha="${sha% *}"
if [ "${prev_sha}" == "" ]; then
prev_sha="${sha}"
- elif [ "${sha}" != "${prev_sha}" ] && { [ "${lib}" != "libcrypto.so" ] || [ "${module}" != "com.android.tethering" ]; }; then
+ elif [ "${sha}" != "${prev_sha}" ] && { [ "${lib}" != "libcrypto.so" ] || [[ "${module}" != *"com.android.tethering" ]]; }; then
echo "Test failed, ${lib} has different hash value"
exit 1
fi
@@ -131,8 +143,22 @@
--product "${product}" \
--dist_dir "${OUTPUT_DIR}/${product}"
- extract_dcla_libs "${product}"
- compare_dcla_libs "${product}"
+ bazel_apexes=()
+ if [[ -n ${TEST_BAZEL+x} ]] && [ "${TEST_BAZEL}" = true ]; then
+ export TARGET_PRODUCT="${product/module/aosp}"
+ call_bazel build --config=bp2build --config=ci --config=android "${BAZEL_TARGETS[@]}"
+ for target in "${BAZEL_TARGETS[@]}"; do
+ apex_path="$(realpath $(call_bazel cquery --config=bp2build --config=android --config=ci --output=files $target))"
+ mkdir -p ${OUTPUT_DIR}/${product}
+ bazel_apex="bazel_$(basename $apex_path)"
+ mv $apex_path ${OUTPUT_DIR}/${product}/${bazel_apex}
+ bazel_apexes+=(${bazel_apex%".apex"})
+ done
+ fi
+
+ all_modeuls=(${MODULES[@]} ${bazel_apexes[@]})
+ extract_dcla_libs "${product}" "${all_modeuls[@]}"
+ compare_dcla_libs "${product}" "${all_modeuls[@]}"
done
echo "Test passed"
diff --git a/tests/genrule_sandbox_test.sh b/tests/genrule_sandbox_test.sh
new file mode 100755
index 0000000..21b476b
--- /dev/null
+++ b/tests/genrule_sandbox_test.sh
@@ -0,0 +1,111 @@
+#!/bin/bash
+
+# Copyright (C) 2023 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.
+
+set -e
+
+# Build the given genrule modules with GENRULE_SANDBOXING enabled and disabled,
+# then compare the output of the modules and report result.
+
+function die() { format=$1; shift; printf >&2 "$format\n" $@; exit 1; }
+
+function usage() {
+ die "usage: ${0##*/} <-t lunch_target> [module]..."
+}
+
+if [ ! -e "build/make/core/Makefile" ]; then
+ die "$0 must be run from the top of the Android source tree."
+fi
+
+declare TARGET=
+while getopts "t:" opt; do
+ case $opt in
+ t)
+ TARGET=$OPTARG ;;
+ *) usage ;;
+ esac
+done
+
+shift $((OPTIND-1))
+MODULES="$@"
+
+source build/envsetup.sh
+
+if [[ -n $TARGET ]]; then
+ lunch $TARGET
+fi
+
+if [[ -z ${OUT_DIR+x} ]]; then
+ OUT_DIR="out"
+fi
+
+OUTPUT_DIR="$(mktemp -d tmp.XXXXXX)"
+PASS=true
+
+function cleanup {
+ if [ $PASS = true ]; then
+ rm -rf "${OUTPUT_DIR}"
+ fi
+}
+trap cleanup EXIT
+
+declare -A GEN_PATH_MAP
+
+function find_gen_paths() {
+ for module in $MODULES; do
+ module_path=$(pathmod "$module")
+ package_path=${module_path#$ANDROID_BUILD_TOP}
+ gen_path=$OUT_DIR/soong/.intermediates$package_path/$module
+ GEN_PATH_MAP[$module]=$gen_path
+ done
+}
+
+function store_outputs() {
+ local dir=$1; shift
+
+ for module in $MODULES; do
+ dest_dir=$dir/${module}
+ mkdir -p $dest_dir
+ gen_path=${GEN_PATH_MAP[$module]}
+ cp -r $gen_path $dest_dir
+ done
+}
+
+function cmp_outputs() {
+ local dir1=$1; shift
+ local dir2=$1; shift
+
+ for module in $MODULES; do
+ if ! diff -rq --exclude=genrule.sbox.textproto $dir1/$module $dir2/$module; then
+ PASS=false
+ echo "$module differ"
+ fi
+ done
+ if [ $PASS = true ]; then
+ echo "Test passed"
+ fi
+}
+
+if [ ! -f "$ANDROID_PRODUCT_OUT/module-info.json" ]; then
+ refreshmod
+fi
+
+find_gen_paths
+m --skip-soong-tests GENRULE_SANDBOXING=true "${MODULES[@]}"
+store_outputs "$OUTPUT_DIR/sandbox"
+m --skip-soong-tests GENRULE_SANDBOXING=false "${MODULES[@]}"
+store_outputs "$OUTPUT_DIR/non_sandbox"
+
+cmp_outputs "$OUTPUT_DIR/non_sandbox" "$OUTPUT_DIR/sandbox"
diff --git a/tests/lib.sh b/tests/lib.sh
index 715eac1..7f3970e 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -99,6 +99,7 @@
symlink_directory external/python
symlink_directory external/sqlite
symlink_directory external/spdx-tools
+ symlink_directory libcore
touch "$MOCK_TOP/Android.bp"
}
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index e1aa70c..db14bd4 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -15,8 +15,8 @@
# mock client.
"$TOP/build/soong/tests/apex_comparison_tests.sh"
"$TOP/build/soong/tests/apex_comparison_tests.sh" "module_arm64only"
-extra_build_params=--bazel-mode-staging "$TOP/build/soong/tests/dcla_apex_comparison_test.sh"
-BUILD_BROKEN_DISABLE_BAZEL=true "$TOP/build/soong/tests/dcla_apex_comparison_test.sh"
+TEST_BAZEL=true extra_build_params=--bazel-mode-staging "$TOP/build/soong/tests/dcla_apex_comparison_test.sh"
+#BUILD_BROKEN_DISABLE_BAZEL=true "$TOP/build/soong/tests/dcla_apex_comparison_test.sh"
"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh"
"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_arm" "armv7-a"
"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_cf_arm64_phone" "armv8-a" "cortex-a53"
diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh
index 2f154cd..94fe51d 100755
--- a/tests/sbom_test.sh
+++ b/tests/sbom_test.sh
@@ -90,10 +90,12 @@
-I /system/lib64/android.hardware.security.sharedsecret-V1-ndk.so \
-I /system/lib64/android.security.compat-ndk.so \
-I /system/lib64/libkeymaster4_1support.so \
+ -I /system/lib64/libkeymaster4support.so \
-I /system/lib64/libkeymint.so \
-I /system/lib64/libkeystore2_aaid.so \
-I /system/lib64/libkeystore2_apc_compat.so \
-I /system/lib64/libkeystore2_crypto.so \
+ -I /system/lib64/libkeystore-attestation-application-id.so \
-I /system/lib64/libkm_compat_service.so \
-I /system/lib64/libkm_compat.so \
-I /system/lib64/vndk-29 \
diff --git a/tests/soong_test.sh b/tests/soong_test.sh
index f7bee40..6779d8a 100755
--- a/tests/soong_test.sh
+++ b/tests/soong_test.sh
@@ -9,12 +9,8 @@
function test_m_clean_works {
setup
- # Create a directory with files that cannot be removed
- mkdir -p out/bad_directory_permissions
- touch out/bad_directory_permissions/unremovable_file
- # File permissions are fine but directory permissions are bad
- chmod a+rwx out/bad_directory_permissions/unremovable_file
- chmod a-rwx out/bad_directory_permissions
+ mkdir -p out/some_directory
+ touch out/some_directory/some_file
run_soong clean
}
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index 49b09af..3c55c51 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -40,9 +40,9 @@
}
var autogenTestConfig = pctx.StaticRule("autogenTestConfig", blueprint.RuleParams{
- Command: "sed 's&{MODULE}&${name}&g;s&{EXTRA_CONFIGS}&'${extraConfigs}'&g;s&{OUTPUT_FILENAME}&'${outputFileName}'&g;s&{TEST_INSTALL_BASE}&'${testInstallBase}'&g' $template > $out",
+ Command: "sed 's&{MODULE}&${name}&g;s&{EXTRA_CONFIGS}&'${extraConfigs}'&g;s&{EXTRA_TEST_RUNNER_CONFIGS}&'${extraTestRunnerConfigs}'&g;s&{OUTPUT_FILENAME}&'${outputFileName}'&g;s&{TEST_INSTALL_BASE}&'${testInstallBase}'&g' $template > $out",
CommandDeps: []string{"$template"},
-}, "name", "template", "extraConfigs", "outputFileName", "testInstallBase")
+}, "name", "template", "extraConfigs", "outputFileName", "testInstallBase", "extraTestRunnerConfigs")
func testConfigPath(ctx android.ModuleContext, prop *string, testSuites []string, autoGenConfig *bool, testConfigTemplateProp *string) (path android.Path, autogenPath android.WritablePath) {
p := getTestConfig(ctx, prop)
@@ -107,7 +107,7 @@
}
-func autogenTemplate(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, outputFileName string, testInstallBase string) {
+func autogenTemplate(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, testRunnerConfigs []Option, outputFileName string, testInstallBase string) {
if template == "" {
ctx.ModuleErrorf("Empty template")
}
@@ -118,16 +118,27 @@
extraConfigs := strings.Join(configStrings, fmt.Sprintf("\\n%s", test_xml_indent))
extraConfigs = proptools.NinjaAndShellEscape(extraConfigs)
+ var testRunnerConfigStrings []string
+ for _, config := range testRunnerConfigs {
+ testRunnerConfigStrings = append(testRunnerConfigStrings, config.Config())
+ }
+ extraTestRunnerConfigs := strings.Join(testRunnerConfigStrings, fmt.Sprintf("\\n%s%s", test_xml_indent, test_xml_indent))
+ if len(extraTestRunnerConfigs) > 0 {
+ extraTestRunnerConfigs += fmt.Sprintf("\\n%s%s", test_xml_indent, test_xml_indent)
+ }
+ extraTestRunnerConfigs = proptools.NinjaAndShellEscape(extraTestRunnerConfigs)
+
ctx.Build(pctx, android.BuildParams{
Rule: autogenTestConfig,
Description: "test config",
Output: output,
Args: map[string]string{
- "name": name,
- "template": template,
- "extraConfigs": extraConfigs,
- "outputFileName": outputFileName,
- "testInstallBase": testInstallBase,
+ "name": name,
+ "template": template,
+ "extraConfigs": extraConfigs,
+ "outputFileName": outputFileName,
+ "testInstallBase": testInstallBase,
+ "extraTestRunnerConfigs": extraTestRunnerConfigs,
},
})
}
@@ -142,6 +153,7 @@
TestSuites []string
Config []Config
OptionsForAutogenerated []Option
+ TestRunnerOptions []Option
AutoGenConfig *bool
UnitTest *bool
TestInstallBase string
@@ -155,6 +167,7 @@
for _, c := range options.OptionsForAutogenerated {
configs = append(configs, c)
}
+ testRunnerConfigs := append([]Option{}, options.TestRunnerOptions...)
name := options.Name
if name == "" {
name = ctx.ModuleName()
@@ -163,15 +176,15 @@
if autogenPath != nil {
templatePath := getTestConfigTemplate(ctx, options.TestConfigTemplateProp)
if templatePath.Valid() {
- autogenTemplate(ctx, name, autogenPath, templatePath.String(), configs, options.OutputFileName, options.TestInstallBase)
+ autogenTemplate(ctx, name, autogenPath, templatePath.String(), configs, testRunnerConfigs, options.OutputFileName, options.TestInstallBase)
} else {
if ctx.Device() {
- autogenTemplate(ctx, name, autogenPath, options.DeviceTemplate, configs, options.OutputFileName, options.TestInstallBase)
+ autogenTemplate(ctx, name, autogenPath, options.DeviceTemplate, configs, testRunnerConfigs, options.OutputFileName, options.TestInstallBase)
} else {
if Bool(options.UnitTest) {
- autogenTemplate(ctx, name, autogenPath, options.HostUnitTestTemplate, configs, options.OutputFileName, options.TestInstallBase)
+ autogenTemplate(ctx, name, autogenPath, options.HostUnitTestTemplate, configs, testRunnerConfigs, options.OutputFileName, options.TestInstallBase)
} else {
- autogenTemplate(ctx, name, autogenPath, options.HostTemplate, configs, options.OutputFileName, options.TestInstallBase)
+ autogenTemplate(ctx, name, autogenPath, options.HostTemplate, configs, testRunnerConfigs, options.OutputFileName, options.TestInstallBase)
}
}
}
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index fd60177..ee53327 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -17,7 +17,6 @@
import (
"bytes"
"fmt"
- "io/fs"
"io/ioutil"
"os"
"path/filepath"
@@ -59,37 +58,9 @@
FILEMODE_USER_EXECUTE = FILEMODE_EXECUTE << FILEMODE_USER_SHIFT
)
-// Ensures that files and directories in the out dir can be deleted.
-// For example, Bazen can generate output directories where the write bit isn't set, causing 'm' clean' to fail.
-func ensureOutDirRemovable(ctx Context, config Config) {
- err := filepath.WalkDir(config.OutDir(), func(path string, d fs.DirEntry, err error) error {
- if err != nil {
- return err
- }
- if d.IsDir() {
- info, err := d.Info()
- if err != nil {
- return err
- }
- // Equivalent to running chmod u+rwx on each directory
- newMode := info.Mode() | FILEMODE_USER_READ | FILEMODE_USER_WRITE | FILEMODE_USER_EXECUTE
- if err := os.Chmod(path, newMode); err != nil {
- return err
- }
- }
- // Continue walking the out dir...
- return nil
- })
- if err != nil && !os.IsNotExist(err) {
- // Display the error, but don't crash.
- ctx.Println(err.Error())
- }
-}
-
// Remove everything under the out directory. Don't remove the out directory
// itself in case it's a symlink.
func clean(ctx Context, config Config) {
- ensureOutDirRemovable(ctx, config)
removeGlobs(ctx, filepath.Join(config.OutDir(), "*"))
ctx.Println("Entire build directory removed.")
}
diff --git a/ui/build/config.go b/ui/build/config.go
index 8ec9680..711774a 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -15,7 +15,6 @@
package build
import (
- "context"
"encoding/json"
"fmt"
"io/ioutil"
@@ -39,9 +38,6 @@
const (
envConfigDir = "vendor/google/tools/soong_config"
jsonSuffix = "json"
-
- configFetcher = "vendor/google/tools/soong/expconfigfetcher"
- envConfigFetchTimeout = 10 * time.Second
)
var (
@@ -170,87 +166,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
@@ -316,8 +231,9 @@
func NewConfig(ctx Context, args ...string) Config {
ret := &configImpl{
- environ: OsEnvironment(),
- sandboxConfig: &SandboxConfig{},
+ environ: OsEnvironment(),
+ sandboxConfig: &SandboxConfig{},
+ ninjaWeightListSource: NINJA_LOG,
}
// Default matching ninja
@@ -350,9 +266,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)
}
@@ -1229,6 +1142,13 @@
panic("TARGET_PRODUCT is not defined")
}
+func (c *configImpl) TargetProductOrErr() (string, error) {
+ if v, ok := c.environ.Get("TARGET_PRODUCT"); ok {
+ return v, nil
+ }
+ return "", fmt.Errorf("TARGET_PRODUCT is not defined")
+}
+
func (c *configImpl) TargetDevice() string {
return c.targetDevice
}
@@ -1486,7 +1406,7 @@
if googleProdCredsExistCache {
return googleProdCredsExistCache
}
- if _, err := exec.Command("/usr/bin/prodcertstatus", "--simple_output", "--nocheck_loas").Output(); err != nil {
+ if _, err := exec.Command("/usr/bin/gcertstatus").Output(); err != nil {
return false
}
googleProdCredsExistCache = true
@@ -1554,11 +1474,21 @@
}
func (c *configImpl) SoongVarsFile() string {
- return filepath.Join(c.SoongOutDir(), "soong.variables")
+ targetProduct, err := c.TargetProductOrErr()
+ if err != nil {
+ return filepath.Join(c.SoongOutDir(), "soong.variables")
+ } else {
+ return filepath.Join(c.SoongOutDir(), "soong."+targetProduct+".variables")
+ }
}
func (c *configImpl) SoongNinjaFile() string {
- return filepath.Join(c.SoongOutDir(), "build.ninja")
+ targetProduct, err := c.TargetProductOrErr()
+ if err != nil {
+ return filepath.Join(c.SoongOutDir(), "build.ninja")
+ } else {
+ return filepath.Join(c.SoongOutDir(), "build."+targetProduct+".ninja")
+ }
}
func (c *configImpl) CombinedNinjaFile() string {
@@ -1712,6 +1642,16 @@
return c.Environment().IsEnvTrue("USE_PERSISTENT_BAZEL")
}
+// GetBazeliskBazelVersion returns the Bazel version to use for this build,
+// or the empty string if the current canonical prod Bazel should be used.
+// This environment variable should only be set to debug the build system.
+// The Bazel version, if set, will be passed to Bazelisk, and Bazelisk will
+// handle downloading and invoking the correct Bazel binary.
+func (c *configImpl) GetBazeliskBazelVersion() string {
+ value, _ := c.Environment().Get("USE_BAZEL_VERSION")
+ return value
+}
+
func (c *configImpl) BazelModulesForceEnabledByFlag() string {
return c.bazelForceEnabledModules
}
diff --git a/ui/build/kati.go b/ui/build/kati.go
index dad68fa..aea56d3 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -22,6 +22,7 @@
"os/user"
"path/filepath"
"strings"
+ "time"
"android/soong/ui/metrics"
"android/soong/ui/status"
@@ -66,6 +67,21 @@
}
}
+func writeValueIfChanged(ctx Context, config Config, dir string, filename string, value string) {
+ filePath := filepath.Join(dir, filename)
+ previousValue := ""
+ rawPreviousValue, err := ioutil.ReadFile(filePath)
+ if err == nil {
+ previousValue = string(rawPreviousValue)
+ }
+
+ if previousValue != value {
+ if err = ioutil.WriteFile(filePath, []byte(value), 0666); err != nil {
+ ctx.Fatalf("Failed to write: %v", err)
+ }
+ }
+}
+
// Base function to construct and run the Kati command line with additional
// arguments, and a custom function closure to mutate the environment Kati runs
// in.
@@ -157,28 +173,60 @@
}
cmd.Stderr = cmd.Stdout
- // Apply the caller's function closure to mutate the environment variables.
- envFunc(cmd.Environment)
-
+ var username string
// Pass on various build environment metadata to Kati.
- if _, ok := cmd.Environment.Get("BUILD_USERNAME"); !ok {
- username := "unknown"
+ if usernameFromEnv, ok := cmd.Environment.Get("BUILD_USERNAME"); !ok {
+ username = "unknown"
if u, err := user.Current(); err == nil {
username = u.Username
} else {
ctx.Println("Failed to get current user:", err)
}
cmd.Environment.Set("BUILD_USERNAME", username)
+ } else {
+ username = usernameFromEnv
}
- if _, ok := cmd.Environment.Get("BUILD_HOSTNAME"); !ok {
- hostname, err := os.Hostname()
+ hostname, ok := cmd.Environment.Get("BUILD_HOSTNAME")
+ // Unset BUILD_HOSTNAME during kati run to avoid kati rerun, kati will use BUILD_HOSTNAME from a file.
+ cmd.Environment.Unset("BUILD_HOSTNAME")
+ if !ok {
+ hostname, err = os.Hostname()
if err != nil {
ctx.Println("Failed to read hostname:", err)
hostname = "unknown"
}
- cmd.Environment.Set("BUILD_HOSTNAME", hostname)
}
+ writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_hostname.txt", hostname)
+
+ // BUILD_NUMBER should be set to the source control value that
+ // represents the current state of the source code. E.g., a
+ // perforce changelist number or a git hash. Can be an arbitrary string
+ // (to allow for source control that uses something other than numbers),
+ // but must be a single word and a valid file name.
+ //
+ // If no BUILD_NUMBER is set, create a useful "I am an engineering build
+ // from this date/time" value. Make it start with a non-digit so that
+ // anyone trying to parse it as an integer will probably get "0".
+ cmd.Environment.Unset("HAS_BUILD_NUMBER")
+ buildNumber, ok := cmd.Environment.Get("BUILD_NUMBER")
+ // Unset BUILD_NUMBER during kati run to avoid kati rerun, kati will use BUILD_NUMBER from a file.
+ cmd.Environment.Unset("BUILD_NUMBER")
+ if ok {
+ cmd.Environment.Set("HAS_BUILD_NUMBER", "true")
+ writeValueIfChanged(ctx, config, config.OutDir(), "file_name_tag.txt", buildNumber)
+ } else {
+ buildNumber = fmt.Sprintf("eng.%.6s.%s", username, time.Now().Format("20060102.150405" /* YYYYMMDD.HHMMSS */))
+ cmd.Environment.Set("HAS_BUILD_NUMBER", "false")
+ writeValueIfChanged(ctx, config, config.OutDir(), "file_name_tag.txt", username)
+ }
+ // Write the build number to a file so it can be read back in
+ // without changing the command line every time. Avoids rebuilds
+ // when using ninja.
+ writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_number.txt", buildNumber)
+
+ // Apply the caller's function closure to mutate the environment variables.
+ envFunc(cmd.Environment)
cmd.StartOrFatal()
// Set up the ToolStatus command line reader for Kati for a consistent UI
@@ -336,6 +384,7 @@
"ANDROID_BUILD_SHELL",
"DIST_DIR",
"OUT_DIR",
+ "FILE_NAME_TAG",
}...)
if config.Dist() {
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 5d56531..61aaad8 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -35,48 +35,6 @@
ninjaWeightListFileName = ".ninja_weight_list"
)
-func useNinjaBuildLog(ctx Context, config Config, cmd *Cmd) {
- ninjaLogFile := filepath.Join(config.OutDir(), ninjaLogFileName)
- data, err := os.ReadFile(ninjaLogFile)
- var outputBuilder strings.Builder
- if err == nil {
- lines := strings.Split(strings.TrimSpace(string(data)), "\n")
- // ninja log: <start> <end> <restat> <name> <cmdhash>
- // ninja weight list: <name>,<end-start+1>
- for _, line := range lines {
- if strings.HasPrefix(line, "#") {
- continue
- }
- fields := strings.Split(line, "\t")
- path := fields[3]
- start, err := strconv.Atoi(fields[0])
- if err != nil {
- continue
- }
- end, err := strconv.Atoi(fields[1])
- if err != nil {
- continue
- }
- outputBuilder.WriteString(path)
- outputBuilder.WriteString(",")
- outputBuilder.WriteString(strconv.Itoa(end-start+1) + "\n")
- }
- } else {
- // If there is no ninja log file, just pass empty ninja weight list.
- // Because it is still efficient with critical path calculation logic even without weight.
- ctx.Verbosef("There is an error during reading ninja log, so ninja will use empty weight list: %s", err)
- }
-
- weightListFile := filepath.Join(config.OutDir(), ninjaWeightListFileName)
-
- err = os.WriteFile(weightListFile, []byte(outputBuilder.String()), 0644)
- if err == nil {
- cmd.Args = append(cmd.Args, "-o", "usesweightlist="+weightListFile)
- } else {
- ctx.Panicf("Could not write ninja weight list file %s", err)
- }
-}
-
// Constructs and runs the Ninja command line with a restricted set of
// environment variables. It's important to restrict the environment Ninja runs
// for hermeticity reasons, and to avoid spurious rebuilds.
@@ -131,7 +89,7 @@
switch config.NinjaWeightListSource() {
case NINJA_LOG:
- useNinjaBuildLog(ctx, config, cmd)
+ cmd.Args = append(cmd.Args, "-o", "usesninjalogasweightlist=yes")
case EVENLY_DISTRIBUTED:
// pass empty weight list means ninja considers every tasks's weight as 1(default value).
cmd.Args = append(cmd.Args, "-o", "usesweightlist=/dev/null")
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 18bf3b9..986ec70 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -235,7 +235,7 @@
} else if !exists {
// The tree is out of date for the current epoch, delete files used by bootstrap
// and force the primary builder to rerun.
- os.Remove(filepath.Join(config.SoongOutDir(), "build.ninja"))
+ os.Remove(config.SoongNinjaFile())
for _, globFile := range bootstrapGlobFileList(config) {
os.Remove(globFile)
}
@@ -263,7 +263,9 @@
// Clean up some files for incremental builds across incompatible changes.
bootstrapEpochCleanup(ctx, config)
- mainSoongBuildExtraArgs := []string{"-o", config.SoongNinjaFile()}
+ baseArgs := []string{"--soong_variables", config.SoongVarsFile()}
+
+ mainSoongBuildExtraArgs := append(baseArgs, "-o", config.SoongNinjaFile())
if config.EmptyNinjaFile() {
mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--empty-ninja-file")
}
@@ -306,49 +308,59 @@
specificArgs: mainSoongBuildExtraArgs,
},
{
- name: bp2buildFilesTag,
- description: fmt.Sprintf("converting Android.bp files to BUILD files at %s/bp2build", config.SoongOutDir()),
- config: config,
- output: config.Bp2BuildFilesMarkerFile(),
- specificArgs: []string{"--bp2build_marker", config.Bp2BuildFilesMarkerFile()},
+ name: bp2buildFilesTag,
+ description: fmt.Sprintf("converting Android.bp files to BUILD files at %s/bp2build", config.SoongOutDir()),
+ config: config,
+ output: config.Bp2BuildFilesMarkerFile(),
+ specificArgs: append(baseArgs,
+ "--bp2build_marker", config.Bp2BuildFilesMarkerFile(),
+ ),
},
{
- name: bp2buildWorkspaceTag,
- description: "Creating Bazel symlink forest",
- config: config,
- output: config.Bp2BuildWorkspaceMarkerFile(),
- specificArgs: []string{"--symlink_forest_marker", config.Bp2BuildWorkspaceMarkerFile()},
+ name: bp2buildWorkspaceTag,
+ description: "Creating Bazel symlink forest",
+ config: config,
+ output: config.Bp2BuildWorkspaceMarkerFile(),
+ specificArgs: append(baseArgs,
+ "--symlink_forest_marker", config.Bp2BuildWorkspaceMarkerFile(),
+ ),
},
{
name: jsonModuleGraphTag,
description: fmt.Sprintf("generating the Soong module graph at %s", config.ModuleGraphFile()),
config: config,
output: config.ModuleGraphFile(),
- specificArgs: []string{
+ specificArgs: append(baseArgs,
"--module_graph_file", config.ModuleGraphFile(),
"--module_actions_file", config.ModuleActionsFile(),
- },
+ ),
},
{
- name: queryviewTag,
- description: fmt.Sprintf("generating the Soong module graph as a Bazel workspace at %s", queryviewDir),
- config: config,
- output: config.QueryviewMarkerFile(),
- specificArgs: []string{"--bazel_queryview_dir", queryviewDir},
+ name: queryviewTag,
+ description: fmt.Sprintf("generating the Soong module graph as a Bazel workspace at %s", queryviewDir),
+ config: config,
+ output: config.QueryviewMarkerFile(),
+ specificArgs: append(baseArgs,
+ "--bazel_queryview_dir", queryviewDir,
+ ),
},
{
- name: apiBp2buildTag,
- description: fmt.Sprintf("generating BUILD files for API contributions at %s", apiBp2buildDir),
- config: config,
- output: config.ApiBp2buildMarkerFile(),
- specificArgs: []string{"--bazel_api_bp2build_dir", apiBp2buildDir},
+ name: apiBp2buildTag,
+ description: fmt.Sprintf("generating BUILD files for API contributions at %s", apiBp2buildDir),
+ config: config,
+ output: config.ApiBp2buildMarkerFile(),
+ specificArgs: append(baseArgs,
+ "--bazel_api_bp2build_dir", apiBp2buildDir,
+ ),
},
{
- name: soongDocsTag,
- description: fmt.Sprintf("generating Soong docs at %s", config.SoongDocsHtml()),
- config: config,
- output: config.SoongDocsHtml(),
- specificArgs: []string{"--soong_docs", config.SoongDocsHtml()},
+ name: soongDocsTag,
+ description: fmt.Sprintf("generating Soong docs at %s", config.SoongDocsHtml()),
+ config: config,
+ output: config.SoongDocsHtml(),
+ specificArgs: append(baseArgs,
+ "--soong_docs", config.SoongDocsHtml(),
+ ),
},
}
@@ -521,7 +533,7 @@
defer ctx.EndTrace()
if config.IsPersistentBazelEnabled() {
- bazelProxy := bazel.NewProxyServer(ctx.Logger, config.OutDir(), filepath.Join(config.SoongOutDir(), "workspace"))
+ bazelProxy := bazel.NewProxyServer(ctx.Logger, config.OutDir(), filepath.Join(config.SoongOutDir(), "workspace"), config.GetBazeliskBazelVersion())
bazelProxy.Start()
defer bazelProxy.Close()
}
diff --git a/ui/metrics/BUILD.bazel b/ui/metrics/BUILD.bazel
index 15ebb88..2dc1ab6 100644
--- a/ui/metrics/BUILD.bazel
+++ b/ui/metrics/BUILD.bazel
@@ -16,7 +16,7 @@
py_proto_library(
name = "metrics-py-proto",
- visibility = ["//build/bazel/scripts/incremental_build:__pkg__"],
+ visibility = ["//build/bazel/scripts:__subpackages__"],
deps = [":metrics-proto"],
)