Merge "Allow PrevVendorApiLevel to be less than 34" into main
diff --git a/aconfig/all_aconfig_declarations.go b/aconfig/all_aconfig_declarations.go
index b6c9023..72fe495 100644
--- a/aconfig/all_aconfig_declarations.go
+++ b/aconfig/all_aconfig_declarations.go
@@ -31,7 +31,8 @@
}
type allAconfigDeclarationsSingleton struct {
- intermediatePath android.OutputPath
+ intermediateBinaryProtoPath android.OutputPath
+ intermediateTextProtoPath android.OutputPath
}
func (this *allAconfigDeclarationsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
@@ -59,20 +60,37 @@
panic(fmt.Errorf("Only one aconfig_declarations allowed for each package."))
}
- // Generate build action for aconfig
- this.intermediatePath = android.PathForIntermediates(ctx, "all_aconfig_declarations.pb")
+ // Generate build action for aconfig (binary proto output)
+ this.intermediateBinaryProtoPath = android.PathForIntermediates(ctx, "all_aconfig_declarations.pb")
ctx.Build(pctx, android.BuildParams{
Rule: AllDeclarationsRule,
Inputs: cacheFiles,
- Output: this.intermediatePath,
+ Output: this.intermediateBinaryProtoPath,
Description: "all_aconfig_declarations",
Args: map[string]string{
"cache_files": android.JoinPathsWithPrefix(cacheFiles, "--cache "),
},
})
- ctx.Phony("all_aconfig_declarations", this.intermediatePath)
+ ctx.Phony("all_aconfig_declarations", this.intermediateBinaryProtoPath)
+
+ // Generate build action for aconfig (text proto output)
+ this.intermediateTextProtoPath = android.PathForIntermediates(ctx, "all_aconfig_declarations.textproto")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: AllDeclarationsRuleTextProto,
+ Inputs: cacheFiles,
+ Output: this.intermediateTextProtoPath,
+ Description: "all_aconfig_declarations_textproto",
+ Args: map[string]string{
+ "cache_files": android.JoinPathsWithPrefix(cacheFiles, "--cache "),
+ },
+ })
+ ctx.Phony("all_aconfig_declarations_textproto", this.intermediateTextProtoPath)
}
func (this *allAconfigDeclarationsSingleton) MakeVars(ctx android.MakeVarsContext) {
- ctx.DistForGoal("droid", this.intermediatePath)
+ ctx.DistForGoal("droid", this.intermediateBinaryProtoPath)
+ for _, goal := range []string{"droid", "sdk"} {
+ ctx.DistForGoalWithFilename(goal, this.intermediateBinaryProtoPath, "flags.pb")
+ ctx.DistForGoalWithFilename(goal, this.intermediateTextProtoPath, "flags.textproto")
+ }
}
diff --git a/aconfig/codegen/java_aconfig_library.go b/aconfig/codegen/java_aconfig_library.go
index 7d7296e..3d15ac9 100644
--- a/aconfig/codegen/java_aconfig_library.go
+++ b/aconfig/codegen/java_aconfig_library.go
@@ -92,12 +92,12 @@
if !isModeSupported(mode) {
ctx.PropertyErrorf("mode", "%q is not a supported mode", mode)
}
- // TODO: uncomment this part after internal clean up
- //if mode == "exported" && !declarations.Exportable {
- // // if mode is exported, the corresponding aconfig_declaration must mark its
- // // exportable property true
- // ctx.PropertyErrorf("mode", "exported mode requires its aconfig_declaration has exportable prop true")
- //}
+
+ if mode == "exported" && !declarations.Exportable {
+ // if mode is exported, the corresponding aconfig_declaration must mark its
+ // exportable property true
+ ctx.PropertyErrorf("mode", "exported mode requires its aconfig_declaration has exportable prop true")
+ }
ctx.Build(pctx, android.BuildParams{
Rule: javaRule,
diff --git a/aconfig/init.go b/aconfig/init.go
index 16fb0cd..e64429f 100644
--- a/aconfig/init.go
+++ b/aconfig/init.go
@@ -75,6 +75,21 @@
"${aconfig}",
},
}, "cache_files")
+ AllDeclarationsRuleTextProto = pctx.AndroidStaticRule("All_aconfig_declarations_dump_textproto",
+ blueprint.RuleParams{
+ Command: `${aconfig} dump-cache --dedup --format textproto --out ${out} ${cache_files}`,
+ CommandDeps: []string{
+ "${aconfig}",
+ },
+ }, "cache_files")
+
+ CreateStorageRule = pctx.AndroidStaticRule("aconfig_create_storage",
+ blueprint.RuleParams{
+ Command: `${aconfig} create-storage --container ${container} --file ${file_type} --out ${out} ${cache_files}`,
+ CommandDeps: []string{
+ "${aconfig}",
+ },
+ }, "container", "file_type", "cache_files")
// For exported_java_aconfig_library: Generate a JAR from all
// java_aconfig_libraries to be consumed by apps built outside the
diff --git a/android/Android.bp b/android/Android.bp
index e73f355..03619f4 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -16,7 +16,6 @@
"soong-remoteexec",
"soong-response",
"soong-shared",
- "soong-starlark",
"soong-starlark-format",
"soong-ui-metrics_proto",
"soong-android-allowlists",
@@ -135,6 +134,7 @@
"rule_builder_test.go",
"sdk_version_test.go",
"sdk_test.go",
+ "selects_test.go",
"singleton_module_test.go",
"soong_config_modules_test.go",
"util_test.go",
diff --git a/android/apex_contributions.go b/android/apex_contributions.go
index 236abf6..c388aff 100644
--- a/android/apex_contributions.go
+++ b/android/apex_contributions.go
@@ -15,6 +15,8 @@
package android
import (
+ "strings"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -98,6 +100,19 @@
func (a *allApexContributions) SetPrebuiltSelectionInfoProvider(ctx BaseModuleContext) {
addContentsToProvider := func(p *PrebuiltSelectionInfoMap, m *apexContributions) {
for _, content := range m.Contents() {
+ // Skip any apexes that have been added to the product specific ignore list
+ if InList(content, ctx.Config().BuildIgnoreApexContributionContents()) {
+ continue
+ }
+ // Coverage builds for TARGET_RELEASE=foo should always build from source,
+ // even if TARGET_RELEASE=foo uses prebuilt mainline modules.
+ // This is necessary because the checked-in prebuilts were generated with
+ // instrumentation turned off.
+ //
+ // Skip any prebuilt contents in coverage builds
+ if strings.HasPrefix(content, "prebuilt_") && (ctx.Config().JavaCoverageEnabled() || ctx.DeviceConfig().NativeCoverageEnabled()) {
+ continue
+ }
if !ctx.OtherModuleExists(content) && !ctx.Config().AllowMissingDependencies() {
ctx.ModuleErrorf("%s listed in apex_contributions %s does not exist\n", content, m.Name())
}
diff --git a/android/api_levels.go b/android/api_levels.go
index 6fa4a0e..1130c3e 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -15,7 +15,6 @@
package android
import (
- "android/soong/starlark_import"
"encoding/json"
"fmt"
"strconv"
@@ -440,7 +439,28 @@
}
func getApiLevelsMapReleasedVersions() (map[string]int, error) {
- return starlark_import.GetStarlarkValue[map[string]int]("api_levels_released_versions")
+ return map[string]int{
+ "G": 9,
+ "I": 14,
+ "J": 16,
+ "J-MR1": 17,
+ "J-MR2": 18,
+ "K": 19,
+ "L": 21,
+ "L-MR1": 22,
+ "M": 23,
+ "N": 24,
+ "N-MR1": 25,
+ "O": 26,
+ "O-MR1": 27,
+ "P": 28,
+ "Q": 29,
+ "R": 30,
+ "S": 31,
+ "S-V2": 32,
+ "Tiramisu": 33,
+ "UpsideDownCake": 34,
+ }, nil
}
var finalCodenamesMapKey = NewOnceKey("FinalCodenamesMap")
diff --git a/android/config.go b/android/config.go
index 9f009e4..1bb1a22 100644
--- a/android/config.go
+++ b/android/config.go
@@ -91,8 +91,6 @@
ModuleActionsFile string
DocFile string
- MultitreeBuild bool
-
BuildFromSourceStub bool
EnsureAllowlistIntegrity bool
@@ -213,7 +211,7 @@
// Enables flagged apis annotated with READ_WRITE aconfig flags to be included in the stubs
// and hiddenapi flags so that they are accessible at runtime
func (c Config) ReleaseExportRuntimeApis() bool {
- return c.config.productVariables.GetBuildFlagBool("RELEASE_EXPORT_RUNTIME_APIS")
+ return Bool(c.config.productVariables.ExportRuntimeApis)
}
// Enables ABI monitoring of NDK libraries
@@ -222,7 +220,8 @@
}
func (c Config) ReleaseHiddenApiExportableStubs() bool {
- return c.config.productVariables.GetBuildFlagBool("RELEASE_HIDDEN_API_EXPORTABLE_STUBS")
+ return c.config.productVariables.GetBuildFlagBool("RELEASE_HIDDEN_API_EXPORTABLE_STUBS") ||
+ Bool(c.config.productVariables.HiddenapiExportableStubs)
}
// A DeviceConfig object represents the configuration for a particular device
@@ -287,10 +286,6 @@
BuildMode SoongBuildMode
- // If MultitreeBuild is true then this is one inner tree of a multitree
- // build directed by the multitree orchestrator.
- MultitreeBuild bool
-
// If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error
// in tests when a path doesn't exist.
TestAllowNonExistentPaths bool
@@ -540,8 +535,6 @@
moduleListFile: cmdArgs.ModuleListFile,
fs: pathtools.NewOsFs(absSrcDir),
- MultitreeBuild: cmdArgs.MultitreeBuild,
-
buildFromSourceStub: cmdArgs.BuildFromSourceStub,
}
@@ -645,15 +638,19 @@
"framework-adservices": {},
"framework-appsearch": {},
"framework-bluetooth": {},
+ "framework-configinfrastructure": {},
"framework-connectivity": {},
"framework-connectivity-t": {},
+ "framework-devicelock": {},
"framework-graphics": {},
+ "framework-healthfitness": {},
"framework-location": {},
"framework-media": {},
"framework-mediaprovider": {},
"framework-nfc": {},
"framework-ondevicepersonalization": {},
"framework-pdf": {},
+ "framework-pdf-v": {},
"framework-permission": {},
"framework-permission-s": {},
"framework-scheduling": {},
@@ -2028,25 +2025,35 @@
var (
mainlineApexContributionBuildFlags = []string{
+ "RELEASE_APEX_CONTRIBUTIONS_ADBD",
"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES",
"RELEASE_APEX_CONTRIBUTIONS_APPSEARCH",
"RELEASE_APEX_CONTRIBUTIONS_ART",
"RELEASE_APEX_CONTRIBUTIONS_BLUETOOTH",
+ "RELEASE_APEX_CONTRIBUTIONS_CAPTIVEPORTALLOGIN",
+ "RELEASE_APEX_CONTRIBUTIONS_CELLBROADCAST",
"RELEASE_APEX_CONTRIBUTIONS_CONFIGINFRASTRUCTURE",
"RELEASE_APEX_CONTRIBUTIONS_CONNECTIVITY",
"RELEASE_APEX_CONTRIBUTIONS_CONSCRYPT",
"RELEASE_APEX_CONTRIBUTIONS_CRASHRECOVERY",
"RELEASE_APEX_CONTRIBUTIONS_DEVICELOCK",
+ "RELEASE_APEX_CONTRIBUTIONS_DOCUMENTSUIGOOGLE",
+ "RELEASE_APEX_CONTRIBUTIONS_EXTSERVICES",
"RELEASE_APEX_CONTRIBUTIONS_HEALTHFITNESS",
"RELEASE_APEX_CONTRIBUTIONS_IPSEC",
"RELEASE_APEX_CONTRIBUTIONS_MEDIA",
"RELEASE_APEX_CONTRIBUTIONS_MEDIAPROVIDER",
+ "RELEASE_APEX_CONTRIBUTIONS_NETWORKSTACKGOOGLE",
+ "RELEASE_APEX_CONTRIBUTIONS_NEURALNETWORKS",
"RELEASE_APEX_CONTRIBUTIONS_ONDEVICEPERSONALIZATION",
"RELEASE_APEX_CONTRIBUTIONS_PERMISSION",
"RELEASE_APEX_CONTRIBUTIONS_REMOTEKEYPROVISIONING",
+ "RELEASE_APEX_CONTRIBUTIONS_RESOLV",
"RELEASE_APEX_CONTRIBUTIONS_SCHEDULING",
"RELEASE_APEX_CONTRIBUTIONS_SDKEXTENSIONS",
+ "RELEASE_APEX_CONTRIBUTIONS_SWCODEC",
"RELEASE_APEX_CONTRIBUTIONS_STATSD",
+ "RELEASE_APEX_CONTRIBUTIONS_TZDATA",
"RELEASE_APEX_CONTRIBUTIONS_UWB",
"RELEASE_APEX_CONTRIBUTIONS_WIFI",
}
@@ -2063,3 +2070,7 @@
}
return ret
}
+
+func (c *config) BuildIgnoreApexContributionContents() []string {
+ return c.productVariables.BuildIgnoreApexContributionContents
+}
diff --git a/android/module_context.go b/android/module_context.go
index 1cab630..3fc5d01 100644
--- a/android/module_context.go
+++ b/android/module_context.go
@@ -21,6 +21,7 @@
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/parser"
"github.com/google/blueprint/proptools"
)
@@ -212,6 +213,10 @@
// GenerateAndroidBuildActions. If it is called then the struct will be written out and included in
// the module-info.json generated by Make, and Make will not generate its own data for this module.
ModuleInfoJSON() *ModuleInfoJSON
+
+ // EvaluateConfiguration makes ModuleContext a valid proptools.ConfigurableEvaluator, so this context
+ // can be used to evaluate the final value of Configurable properties.
+ EvaluateConfiguration(parser.SelectType, string) (string, bool)
}
type moduleContext struct {
@@ -714,3 +719,32 @@
func (m *moduleContext) TargetRequiredModuleNames() []string {
return m.module.TargetRequiredModuleNames()
}
+
+func (m *moduleContext) EvaluateConfiguration(ty parser.SelectType, condition string) (string, bool) {
+ switch ty {
+ case parser.SelectTypeReleaseVariable:
+ if v, ok := m.Config().productVariables.BuildFlags[condition]; ok {
+ return v, true
+ }
+ return "", false
+ case parser.SelectTypeProductVariable:
+ // TODO: Might add these on a case-by-case basis
+ m.ModuleErrorf("TODO(b/323382414): Product variables are not yet supported in selects")
+ return "", false
+ case parser.SelectTypeSoongConfigVariable:
+ parts := strings.Split(condition, ":")
+ namespace := parts[0]
+ variable := parts[1]
+ if n, ok := m.Config().productVariables.VendorVars[namespace]; ok {
+ if v, ok := n[variable]; ok {
+ return v, true
+ }
+ }
+ return "", false
+ case parser.SelectTypeVariant:
+ m.ModuleErrorf("TODO(b/323382414): Variants are not yet supported in selects")
+ return "", false
+ default:
+ panic("Should be unreachable")
+ }
+}
diff --git a/android/ninja_deps.go b/android/ninja_deps.go
index 1d50a47..bdf465e 100644
--- a/android/ninja_deps.go
+++ b/android/ninja_deps.go
@@ -15,7 +15,6 @@
package android
import (
- "android/soong/starlark_import"
"sort"
)
@@ -43,11 +42,4 @@
func (ninjaDepsSingleton) GenerateBuildActions(ctx SingletonContext) {
ctx.AddNinjaFileDeps(ctx.Config().ninjaFileDeps()...)
-
- deps, err := starlark_import.GetNinjaDeps()
- if err != nil {
- ctx.Errorf("Error running starlark code: %s", err)
- } else {
- ctx.AddNinjaFileDeps(deps...)
- }
}
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 13cda9d..5a94a0f 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -534,6 +534,35 @@
for _, moduleInFamily := range allModulesInFamily {
if moduleInFamily.Name() != selectedModuleInFamily.Name() {
moduleInFamily.HideFromMake()
+ // If this is a prebuilt module, unset properties.UsePrebuilt
+ // properties.UsePrebuilt might evaluate to true via soong config var fallback mechanism
+ // Set it to false explicitly so that the following mutator does not replace rdeps to this unselected prebuilt
+ if p := GetEmbeddedPrebuilt(moduleInFamily); p != nil {
+ p.properties.UsePrebuilt = false
+ }
+ }
+ }
+ }
+ // Do a validation pass to make sure that multiple prebuilts of a specific module are not selected.
+ // This might happen if the prebuilts share the same soong config var namespace.
+ // This should be an error, unless one of the prebuilts has been explicitly declared in apex_contributions
+ var selectedPrebuilt Module
+ for _, moduleInFamily := range allModulesInFamily {
+ // Skip if this module is in a different namespace
+ if !moduleInFamily.ExportedToMake() {
+ continue
+ }
+ // Skip for the top-level java_sdk_library_(_import). This has some special cases that need to be addressed first.
+ // This does not run into non-determinism because PrebuiltPostDepsMutator also has the special case
+ if sdkLibrary, ok := moduleInFamily.(interface{ SdkLibraryName() *string }); ok && sdkLibrary.SdkLibraryName() != nil {
+ continue
+ }
+ if p := GetEmbeddedPrebuilt(moduleInFamily); p != nil && p.properties.UsePrebuilt {
+ if selectedPrebuilt == nil {
+ selectedPrebuilt = moduleInFamily
+ } else {
+ ctx.ModuleErrorf("Multiple prebuilt modules %v and %v have been marked as preferred for this source module. "+
+ "Please add the appropriate prebuilt module to apex_contributions for this release config.", selectedPrebuilt.Name(), moduleInFamily.Name())
}
}
}
@@ -562,7 +591,7 @@
// If we do not special-case this here, rdeps referring to a java_sdk_library in next builds via libs
// will get prebuilt stubs
// TODO (b/308187268): Remove this after the apexes have been added to apex_contributions
- if psi.IsSelected(*sdkLibrary.SdkLibraryName()) {
+ if psi.IsSelected(name) {
return false
}
}
@@ -625,6 +654,17 @@
CreatedByJavaSdkLibraryName() *string
}
+// Returns true if the prebuilt variant is disabled
+// e.g. for a cc_prebuilt_library_shared, this will return
+// - true for the static variant of the module
+// - false for the shared variant of the module
+//
+// Even though this is a cc_prebuilt_library_shared, we create both the variants today
+// https://source.corp.google.com/h/googleplex-android/platform/build/soong/+/e08e32b45a18a77bc3c3e751f730539b1b374f1b:cc/library.go;l=2113-2116;drc=2c4a9779cd1921d0397a12b3d3521f4c9b30d747;bpv=1;bpt=0
+func (p *Prebuilt) variantIsDisabled(ctx BaseMutatorContext, prebuilt Module) bool {
+ return p.srcsSupplier != nil && len(p.srcsSupplier(ctx, prebuilt)) == 0
+}
+
// usePrebuilt returns true if a prebuilt should be used instead of the source module. The prebuilt
// will be used if it is marked "prefer" or if the source module is disabled.
func (p *Prebuilt) usePrebuilt(ctx BaseMutatorContext, source Module, prebuilt Module) bool {
@@ -639,7 +679,7 @@
return false
}
// If the prebuilt module is explicitly listed in the metadata module, use that
- if isSelected(psi, prebuilt) {
+ if isSelected(psi, prebuilt) && !p.variantIsDisabled(ctx, prebuilt) {
return true
}
@@ -647,7 +687,7 @@
// fall back to the existing source vs prebuilt selection.
// TODO: Drop the fallback mechanisms
- if p.srcsSupplier != nil && len(p.srcsSupplier(ctx, prebuilt)) == 0 {
+ if p.variantIsDisabled(ctx, prebuilt) {
return false
}
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index 4a69628..2241b08 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -762,3 +762,45 @@
}
`, selectMainlineModuleContritbutions)
}
+
+// Test that apex_contributions of prebuilt modules are ignored in coverage builds
+func TestSourceIsSelectedInCoverageBuilds(t *testing.T) {
+ prebuiltMainlineContributions := GroupFixturePreparers(
+ FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+ variables.BuildFlags = map[string]string{
+ "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_prebuilt_apex_contributions",
+ }
+ }),
+ FixtureMergeEnv(map[string]string{
+ "EMMA_INSTRUMENT_FRAMEWORK": "true",
+ }),
+ )
+ bp := `
+ source {
+ name: "foo",
+ }
+ prebuilt {
+ name: "foo",
+ srcs: ["prebuilt_file"],
+ }
+ apex_contributions {
+ name: "my_prebuilt_apex_contributions",
+ api_domain: "my_mainline_module",
+ contents: [
+ "prebuilt_foo",
+ ],
+ }
+ all_apex_contributions {
+ name: "all_apex_contributions",
+ }
+ `
+ ctx := GroupFixturePreparers(
+ PrepareForTestWithArchMutator,
+ PrepareForTestWithPrebuilts,
+ FixtureRegisterWithContext(registerTestPrebuiltModules),
+ prebuiltMainlineContributions).RunTestWithBp(t, bp)
+ source := ctx.ModuleForTests("foo", "android_common").Module()
+ AssertBoolEquals(t, "Source should be preferred in coverage builds", true, !source.IsHideFromMake())
+ prebuilt := ctx.ModuleForTests("prebuilt_foo", "android_common").Module()
+ AssertBoolEquals(t, "Prebuilt should not be preferred in coverage builds", false, !prebuilt.IsHideFromMake())
+}
diff --git a/android/selects_test.go b/android/selects_test.go
new file mode 100644
index 0000000..dca3789
--- /dev/null
+++ b/android/selects_test.go
@@ -0,0 +1,282 @@
+// Copyright 2024 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 (
+ "fmt"
+ "reflect"
+ "testing"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+func TestSelects(t *testing.T) {
+ testCases := []struct {
+ name string
+ bp string
+ provider selectsTestProvider
+ vendorVars map[string]map[string]string
+ expectedError string
+ }{
+ {
+ name: "basic string list",
+ bp: `
+ my_module_type {
+ name: "foo",
+ my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
+ "a": ["a.cpp"],
+ "b": ["b.cpp"],
+ _: ["c.cpp"],
+ }),
+ }
+ `,
+ provider: selectsTestProvider{
+ my_string_list: &[]string{"c.cpp"},
+ },
+ },
+ {
+ name: "basic string",
+ bp: `
+ my_module_type {
+ name: "foo",
+ my_string: select(soong_config_variable("my_namespace", "my_variable"), {
+ "a": "a.cpp",
+ "b": "b.cpp",
+ _: "c.cpp",
+ }),
+ }
+ `,
+ provider: selectsTestProvider{
+ my_string: proptools.StringPtr("c.cpp"),
+ },
+ },
+ {
+ name: "basic bool",
+ bp: `
+ my_module_type {
+ name: "foo",
+ my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
+ "a": true,
+ "b": false,
+ _: true,
+ }),
+ }
+ `,
+ provider: selectsTestProvider{
+ my_bool: proptools.BoolPtr(true),
+ },
+ },
+ {
+ name: "Differing types",
+ bp: `
+ my_module_type {
+ name: "foo",
+ my_string: select(soong_config_variable("my_namespace", "my_variable"), {
+ "a": "a.cpp",
+ "b": true,
+ _: "c.cpp",
+ }),
+ }
+ `,
+ expectedError: `can't assign bool value to string property "my_string\[1\]"`,
+ },
+ {
+ name: "String list non-default",
+ bp: `
+ my_module_type {
+ name: "foo",
+ my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
+ "a": ["a.cpp"],
+ "b": ["b.cpp"],
+ _: ["c.cpp"],
+ }),
+ }
+ `,
+ provider: selectsTestProvider{
+ my_string_list: &[]string{"a.cpp"},
+ },
+ vendorVars: map[string]map[string]string{
+ "my_namespace": {
+ "my_variable": "a",
+ },
+ },
+ },
+ {
+ name: "String list append",
+ bp: `
+ my_module_type {
+ name: "foo",
+ my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
+ "a": ["a.cpp"],
+ "b": ["b.cpp"],
+ _: ["c.cpp"],
+ }) + select(soong_config_variable("my_namespace", "my_variable_2"), {
+ "a2": ["a2.cpp"],
+ "b2": ["b2.cpp"],
+ _: ["c2.cpp"],
+ }),
+ }
+ `,
+ provider: selectsTestProvider{
+ my_string_list: &[]string{"a.cpp", "c2.cpp"},
+ },
+ vendorVars: map[string]map[string]string{
+ "my_namespace": {
+ "my_variable": "a",
+ },
+ },
+ },
+ {
+ name: "String list prepend literal",
+ bp: `
+ my_module_type {
+ name: "foo",
+ my_string_list: ["literal.cpp"] + select(soong_config_variable("my_namespace", "my_variable"), {
+ "a2": ["a2.cpp"],
+ "b2": ["b2.cpp"],
+ _: ["c2.cpp"],
+ }),
+ }
+ `,
+ provider: selectsTestProvider{
+ my_string_list: &[]string{"literal.cpp", "c2.cpp"},
+ },
+ },
+ {
+ name: "String list append literal",
+ bp: `
+ my_module_type {
+ name: "foo",
+ my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
+ "a2": ["a2.cpp"],
+ "b2": ["b2.cpp"],
+ _: ["c2.cpp"],
+ }) + ["literal.cpp"],
+ }
+ `,
+ provider: selectsTestProvider{
+ my_string_list: &[]string{"c2.cpp", "literal.cpp"},
+ },
+ },
+ {
+ name: "Can't append bools",
+ bp: `
+ my_module_type {
+ name: "foo",
+ my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
+ "a": true,
+ "b": false,
+ _: true,
+ }) + false,
+ }
+ `,
+ expectedError: "my_bool: Cannot append bools",
+ },
+ {
+ name: "Append string",
+ bp: `
+ my_module_type {
+ name: "foo",
+ my_string: select(soong_config_variable("my_namespace", "my_variable"), {
+ "a": "a",
+ "b": "b",
+ _: "c",
+ }) + ".cpp",
+ }
+ `,
+ provider: selectsTestProvider{
+ my_string: proptools.StringPtr("c.cpp"),
+ },
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ fixtures := GroupFixturePreparers(
+ FixtureRegisterWithContext(func(ctx RegistrationContext) {
+ ctx.RegisterModuleType("my_module_type", newSelectsMockModule)
+ }),
+ FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+ variables.VendorVars = tc.vendorVars
+ }),
+ )
+ if tc.expectedError != "" {
+ fixtures = fixtures.ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(tc.expectedError))
+ }
+ result := fixtures.RunTestWithBp(t, tc.bp)
+
+ if tc.expectedError == "" {
+ m := result.ModuleForTests("foo", "")
+ p, _ := OtherModuleProvider[selectsTestProvider](result.testContext.OtherModuleProviderAdaptor(), m.Module(), selectsTestProviderKey)
+ if !reflect.DeepEqual(p, tc.provider) {
+ t.Errorf("Expected:\n %q\ngot:\n %q", tc.provider.String(), p.String())
+ }
+ }
+ })
+ }
+}
+
+type selectsTestProvider struct {
+ my_bool *bool
+ my_string *string
+ my_string_list *[]string
+}
+
+func (p *selectsTestProvider) String() string {
+ myBoolStr := "nil"
+ if p.my_bool != nil {
+ myBoolStr = fmt.Sprintf("%t", *p.my_bool)
+ }
+ myStringStr := "nil"
+ if p.my_string != nil {
+ myStringStr = *p.my_string
+ }
+ return fmt.Sprintf(`selectsTestProvider {
+ my_bool: %v,
+ my_string: %s,
+ my_string_list: %s,
+}`, myBoolStr, myStringStr, p.my_string_list)
+}
+
+var selectsTestProviderKey = blueprint.NewProvider[selectsTestProvider]()
+
+type selectsMockModuleProperties struct {
+ My_bool proptools.Configurable[bool]
+ My_string proptools.Configurable[string]
+ My_string_list proptools.Configurable[[]string]
+}
+
+type selectsMockModule struct {
+ ModuleBase
+ DefaultableModuleBase
+ properties selectsMockModuleProperties
+}
+
+func (p *selectsMockModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ SetProvider[selectsTestProvider](ctx, selectsTestProviderKey, selectsTestProvider{
+ my_bool: p.properties.My_bool.Evaluate(ctx),
+ my_string: p.properties.My_string.Evaluate(ctx),
+ my_string_list: p.properties.My_string_list.Evaluate(ctx),
+ })
+}
+
+func newSelectsMockModule() Module {
+ m := &selectsMockModule{}
+ m.AddProperties(&m.properties)
+ InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
+ InitDefaultableModule(m)
+ return m
+}
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index d525bdc..c78b726 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -681,6 +681,14 @@
if !propStruct.IsValid() {
return nil, nil
}
+ if err := s.printfIntoPropertyRecursive(nil, propStruct, configValue); err != nil {
+ return nil, err
+ }
+
+ return values.Interface(), nil
+}
+
+func (s *valueVariable) printfIntoPropertyRecursive(fieldName []string, propStruct reflect.Value, configValue string) error {
for i := 0; i < propStruct.NumField(); i++ {
field := propStruct.Field(i)
kind := field.Kind()
@@ -695,23 +703,31 @@
case reflect.String:
err := printfIntoProperty(field, configValue)
if err != nil {
- return nil, fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, propStruct.Type().Field(i).Name, err)
+ fieldName = append(fieldName, propStruct.Type().Field(i).Name)
+ return fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, strings.Join(fieldName, "."), err)
}
case reflect.Slice:
for j := 0; j < field.Len(); j++ {
err := printfIntoProperty(field.Index(j), configValue)
if err != nil {
- return nil, fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, propStruct.Type().Field(i).Name, err)
+ fieldName = append(fieldName, propStruct.Type().Field(i).Name)
+ return fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, strings.Join(fieldName, "."), err)
}
}
case reflect.Bool:
// Nothing to do
+ case reflect.Struct:
+ fieldName = append(fieldName, propStruct.Type().Field(i).Name)
+ if err := s.printfIntoPropertyRecursive(fieldName, field, configValue); err != nil {
+ return err
+ }
+ fieldName = fieldName[:len(fieldName)-1]
default:
- return nil, fmt.Errorf("soong_config_variables.%s.%s: unsupported property type %q", s.variable, propStruct.Type().Field(i).Name, kind)
+ fieldName = append(fieldName, propStruct.Type().Field(i).Name)
+ return fmt.Errorf("soong_config_variables.%s.%s: unsupported property type %q", s.variable, strings.Join(fieldName, "."), kind)
}
}
-
- return values.Interface(), nil
+ return nil
}
func printfIntoProperty(propertyValue reflect.Value, configValue string) error {
diff --git a/android/soongconfig/modules_test.go b/android/soongconfig/modules_test.go
index db2c83c..1da0b49 100644
--- a/android/soongconfig/modules_test.go
+++ b/android/soongconfig/modules_test.go
@@ -429,6 +429,76 @@
}
}
+func Test_PropertiesToApply_Value_Nested(t *testing.T) {
+ mt, _ := newModuleType(&ModuleTypeProperties{
+ Module_type: "foo",
+ Config_namespace: "bar",
+ Value_variables: []string{"my_value_var"},
+ Properties: []string{"a.b"},
+ })
+ type properties struct {
+ A struct {
+ B string
+ }
+ }
+ conditionsDefault := &properties{
+ A: struct{ B string }{
+ B: "default",
+ },
+ }
+ type valueVarProps struct {
+ A struct {
+ B string
+ }
+ Conditions_default *properties
+ }
+ actualProps := &struct {
+ Soong_config_variables valueSoongConfigVars
+ }{
+ Soong_config_variables: valueSoongConfigVars{
+ My_value_var: &valueVarProps{
+ A: struct{ B string }{
+ B: "A.B=%s",
+ },
+ Conditions_default: conditionsDefault,
+ },
+ },
+ }
+ props := reflect.ValueOf(actualProps)
+
+ testCases := []struct {
+ name string
+ config SoongConfig
+ wantProps []interface{}
+ }{
+ {
+ name: "no_vendor_config",
+ config: Config(map[string]string{}),
+ wantProps: []interface{}{conditionsDefault},
+ },
+ {
+ name: "value_var_set",
+ config: Config(map[string]string{"my_value_var": "Hello"}),
+ wantProps: []interface{}{&properties{
+ A: struct{ B string }{
+ B: "A.B=Hello",
+ },
+ }},
+ },
+ }
+
+ for _, tc := range testCases {
+ gotProps, err := PropertiesToApply(mt, props, tc.config)
+ if err != nil {
+ t.Errorf("%s: Unexpected error in PropertiesToApply: %s", tc.name, err)
+ }
+
+ if !reflect.DeepEqual(gotProps, tc.wantProps) {
+ t.Errorf("%s: Expected %s, got %s", tc.name, tc.wantProps, gotProps)
+ }
+ }
+}
+
func Test_PropertiesToApply_String_Error(t *testing.T) {
mt, _ := newModuleType(&ModuleTypeProperties{
Module_type: "foo",
diff --git a/android/updatable_modules.go b/android/updatable_modules.go
index 6d0eeb7..1548170 100644
--- a/android/updatable_modules.go
+++ b/android/updatable_modules.go
@@ -33,4 +33,4 @@
// * AOSP - xx9990000
// * x-mainline-prod - xx9990000
// * master - 990090000
-const DefaultUpdatableModuleVersion = "340090000"
+const DefaultUpdatableModuleVersion = "990090000"
diff --git a/android/variable.go b/android/variable.go
index 758967e..be3c80d 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -494,6 +494,12 @@
BuildFlags map[string]string `json:",omitempty"`
BuildFromSourceStub *bool `json:",omitempty"`
+
+ BuildIgnoreApexContributionContents []string `json:",omitempty"`
+
+ HiddenapiExportableStubs *bool `json:",omitempty"`
+
+ ExportRuntimeApis *bool `json:",omitempty"`
}
type PartitionQualifiedVariablesType struct {
diff --git a/apex/apex.go b/apex/apex.go
index 557b9b7..9d7af18 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -842,10 +842,12 @@
}
addDependenciesForNativeModules(ctx, deps, target, imageVariation)
- ctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "os", Variation: target.OsVariation()},
- {Mutator: "arch", Variation: target.ArchVariation()},
- }, shBinaryTag, a.properties.Sh_binaries...)
+ if isPrimaryAbi {
+ ctx.AddFarVariationDependencies([]blueprint.Variation{
+ {Mutator: "os", Variation: target.OsVariation()},
+ {Mutator: "arch", Variation: target.ArchVariation()},
+ }, shBinaryTag, a.properties.Sh_binaries...)
+ }
}
// Common-arch dependencies come next
@@ -2073,8 +2075,10 @@
return true // track transitive dependencies
case *java.AndroidAppImport:
vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
+ addAconfigFiles(vctx, ctx, child)
case *java.AndroidTestHelperApp:
vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
+ addAconfigFiles(vctx, ctx, child)
case *java.AndroidAppSet:
appDir := "app"
if ap.Privileged() {
@@ -2088,6 +2092,7 @@
af := newApexFile(ctx, ap.OutputFile(), ap.BaseModuleName(), appDirName, appSet, ap)
af.certificate = java.PresignedCertificate
vctx.filesInfo = append(vctx.filesInfo, af)
+ addAconfigFiles(vctx, ctx, child)
default:
ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
}
@@ -2116,6 +2121,7 @@
case prebuiltTag:
if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
+ addAconfigFiles(vctx, ctx, child)
} else {
ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
}
@@ -2139,6 +2145,7 @@
af := apexFileForExecutable(ctx, ccTest)
af.class = nativeTest
vctx.filesInfo = append(vctx.filesInfo, af)
+ addAconfigFiles(vctx, ctx, child)
}
return true // track transitive dependencies
} else {
@@ -2228,11 +2235,13 @@
}
vctx.filesInfo = append(vctx.filesInfo, af)
+ addAconfigFiles(vctx, ctx, child)
return true // track transitive dependencies
} else if rm, ok := child.(*rust.Module); ok {
af := apexFileForRustLibrary(ctx, rm)
af.transitiveDep = true
vctx.filesInfo = append(vctx.filesInfo, af)
+ addAconfigFiles(vctx, ctx, child)
return true // track transitive dependencies
}
} else if cc.IsTestPerSrcDepTag(depTag) {
@@ -2261,6 +2270,7 @@
af := apexFileForRustLibrary(ctx, rustm)
af.transitiveDep = true
vctx.filesInfo = append(vctx.filesInfo, af)
+ addAconfigFiles(vctx, ctx, child)
return true // track transitive dependencies
}
} else if rust.IsRlibDepTag(depTag) {
@@ -2279,6 +2289,7 @@
return false
}
vctx.filesInfo = append(vctx.filesInfo, af)
+ addAconfigFiles(vctx, ctx, child)
return true // track transitive dependencies
default:
ctx.PropertyErrorf("bootclasspath_fragments",
@@ -2293,6 +2304,7 @@
if profileAf := apexFileForJavaModuleProfile(ctx, child.(javaModule)); profileAf != nil {
vctx.filesInfo = append(vctx.filesInfo, *profileAf)
}
+ addAconfigFiles(vctx, ctx, child)
return true // track transitive dependencies
default:
ctx.PropertyErrorf("systemserverclasspath_fragments",
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 5cc50dd..54d2d08 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -5046,6 +5046,7 @@
key: "myapex.key",
sh_binaries: ["myscript"],
updatable: false,
+ compile_multilib: "both",
}
apex_key {
@@ -6198,7 +6199,7 @@
`)
})
- t.Run("Co-existing unflagged apexes should create a duplicate deapexer error in hiddenapi processing", func(t *testing.T) {
+ t.Run("Co-existing unflagged apexes should create a duplicate module error", func(t *testing.T) {
bp := `
// Source
apex {
@@ -6272,7 +6273,7 @@
}
`
- testDexpreoptWithApexes(t, bp, "Multiple installable prebuilt APEXes provide ambiguous deapexers: prebuilt_myapex.v1 and prebuilt_myapex.v2", preparer, fragment)
+ testDexpreoptWithApexes(t, bp, "Multiple prebuilt modules prebuilt_myapex.v1 and prebuilt_myapex.v2 have been marked as preferred for this source module", preparer, fragment)
})
}
@@ -11115,25 +11116,23 @@
mod := ctx.ModuleForTests("myapex", "android_common_myapex")
s := mod.Rule("apexRule").Args["copy_commands"]
copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
- if len(copyCmds) != 5 {
+ if len(copyCmds) != 8 {
t.Fatalf("Expected 5 commands, got %d in:\n%s", len(copyCmds), s)
}
- ensureMatches(t, copyCmds[4], "^cp -f .*/aconfig_flags.pb .*/image.apex$")
+ ensureMatches(t, copyCmds[4], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$")
+ ensureMatches(t, copyCmds[5], "^cp -f .*/package.map .*/image.apex/etc$")
+ ensureMatches(t, copyCmds[6], "^cp -f .*/flag.map .*/image.apex/etc$")
+ ensureMatches(t, copyCmds[7], "^cp -f .*/flag.val .*/image.apex/etc$")
- combineAconfigRule := mod.Rule("All_aconfig_declarations_dump")
- s = " " + combineAconfigRule.Args["cache_files"]
- aconfigArgs := regexp.MustCompile(" --cache ").Split(s, -1)[1:]
- if len(aconfigArgs) != 2 {
- t.Fatalf("Expected 2 commands, got %d in:\n%s", len(aconfigArgs), s)
+ inputs := []string{
+ "my_aconfig_declarations_foo/intermediate.pb",
+ "my_aconfig_declarations_bar/intermediate.pb",
}
- android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/intermediate.pb")
- android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_bar/intermediate.pb")
-
- buildParams := combineAconfigRule.BuildParams
- android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb")
- android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_bar/intermediate.pb")
- ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb")
+ VerifyAconfigRule(t, &mod, "combine_aconfig_declarations", inputs, "android_common_myapex/aconfig_flags.pb", "", "")
+ VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map")
+ VerifyAconfigRule(t, &mod, "create_aconfig_flag_map_file", inputs, "android_common_myapex/flag.map", "myapex", "flag_map")
+ VerifyAconfigRule(t, &mod, "create_aconfig_flag_val_file", inputs, "android_common_myapex/flag.val", "myapex", "flag_val")
}
func TestAconfigFilesJavaAndCcDeps(t *testing.T) {
@@ -11241,30 +11240,24 @@
mod := ctx.ModuleForTests("myapex", "android_common_myapex")
s := mod.Rule("apexRule").Args["copy_commands"]
copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
- if len(copyCmds) != 9 {
- t.Fatalf("Expected 9 commands, got %d in:\n%s", len(copyCmds), s)
+ if len(copyCmds) != 12 {
+ t.Fatalf("Expected 12 commands, got %d in:\n%s", len(copyCmds), s)
}
- ensureMatches(t, copyCmds[8], "^cp -f .*/aconfig_flags.pb .*/image.apex$")
+ ensureMatches(t, copyCmds[8], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$")
+ ensureMatches(t, copyCmds[9], "^cp -f .*/package.map .*/image.apex/etc$")
+ ensureMatches(t, copyCmds[10], "^cp -f .*/flag.map .*/image.apex/etc$")
+ ensureMatches(t, copyCmds[11], "^cp -f .*/flag.val .*/image.apex/etc$")
- combineAconfigRule := mod.Rule("All_aconfig_declarations_dump")
- s = " " + combineAconfigRule.Args["cache_files"]
- aconfigArgs := regexp.MustCompile(" --cache ").Split(s, -1)[1:]
- if len(aconfigArgs) != 3 {
- t.Fatalf("Expected 3 commands, got %d in:\n%s", len(aconfigArgs), s)
+ inputs := []string{
+ "my_aconfig_declarations_foo/intermediate.pb",
+ "my_cc_library_bar/android_arm64_armv8-a_shared_apex10000/myapex/aconfig_merged.pb",
+ "my_aconfig_declarations_baz/intermediate.pb",
}
- android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/intermediate.pb")
- android.EnsureListContainsSuffix(t, aconfigArgs, "my_cc_library_bar/android_arm64_armv8-a_shared_apex10000/myapex/aconfig_merged.pb")
- android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_baz/intermediate.pb")
-
- buildParams := combineAconfigRule.BuildParams
- if len(buildParams.Inputs) != 3 {
- t.Fatalf("Expected 3 input, got %d", len(buildParams.Inputs))
- }
- android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb")
- android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_cc_library_bar/android_arm64_armv8-a_shared_apex10000/myapex/aconfig_merged.pb")
- android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_baz/intermediate.pb")
- ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb")
+ VerifyAconfigRule(t, &mod, "combine_aconfig_declarations", inputs, "android_common_myapex/aconfig_flags.pb", "", "")
+ VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map")
+ VerifyAconfigRule(t, &mod, "create_aconfig_flag_map_file", inputs, "android_common_myapex/flag.map", "myapex", "flag_map")
+ VerifyAconfigRule(t, &mod, "create_aconfig_flag_val_file", inputs, "android_common_myapex/flag.val", "myapex", "flag_val")
}
func TestAconfigFilesRustDeps(t *testing.T) {
@@ -11388,28 +11381,45 @@
mod := ctx.ModuleForTests("myapex", "android_common_myapex")
s := mod.Rule("apexRule").Args["copy_commands"]
copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
- if len(copyCmds) != 23 {
- t.Fatalf("Expected 23 commands, got %d in:\n%s", len(copyCmds), s)
+ if len(copyCmds) != 26 {
+ t.Fatalf("Expected 26 commands, got %d in:\n%s", len(copyCmds), s)
}
- ensureMatches(t, copyCmds[22], "^cp -f .*/aconfig_flags.pb .*/image.apex$")
+ ensureMatches(t, copyCmds[22], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$")
+ ensureMatches(t, copyCmds[23], "^cp -f .*/package.map .*/image.apex/etc$")
+ ensureMatches(t, copyCmds[24], "^cp -f .*/flag.map .*/image.apex/etc$")
+ ensureMatches(t, copyCmds[25], "^cp -f .*/flag.val .*/image.apex/etc$")
- combineAconfigRule := mod.Rule("All_aconfig_declarations_dump")
- s = " " + combineAconfigRule.Args["cache_files"]
+ inputs := []string{
+ "my_aconfig_declarations_foo/intermediate.pb",
+ "my_aconfig_declarations_bar/intermediate.pb",
+ "my_aconfig_declarations_baz/intermediate.pb",
+ "my_rust_binary/android_arm64_armv8-a_apex10000/myapex/aconfig_merged.pb",
+ }
+ VerifyAconfigRule(t, &mod, "combine_aconfig_declarations", inputs, "android_common_myapex/aconfig_flags.pb", "", "")
+ VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map")
+ VerifyAconfigRule(t, &mod, "create_aconfig_flag_map_file", inputs, "android_common_myapex/flag.map", "myapex", "flag_map")
+ VerifyAconfigRule(t, &mod, "create_aconfig_flag_val_file", inputs, "android_common_myapex/flag.val", "myapex", "flag_val")
+}
+
+func VerifyAconfigRule(t *testing.T, mod *android.TestingModule, desc string, inputs []string, output string, container string, file_type string) {
+ aconfigRule := mod.Description(desc)
+ s := " " + aconfigRule.Args["cache_files"]
aconfigArgs := regexp.MustCompile(" --cache ").Split(s, -1)[1:]
- if len(aconfigArgs) != 2 {
- t.Fatalf("Expected 2 commands, got %d in:\n%s", len(aconfigArgs), s)
+ if len(aconfigArgs) != len(inputs) {
+ t.Fatalf("Expected %d commands, got %d in:\n%s", len(inputs), len(aconfigArgs), s)
}
- android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/intermediate.pb")
- android.EnsureListContainsSuffix(t, aconfigArgs, "my_rust_binary/android_arm64_armv8-a_apex10000/myapex/aconfig_merged.pb")
- buildParams := combineAconfigRule.BuildParams
- if len(buildParams.Inputs) != 2 {
- t.Fatalf("Expected 3 input, got %d", len(buildParams.Inputs))
+ ensureEquals(t, container, aconfigRule.Args["container"])
+ ensureEquals(t, file_type, aconfigRule.Args["file_type"])
+
+ buildParams := aconfigRule.BuildParams
+ for _, input := range inputs {
+ android.EnsureListContainsSuffix(t, aconfigArgs, input)
+ android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), input)
}
- android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb")
- android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_rust_binary/android_arm64_armv8-a_apex10000/myapex/aconfig_merged.pb")
- ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb")
+
+ ensureContains(t, buildParams.Output.String(), output)
}
func TestAconfigFilesOnlyMatchCurrentApex(t *testing.T) {
diff --git a/apex/builder.go b/apex/builder.go
index 3d61219..6ad282a 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -85,6 +85,18 @@
pctx.HostBinToolVariable("aconfig", "aconfig")
}
+type createStorageStruct struct {
+ Output_file string
+ Desc string
+ File_type string
+}
+
+var createStorageInfo = []createStorageStruct{
+ {"package.map", "create_aconfig_package_map_file", "package_map"},
+ {"flag.map", "create_aconfig_flag_map_file", "flag_map"},
+ {"flag.val", "create_aconfig_flag_val_file", "flag_val"},
+}
+
var (
apexManifestRule = pctx.StaticRule("apexManifestRule", blueprint.RuleParams{
Command: `rm -f $out && ${jsonmodify} $in ` +
@@ -633,6 +645,7 @@
prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
defaultReadOnlyFiles := []string{"apex_manifest.json", "apex_manifest.pb"}
+ aconfigDest := imageDir.Join(ctx, "etc").String()
if len(a.aconfigFiles) > 0 {
apexAconfigFile := android.PathForModuleOut(ctx, "aconfig_flags.pb")
ctx.Build(pctx, android.BuildParams{
@@ -645,9 +658,28 @@
},
})
- copyCommands = append(copyCommands, "cp -f "+apexAconfigFile.String()+" "+imageDir.String())
+ copyCommands = append(copyCommands, "cp -f "+apexAconfigFile.String()+" "+aconfigDest)
implicitInputs = append(implicitInputs, apexAconfigFile)
- defaultReadOnlyFiles = append(defaultReadOnlyFiles, apexAconfigFile.Base())
+ defaultReadOnlyFiles = append(defaultReadOnlyFiles, "etc/"+apexAconfigFile.Base())
+
+ for _, info := range createStorageInfo {
+ outputFile := android.PathForModuleOut(ctx, info.Output_file)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: aconfig.CreateStorageRule,
+ Inputs: a.aconfigFiles,
+ Output: outputFile,
+ Description: info.Desc,
+ Args: map[string]string{
+ "container": ctx.ModuleName(),
+ "file_type": info.File_type,
+ "cache_files": android.JoinPathsWithPrefix(a.aconfigFiles, "--cache "),
+ },
+ })
+
+ copyCommands = append(copyCommands, "cp -f "+outputFile.String()+" "+aconfigDest)
+ implicitInputs = append(implicitInputs, outputFile)
+ defaultReadOnlyFiles = append(defaultReadOnlyFiles, "etc/"+outputFile.Base())
+ }
}
////////////////////////////////////////////////////////////////////////////////////
diff --git a/bloaty/bloaty.go b/bloaty/bloaty.go
index 43fb71d..b72b6d3 100644
--- a/bloaty/bloaty.go
+++ b/bloaty/bloaty.go
@@ -85,6 +85,9 @@
func (singleton *sizesSingleton) GenerateBuildActions(ctx android.SingletonContext) {
var deps android.Paths
ctx.VisitAllModules(func(m android.Module) {
+ if !m.ExportedToMake() {
+ return
+ }
filePaths, ok := android.SingletonModuleProvider(ctx, m, fileSizeMeasurerKey)
if !ok {
return
diff --git a/bpf/bpf.go b/bpf/bpf.go
index e1b512f..38fbd88 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -203,6 +203,15 @@
}
}
+
+ installDir := android.PathForModuleInstall(ctx, "etc", "bpf")
+ if len(bpf.properties.Sub_dir) > 0 {
+ installDir = installDir.Join(ctx, bpf.properties.Sub_dir)
+ }
+ for _, obj := range bpf.objs {
+ ctx.PackageFile(installDir, obj.Base(), obj)
+ }
+
android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
}
diff --git a/cc/cc.go b/cc/cc.go
index 39024aa..2770fb2 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -3361,7 +3361,7 @@
c.sabi.Properties.ReexportedIncludes, depExporterInfo.IncludeDirs.Strings()...)
}
- makeLibName := MakeLibName(ctx, c, ccDep, depName) + libDepTag.makeSuffix
+ makeLibName := MakeLibName(ctx, c, ccDep, ccDep.BaseModuleName()) + libDepTag.makeSuffix
switch {
case libDepTag.header():
c.Properties.AndroidMkHeaderLibs = append(
@@ -3402,7 +3402,7 @@
switch depTag {
case runtimeDepTag:
c.Properties.AndroidMkRuntimeLibs = append(
- c.Properties.AndroidMkRuntimeLibs, MakeLibName(ctx, c, ccDep, depName)+libDepTag.makeSuffix)
+ c.Properties.AndroidMkRuntimeLibs, MakeLibName(ctx, c, ccDep, ccDep.BaseModuleName())+libDepTag.makeSuffix)
// Record BaseLibName for snapshots.
c.Properties.SnapshotRuntimeLibs = append(c.Properties.SnapshotRuntimeLibs, BaseLibName(depName))
case objDepTag:
diff --git a/cc/check.go b/cc/check.go
index 58ff5b2..32d1f06 100644
--- a/cc/check.go
+++ b/cc/check.go
@@ -45,6 +45,8 @@
ctx.PropertyErrorf(prop, "-Weverything is not allowed in Android.bp files. "+
"Build with `m ANDROID_TEMPORARILY_ALLOW_WEVERYTHING=true` to experiment locally with -Weverything.")
}
+ } else if strings.HasPrefix(flag, "-target") || strings.HasPrefix(flag, "--target") {
+ ctx.PropertyErrorf(prop, "Bad flag: `%s`, use the correct target soong rule.", flag)
} else if strings.Contains(flag, " ") {
args := strings.Split(flag, " ")
if args[0] == "-include" {
diff --git a/cc/config/global.go b/cc/config/global.go
index d3c2658..b21d56c 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -367,8 +367,6 @@
"-Wno-gnu-offsetof-extensions",
// TODO: Enable this warning http://b/315245071
"-Wno-fortify-source",
- "-Wno-tautological-negation-compare",
- "-Wno-tautological-undefined-compare",
}
llvmNextExtraCommonGlobalCflags = []string{
diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go
index deb922b..6a84fee 100644
--- a/cc/config/riscv64_device.go
+++ b/cc/config/riscv64_device.go
@@ -26,9 +26,7 @@
// Help catch common 32/64-bit errors.
"-Werror=implicit-function-declaration",
"-march=rv64gcv_zba_zbb_zbs",
- // Equivalent to "-munaligned-access", but our clang doesn't have that yet.
- "-Xclang -target-feature -Xclang +unaligned-scalar-mem",
- "-Xclang -target-feature -Xclang +unaligned-vector-mem",
+ "-munaligned-access",
// Until https://gitlab.com/qemu-project/qemu/-/issues/1976 is fixed...
"-mno-implicit-float",
// (https://github.com/google/android-riscv64/issues/124)
@@ -40,9 +38,7 @@
riscv64Ldflags = []string{
"-Wl,--hash-style=gnu",
"-march=rv64gcv_zba_zbb_zbs",
- // Equivalent to "-munaligned-access", but our clang doesn't have that yet.
- "-Xclang -target-feature -Xclang +unaligned-scalar-mem",
- "-Xclang -target-feature -Xclang +unaligned-vector-mem",
+ "-munaligned-access",
// We should change the default for this in clang, but for now...
// (https://github.com/google/android-riscv64/issues/124)
"-Wl,-mllvm -Wl,-jump-is-expensive=false",
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 8f4b7df..cbb5d58 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -260,6 +260,9 @@
func (p *prebuiltLibraryLinker) disablePrebuilt() {
p.properties.Srcs = nil
+ p.properties.Sanitized.None.Srcs = nil
+ p.properties.Sanitized.Address.Srcs = nil
+ p.properties.Sanitized.Hwaddress.Srcs = nil
}
// Implements versionedInterface
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index 95fb7ed..71b7e43 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -595,6 +595,9 @@
libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
expectedDependency := ctx.ModuleForTests(tc.expectedDependencyName, "android_arm64_armv8-a_shared").Module()
android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", libfoo.Name(), tc.expectedDependencyName), true, hasDep(ctx, libfoo, expectedDependency))
+ // check that LOCAL_SHARED_LIBRARIES contains libbar and not libbar.v<N>
+ entries := android.AndroidMkEntriesForTest(t, ctx, libfoo)[0]
+ android.AssertStringListContains(t, "Version should not be present in LOCAL_SHARED_LIBRARIES", entries.EntryMap["LOCAL_SHARED_LIBRARIES"], "libbar")
// check installation rules
// the selected soong module should be exported to make
@@ -603,7 +606,157 @@
// check LOCAL_MODULE of the selected module name
// the prebuilt should have the same LOCAL_MODULE when exported to make
- entries := android.AndroidMkEntriesForTest(t, ctx, libbar)[0]
+ entries = android.AndroidMkEntriesForTest(t, ctx, libbar)[0]
android.AssertStringEquals(t, "unexpected LOCAL_MODULE", "libbar", entries.EntryMap["LOCAL_MODULE"][0])
}
}
+
+// Setting prefer on multiple prebuilts is an error, unless one of them is also listed in apex_contributions
+func TestMultiplePrebuiltsPreferredUsingLegacyFlags(t *testing.T) {
+ bp := `
+ // an rdep
+ cc_library {
+ name: "libfoo",
+ shared_libs: ["libbar"],
+ }
+
+ // multiple variations of dep
+ // source
+ cc_library {
+ name: "libbar",
+ }
+ // prebuilt "v1"
+ cc_prebuilt_library_shared {
+ name: "libbar",
+ srcs: ["libbar.so"],
+ prefer: true,
+ }
+ // prebuilt "v2"
+ cc_prebuilt_library_shared {
+ name: "libbar.v2",
+ stem: "libbar",
+ source_module_name: "libbar",
+ srcs: ["libbar.so"],
+ prefer: true,
+ }
+
+ // selectors
+ apex_contributions {
+ name: "myapex_contributions",
+ contents: [%v],
+ }
+ all_apex_contributions {name: "all_apex_contributions"}
+ `
+ hasDep := func(ctx *android.TestContext, m android.Module, wantDep android.Module) bool {
+ t.Helper()
+ var found bool
+ ctx.VisitDirectDeps(m, func(dep blueprint.Module) {
+ if dep == wantDep {
+ found = true
+ }
+ })
+ return found
+ }
+
+ testCases := []struct {
+ desc string
+ selectedDependencyName string
+ expectedDependencyName string
+ expectedErr string
+ }{
+ {
+ desc: "Multiple prebuilts have prefer: true",
+ expectedErr: "Multiple prebuilt modules prebuilt_libbar and prebuilt_libbar.v2 have been marked as preferred for this source module",
+ },
+ {
+ desc: "Multiple prebuilts have prefer: true. The prebuilt listed in apex_contributions wins.",
+ selectedDependencyName: `"prebuilt_libbar"`,
+ expectedDependencyName: "prebuilt_libbar",
+ },
+ }
+
+ for _, tc := range testCases {
+ preparer := android.GroupFixturePreparers(
+ android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+ android.RegisterApexContributionsBuildComponents(ctx)
+ }),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BuildFlags = map[string]string{
+ "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "myapex_contributions",
+ }
+ }),
+ )
+ if tc.expectedErr != "" {
+ preparer = preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(tc.expectedErr))
+ }
+
+ ctx := testPrebuilt(t, fmt.Sprintf(bp, tc.selectedDependencyName), map[string][]byte{
+ "libbar.so": nil,
+ "crtx.o": nil,
+ }, preparer)
+ if tc.expectedErr != "" {
+ return // the fixture will assert that the excepted err has been raised
+ }
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
+ expectedDependency := ctx.ModuleForTests(tc.expectedDependencyName, "android_arm64_armv8-a_shared").Module()
+ android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", libfoo.Name(), tc.expectedDependencyName), true, hasDep(ctx, libfoo, expectedDependency))
+ }
+}
+
+// If module sdk cannot provide a cc module variant (e.g. static), then the module variant from source should be used
+func TestMissingVariantInModuleSdk(t *testing.T) {
+ bp := `
+ // an rdep
+ cc_library {
+ name: "libfoo",
+ static_libs: ["libbar"],
+ }
+
+ // source
+ cc_library {
+ name: "libbar",
+ }
+ // prebuilt
+ // libbar only exists as a shared library
+ cc_prebuilt_library_shared {
+ name: "libbar",
+ srcs: ["libbar.so"],
+ }
+ // selectors
+ apex_contributions {
+ name: "myapex_contributions",
+ contents: ["prebuilt_libbar"],
+ }
+ all_apex_contributions {name: "all_apex_contributions"}
+ `
+ hasDep := func(ctx *android.TestContext, m android.Module, wantDep android.Module) bool {
+ t.Helper()
+ var found bool
+ ctx.VisitDirectDeps(m, func(dep blueprint.Module) {
+ if dep == wantDep {
+ found = true
+ }
+ })
+ return found
+ }
+
+ preparer := android.GroupFixturePreparers(
+ android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+ android.RegisterApexContributionsBuildComponents(ctx)
+ }),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BuildFlags = map[string]string{
+ "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "myapex_contributions",
+ }
+ }),
+ )
+ ctx := testPrebuilt(t, bp, map[string][]byte{
+ "libbar.so": nil,
+ "crtx.o": nil,
+ }, preparer)
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
+ sourceLibBar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_static").Module()
+ // Even though the prebuilt is listed in apex_contributions, the prebuilt does not have a static variant.
+ // Therefore source of libbar should be used.
+ android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from libfoo to source libbar"), true, hasDep(ctx, libfoo, sourceLibBar))
+}
diff --git a/cc/stl.go b/cc/stl.go
index 63c23d7..de2066f 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -205,12 +205,14 @@
flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++")
if ctx.Windows() {
flags.Local.CppFlags = append(flags.Local.CppFlags,
- // Disable visiblity annotations since we're using static
- // libc++.
- "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
- "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+ // These macros can also be defined by libc++'s __config
+ // or __config_site headers so define them the same way
+ // (i.e. to nothing). Disable visibility annotations since
+ // we're using static libc++.
+ "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS=",
+ "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS=",
// Use Win32 threads in libc++.
- "-D_LIBCPP_HAS_THREAD_API_WIN32")
+ "-D_LIBCPP_HAS_THREAD_API_WIN32=")
}
}
case "libstdc++":
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 673f305..d64010e 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -76,7 +76,6 @@
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.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")
flag.BoolVar(&cmdlineArgs.BuildFromSourceStub, "build-from-source-stub", false, "build Java stubs from source files instead of API text files")
flag.BoolVar(&cmdlineArgs.EnsureAllowlistIntegrity, "ensure-allowlist-integrity", false, "verify that allowlisted modules are mixed-built")
flag.StringVar(&cmdlineArgs.ModuleDebugFile, "soong_module_debug", "", "soong module debug info file to write")
diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go
index 5c2316a..eafd67a 100644
--- a/cmd/soong_build/queryview.go
+++ b/cmd/soong_build/queryview.go
@@ -22,7 +22,6 @@
"android/soong/android"
"android/soong/bp2build"
- "android/soong/starlark_import"
)
// A helper function to generate a Read-only Bazel workspace in outDir
@@ -47,14 +46,6 @@
}
}
- // Add starlark deps here, so that they apply to both queryview and apibp2build which
- // both run this function.
- starlarkDeps, err2 := starlark_import.GetNinjaDeps()
- if err2 != nil {
- return err2
- }
- ctx.AddNinjaFileDeps(starlarkDeps...)
-
return nil
}
diff --git a/filesystem/Android.bp b/filesystem/Android.bp
index 07d57c9..cdf6682 100644
--- a/filesystem/Android.bp
+++ b/filesystem/Android.bp
@@ -9,6 +9,7 @@
"blueprint",
"soong",
"soong-android",
+ "soong-bpf", // for testing
"soong-linkerconfig",
],
srcs: [
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 6612a6f..795a0aa 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -311,18 +311,16 @@
}
func (f *filesystem) buildPropFile(ctx android.ModuleContext) (propFile android.OutputPath, toolDeps android.Paths) {
- type prop struct {
- name string
- value string
- }
-
- var props []prop
var deps android.Paths
+ var propFileString strings.Builder
addStr := func(name string, value string) {
- props = append(props, prop{name, value})
+ propFileString.WriteString(name)
+ propFileString.WriteRune('=')
+ propFileString.WriteString(value)
+ propFileString.WriteRune('\n')
}
addPath := func(name string, path android.Path) {
- props = append(props, prop{name, path.String()})
+ addStr(name, path.String())
deps = append(deps, path)
}
@@ -376,15 +374,7 @@
addStr("hash_seed", uuid)
}
propFile = android.PathForModuleOut(ctx, "prop").OutputPath
- builder := android.NewRuleBuilder(pctx, ctx)
- builder.Command().Text("rm").Flag("-rf").Output(propFile)
- for _, p := range props {
- builder.Command().
- Text("echo").
- Flag(`"` + p.name + "=" + p.value + `"`).
- Text(">>").Output(propFile)
- }
- builder.Build("build_filesystem_prop", fmt.Sprintf("Creating filesystem props for %s", f.BaseModuleName()))
+ android.WriteFileRuleVerbatim(ctx, propFile, propFileString.String())
return propFile, deps
}
diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go
index aef4756..c448105 100644
--- a/filesystem/filesystem_test.go
+++ b/filesystem/filesystem_test.go
@@ -19,6 +19,7 @@
"testing"
"android/soong/android"
+ "android/soong/bpf"
"android/soong/cc"
"android/soong/etc"
@@ -31,6 +32,7 @@
var fixture = android.GroupFixturePreparers(
android.PrepareForIntegrationTestWithAndroid,
+ bpf.PrepareForTestWithBpf,
etc.PrepareForTestWithPrebuiltEtc,
cc.PrepareForIntegrationTestWithCc,
PrepareForTestWithFilesystemBuildComponents,
@@ -40,11 +42,55 @@
result := fixture.RunTestWithBp(t, `
android_filesystem {
name: "myfilesystem",
+ multilib: {
+ common: {
+ deps: [
+ "bpf.o",
+ ],
+ },
+ lib32: {
+ deps: [
+ "foo",
+ "libbar",
+ ],
+ },
+ lib64: {
+ deps: [
+ "libbar",
+ ],
+ },
+ },
+ compile_multilib: "both",
+ }
+
+ bpf {
+ name: "bpf.o",
+ srcs: ["bpf.c"],
+ }
+
+ cc_binary {
+ name: "foo",
+ compile_multilib: "prefer32",
+ }
+
+ cc_library {
+ name: "libbar",
}
`)
// produces "myfilesystem.img"
result.ModuleForTests("myfilesystem", "android_common").Output("myfilesystem.img")
+
+ fs := result.ModuleForTests("myfilesystem", "android_common").Module().(*filesystem)
+ expected := []string{
+ "bin/foo",
+ "lib/libbar.so",
+ "lib64/libbar.so",
+ "etc/bpf/bpf.o",
+ }
+ for _, e := range expected {
+ android.AssertStringListContains(t, "missing entry", fs.entries, e)
+ }
}
func TestFileSystemFillsLinkerConfigWithStubLibs(t *testing.T) {
diff --git a/java/aapt2.go b/java/aapt2.go
index 445e912..f704fc6 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -309,7 +309,8 @@
var aapt2ConvertRule = pctx.AndroidStaticRule("aapt2Convert",
blueprint.RuleParams{
- Command: `${config.Aapt2Cmd} convert --output-format $format $in -o $out`,
+ Command: `${config.Aapt2Cmd} convert --enable-compact-entries ` +
+ `--output-format $format $in -o $out`,
CommandDeps: []string{"${config.Aapt2Cmd}"},
}, "format",
)
diff --git a/java/aar.go b/java/aar.go
index 146b173..27dd38b 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -204,6 +204,8 @@
// Flags specified in Android.bp
linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...)
+ linkFlags = append(linkFlags, "--enable-compact-entries")
+
// Find implicit or explicit asset and resource dirs
assets := android.PathsRelativeToModuleSourceDir(android.SourceInput{
Context: ctx,
@@ -453,6 +455,11 @@
// as imports. The resources from dependencies will not be merged into this module's package-res.apk, and
// instead modules depending on this module will reference package-res.apk from all transitive static
// dependencies.
+ for _, sharedDep := range sharedDeps {
+ if sharedDep.usedResourceProcessor {
+ transitiveRJars = append(transitiveRJars, sharedDep.rJar)
+ }
+ }
for _, staticDep := range staticDeps {
linkDeps = append(linkDeps, staticDep.resPackage)
linkFlags = append(linkFlags, "-I "+staticDep.resPackage.String())
@@ -460,11 +467,6 @@
transitiveRJars = append(transitiveRJars, staticDep.rJar)
}
}
- for _, sharedDep := range sharedDeps {
- if sharedDep.usedResourceProcessor {
- transitiveRJars = append(transitiveRJars, sharedDep.rJar)
- }
- }
} else {
// When building an app or building a library without ResourceProcessorBusyBox enabled all static
// dependencies are compiled into this module's package-res.apk as overlays.
@@ -554,6 +556,10 @@
transitiveAaptResourcePackagesFile := android.PathForModuleOut(ctx, "transitive-res-packages")
android.WriteFileRule(ctx, transitiveAaptResourcePackagesFile, strings.Join(transitiveAaptResourcePackages, "\n"))
+ // Reverse the list of R.jar files so that the current module comes first, and direct dependencies come before
+ // transitive dependencies.
+ transitiveRJars = android.ReversePaths(transitiveRJars)
+
a.aaptSrcJar = srcJar
a.transitiveAaptRJars = transitiveRJars
a.transitiveAaptResourcePackagesFile = transitiveAaptResourcePackagesFile
@@ -803,6 +809,9 @@
func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
a.aapt.isLibrary = true
a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
+ if a.usesLibrary.shouldDisableDexpreopt {
+ a.dexpreopter.disableDexpreopt()
+ }
a.aapt.buildActions(ctx,
aaptBuildActionOptions{
sdkContext: android.SdkContext(a),
@@ -1131,7 +1140,7 @@
extractedAARDir := android.PathForModuleOut(ctx, "aar")
a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar")
a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml")
- aarRTxt := extractedAARDir.Join(ctx, "R.txt")
+ a.rTxt = extractedAARDir.Join(ctx, "R.txt")
a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip")
a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
android.SetProvider(ctx, ProguardSpecInfoProvider, ProguardSpecInfo{
@@ -1145,7 +1154,7 @@
ctx.Build(pctx, android.BuildParams{
Rule: unzipAAR,
Input: a.aarPath,
- Outputs: android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest, a.assetsPackage, aarRTxt},
+ Outputs: android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest, a.assetsPackage, a.rTxt},
Description: "unzip AAR",
Args: map[string]string{
"outDir": extractedAARDir.String(),
@@ -1163,7 +1172,7 @@
a.exportPackage = android.PathForModuleOut(ctx, "package-res.apk")
proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
- a.rTxt = android.PathForModuleOut(ctx, "R.txt")
+ aaptRTxt := android.PathForModuleOut(ctx, "R.txt")
a.extraAaptPackagesFile = android.PathForModuleOut(ctx, "extra_packages")
var linkDeps android.Paths
@@ -1200,7 +1209,7 @@
}
transitiveAssets := android.ReverseSliceInPlace(staticDeps.assets())
- aapt2Link(ctx, a.exportPackage, nil, proguardOptionsFile, a.rTxt,
+ aapt2Link(ctx, a.exportPackage, nil, proguardOptionsFile, aaptRTxt,
linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil, nil)
a.rJar = android.PathForModuleOut(ctx, "busybox/R.jar")
diff --git a/java/androidmk.go b/java/androidmk.go
index b7df9bf..498962f 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -691,9 +691,10 @@
return nil
}
return []android.AndroidMkEntries{android.AndroidMkEntries{
- Class: "APPS",
- OutputFile: android.OptionalPathForPath(a.outputFile),
- Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
+ Class: "APPS",
+ OutputFile: android.OptionalPathForPath(a.outputFile),
+ OverrideName: a.BaseModuleName(), // TODO (spandandas): Add a test
+ Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", a.Privileged())
diff --git a/java/app.go b/java/app.go
index 9a1f2d1..8209d4c 100755
--- a/java/app.go
+++ b/java/app.go
@@ -778,6 +778,9 @@
a.onDeviceDir = android.InstallPathToOnDevicePath(ctx, a.installDir)
a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
+ if a.usesLibrary.shouldDisableDexpreopt {
+ a.dexpreopter.disableDexpreopt()
+ }
var noticeAssetPath android.WritablePath
if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
@@ -1313,6 +1316,12 @@
a.extraTestConfigs = android.PathsForModuleSrc(ctx, a.testProperties.Test_options.Extra_test_configs)
a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+ android.SetProvider(ctx, tradefed.BaseTestProviderKey, tradefed.BaseTestProviderData{
+ InstalledFiles: a.data,
+ OutputFile: a.OutputFile(),
+ TestConfig: a.testConfig,
+ HostRequiredModuleNames: a.HostRequiredModuleNames(),
+ })
}
func (a *AndroidTest) FixTestConfig(ctx android.ModuleContext, testConfig android.Path) android.Path {
@@ -1566,6 +1575,9 @@
// Whether to enforce verify_uses_library check.
enforce bool
+
+ // Whether dexpreopt should be disabled
+ shouldDisableDexpreopt bool
}
func (u *usesLibrary) addLib(lib string, optional bool) {
@@ -1647,6 +1659,15 @@
}
}
+ // Skip java_sdk_library dependencies that provide stubs, but not an implementation.
+ // This will be restricted to optional_uses_libs
+ if sdklib, ok := m.(SdkLibraryDependency); ok {
+ if tag == usesLibOptTag && sdklib.DexJarBuildPath(ctx).PathOrNil() == nil {
+ u.shouldDisableDexpreopt = true
+ return
+ }
+ }
+
if lib, ok := m.(UsesLibraryDependency); ok {
libName := dep
if ulib, ok := m.(ProvidesUsesLib); ok && ulib.ProvidesUsesLib() != nil {
diff --git a/java/app_import.go b/java/app_import.go
index 12ead0a..dc84fc2 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -70,9 +70,10 @@
android.ApexModuleBase
prebuilt android.Prebuilt
- properties AndroidAppImportProperties
- dpiVariants interface{}
- archVariants interface{}
+ properties AndroidAppImportProperties
+ dpiVariants interface{}
+ archVariants interface{}
+ arch_dpiVariants interface{}
outputFile android.Path
certificate Certificate
@@ -144,6 +145,11 @@
// Whether or not to skip checking the preprocessed apk for proper alignment and uncompressed
// JNI libs and dex files. Default is false
Skip_preprocessed_apk_checks *bool
+
+ // Name of the source soong module that gets shadowed by this prebuilt
+ // If unspecified, follows the naming convention that the source module of
+ // the prebuilt is Name() without "prebuilt_" prefix
+ Source_module_name *string
}
func (a *AndroidAppImport) IsInstallable() bool {
@@ -155,8 +161,8 @@
// soong config variables are applied.
func (a *AndroidAppImport) processVariants(ctx android.DefaultableHookContext) {
config := ctx.Config()
+ dpiProps := reflect.ValueOf(a.dpiVariants).Elem().FieldByName(DpiGroupName)
- dpiProps := reflect.ValueOf(a.dpiVariants).Elem().FieldByName("Dpi_variants")
// Try DPI variant matches in the reverse-priority order so that the highest priority match
// overwrites everything else.
// TODO(jungjw): Can we optimize this by making it priority order?
@@ -166,11 +172,27 @@
if config.ProductAAPTPreferredConfig() != "" {
MergePropertiesFromVariant(ctx, &a.properties, dpiProps, config.ProductAAPTPreferredConfig())
}
-
- archProps := reflect.ValueOf(a.archVariants).Elem().FieldByName("Arch")
+ archProps := reflect.ValueOf(a.archVariants).Elem().FieldByName(ArchGroupName)
archType := ctx.Config().AndroidFirstDeviceTarget.Arch.ArchType
MergePropertiesFromVariant(ctx, &a.properties, archProps, archType.Name)
+ // Process "arch" includes "dpi_variants"
+ archStructPtr := reflect.ValueOf(a.arch_dpiVariants).Elem().FieldByName(ArchGroupName)
+ if archStruct := archStructPtr.Elem(); archStruct.IsValid() {
+ archPartPropsPtr := archStruct.FieldByName(proptools.FieldNameForProperty(archType.Name))
+ if archPartProps := archPartPropsPtr.Elem(); archPartProps.IsValid() {
+ archDpiPropsPtr := archPartProps.FieldByName(DpiGroupName)
+ if archDpiProps := archDpiPropsPtr.Elem(); archDpiProps.IsValid() {
+ for i := len(config.ProductAAPTPrebuiltDPI()) - 1; i >= 0; i-- {
+ MergePropertiesFromVariant(ctx, &a.properties, archDpiProps, config.ProductAAPTPrebuiltDPI()[i])
+ }
+ if config.ProductAAPTPreferredConfig() != "" {
+ MergePropertiesFromVariant(ctx, &a.properties, archDpiProps, config.ProductAAPTPreferredConfig())
+ }
+ }
+ }
+ }
+
if String(a.properties.Apk) == "" {
// Disable this module since the apk property is still empty after processing all matching
// variants. This likely means there is no matching variant, and the default variant doesn't
@@ -257,6 +279,10 @@
return a.BaseModuleName()
}
+func (a *AndroidAppImport) BaseModuleName() string {
+ return proptools.StringDefault(a.properties.Source_module_name, a.ModuleBase.Name())
+}
+
func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext) {
if a.Name() == "prebuilt_framework-res" {
ctx.ModuleErrorf("prebuilt_framework-res found. This used to have special handling in soong, but was removed due to prebuilt_framework-res no longer existing. This check is to ensure it doesn't come back without readding the special handling.")
@@ -319,6 +345,9 @@
a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
+ if a.usesLibrary.shouldDisableDexpreopt {
+ a.dexpreopter.disableDexpreopt()
+ }
if a.usesLibrary.enforceUsesLibraries() {
a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
@@ -448,18 +477,25 @@
return android.OptionalPath{}
}
+const (
+ ArchGroupName = "Arch"
+ DpiGroupName = "Dpi_variants"
+)
+
var dpiVariantGroupType reflect.Type
var archVariantGroupType reflect.Type
+var archdpiVariantGroupType reflect.Type
var supportedDpis = []string{"ldpi", "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"}
func initAndroidAppImportVariantGroupTypes() {
- dpiVariantGroupType = createVariantGroupType(supportedDpis, "Dpi_variants")
+ dpiVariantGroupType = createVariantGroupType(supportedDpis, DpiGroupName)
archNames := make([]string, len(android.ArchTypeList()))
for i, archType := range android.ArchTypeList() {
archNames[i] = archType.Name
}
- archVariantGroupType = createVariantGroupType(archNames, "Arch")
+ archVariantGroupType = createVariantGroupType(archNames, ArchGroupName)
+ archdpiVariantGroupType = createArchDpiVariantGroupType(archNames, supportedDpis)
}
// Populates all variant struct properties at creation time.
@@ -469,6 +505,9 @@
a.archVariants = reflect.New(archVariantGroupType).Interface()
a.AddProperties(a.archVariants)
+
+ a.arch_dpiVariants = reflect.New(archdpiVariantGroupType).Interface()
+ a.AddProperties(a.arch_dpiVariants)
}
func (a *AndroidAppImport) Privileged() bool {
@@ -523,6 +562,42 @@
})
}
+func createArchDpiVariantGroupType(archNames []string, dpiNames []string) reflect.Type {
+ props := reflect.TypeOf((*AndroidAppImportProperties)(nil))
+
+ dpiVariantFields := make([]reflect.StructField, len(dpiNames))
+ for i, variant_dpi := range dpiNames {
+ dpiVariantFields[i] = reflect.StructField{
+ Name: proptools.FieldNameForProperty(variant_dpi),
+ Type: props,
+ }
+ }
+ dpiVariantGroupStruct := reflect.StructOf(dpiVariantFields)
+ dpi_struct := reflect.StructOf([]reflect.StructField{
+ {
+ Name: DpiGroupName,
+ Type: reflect.PointerTo(dpiVariantGroupStruct),
+ },
+ })
+
+ archVariantFields := make([]reflect.StructField, len(archNames))
+ for i, variant_arch := range archNames {
+ archVariantFields[i] = reflect.StructField{
+ Name: proptools.FieldNameForProperty(variant_arch),
+ Type: reflect.PointerTo(dpi_struct),
+ }
+ }
+ archVariantGroupStruct := reflect.StructOf(archVariantFields)
+
+ return_struct := reflect.StructOf([]reflect.StructField{
+ {
+ Name: ArchGroupName,
+ Type: reflect.PointerTo(archVariantGroupStruct),
+ },
+ })
+ return return_struct
+}
+
// android_app_import imports a prebuilt apk with additional processing specified in the module.
// DPI-specific apk source files can be specified using dpi_variants. Example:
//
diff --git a/java/app_import_test.go b/java/app_import_test.go
index 44f8f16..5de50e7 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -472,6 +472,35 @@
artifactPath: "prebuilts/apk/app_arm.apk",
installPath: "/system/app/foo/foo.apk",
},
+ {
+ name: "matching arch and dpi_variants",
+ bp: `
+ android_app_import {
+ name: "foo",
+ apk: "prebuilts/apk/app.apk",
+ arch: {
+ arm64: {
+ apk: "prebuilts/apk/app_arm64.apk",
+ dpi_variants: {
+ mdpi: {
+ apk: "prebuilts/apk/app_arm64_mdpi.apk",
+ },
+ xhdpi: {
+ apk: "prebuilts/apk/app_arm64_xhdpi.apk",
+ },
+ },
+ },
+ },
+ presigned: true,
+ dex_preopt: {
+ enabled: true,
+ },
+ }
+ `,
+ expected: "verify_uses_libraries/apk/app_arm64_xhdpi.apk",
+ artifactPath: "prebuilts/apk/app_arm64_xhdpi.apk",
+ installPath: "/system/app/foo/foo.apk",
+ },
}
for _, test := range testCases {
diff --git a/java/app_test.go b/java/app_test.go
index 362bef9..5d7b048 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -931,8 +931,8 @@
"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
},
appCombined: []string{
- "out/soong/.intermediates/app/android_common/busybox/R.jar",
"out/soong/.intermediates/app/android_common/javac/app.jar",
+ "out/soong/.intermediates/app/android_common/busybox/R.jar",
"out/soong/.intermediates/direct/android_common/combined/direct.jar",
"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
},
@@ -948,10 +948,10 @@
directSrcJars: nil,
directClasspath: []string{
"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
- "out/soong/.intermediates/transitive_import/android_common/busybox/R.jar",
- "out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar",
- "out/soong/.intermediates/transitive/android_common/busybox/R.jar",
"out/soong/.intermediates/direct/android_common/busybox/R.jar",
+ "out/soong/.intermediates/transitive/android_common/busybox/R.jar",
+ "out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar",
+ "out/soong/.intermediates/transitive_import/android_common/busybox/R.jar",
"out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
},
@@ -981,9 +981,9 @@
sharedSrcJars: nil,
sharedClasspath: []string{
"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+ "out/soong/.intermediates/shared/android_common/busybox/R.jar",
"out/soong/.intermediates/shared_transitive_static/android_common/busybox/R.jar",
"out/soong/.intermediates/shared_transitive_shared/android_common/busybox/R.jar",
- "out/soong/.intermediates/shared/android_common/busybox/R.jar",
"out/soong/.intermediates/shared_transitive_shared/android_common/turbine-combined/shared_transitive_shared.jar",
"out/soong/.intermediates/shared_transitive_static/android_common/turbine-combined/shared_transitive_static.jar",
},
@@ -1037,8 +1037,8 @@
"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
},
appCombined: []string{
- "out/soong/.intermediates/app/android_common/busybox/R.jar",
"out/soong/.intermediates/app/android_common/javac/app.jar",
+ "out/soong/.intermediates/app/android_common/busybox/R.jar",
"out/soong/.intermediates/direct/android_common/combined/direct.jar",
"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
},
@@ -1094,9 +1094,9 @@
directSrcJars: nil,
directClasspath: []string{
"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
- "out/soong/.intermediates/transitive_import/android_common/busybox/R.jar",
- "out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar",
"out/soong/.intermediates/direct/android_common/busybox/R.jar",
+ "out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar",
+ "out/soong/.intermediates/transitive_import/android_common/busybox/R.jar",
"out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
},
@@ -4378,3 +4378,26 @@
"--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt",
)
}
+
+// Test that dexpreopt is disabled if an optional_uses_libs exists, but does not provide an implementation.
+func TestNoDexpreoptOptionalUsesLibDoesNotHaveImpl(t *testing.T) {
+ bp := `
+ java_sdk_library_import {
+ name: "sdklib_noimpl",
+ public: {
+ jars: ["stub.jar"],
+ },
+ }
+ android_app {
+ name: "app",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ optional_uses_libs: [
+ "sdklib_noimpl",
+ ],
+ }
+ `
+ result := prepareForJavaTest.RunTestWithBp(t, bp)
+ dexpreopt := result.ModuleForTests("app", "android_common").MaybeRule("dexpreopt").Rule
+ android.AssertBoolEquals(t, "dexpreopt should be disabled if optional_uses_libs does not have an implementation", true, dexpreopt == nil)
+}
diff --git a/java/base.go b/java/base.go
index 7f4ea08..d8ccec6 100644
--- a/java/base.go
+++ b/java/base.go
@@ -95,6 +95,9 @@
// if not blank, used as prefix to generate repackage rule
Jarjar_prefix *string
+ // if set to true, skip the jarjar repackaging
+ Skip_jarjar_repackage *bool
+
// If not blank, set the java version passed to javac as -source and -target
Java_version *string
@@ -1101,11 +1104,13 @@
jarjarProviderData := j.collectJarJarRules(ctx)
if jarjarProviderData != nil {
android.SetProvider(ctx, JarJarProvider, *jarjarProviderData)
- text := getJarJarRuleText(jarjarProviderData)
- if text != "" {
- ruleTextFile := android.PathForModuleOut(ctx, "repackaged-jarjar", "repackaging.txt")
- android.WriteFileRule(ctx, ruleTextFile, text)
- j.repackageJarjarRules = ruleTextFile
+ if !proptools.Bool(j.properties.Skip_jarjar_repackage) {
+ text := getJarJarRuleText(jarjarProviderData)
+ if text != "" {
+ ruleTextFile := android.PathForModuleOut(ctx, "repackaged-jarjar", "repackaging.txt")
+ android.WriteFileRule(ctx, ruleTextFile, text)
+ j.repackageJarjarRules = ruleTextFile
+ }
}
}
@@ -1307,7 +1312,7 @@
}
}
- jars := append(android.Paths(nil), kotlinJars...)
+ jars := slices.Clone(kotlinJars)
j.compiledSrcJars = srcJars
@@ -1322,7 +1327,7 @@
// allow for the use of annotation processors that do function correctly
// with sharding enabled. See: b/77284273.
}
- extraJars := append(android.CopyOf(extraCombinedJars), kotlinHeaderJars...)
+ extraJars := append(slices.Clone(kotlinHeaderJars), extraCombinedJars...)
headerJarFileWithoutDepsOrJarjar, j.headerJarFile, j.repackagedHeaderJarFile =
j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars)
if ctx.Failed() {
@@ -1396,6 +1401,8 @@
}
}
+ jars = append(jars, extraCombinedJars...)
+
j.srcJarArgs, j.srcJarDeps = resourcePathsToJarArgs(srcFiles), srcFiles
var includeSrcJar android.WritablePath
@@ -1482,8 +1489,6 @@
jars = append(jars, servicesJar)
}
- jars = append(android.CopyOf(extraCombinedJars), jars...)
-
// Combine the classes built from sources, any manifests, and any static libraries into
// classes.jar. If there is only one input jar this step will be skipped.
var outputFile android.OutputPath
@@ -2408,7 +2413,8 @@
func (this JarJarProviderData) GetDebugString() string {
result := ""
- for k, v := range this.Rename {
+ for _, k := range android.SortedKeys(this.Rename) {
+ v := this.Rename[k]
if strings.Contains(k, "android.companion.virtual.flags.FakeFeatureFlagsImpl") {
result += k + "-->" + v + ";"
}
@@ -2664,7 +2670,8 @@
// to "" won't be in this list because they shouldn't be renamed yet.
func getJarJarRuleText(provider *JarJarProviderData) string {
result := ""
- for orig, renamed := range provider.Rename {
+ for _, orig := range android.SortedKeys(provider.Rename) {
+ renamed := provider.Rename[orig]
if renamed != "" {
result += "rule " + orig + " " + renamed + "\n"
}
diff --git a/java/builder.go b/java/builder.go
index 74a05f2..b07a622 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -212,6 +212,14 @@
CommandDeps: []string{"${config.MergeZipsCmd}"},
},
"jarArgs")
+ combineJarRsp = pctx.AndroidStaticRule("combineJarRsp",
+ blueprint.RuleParams{
+ Command: `${config.MergeZipsCmd} --ignore-duplicates -j $jarArgs $out @$out.rsp`,
+ CommandDeps: []string{"${config.MergeZipsCmd}"},
+ Rspfile: "$out.rsp",
+ RspfileContent: "$in",
+ },
+ "jarArgs")
jarjar = pctx.AndroidStaticRule("jarjar",
blueprint.RuleParams{
@@ -418,7 +426,7 @@
})
}
-func turbineFlags(ctx android.ModuleContext, flags javaBuilderFlags) (string, android.Paths) {
+func turbineFlags(ctx android.ModuleContext, flags javaBuilderFlags, dir string) (string, android.Paths) {
var deps android.Paths
classpath := flags.classpath
@@ -443,13 +451,21 @@
deps = append(deps, classpath...)
turbineFlags := bootClasspath + " " + classpath.FormTurbineClassPath("--classpath ")
+ const flagsLimit = 32 * 1024
+ if len(turbineFlags) > flagsLimit {
+ flagsRspFile := android.PathForModuleOut(ctx, dir, "turbine-flags.rsp")
+ android.WriteFileRule(ctx, flagsRspFile, turbineFlags)
+ turbineFlags = "@" + flagsRspFile.String()
+ deps = append(deps, flagsRspFile)
+ }
+
return turbineFlags, deps
}
func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android.WritablePath,
srcFiles, srcJars android.Paths, flags javaBuilderFlags) {
- turbineFlags, deps := turbineFlags(ctx, flags)
+ turbineFlags, deps := turbineFlags(ctx, flags, "turbine")
deps = append(deps, srcJars...)
@@ -481,7 +497,7 @@
func TurbineApt(ctx android.ModuleContext, outputSrcJar, outputResJar android.WritablePath,
srcFiles, srcJars android.Paths, flags javaBuilderFlags) {
- turbineFlags, deps := turbineFlags(ctx, flags)
+ turbineFlags, deps := turbineFlags(ctx, flags, "kapt")
deps = append(deps, srcJars...)
@@ -534,14 +550,14 @@
deps = append(deps, srcJars...)
- classpath := flags.classpath
+ javacClasspath := flags.classpath
var bootClasspath string
if flags.javaVersion.usesJavaModules() {
var systemModuleDeps android.Paths
bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(ctx.Device())
deps = append(deps, systemModuleDeps...)
- classpath = append(flags.java9Classpath, classpath...)
+ javacClasspath = append(flags.java9Classpath, javacClasspath...)
} else {
deps = append(deps, flags.bootClasspath...)
if len(flags.bootClasspath) == 0 && ctx.Device() {
@@ -553,7 +569,19 @@
}
}
- deps = append(deps, classpath...)
+ classpathArg := javacClasspath.FormJavaClassPath("-classpath")
+
+ // Keep the command line under the MAX_ARG_STRLEN limit by putting the classpath argument into an rsp file
+ // if it is too long.
+ const classpathLimit = 64 * 1024
+ if len(classpathArg) > classpathLimit {
+ classpathRspFile := outputFile.ReplaceExtension(ctx, "classpath")
+ android.WriteFileRule(ctx, classpathRspFile, classpathArg)
+ deps = append(deps, classpathRspFile)
+ classpathArg = "@" + classpathRspFile.String()
+ }
+
+ deps = append(deps, javacClasspath...)
deps = append(deps, flags.processorPath...)
processor := "-proc:none"
@@ -584,7 +612,7 @@
Args: map[string]string{
"javacFlags": flags.javacFlags,
"bootClasspath": bootClasspath,
- "classpath": classpath.FormJavaClassPath("-classpath"),
+ "classpath": classpathArg,
"processorpath": flags.processorPath.FormJavaClassPath("-processorpath"),
"processor": processor,
"srcJars": strings.Join(srcJars.Strings(), " "),
@@ -643,8 +671,23 @@
jarArgs = append(jarArgs, "-D")
}
+ rule := combineJar
+ // Keep the command line under the MAX_ARG_STRLEN limit by putting the list of jars into an rsp file
+ // if it is too long.
+ const jarsLengthLimit = 64 * 1024
+ jarsLength := 0
+ for i, jar := range jars {
+ if i != 0 {
+ jarsLength += 1
+ }
+ jarsLength += len(jar.String())
+ }
+ if jarsLength > jarsLengthLimit {
+ rule = combineJarRsp
+ }
+
ctx.Build(pctx, android.BuildParams{
- Rule: combineJar,
+ Rule: rule,
Description: desc,
Output: outputFile,
Inputs: jars,
diff --git a/java/config/config.go b/java/config/config.go
index 6a945ac..d720046 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -131,12 +131,7 @@
if override := ctx.Config().Getenv("OVERRIDE_JLINK_VERSION_NUMBER"); override != "" {
return override
}
- switch ctx.Config().Getenv("EXPERIMENTAL_USE_OPENJDK21_TOOLCHAIN") {
- case "true":
- return "21"
- default:
- return "17"
- }
+ return "21"
})
pctx.SourcePathVariable("JavaToolchain", "${JavaHome}/bin")
diff --git a/java/config/droidstubs.go b/java/config/droidstubs.go
index f46c893..39eec44 100644
--- a/java/config/droidstubs.go
+++ b/java/config/droidstubs.go
@@ -23,7 +23,6 @@
"--format=v2",
"--repeat-errors-max 10",
"--hide UnresolvedImport",
- "--hide InvalidNullabilityOverride",
// Force metalava to ignore classes on the classpath when an API file contains missing classes.
// See b/285140653 for more information.
@@ -49,9 +48,6 @@
// TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
"--hide HiddenTypedefConstant",
"--hide SuperfluousPrefix",
- "--hide AnnotationExtraction",
- // b/222738070
- "--hide BannedThrow",
}
MetalavaAnnotationsWarningsFlags = strings.Join(metalavaAnnotationsWarningsFlags, " ")
diff --git a/java/core-libraries/Android.bp b/java/core-libraries/Android.bp
index 8ffe511..ab72e8b 100644
--- a/java/core-libraries/Android.bp
+++ b/java/core-libraries/Android.bp
@@ -64,6 +64,7 @@
"stub-annotations",
],
enable_validation: false,
+ stubs_type: "everything",
}
java_library {
@@ -248,6 +249,7 @@
"stub-annotations",
],
visibility: ["//visibility:private"],
+ stubs_type: "everything",
}
// Produces a dist file that is used by the
@@ -358,6 +360,7 @@
libs: [
"stub-annotations",
],
+ stubs_type: "everything",
}
java_library {
@@ -446,6 +449,7 @@
libs: [
"stub-annotations",
],
+ stubs_type: "everything",
}
java_library {
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 9db9b1b..38ed856 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -102,6 +102,11 @@
dexpreoptProperties DexpreoptProperties
importDexpreoptProperties ImportDexpreoptProperties
+ // If true, the dexpreopt rules will not be generated
+ // Unlike Dex_preopt.Enabled which is user-facing,
+ // shouldDisableDexpreopt is a mutated propery.
+ shouldDisableDexpreopt bool
+
installPath android.InstallPath
uncompressedDex bool
isSDKLibrary bool
@@ -182,6 +187,33 @@
return apexInfo.ForPrebuiltApex
}
+// For apex variant of modules, this returns true on the source variant if the prebuilt apex
+// has been selected using apex_contributions.
+// The prebuilt apex will be responsible for generating the dexpreopt rules of the deapexed java lib.
+func disableSourceApexVariant(ctx android.BaseModuleContext) bool {
+ if !isApexVariant(ctx) {
+ return false // platform variant
+ }
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+ psi := android.PrebuiltSelectionInfoMap{}
+ ctx.VisitDirectDepsWithTag(android.PrebuiltDepTag, func(am android.Module) {
+ psi, _ = android.OtherModuleProvider(ctx, am, android.PrebuiltSelectionInfoProvider)
+ })
+ // Find the apex variant for this module
+ _, apexVariantsWithoutTestApexes, _ := android.ListSetDifference(apexInfo.InApexVariants, apexInfo.TestApexes)
+ disableSource := false
+ // find the selected apexes
+ for _, apexVariant := range apexVariantsWithoutTestApexes {
+ for _, selected := range psi.GetSelectedModulesForApiDomain(apexVariant) {
+ // If the apex_contribution for this api domain contains a prebuilt apex, disable the source variant
+ if strings.HasPrefix(selected, "prebuilt_com.google.android") {
+ disableSource = true
+ }
+ }
+ }
+ return disableSource
+}
+
// Returns whether dexpreopt is applicable to the module.
// When it returns true, neither profile nor dexpreopt artifacts will be generated.
func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext, libName string) bool {
@@ -197,6 +229,10 @@
return true
}
+ if d.shouldDisableDexpreopt {
+ return true
+ }
+
// If the module is from a prebuilt APEX, it shouldn't be installable, but it can still be
// dexpreopted.
if !ctx.Module().(DexpreopterInterface).IsInstallable() && !forPrebuiltApex(ctx) {
@@ -207,6 +243,10 @@
return true
}
+ if disableSourceApexVariant(ctx) {
+ return true
+ }
+
if _, isApex := android.ModuleProvider(ctx, android.ApexBundleInfoProvider); isApex {
// dexpreopt rules for system server jars can be generated in the ModuleCtx of prebuilt apexes
return false
@@ -528,3 +568,7 @@
func (d *dexpreopter) OutputProfilePathOnHost() android.Path {
return d.outputProfilePathOnHost
}
+
+func (d *dexpreopter) disableDexpreopt() {
+ d.shouldDisableDexpreopt = true
+}
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 51503f2..76c8d88 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -52,6 +52,19 @@
}
}
+func StringToStubsType(s string) StubsType {
+ switch strings.ToLower(s) {
+ case Everything.String():
+ return Everything
+ case Runtime.String():
+ return Runtime
+ case Exportable.String():
+ return Exportable
+ default:
+ return Unavailable
+ }
+}
+
func init() {
RegisterStubsBuildComponents(android.InitRegistrationContext)
}
@@ -723,7 +736,7 @@
// defined for a module, simply revert all flagged apis annotations. If aconfig_declarations
// property is defined, apply transformations and only revert the flagged apis that are not
// enabled via release configurations and are not specified in aconfig_declarations
-func (d *Droidstubs) generateRevertAnnotationArgs(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, aconfigFlagsPaths android.Paths) {
+func generateRevertAnnotationArgs(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, aconfigFlagsPaths android.Paths) {
if len(aconfigFlagsPaths) == 0 {
cmd.Flag("--revert-annotation android.annotation.FlaggedApi")
@@ -1063,7 +1076,7 @@
cmd := d.commonMetalavaStubCmd(ctx, rule, params)
- d.generateRevertAnnotationArgs(ctx, cmd, params.stubConfig.stubsType, params.stubConfig.deps.aconfigProtoFiles)
+ generateRevertAnnotationArgs(ctx, cmd, params.stubConfig.stubsType, params.stubConfig.deps.aconfigProtoFiles)
if params.stubConfig.doApiLint {
// Pass the lint baseline file as an input to resolve the lint errors.
diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go
index caa8345..8da695f 100644
--- a/java/droidstubs_test.go
+++ b/java/droidstubs_test.go
@@ -22,6 +22,8 @@
"testing"
"android/soong/android"
+
+ "github.com/google/blueprint/proptools"
)
func TestDroidstubs(t *testing.T) {
@@ -335,6 +337,7 @@
name: "bar",
api_surface: "public",
api_contributions: ["foo.api.contribution"],
+ stubs_type: "everything",
}
`
ctx, _ := testJavaWithFS(t, `
@@ -419,8 +422,8 @@
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.BuildFlags = map[string]string{
"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
- "RELEASE_EXPORT_RUNTIME_APIS": "true",
}
+ variables.ExportRuntimeApis = proptools.BoolPtr(true)
}),
android.FixtureMergeMockFs(map[string][]byte{
"a/A.java": nil,
diff --git a/java/java.go b/java/java.go
index 1a266b8..794020d 100644
--- a/java/java.go
+++ b/java/java.go
@@ -24,6 +24,7 @@
"sort"
"strings"
+ "android/soong/aconfig"
"android/soong/remoteexec"
"android/soong/testing"
@@ -699,8 +700,178 @@
}
}
-func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+// list of java_library modules that set platform_apis: true
+// this property is a no-op for java_library
+// TODO (b/215379393): Remove this allowlist
+var (
+ aospPlatformApiAllowlist = map[string]bool{
+ "adservices-test-scenarios": true,
+ "aidl-cpp-java-test-interface-java": true,
+ "aidl-test-extras-java": true,
+ "aidl-test-interface-java": true,
+ "aidl-test-interface-permission-java": true,
+ "aidl_test_java_client_permission": true,
+ "aidl_test_java_client_sdk1": true,
+ "aidl_test_java_client_sdk29": true,
+ "aidl_test_java_client": true,
+ "aidl_test_java_service_permission": true,
+ "aidl_test_java_service_sdk1": true,
+ "aidl_test_java_service_sdk29": true,
+ "aidl_test_java_service": true,
+ "aidl_test_loggable_interface-java": true,
+ "aidl_test_nonvintf_parcelable-V1-java": true,
+ "aidl_test_nonvintf_parcelable-V2-java": true,
+ "aidl_test_unstable_parcelable-java": true,
+ "aidl_test_vintf_parcelable-V1-java": true,
+ "aidl_test_vintf_parcelable-V2-java": true,
+ "android.aidl.test.trunk-V1-java": true,
+ "android.aidl.test.trunk-V2-java": true,
+ "android.frameworks.location.altitude-V1-java": true,
+ "android.frameworks.location.altitude-V2-java": true,
+ "android.frameworks.stats-V1-java": true,
+ "android.frameworks.stats-V2-java": true,
+ "android.frameworks.stats-V3-java": true,
+ "android.hardware.authsecret-V1-java": true,
+ "android.hardware.authsecret-V2-java": true,
+ "android.hardware.biometrics.common-V1-java": true,
+ "android.hardware.biometrics.common-V2-java": true,
+ "android.hardware.biometrics.common-V3-java": true,
+ "android.hardware.biometrics.common-V4-java": true,
+ "android.hardware.biometrics.face-V1-java": true,
+ "android.hardware.biometrics.face-V2-java": true,
+ "android.hardware.biometrics.face-V3-java": true,
+ "android.hardware.biometrics.face-V4-java": true,
+ "android.hardware.biometrics.fingerprint-V1-java": true,
+ "android.hardware.biometrics.fingerprint-V2-java": true,
+ "android.hardware.biometrics.fingerprint-V3-java": true,
+ "android.hardware.biometrics.fingerprint-V4-java": true,
+ "android.hardware.bluetooth.lmp_event-V1-java": true,
+ "android.hardware.confirmationui-V1-java": true,
+ "android.hardware.confirmationui-V2-java": true,
+ "android.hardware.gatekeeper-V1-java": true,
+ "android.hardware.gatekeeper-V2-java": true,
+ "android.hardware.gnss-V1-java": true,
+ "android.hardware.gnss-V2-java": true,
+ "android.hardware.gnss-V3-java": true,
+ "android.hardware.gnss-V4-java": true,
+ "android.hardware.graphics.common-V1-java": true,
+ "android.hardware.graphics.common-V2-java": true,
+ "android.hardware.graphics.common-V3-java": true,
+ "android.hardware.graphics.common-V4-java": true,
+ "android.hardware.graphics.common-V5-java": true,
+ "android.hardware.identity-V1-java": true,
+ "android.hardware.identity-V2-java": true,
+ "android.hardware.identity-V3-java": true,
+ "android.hardware.identity-V4-java": true,
+ "android.hardware.identity-V5-java": true,
+ "android.hardware.identity-V6-java": true,
+ "android.hardware.keymaster-V1-java": true,
+ "android.hardware.keymaster-V2-java": true,
+ "android.hardware.keymaster-V3-java": true,
+ "android.hardware.keymaster-V4-java": true,
+ "android.hardware.keymaster-V5-java": true,
+ "android.hardware.oemlock-V1-java": true,
+ "android.hardware.oemlock-V2-java": true,
+ "android.hardware.power.stats-V1-java": true,
+ "android.hardware.power.stats-V2-java": true,
+ "android.hardware.power.stats-V3-java": true,
+ "android.hardware.power-V1-java": true,
+ "android.hardware.power-V2-java": true,
+ "android.hardware.power-V3-java": true,
+ "android.hardware.power-V4-java": true,
+ "android.hardware.power-V5-java": true,
+ "android.hardware.rebootescrow-V1-java": true,
+ "android.hardware.rebootescrow-V2-java": true,
+ "android.hardware.security.authgraph-V1-java": true,
+ "android.hardware.security.keymint-V1-java": true,
+ "android.hardware.security.keymint-V2-java": true,
+ "android.hardware.security.keymint-V3-java": true,
+ "android.hardware.security.keymint-V4-java": true,
+ "android.hardware.security.secureclock-V1-java": true,
+ "android.hardware.security.secureclock-V2-java": true,
+ "android.hardware.thermal-V1-java": true,
+ "android.hardware.thermal-V2-java": true,
+ "android.hardware.threadnetwork-V1-java": true,
+ "android.hardware.weaver-V1-java": true,
+ "android.hardware.weaver-V2-java": true,
+ "android.hardware.weaver-V3-java": true,
+ "android.security.attestationmanager-java": true,
+ "android.security.authorization-java": true,
+ "android.security.compat-java": true,
+ "android.security.legacykeystore-java": true,
+ "android.security.maintenance-java": true,
+ "android.security.metrics-java": true,
+ "android.system.keystore2-V1-java": true,
+ "android.system.keystore2-V2-java": true,
+ "android.system.keystore2-V3-java": true,
+ "android.system.keystore2-V4-java": true,
+ "binderReadParcelIface-java": true,
+ "binderRecordReplayTestIface-java": true,
+ "car-experimental-api-static-lib": true,
+ "collector-device-lib-platform": true,
+ "com.android.car.oem": true,
+ "com.google.hardware.pixel.display-V10-java": true,
+ "com.google.hardware.pixel.display-V1-java": true,
+ "com.google.hardware.pixel.display-V2-java": true,
+ "com.google.hardware.pixel.display-V3-java": true,
+ "com.google.hardware.pixel.display-V4-java": true,
+ "com.google.hardware.pixel.display-V5-java": true,
+ "com.google.hardware.pixel.display-V6-java": true,
+ "com.google.hardware.pixel.display-V7-java": true,
+ "com.google.hardware.pixel.display-V8-java": true,
+ "com.google.hardware.pixel.display-V9-java": true,
+ "conscrypt-support": true,
+ "cts-keystore-test-util": true,
+ "cts-keystore-user-auth-helper-library": true,
+ "ctsmediautil": true,
+ "CtsNetTestsNonUpdatableLib": true,
+ "DpmWrapper": true,
+ "flickerlib-apphelpers": true,
+ "flickerlib-helpers": true,
+ "flickerlib-parsers": true,
+ "flickerlib": true,
+ "hardware.google.bluetooth.ccc-V1-java": true,
+ "hardware.google.bluetooth.sar-V1-java": true,
+ "monet": true,
+ "pixel-power-ext-V1-java": true,
+ "pixel-power-ext-V2-java": true,
+ "pixel_stateresidency_provider_aidl_interface-java": true,
+ "pixel-thermal-ext-V1-java": true,
+ "protolog-lib": true,
+ "RkpRegistrationCheck": true,
+ "rotary-service-javastream-protos": true,
+ "service_based_camera_extensions": true,
+ "statsd-helper-test": true,
+ "statsd-helper": true,
+ "test-piece-2-V1-java": true,
+ "test-piece-2-V2-java": true,
+ "test-piece-3-V1-java": true,
+ "test-piece-3-V2-java": true,
+ "test-piece-3-V3-java": true,
+ "test-piece-4-V1-java": true,
+ "test-piece-4-V2-java": true,
+ "test-root-package-V1-java": true,
+ "test-root-package-V2-java": true,
+ "test-root-package-V3-java": true,
+ "test-root-package-V4-java": true,
+ "testServiceIface-java": true,
+ "wm-flicker-common-app-helpers": true,
+ "wm-flicker-common-assertions": true,
+ "wm-shell-flicker-utils": true,
+ "wycheproof-keystore": true,
+ }
+ // Union of aosp and internal allowlists
+ PlatformApiAllowlist = map[string]bool{}
+)
+
+func init() {
+ for k, v := range aospPlatformApiAllowlist {
+ PlatformApiAllowlist[k] = v
+ }
+}
+
+func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.provideHiddenAPIPropertyInfo(ctx)
j.sdkVersion = j.SdkVersion(ctx)
@@ -743,6 +914,9 @@
setUncompressDex(ctx, &j.dexpreopter, &j.dexer)
j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
j.classLoaderContexts = j.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
+ if j.usesLibrary.shouldDisableDexpreopt {
+ j.dexpreopter.disableDexpreopt()
+ }
}
j.compile(ctx, nil, nil, nil)
@@ -1690,6 +1864,10 @@
dexJarFile OptionalDexJarPath
validationPaths android.Paths
+
+ stubsType StubsType
+
+ aconfigProtoFiles android.Paths
}
type JavaApiLibraryProperties struct {
@@ -1731,6 +1909,20 @@
// in sync with the source Java files. However, the environment variable
// DISABLE_STUB_VALIDATION has precedence over this property.
Enable_validation *bool
+
+ // Type of stubs the module should generate. Must be one of "everything", "runtime" or
+ // "exportable". Defaults to "everything".
+ // - "everything" stubs include all non-flagged apis and flagged apis, regardless of the state
+ // of the flag.
+ // - "runtime" stubs include all non-flagged apis and flagged apis that are ENABLED or
+ // READ_WRITE, and all other flagged apis are stripped.
+ // - "exportable" stubs include all non-flagged apis and flagged apis that are ENABLED and
+ // READ_ONLY, and all other flagged apis are stripped.
+ Stubs_type *string
+
+ // List of aconfig_declarations module names that the stubs generated in this module
+ // depend on.
+ Aconfig_declarations []string
}
func ApiLibraryFactory() android.Module {
@@ -1894,6 +2086,9 @@
if al.properties.System_modules != nil {
ctx.AddVariationDependencies(nil, systemModulesTag, String(al.properties.System_modules))
}
+ for _, aconfigDeclarationsName := range al.properties.Aconfig_declarations {
+ ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfigDeclarationsName)
+ }
}
// Map where key is the api scope name and value is the int value
@@ -1914,7 +2109,23 @@
return srcFilesInfo
}
+var validstubsType = []StubsType{Everything, Runtime, Exportable}
+
+func (al *ApiLibrary) validateProperties(ctx android.ModuleContext) {
+ if al.properties.Stubs_type == nil {
+ ctx.ModuleErrorf("java_api_library module type must specify stubs_type property.")
+ } else {
+ al.stubsType = StringToStubsType(proptools.String(al.properties.Stubs_type))
+ }
+
+ if !android.InList(al.stubsType, validstubsType) {
+ ctx.PropertyErrorf("stubs_type", "%s is not a valid stubs_type property value. "+
+ "Must be one of %s.", proptools.String(al.properties.Stubs_type), validstubsType)
+ }
+}
+
func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ al.validateProperties(ctx)
rule := android.NewRuleBuilder(pctx, ctx)
@@ -1958,6 +2169,18 @@
if currentApiTimestampProvider, ok := dep.(currentApiTimestampProvider); ok {
al.validationPaths = append(al.validationPaths, currentApiTimestampProvider.CurrentApiTimestamp())
}
+ case aconfigDeclarationTag:
+ if provider, ok := android.OtherModuleProvider(ctx, dep, android.AconfigDeclarationsProviderKey); ok {
+ al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.IntermediateCacheOutputPath)
+ } else if provider, ok := android.OtherModuleProvider(ctx, dep, aconfig.CodegenInfoProvider); ok {
+ al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.IntermediateCacheOutputPaths...)
+ } else {
+ ctx.ModuleErrorf("Only aconfig_declarations and aconfig_declarations_group "+
+ "module type is allowed for flags_packages property, but %s is neither "+
+ "of these supported module types",
+ dep.Name(),
+ )
+ }
}
})
@@ -1983,6 +2206,8 @@
al.addValidation(ctx, cmd, al.validationPaths)
+ generateRevertAnnotationArgs(ctx, cmd, al.stubsType, al.aconfigProtoFiles)
+
al.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
al.stubsJarWithoutStaticLibs = android.PathForModuleOut(ctx, "metalava", "stubs.jar")
al.stubsJar = android.PathForModuleOut(ctx, ctx.ModuleName(), fmt.Sprintf("%s.jar", ctx.ModuleName()))
diff --git a/java/java_test.go b/java/java_test.go
index 42301d8..2f3ccb9 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1756,6 +1756,7 @@
name: "bar",
api_surface: "public",
api_contributions: ["foo"],
+ stubs_type: "everything",
}
`)
}
@@ -1792,12 +1793,14 @@
name: "bar1",
api_surface: "public",
api_contributions: ["foo1"],
+ stubs_type: "everything",
}
java_api_library {
name: "bar2",
api_surface: "system",
api_contributions: ["foo1", "foo2"],
+ stubs_type: "everything",
}
`)
@@ -1885,12 +1888,14 @@
name: "bar1",
api_surface: "public",
api_contributions: ["foo1"],
+ stubs_type: "everything",
}
java_api_library {
name: "bar2",
api_surface: "public",
defaults:["baz1"],
+ stubs_type: "everything",
}
java_api_library {
@@ -1898,6 +1903,7 @@
api_surface: "system",
defaults:["baz1", "baz2"],
api_contributions: ["foo4"],
+ stubs_type: "everything",
}
`)
@@ -1962,12 +1968,14 @@
name: "bar1",
api_surface: "public",
api_contributions: ["foo1"],
+ stubs_type: "everything",
}
java_api_library {
name: "bar2",
api_surface: "system",
api_contributions: ["foo1", "foo2"],
+ stubs_type: "everything",
}
`)
@@ -2044,6 +2052,7 @@
api_surface: "public",
api_contributions: ["foo1"],
libs: ["lib1"],
+ stubs_type: "everything",
}
java_api_library {
@@ -2051,6 +2060,7 @@
api_surface: "system",
api_contributions: ["foo1", "foo2"],
libs: ["lib1", "lib2", "bar1"],
+ stubs_type: "everything",
}
`)
@@ -2130,6 +2140,7 @@
api_surface: "public",
api_contributions: ["foo1"],
static_libs: ["lib1"],
+ stubs_type: "everything",
}
java_api_library {
@@ -2137,6 +2148,7 @@
api_surface: "system",
api_contributions: ["foo1", "foo2"],
static_libs: ["lib1", "lib2", "bar1"],
+ stubs_type: "everything",
}
`)
@@ -2184,6 +2196,7 @@
name: "lib1",
api_surface: "public",
api_contributions: ["foo1", "foo2"],
+ stubs_type: "everything",
}
`
@@ -2207,6 +2220,7 @@
api_surface: "public",
api_contributions: ["foo1"],
full_api_surface_stub: "lib1",
+ stubs_type: "everything",
}
`)
@@ -2368,6 +2382,7 @@
java_api_library {
name: "foo",
api_contributions: ["bar"],
+ stubs_type: "everything",
}
java_api_contribution_import {
name: "bar",
@@ -2394,6 +2409,7 @@
"module-lib-api-stubs-docs-non-updatable.api.contribution",
"api-stubs-docs-non-updatable.api.contribution",
],
+ stubs_type: "everything",
}
`)
m := ctx.ModuleForTests("foo", "android_common")
@@ -2466,6 +2482,7 @@
"api-stubs-docs-non-updatable.api.contribution",
],
enable_validation: true,
+ stubs_type: "everything",
}
java_api_library {
name: "bar",
@@ -2473,6 +2490,7 @@
"api-stubs-docs-non-updatable.api.contribution",
],
enable_validation: false,
+ stubs_type: "everything",
}
`)
@@ -2624,3 +2642,54 @@
android.AssertStringEquals(t, "unexpected LOCAL_MODULE", "bar", entries.EntryMap["LOCAL_MODULE"][0])
}
}
+
+func TestApiLibraryAconfigDeclarations(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ }),
+ android.FixtureMergeMockFs(map[string][]byte{
+ "a/A.java": nil,
+ "a/current.txt": nil,
+ "a/removed.txt": nil,
+ }),
+ ).RunTestWithBp(t, `
+ aconfig_declarations {
+ name: "bar",
+ package: "com.example.package",
+ srcs: [
+ "bar.aconfig",
+ ],
+ }
+ java_api_contribution {
+ name: "baz",
+ api_file: "a/current.txt",
+ api_surface: "public",
+ }
+ java_api_library {
+ name: "foo",
+ api_surface: "public",
+ api_contributions: [
+ "baz",
+ ],
+ aconfig_declarations: [
+ "bar",
+ ],
+ stubs_type: "exportable",
+ enable_validation: false,
+ }
+ `)
+
+ // Check if java_api_library depends on aconfig_declarations
+ android.AssertBoolEquals(t, "foo expected to depend on bar",
+ CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "bar"), true)
+
+ m := result.ModuleForTests("foo", "android_common")
+ android.AssertStringDoesContain(t, "foo generates revert annotations file",
+ strings.Join(m.AllOutputs(), ""), "revert-annotations-exportable.txt")
+
+ // revert-annotations.txt passed to exportable stubs generation metalava command
+ manifest := m.Output("metalava.sbox.textproto")
+ cmdline := String(android.RuleBuilderSboxProtoForTests(t, result.TestContext, manifest).Commands[0].Command)
+ android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "revert-annotations-exportable.txt")
+}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 2e4f2e3..cdd0448 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1997,8 +1997,10 @@
tag string
pattern string
}{
- {tag: ".api.txt", pattern: "%s.txt"},
- {tag: ".removed-api.txt", pattern: "%s-removed.txt"},
+ // "exportable" api files are copied to the dist directory instead of the
+ // "everything" api files.
+ {tag: ".exportable.api.txt", pattern: "%s.txt"},
+ {tag: ".exportable.removed-api.txt", pattern: "%s-removed.txt"},
} {
props.Dists = append(props.Dists, android.Dist{
Targets: []string{"sdk", "win_sdk"},
@@ -2022,6 +2024,7 @@
Full_api_surface_stub *string
System_modules *string
Enable_validation *bool
+ Stubs_type *string
}{}
props.Name = proptools.StringPtr(module.apiLibraryModuleName(apiScope))
@@ -2071,6 +2074,7 @@
props.System_modules = module.deviceProperties.System_modules
props.Enable_validation = proptools.BoolPtr(true)
+ props.Stubs_type = proptools.StringPtr("everything")
mctx.CreateModule(ApiLibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
}
diff --git a/java/testing.go b/java/testing.go
index 04e8c73..631d516 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -523,10 +523,11 @@
for libName, droidstubs := range extraApiLibraryModules {
bp += fmt.Sprintf(`
- java_api_library {
- name: "%s",
- api_contributions: ["%s"],
- }
+ java_api_library {
+ name: "%s",
+ api_contributions: ["%s"],
+ stubs_type: "everything",
+ }
`, libName, droidstubs.name+".api.contribution")
}
diff --git a/mk2rbc/test/version_defaults.mk.test b/mk2rbc/test/version_defaults.mk.test
index 1666392..3ce60bc 100644
--- a/mk2rbc/test/version_defaults.mk.test
+++ b/mk2rbc/test/version_defaults.mk.test
@@ -3,8 +3,8 @@
include $(INTERNAL_BUILD_ID_MAKEFILE)
endif
-DEFAULT_PLATFORM_VERSION := TP1A
-.KATI_READONLY := DEFAULT_PLATFORM_VERSION
+RELEASE_PLATFORM_VERSION := TP1A
+.KATI_READONLY := RELEASE_PLATFORM_VERSION
MIN_PLATFORM_VERSION := TP1A
MAX_PLATFORM_VERSION := TP1A
PLATFORM_VERSION_LAST_STABLE := 12
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 85cc220..454dd87 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -263,10 +263,9 @@
// clang: error: '-x c' after last input file has no effect [-Werror,-Wunused-command-line-argument]
cflags = append(cflags, "-Wno-unused-command-line-argument")
- // LLVM_NEXT may contain flags that bindgen doesn't recognise. Turn off unknown flags warning.
- if ctx.Config().IsEnvTrue("LLVM_NEXT") {
- cflags = append(cflags, "-Wno-unknown-warning-option")
- }
+ // The Clang version used by CXX can be newer than the one used by Bindgen, and uses warning related flags that
+ // it cannot recognize. Turn off unknown warning flags warning.
+ cflags = append(cflags, "-Wno-unknown-warning-option")
outputFile := android.PathForModuleOut(ctx, b.BaseSourceProvider.getStem(ctx)+".rs")
diff --git a/rust/config/global.go b/rust/config/global.go
index aebbb1b..418eca4 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -25,7 +25,7 @@
pctx = android.NewPackageContext("android/soong/rust/config")
ExportedVars = android.NewExportedVariables(pctx)
- RustDefaultVersion = "1.74.1"
+ RustDefaultVersion = "1.75.0"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2021"
Stdlibs = []string{
diff --git a/rust/config/lints.go b/rust/config/lints.go
index 7770af0..735aa16 100644
--- a/rust/config/lints.go
+++ b/rust/config/lints.go
@@ -53,6 +53,8 @@
// It should be assumed that any warning lint will be promoted to a
// deny.
defaultClippyLints = []string{
+ // Let people hack in peace. ;)
+ "-A clippy::disallowed_names",
"-A clippy::type-complexity",
"-A clippy::unnecessary_fallible_conversions",
"-A clippy::unnecessary-wraps",
diff --git a/rust/testing.go b/rust/testing.go
index 0b34c97..d9cacdc 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -75,6 +75,7 @@
apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
min_sdk_version: "29",
vendor_available: true,
+ host_supported: true,
recovery_available: true,
llndk: {
symbol_file: "liblog.map.txt",
diff --git a/scripts/test_config_fixer.py b/scripts/test_config_fixer.py
index 07e01a1..2876bcb 100644
--- a/scripts/test_config_fixer.py
+++ b/scripts/test_config_fixer.py
@@ -19,6 +19,7 @@
from __future__ import print_function
import argparse
+import json
import sys
from xml.dom import minidom
@@ -31,6 +32,8 @@
KNOWN_PREPARERS = ['com.android.tradefed.targetprep.TestAppInstallSetup',
'com.android.tradefed.targetprep.suite.SuiteApkInstaller']
+KNOWN_TEST_RUNNERS = ['com.android.tradefed.testtype.AndroidJUnitTest']
+
MAINLINE_CONTROLLER = 'com.android.tradefed.testtype.suite.module.MainlineTestModuleController'
def parse_args():
@@ -43,8 +46,12 @@
help=('overwrite package fields in the test config'))
parser.add_argument('--test-file-name', default='', dest='test_file_name',
help=('overwrite test file name in the test config'))
+ parser.add_argument('--orig-test-file-name', default='', dest='orig_test_file_name',
+ help=('Use with test-file-name to only override a single apk'))
parser.add_argument('--mainline-package-name', default='', dest='mainline_package_name',
help=('overwrite mainline module package name in the test config'))
+ parser.add_argument('--test-runner-options', default='', dest='test_runner_options',
+ help=('Add test runner options in the test config'))
parser.add_argument('input', help='input test config file')
parser.add_argument('output', help='output test config file')
return parser.parse_args()
@@ -76,6 +83,18 @@
if option.getAttribute('name') == "test-file-name":
option.setAttribute('value', test_file_name)
+def overwrite_single_test_file_name(test_config_doc, orig_test_file_name, new_test_file_name):
+
+ test_config = parse_test_config(test_config_doc)
+ tests = get_children_with_tag(test_config, 'target_preparer')
+
+ for test in tests:
+ if test.getAttribute('class') in KNOWN_PREPARERS:
+ options = get_children_with_tag(test, 'option')
+ for option in options:
+ if option.getAttribute('name') == "test-file-name" and option.getAttribute('value') == orig_test_file_name:
+ option.setAttribute('value', new_test_file_name)
+
def overwrite_mainline_module_package_name(test_config_doc, mainline_package_name):
test_config = parse_test_config(test_config_doc)
@@ -86,6 +105,31 @@
if option.getAttribute('name') == "mainline-module-package-name":
option.setAttribute('value', mainline_package_name)
+def add_test_runner_options_toplevel(test_config_doc, test_runner_options):
+
+ test_config = parse_test_config(test_config_doc)
+
+ test_config.appendChild(test_config_doc.createComment("Options from Android.bp"))
+ test_config.appendChild(test_config_doc.createTextNode("\n"))
+ for new_option in json.loads(test_runner_options):
+ option = test_config_doc.createElement("option")
+ # name and value are mandatory,
+ name = new_option.get('Name')
+ if not name:
+ raise RuntimeError('"name" must set in test_runner_option"')
+ value = new_option.get('Value')
+ if not value:
+ raise RuntimeError('"value" must set in test_runner_option"')
+ option.setAttribute('name', name) # 'include-filter')
+ option.setAttribute('value', value) # 'android.test.example.devcodelab.DevCodelabTest#testHelloFail')
+ key = new_option.get('Key')
+ if key:
+ option.setAttribute('key', key) # 'include-filter')
+ # add tab and newline for readability
+ test_config.appendChild(test_config_doc.createTextNode(" "))
+ test_config.appendChild(option)
+ test_config.appendChild(test_config_doc.createTextNode("\n"))
+
def main():
"""Program entry point."""
try:
@@ -100,11 +144,20 @@
overwrite_package_name(doc, manifest_doc, args.package_name)
if args.test_file_name:
- overwrite_test_file_name(doc, args.test_file_name)
+ if args.orig_test_file_name:
+ overwrite_single_test_file_name(doc, args.orig_test_file_name, args.test_file_name)
+ else:
+ # You probably never want to override the test_file_name if there
+ # are several in the xml, but this is currently only used on generated
+ # AndroidTest.xml where there is only a single test-file-name (no data)
+ overwrite_test_file_name(doc, args.test_file_name)
if args.mainline_package_name:
overwrite_mainline_module_package_name(doc, args.mainline_package_name)
+ if args.test_runner_options:
+ add_test_runner_options_toplevel(doc, args.test_runner_options)
+
with open(args.output, 'w') as f:
write_xml(f, doc)
diff --git a/sdk/update.go b/sdk/update.go
index 095e0c2..a731414 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -89,19 +89,6 @@
indentLevel int
}
-// generatedFile abstracts operations for writing contents into a file and emit a build rule
-// for the file.
-type generatedFile struct {
- generatedContents
- path android.OutputPath
-}
-
-func newGeneratedFile(ctx android.ModuleContext, path ...string) *generatedFile {
- return &generatedFile{
- path: android.PathForModuleOut(ctx, path...).OutputPath,
- }
-}
-
func (gc *generatedContents) Indent() {
gc.indentLevel++
}
@@ -122,26 +109,6 @@
_, _ = fmt.Fprintf(&(gc.content), format, args...)
}
-func (gf *generatedFile) build(pctx android.PackageContext, ctx android.BuilderContext, implicits android.Paths) {
- rb := android.NewRuleBuilder(pctx, ctx)
-
- content := gf.content.String()
-
- // ninja consumes newline characters in rspfile_content. Prevent it by
- // escaping the backslash in the newline character. The extra backslash
- // is removed when the rspfile is written to the actual script file
- content = strings.ReplaceAll(content, "\n", "\\n")
-
- rb.Command().
- Implicits(implicits).
- Text("echo -n").Text(proptools.ShellEscape(content)).
- // convert \\n to \n
- Text("| sed 's/\\\\n/\\n/g' >").Output(gf.path)
- rb.Command().
- Text("chmod a+x").Output(gf.path)
- rb.Build(gf.path.Base(), "Build "+gf.path.Base())
-}
-
// Collect all the members.
//
// Updates the sdk module with a list of sdkMemberVariantDep instances and details as to which
@@ -170,7 +137,7 @@
var container android.Module
if parent != ctx.Module() {
- container = parent.(android.Module)
+ container = parent
}
minApiLevel := android.MinApiLevelForSdkSnapshot(ctx, child)
@@ -179,7 +146,7 @@
s.memberVariantDeps = append(s.memberVariantDeps, sdkMemberVariantDep{
sdkVariant: s,
memberType: memberType,
- variant: child.(android.Module),
+ variant: child,
minApiLevel: minApiLevel,
container: container,
export: export,
@@ -375,7 +342,7 @@
snapshotDir := android.PathForModuleOut(ctx, "snapshot")
- bp := newGeneratedFile(ctx, "snapshot", "Android.bp")
+ bp := android.PathForModuleOut(ctx, "snapshot", "Android.bp")
bpFile := &bpFile{
modules: make(map[string]*bpModule),
@@ -389,7 +356,7 @@
sdk: s,
snapshotDir: snapshotDir.OutputPath,
copies: make(map[string]string),
- filesToZip: []android.Path{bp.path},
+ filesToZip: []android.Path{bp},
bpFile: bpFile,
prebuiltModules: make(map[string]*bpModule),
allMembersByName: allMembersByName,
@@ -463,17 +430,14 @@
}
// generate Android.bp
- bp = newGeneratedFile(ctx, "snapshot", "Android.bp")
- generateBpContents(&bp.generatedContents, bpFile)
-
- contents := bp.content.String()
+ contents := generateBpContents(bpFile)
// If the snapshot is being generated for the current build release then check the syntax to make
// sure that it is compatible.
if targetBuildRelease == buildReleaseCurrent {
syntaxCheckSnapshotBpFile(ctx, contents)
}
- bp.build(pctx, ctx, nil)
+ android.WriteFileRuleVerbatim(ctx, bp, contents)
// Copy the build number file into the snapshot.
builder.CopyToSnapshot(ctx.Config().BuildNumberFile(ctx), BUILD_NUMBER_FILE)
@@ -522,16 +486,14 @@
modules := s.generateInfoData(ctx, memberVariantDeps)
// Output the modules information as pretty printed JSON.
- info := newGeneratedFile(ctx, fmt.Sprintf("%s%s.info", ctx.ModuleName(), snapshotFileSuffix))
+ info := android.PathForModuleOut(ctx, fmt.Sprintf("%s%s.info", ctx.ModuleName(), snapshotFileSuffix))
output, err := json.MarshalIndent(modules, "", " ")
if err != nil {
ctx.ModuleErrorf("error generating %q: %s", info, err)
}
builder.infoContents = string(output)
- info.generatedContents.UnindentedPrintf("%s", output)
- info.build(pctx, ctx, nil)
- infoPath := info.path
- installedInfo := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), infoPath.Base(), infoPath)
+ android.WriteFileRuleVerbatim(ctx, info, builder.infoContents)
+ installedInfo := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), info.Base(), info)
s.infoFile = android.OptionalPathForPath(installedInfo)
// Install the zip, making sure that the info file has been installed as well.
@@ -718,105 +680,6 @@
}
}
-// snapshotModuleStaticProperties contains snapshot static (i.e. not dynamically generated) properties.
-type snapshotModuleStaticProperties struct {
- Compile_multilib string `android:"arch_variant"`
-}
-
-// combinedSnapshotModuleProperties are the properties that are associated with the snapshot module.
-type combinedSnapshotModuleProperties struct {
- // The sdk variant from which this information was collected.
- sdkVariant *sdk
-
- // Static snapshot module properties.
- staticProperties *snapshotModuleStaticProperties
-
- // The dynamically generated member list properties.
- dynamicProperties interface{}
-}
-
-// collateSnapshotModuleInfo collates all the snapshot module info from supplied sdk variants.
-func (s *sdk) collateSnapshotModuleInfo(ctx android.BaseModuleContext, sdkVariants []*sdk, memberVariantDeps []sdkMemberVariantDep) []*combinedSnapshotModuleProperties {
- sdkVariantToCombinedProperties := map[*sdk]*combinedSnapshotModuleProperties{}
- var list []*combinedSnapshotModuleProperties
- for _, sdkVariant := range sdkVariants {
- staticProperties := &snapshotModuleStaticProperties{
- Compile_multilib: sdkVariant.multilibUsages.String(),
- }
- dynamicProperties := s.dynamicSdkMemberTypes.createMemberTypeListProperties()
-
- combinedProperties := &combinedSnapshotModuleProperties{
- sdkVariant: sdkVariant,
- staticProperties: staticProperties,
- dynamicProperties: dynamicProperties,
- }
- sdkVariantToCombinedProperties[sdkVariant] = combinedProperties
-
- list = append(list, combinedProperties)
- }
-
- for _, memberVariantDep := range memberVariantDeps {
- // If the member dependency is internal then do not add the dependency to the snapshot member
- // list properties.
- if !memberVariantDep.export {
- continue
- }
-
- combined := sdkVariantToCombinedProperties[memberVariantDep.sdkVariant]
- memberListProperty := s.memberTypeListProperty(memberVariantDep.memberType)
- memberName := ctx.OtherModuleName(memberVariantDep.variant)
-
- if memberListProperty.getter == nil {
- continue
- }
-
- // Append the member to the appropriate list, if it is not already present in the list.
- memberList := memberListProperty.getter(combined.dynamicProperties)
- if !android.InList(memberName, memberList) {
- memberList = append(memberList, memberName)
- }
- memberListProperty.setter(combined.dynamicProperties, memberList)
- }
-
- return list
-}
-
-func (s *sdk) optimizeSnapshotModuleProperties(ctx android.ModuleContext, list []*combinedSnapshotModuleProperties) *combinedSnapshotModuleProperties {
-
- // Extract the dynamic properties and add them to a list of propertiesContainer.
- propertyContainers := []propertiesContainer{}
- for _, i := range list {
- propertyContainers = append(propertyContainers, sdkVariantPropertiesContainer{
- sdkVariant: i.sdkVariant,
- properties: i.dynamicProperties,
- })
- }
-
- // Extract the common members, removing them from the original properties.
- commonDynamicProperties := s.dynamicSdkMemberTypes.createMemberTypeListProperties()
- extractor := newCommonValueExtractor(commonDynamicProperties)
- extractCommonProperties(ctx, extractor, commonDynamicProperties, propertyContainers)
-
- // Extract the static properties and add them to a list of propertiesContainer.
- propertyContainers = []propertiesContainer{}
- for _, i := range list {
- propertyContainers = append(propertyContainers, sdkVariantPropertiesContainer{
- sdkVariant: i.sdkVariant,
- properties: i.staticProperties,
- })
- }
-
- commonStaticProperties := &snapshotModuleStaticProperties{}
- extractor = newCommonValueExtractor(commonStaticProperties)
- extractCommonProperties(ctx, extractor, &commonStaticProperties, propertyContainers)
-
- return &combinedSnapshotModuleProperties{
- sdkVariant: nil,
- staticProperties: commonStaticProperties,
- dynamicProperties: commonDynamicProperties,
- }
-}
-
type propertyTag struct {
name string
}
@@ -885,7 +748,8 @@
}
}
-func generateBpContents(contents *generatedContents, bpFile *bpFile) {
+func generateBpContents(bpFile *bpFile) string {
+ contents := &generatedContents{}
contents.IndentedPrintf("// This is auto-generated. DO NOT EDIT.\n")
for _, bpModule := range bpFile.order {
contents.IndentedPrintf("\n")
@@ -893,6 +757,7 @@
outputPropertySet(contents, bpModule.bpPropertySet)
contents.IndentedPrintf("}\n")
}
+ return contents.content.String()
}
func outputPropertySet(contents *generatedContents, set *bpPropertySet) {
@@ -1007,7 +872,7 @@
contents.IndentedPrintf("}")
default:
- panic(fmt.Errorf("Unknown type: %T of value %#v", value, value))
+ panic(fmt.Errorf("unknown type: %T of value %#v", value, value))
}
}
@@ -1018,9 +883,7 @@
}
func (s *sdk) GetAndroidBpContentsForTests() string {
- contents := &generatedContents{}
- generateBpContents(contents, s.builderForTests.bpFile)
- return contents.content.String()
+ return generateBpContents(s.builderForTests.bpFile)
}
func (s *sdk) GetInfoContentsForTests() string {
@@ -1334,7 +1197,7 @@
case "lib64":
return m | multilib64
default:
- panic(fmt.Errorf("Unknown Multilib field in ArchType, expected 'lib32' or 'lib64', found %q", multilib))
+ panic(fmt.Errorf("unknown Multilib field in ArchType, expected 'lib32' or 'lib64', found %q", multilib))
}
}
@@ -1349,7 +1212,7 @@
case multilibBoth:
return "both"
default:
- panic(fmt.Errorf("Unknown multilib value, found %b, expected one of %b, %b, %b or %b",
+ panic(fmt.Errorf("unknown multilib value, found %b, expected one of %b, %b, %b or %b",
m, multilibNone, multilib32, multilib64, multilibBoth))
}
}
@@ -2302,20 +2165,6 @@
optimizableProperties() interface{}
}
-// A wrapper for sdk variant related properties to allow them to be optimized.
-type sdkVariantPropertiesContainer struct {
- sdkVariant *sdk
- properties interface{}
-}
-
-func (c sdkVariantPropertiesContainer) optimizableProperties() interface{} {
- return c.properties
-}
-
-func (c sdkVariantPropertiesContainer) String() string {
- return c.sdkVariant.String()
-}
-
// Extract common properties from a slice of property structures of the same type.
//
// All the property structures must be of the same type.
diff --git a/starlark_import/Android.bp b/starlark_import/Android.bp
deleted file mode 100644
index b43217b..0000000
--- a/starlark_import/Android.bp
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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 {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-bootstrap_go_package {
- name: "soong-starlark",
- pkgPath: "android/soong/starlark_import",
- srcs: [
- "starlark_import.go",
- "unmarshal.go",
- ],
- testSrcs: [
- "starlark_import_test.go",
- "unmarshal_test.go",
- ],
- deps: [
- "go-starlark-starlark",
- "go-starlark-starlarkstruct",
- "go-starlark-starlarkjson",
- "go-starlark-starlarktest",
- ],
-}
diff --git a/starlark_import/README.md b/starlark_import/README.md
deleted file mode 100644
index e444759..0000000
--- a/starlark_import/README.md
+++ /dev/null
@@ -1,14 +0,0 @@
-# starlark_import package
-
-This allows soong to read constant information from starlark files. At package initialization
-time, soong will read `build/bazel/constants_exported_to_soong.bzl`, and then make the
-variables from that file available via `starlark_import.GetStarlarkValue()`. So to import
-a new variable, it must be added to `constants_exported_to_soong.bzl` and then it can
-be accessed by name.
-
-Only constant information can be read, since this is not a full bazel execution but a
-standalone starlark interpreter. This means you can't use bazel contructs like `rule`,
-`provider`, `select`, `glob`, etc.
-
-All starlark files that were loaded must be added as ninja deps that cause soong to rerun.
-The loaded files can be retrieved via `starlark_import.GetNinjaDeps()`.
diff --git a/starlark_import/starlark_import.go b/starlark_import/starlark_import.go
deleted file mode 100644
index ebe4247..0000000
--- a/starlark_import/starlark_import.go
+++ /dev/null
@@ -1,306 +0,0 @@
-// 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 starlark_import
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "sort"
- "strings"
- "sync"
- "time"
-
- "go.starlark.net/starlark"
- "go.starlark.net/starlarkjson"
- "go.starlark.net/starlarkstruct"
-)
-
-func init() {
- go func() {
- startTime := time.Now()
- v, d, err := runStarlarkFile("//build/bazel/constants_exported_to_soong.bzl")
- endTime := time.Now()
- //fmt.Fprintf(os.Stderr, "starlark run time: %s\n", endTime.Sub(startTime).String())
- globalResult.Set(starlarkResult{
- values: v,
- ninjaDeps: d,
- err: err,
- startTime: startTime,
- endTime: endTime,
- })
- }()
-}
-
-type starlarkResult struct {
- values starlark.StringDict
- ninjaDeps []string
- err error
- startTime time.Time
- endTime time.Time
-}
-
-// setOnce wraps a value and exposes Set() and Get() accessors for it.
-// The Get() calls will block until a Set() has been called.
-// A second call to Set() will panic.
-// setOnce must be created using newSetOnce()
-type setOnce[T any] struct {
- value T
- lock sync.Mutex
- wg sync.WaitGroup
- isSet bool
-}
-
-func (o *setOnce[T]) Set(value T) {
- o.lock.Lock()
- defer o.lock.Unlock()
- if o.isSet {
- panic("Value already set")
- }
-
- o.value = value
- o.isSet = true
- o.wg.Done()
-}
-
-func (o *setOnce[T]) Get() T {
- if !o.isSet {
- o.wg.Wait()
- }
- return o.value
-}
-
-func newSetOnce[T any]() *setOnce[T] {
- result := &setOnce[T]{}
- result.wg.Add(1)
- return result
-}
-
-var globalResult = newSetOnce[starlarkResult]()
-
-func GetStarlarkValue[T any](key string) (T, error) {
- result := globalResult.Get()
- if result.err != nil {
- var zero T
- return zero, result.err
- }
- if !result.values.Has(key) {
- var zero T
- return zero, fmt.Errorf("a starlark variable by that name wasn't found, did you update //build/bazel/constants_exported_to_soong.bzl?")
- }
- return Unmarshal[T](result.values[key])
-}
-
-func GetNinjaDeps() ([]string, error) {
- result := globalResult.Get()
- if result.err != nil {
- return nil, result.err
- }
- return result.ninjaDeps, nil
-}
-
-func getTopDir() (string, error) {
- // It's hard to communicate the top dir to this package in any other way than reading the
- // arguments directly, because we need to know this at package initialization time. Many
- // soong constants that we'd like to read from starlark are initialized during package
- // initialization.
- for i, arg := range os.Args {
- if arg == "--top" {
- if i < len(os.Args)-1 && os.Args[i+1] != "" {
- return os.Args[i+1], nil
- }
- }
- }
-
- // When running tests, --top is not passed. Instead, search for the top dir manually
- cwd, err := os.Getwd()
- if err != nil {
- return "", err
- }
- for cwd != "/" {
- if _, err := os.Stat(filepath.Join(cwd, "build/soong/soong_ui.bash")); err == nil {
- return cwd, nil
- }
- cwd = filepath.Dir(cwd)
- }
- return "", fmt.Errorf("could not find top dir")
-}
-
-const callerDirKey = "callerDir"
-
-type modentry struct {
- globals starlark.StringDict
- err error
-}
-
-func unsupportedMethod(t *starlark.Thread, fn *starlark.Builtin, _ starlark.Tuple, _ []starlark.Tuple) (starlark.Value, error) {
- return nil, fmt.Errorf("%sthis file is read by soong, and must therefore be pure starlark and include only constant information. %q is not allowed", t.CallStack().String(), fn.Name())
-}
-
-var builtins = starlark.StringDict{
- "aspect": starlark.NewBuiltin("aspect", unsupportedMethod),
- "glob": starlark.NewBuiltin("glob", unsupportedMethod),
- "json": starlarkjson.Module,
- "provider": starlark.NewBuiltin("provider", unsupportedMethod),
- "rule": starlark.NewBuiltin("rule", unsupportedMethod),
- "struct": starlark.NewBuiltin("struct", starlarkstruct.Make),
- "select": starlark.NewBuiltin("select", unsupportedMethod),
- "transition": starlark.NewBuiltin("transition", unsupportedMethod),
-}
-
-// Takes a module name (the first argument to the load() function) and returns the path
-// it's trying to load, stripping out leading //, and handling leading :s.
-func cleanModuleName(moduleName string, callerDir string) (string, error) {
- if strings.Count(moduleName, ":") > 1 {
- return "", fmt.Errorf("at most 1 colon must be present in starlark path: %s", moduleName)
- }
-
- // We don't have full support for external repositories, but at least support skylib's dicts.
- if moduleName == "@bazel_skylib//lib:dicts.bzl" {
- return "external/bazel-skylib/lib/dicts.bzl", nil
- }
-
- localLoad := false
- if strings.HasPrefix(moduleName, "@//") {
- moduleName = moduleName[3:]
- } else if strings.HasPrefix(moduleName, "//") {
- moduleName = moduleName[2:]
- } else if strings.HasPrefix(moduleName, ":") {
- moduleName = moduleName[1:]
- localLoad = true
- } else {
- return "", fmt.Errorf("load path must start with // or :")
- }
-
- if ix := strings.LastIndex(moduleName, ":"); ix >= 0 {
- moduleName = moduleName[:ix] + string(os.PathSeparator) + moduleName[ix+1:]
- }
-
- if filepath.Clean(moduleName) != moduleName {
- return "", fmt.Errorf("load path must be clean, found: %s, expected: %s", moduleName, filepath.Clean(moduleName))
- }
- if strings.HasPrefix(moduleName, "../") {
- return "", fmt.Errorf("load path must not start with ../: %s", moduleName)
- }
- if strings.HasPrefix(moduleName, "/") {
- return "", fmt.Errorf("load path starts with /, use // for a absolute path: %s", moduleName)
- }
-
- if localLoad {
- return filepath.Join(callerDir, moduleName), nil
- }
-
- return moduleName, nil
-}
-
-// loader implements load statement. The format of the loaded module URI is
-//
-// [//path]:base
-//
-// The file path is $ROOT/path/base if path is present, <caller_dir>/base otherwise.
-func loader(thread *starlark.Thread, module string, topDir string, moduleCache map[string]*modentry, moduleCacheLock *sync.Mutex, filesystem map[string]string) (starlark.StringDict, error) {
- modulePath, err := cleanModuleName(module, thread.Local(callerDirKey).(string))
- if err != nil {
- return nil, err
- }
- moduleCacheLock.Lock()
- e, ok := moduleCache[modulePath]
- if e == nil {
- if ok {
- moduleCacheLock.Unlock()
- return nil, fmt.Errorf("cycle in load graph")
- }
-
- // Add a placeholder to indicate "load in progress".
- moduleCache[modulePath] = nil
- moduleCacheLock.Unlock()
-
- childThread := &starlark.Thread{Name: "exec " + module, Load: thread.Load}
-
- // Cheating for the sake of testing:
- // propagate starlarktest's Reporter key, otherwise testing
- // the load function may cause panic in starlarktest code.
- const testReporterKey = "Reporter"
- if v := thread.Local(testReporterKey); v != nil {
- childThread.SetLocal(testReporterKey, v)
- }
-
- childThread.SetLocal(callerDirKey, filepath.Dir(modulePath))
-
- if filesystem != nil {
- globals, err := starlark.ExecFile(childThread, filepath.Join(topDir, modulePath), filesystem[modulePath], builtins)
- e = &modentry{globals, err}
- } else {
- globals, err := starlark.ExecFile(childThread, filepath.Join(topDir, modulePath), nil, builtins)
- e = &modentry{globals, err}
- }
-
- // Update the cache.
- moduleCacheLock.Lock()
- moduleCache[modulePath] = e
- }
- moduleCacheLock.Unlock()
- return e.globals, e.err
-}
-
-// Run runs the given starlark file and returns its global variables and a list of all starlark
-// files that were loaded. The top dir for starlark's // is found via getTopDir().
-func runStarlarkFile(filename string) (starlark.StringDict, []string, error) {
- topDir, err := getTopDir()
- if err != nil {
- return nil, nil, err
- }
- return runStarlarkFileWithFilesystem(filename, topDir, nil)
-}
-
-func runStarlarkFileWithFilesystem(filename string, topDir string, filesystem map[string]string) (starlark.StringDict, []string, error) {
- if !strings.HasPrefix(filename, "//") && !strings.HasPrefix(filename, ":") {
- filename = "//" + filename
- }
- filename, err := cleanModuleName(filename, "")
- if err != nil {
- return nil, nil, err
- }
- moduleCache := make(map[string]*modentry)
- moduleCache[filename] = nil
- moduleCacheLock := &sync.Mutex{}
- mainThread := &starlark.Thread{
- Name: "main",
- Print: func(_ *starlark.Thread, msg string) {
- // Ignore prints
- },
- Load: func(thread *starlark.Thread, module string) (starlark.StringDict, error) {
- return loader(thread, module, topDir, moduleCache, moduleCacheLock, filesystem)
- },
- }
- mainThread.SetLocal(callerDirKey, filepath.Dir(filename))
-
- var result starlark.StringDict
- if filesystem != nil {
- result, err = starlark.ExecFile(mainThread, filepath.Join(topDir, filename), filesystem[filename], builtins)
- } else {
- result, err = starlark.ExecFile(mainThread, filepath.Join(topDir, filename), nil, builtins)
- }
- return result, sortedStringKeys(moduleCache), err
-}
-
-func sortedStringKeys(m map[string]*modentry) []string {
- s := make([]string, 0, len(m))
- for k := range m {
- s = append(s, k)
- }
- sort.Strings(s)
- return s
-}
diff --git a/starlark_import/starlark_import_test.go b/starlark_import/starlark_import_test.go
deleted file mode 100644
index 8a58e3b..0000000
--- a/starlark_import/starlark_import_test.go
+++ /dev/null
@@ -1,122 +0,0 @@
-// 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 starlark_import
-
-import (
- "strings"
- "testing"
-
- "go.starlark.net/starlark"
-)
-
-func TestBasic(t *testing.T) {
- globals, _, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
- "a.bzl": `
-my_string = "hello, world!"
-`})
- if err != nil {
- t.Error(err)
- return
- }
-
- if globals["my_string"].(starlark.String) != "hello, world!" {
- t.Errorf("Expected %q, got %q", "hello, world!", globals["my_string"].String())
- }
-}
-
-func TestLoad(t *testing.T) {
- globals, _, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
- "a.bzl": `
-load("//b.bzl", _b_string = "my_string")
-my_string = "hello, " + _b_string
-`,
- "b.bzl": `
-my_string = "world!"
-`})
- if err != nil {
- t.Error(err)
- return
- }
-
- if globals["my_string"].(starlark.String) != "hello, world!" {
- t.Errorf("Expected %q, got %q", "hello, world!", globals["my_string"].String())
- }
-}
-
-func TestLoadRelative(t *testing.T) {
- globals, ninjaDeps, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
- "a.bzl": `
-load(":b.bzl", _b_string = "my_string")
-load("//foo/c.bzl", _c_string = "my_string")
-my_string = "hello, " + _b_string
-c_string = _c_string
-`,
- "b.bzl": `
-my_string = "world!"
-`,
- "foo/c.bzl": `
-load(":d.bzl", _d_string = "my_string")
-my_string = "hello, " + _d_string
-`,
- "foo/d.bzl": `
-my_string = "world!"
-`})
- if err != nil {
- t.Error(err)
- return
- }
-
- if globals["my_string"].(starlark.String) != "hello, world!" {
- t.Errorf("Expected %q, got %q", "hello, world!", globals["my_string"].String())
- }
-
- expectedNinjaDeps := []string{
- "a.bzl",
- "b.bzl",
- "foo/c.bzl",
- "foo/d.bzl",
- }
- if !slicesEqual(ninjaDeps, expectedNinjaDeps) {
- t.Errorf("Expected %v ninja deps, got %v", expectedNinjaDeps, ninjaDeps)
- }
-}
-
-func TestLoadCycle(t *testing.T) {
- _, _, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
- "a.bzl": `
-load(":b.bzl", _b_string = "my_string")
-my_string = "hello, " + _b_string
-`,
- "b.bzl": `
-load(":a.bzl", _a_string = "my_string")
-my_string = "hello, " + _a_string
-`})
- if err == nil || !strings.Contains(err.Error(), "cycle in load graph") {
- t.Errorf("Expected cycle in load graph, got: %v", err)
- return
- }
-}
-
-func slicesEqual[T comparable](a []T, b []T) bool {
- if len(a) != len(b) {
- return false
- }
- for i := range a {
- if a[i] != b[i] {
- return false
- }
- }
- return true
-}
diff --git a/starlark_import/unmarshal.go b/starlark_import/unmarshal.go
deleted file mode 100644
index b243471..0000000
--- a/starlark_import/unmarshal.go
+++ /dev/null
@@ -1,304 +0,0 @@
-// 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 starlark_import
-
-import (
- "fmt"
- "math"
- "reflect"
- "unsafe"
-
- "go.starlark.net/starlark"
- "go.starlark.net/starlarkstruct"
-)
-
-func Unmarshal[T any](value starlark.Value) (T, error) {
- x, err := UnmarshalReflect(value, reflect.TypeOf((*T)(nil)).Elem())
- return x.Interface().(T), err
-}
-
-func UnmarshalReflect(value starlark.Value, ty reflect.Type) (reflect.Value, error) {
- if ty == reflect.TypeOf((*starlark.Value)(nil)).Elem() {
- return reflect.ValueOf(value), nil
- }
- zero := reflect.Zero(ty)
- if value == nil {
- panic("nil value")
- }
- var result reflect.Value
- if ty.Kind() == reflect.Interface {
- var err error
- ty, err = typeOfStarlarkValue(value)
- if err != nil {
- return zero, err
- }
- }
- if ty.Kind() == reflect.Map {
- result = reflect.MakeMap(ty)
- } else {
- result = reflect.Indirect(reflect.New(ty))
- }
-
- switch v := value.(type) {
- case starlark.String:
- if result.Type().Kind() != reflect.String {
- return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
- }
- result.SetString(v.GoString())
- case starlark.Int:
- signedValue, signedOk := v.Int64()
- unsignedValue, unsignedOk := v.Uint64()
- switch result.Type().Kind() {
- case reflect.Int64:
- if !signedOk {
- return zero, fmt.Errorf("starlark int didn't fit in go int64")
- }
- result.SetInt(signedValue)
- case reflect.Int32:
- if !signedOk || signedValue > math.MaxInt32 || signedValue < math.MinInt32 {
- return zero, fmt.Errorf("starlark int didn't fit in go int32")
- }
- result.SetInt(signedValue)
- case reflect.Int16:
- if !signedOk || signedValue > math.MaxInt16 || signedValue < math.MinInt16 {
- return zero, fmt.Errorf("starlark int didn't fit in go int16")
- }
- result.SetInt(signedValue)
- case reflect.Int8:
- if !signedOk || signedValue > math.MaxInt8 || signedValue < math.MinInt8 {
- return zero, fmt.Errorf("starlark int didn't fit in go int8")
- }
- result.SetInt(signedValue)
- case reflect.Int:
- if !signedOk || signedValue > math.MaxInt || signedValue < math.MinInt {
- return zero, fmt.Errorf("starlark int didn't fit in go int")
- }
- result.SetInt(signedValue)
- case reflect.Uint64:
- if !unsignedOk {
- return zero, fmt.Errorf("starlark int didn't fit in go uint64")
- }
- result.SetUint(unsignedValue)
- case reflect.Uint32:
- if !unsignedOk || unsignedValue > math.MaxUint32 {
- return zero, fmt.Errorf("starlark int didn't fit in go uint32")
- }
- result.SetUint(unsignedValue)
- case reflect.Uint16:
- if !unsignedOk || unsignedValue > math.MaxUint16 {
- return zero, fmt.Errorf("starlark int didn't fit in go uint16")
- }
- result.SetUint(unsignedValue)
- case reflect.Uint8:
- if !unsignedOk || unsignedValue > math.MaxUint8 {
- return zero, fmt.Errorf("starlark int didn't fit in go uint8")
- }
- result.SetUint(unsignedValue)
- case reflect.Uint:
- if !unsignedOk || unsignedValue > math.MaxUint {
- return zero, fmt.Errorf("starlark int didn't fit in go uint")
- }
- result.SetUint(unsignedValue)
- default:
- return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
- }
- case starlark.Float:
- f := float64(v)
- switch result.Type().Kind() {
- case reflect.Float64:
- result.SetFloat(f)
- case reflect.Float32:
- if f > math.MaxFloat32 || f < -math.MaxFloat32 {
- return zero, fmt.Errorf("starlark float didn't fit in go float32")
- }
- result.SetFloat(f)
- default:
- return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
- }
- case starlark.Bool:
- if result.Type().Kind() != reflect.Bool {
- return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
- }
- result.SetBool(bool(v))
- case starlark.Tuple:
- if result.Type().Kind() != reflect.Slice {
- return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
- }
- elemType := result.Type().Elem()
- // TODO: Add this grow call when we're on go 1.20
- //result.Grow(v.Len())
- for i := 0; i < v.Len(); i++ {
- elem, err := UnmarshalReflect(v.Index(i), elemType)
- if err != nil {
- return zero, err
- }
- result = reflect.Append(result, elem)
- }
- case *starlark.List:
- if result.Type().Kind() != reflect.Slice {
- return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
- }
- elemType := result.Type().Elem()
- // TODO: Add this grow call when we're on go 1.20
- //result.Grow(v.Len())
- for i := 0; i < v.Len(); i++ {
- elem, err := UnmarshalReflect(v.Index(i), elemType)
- if err != nil {
- return zero, err
- }
- result = reflect.Append(result, elem)
- }
- case *starlark.Dict:
- if result.Type().Kind() != reflect.Map {
- return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
- }
- keyType := result.Type().Key()
- valueType := result.Type().Elem()
- for _, pair := range v.Items() {
- key := pair.Index(0)
- value := pair.Index(1)
-
- unmarshalledKey, err := UnmarshalReflect(key, keyType)
- if err != nil {
- return zero, err
- }
- unmarshalledValue, err := UnmarshalReflect(value, valueType)
- if err != nil {
- return zero, err
- }
-
- result.SetMapIndex(unmarshalledKey, unmarshalledValue)
- }
- case *starlarkstruct.Struct:
- if result.Type().Kind() != reflect.Struct {
- return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
- }
- if result.NumField() != len(v.AttrNames()) {
- return zero, fmt.Errorf("starlark struct and go struct have different number of fields (%d and %d)", len(v.AttrNames()), result.NumField())
- }
- for _, attrName := range v.AttrNames() {
- attr, err := v.Attr(attrName)
- if err != nil {
- return zero, err
- }
-
- // TODO(b/279787235): this should probably support tags to rename the field
- resultField := result.FieldByName(attrName)
- if resultField == (reflect.Value{}) {
- return zero, fmt.Errorf("starlark struct had field %s, but requested struct type did not", attrName)
- }
- // This hack allows us to change unexported fields
- resultField = reflect.NewAt(resultField.Type(), unsafe.Pointer(resultField.UnsafeAddr())).Elem()
- x, err := UnmarshalReflect(attr, resultField.Type())
- if err != nil {
- return zero, err
- }
- resultField.Set(x)
- }
- default:
- return zero, fmt.Errorf("unimplemented starlark type: %s", value.Type())
- }
-
- return result, nil
-}
-
-func typeOfStarlarkValue(value starlark.Value) (reflect.Type, error) {
- var err error
- switch v := value.(type) {
- case starlark.String:
- return reflect.TypeOf(""), nil
- case *starlark.List:
- innerType := reflect.TypeOf("")
- if v.Len() > 0 {
- innerType, err = typeOfStarlarkValue(v.Index(0))
- if err != nil {
- return nil, err
- }
- }
- for i := 1; i < v.Len(); i++ {
- innerTypeI, err := typeOfStarlarkValue(v.Index(i))
- if err != nil {
- return nil, err
- }
- if innerType != innerTypeI {
- return nil, fmt.Errorf("List must contain elements of entirely the same type, found %v and %v", innerType, innerTypeI)
- }
- }
- return reflect.SliceOf(innerType), nil
- case *starlark.Dict:
- keyType := reflect.TypeOf("")
- valueType := reflect.TypeOf("")
- keys := v.Keys()
- if v.Len() > 0 {
- firstKey := keys[0]
- keyType, err = typeOfStarlarkValue(firstKey)
- if err != nil {
- return nil, err
- }
- firstValue, found, err := v.Get(firstKey)
- if !found {
- err = fmt.Errorf("value not found")
- }
- if err != nil {
- return nil, err
- }
- valueType, err = typeOfStarlarkValue(firstValue)
- if err != nil {
- return nil, err
- }
- }
- for _, key := range keys {
- keyTypeI, err := typeOfStarlarkValue(key)
- if err != nil {
- return nil, err
- }
- if keyType != keyTypeI {
- return nil, fmt.Errorf("dict must contain elements of entirely the same type, found %v and %v", keyType, keyTypeI)
- }
- value, found, err := v.Get(key)
- if !found {
- err = fmt.Errorf("value not found")
- }
- if err != nil {
- return nil, err
- }
- valueTypeI, err := typeOfStarlarkValue(value)
- if valueType.Kind() != reflect.Interface && valueTypeI != valueType {
- // If we see conflicting value types, change the result value type to an empty interface
- valueType = reflect.TypeOf([]interface{}{}).Elem()
- }
- }
- return reflect.MapOf(keyType, valueType), nil
- case starlark.Int:
- return reflect.TypeOf(0), nil
- case starlark.Float:
- return reflect.TypeOf(0.0), nil
- case starlark.Bool:
- return reflect.TypeOf(true), nil
- default:
- return nil, fmt.Errorf("unimplemented starlark type: %s", value.Type())
- }
-}
-
-// UnmarshalNoneable is like Unmarshal, but it will accept None as the top level (but not nested)
-// starlark value. If the value is None, a nil pointer will be returned, otherwise a pointer
-// to the result of Unmarshal will be returned.
-func UnmarshalNoneable[T any](value starlark.Value) (*T, error) {
- if _, ok := value.(starlark.NoneType); ok {
- return nil, nil
- }
- ret, err := Unmarshal[T](value)
- return &ret, err
-}
diff --git a/starlark_import/unmarshal_test.go b/starlark_import/unmarshal_test.go
deleted file mode 100644
index bc0ea4c..0000000
--- a/starlark_import/unmarshal_test.go
+++ /dev/null
@@ -1,148 +0,0 @@
-// 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 starlark_import
-
-import (
- "reflect"
- "testing"
-
- "go.starlark.net/starlark"
-)
-
-func createStarlarkValue(t *testing.T, code string) starlark.Value {
- t.Helper()
- result, err := starlark.ExecFile(&starlark.Thread{}, "main.bzl", "x = "+code, builtins)
- if err != nil {
- panic(err)
- }
- return result["x"]
-}
-
-func TestUnmarshalConcreteType(t *testing.T) {
- x, err := Unmarshal[string](createStarlarkValue(t, `"foo"`))
- if err != nil {
- t.Error(err)
- return
- }
- if x != "foo" {
- t.Errorf(`Expected "foo", got %q`, x)
- }
-}
-
-func TestUnmarshalConcreteTypeWithInterfaces(t *testing.T) {
- x, err := Unmarshal[map[string]map[string]interface{}](createStarlarkValue(t,
- `{"foo": {"foo2": "foo3"}, "bar": {"bar2": ["bar3"]}}`))
- if err != nil {
- t.Error(err)
- return
- }
- expected := map[string]map[string]interface{}{
- "foo": {"foo2": "foo3"},
- "bar": {"bar2": []string{"bar3"}},
- }
- if !reflect.DeepEqual(x, expected) {
- t.Errorf(`Expected %v, got %v`, expected, x)
- }
-}
-
-func TestUnmarshalToStarlarkValue(t *testing.T) {
- x, err := Unmarshal[map[string]starlark.Value](createStarlarkValue(t,
- `{"foo": "Hi", "bar": None}`))
- if err != nil {
- t.Error(err)
- return
- }
- if x["foo"].(starlark.String).GoString() != "Hi" {
- t.Errorf("Expected \"Hi\", got: %q", x["foo"].(starlark.String).GoString())
- }
- if x["bar"].Type() != "NoneType" {
- t.Errorf("Expected \"NoneType\", got: %q", x["bar"].Type())
- }
-}
-
-func TestUnmarshal(t *testing.T) {
- testCases := []struct {
- input string
- expected interface{}
- }{
- {
- input: `"foo"`,
- expected: "foo",
- },
- {
- input: `5`,
- expected: 5,
- },
- {
- input: `["foo", "bar"]`,
- expected: []string{"foo", "bar"},
- },
- {
- input: `("foo", "bar")`,
- expected: []string{"foo", "bar"},
- },
- {
- input: `("foo",5)`,
- expected: []interface{}{"foo", 5},
- },
- {
- input: `{"foo": 5, "bar": 10}`,
- expected: map[string]int{"foo": 5, "bar": 10},
- },
- {
- input: `{"foo": ["qux"], "bar": []}`,
- expected: map[string][]string{"foo": {"qux"}, "bar": nil},
- },
- {
- input: `struct(Foo="foo", Bar=5)`,
- expected: struct {
- Foo string
- Bar int
- }{Foo: "foo", Bar: 5},
- },
- {
- // Unexported fields version of the above
- input: `struct(foo="foo", bar=5)`,
- expected: struct {
- foo string
- bar int
- }{foo: "foo", bar: 5},
- },
- {
- input: `{"foo": "foo2", "bar": ["bar2"], "baz": 5, "qux": {"qux2": "qux3"}, "quux": {"quux2": "quux3", "quux4": 5}}`,
- expected: map[string]interface{}{
- "foo": "foo2",
- "bar": []string{"bar2"},
- "baz": 5,
- "qux": map[string]string{"qux2": "qux3"},
- "quux": map[string]interface{}{
- "quux2": "quux3",
- "quux4": 5,
- },
- },
- },
- }
-
- for _, tc := range testCases {
- x, err := UnmarshalReflect(createStarlarkValue(t, tc.input), reflect.TypeOf(tc.expected))
- if err != nil {
- t.Error(err)
- continue
- }
- if !reflect.DeepEqual(x.Interface(), tc.expected) {
- t.Errorf(`Expected %#v, got %#v`, tc.expected, x.Interface())
- }
- }
-}
diff --git a/sysprop/Android.bp b/sysprop/Android.bp
index 1d5eb31..a00a5e4 100644
--- a/sysprop/Android.bp
+++ b/sysprop/Android.bp
@@ -11,6 +11,7 @@
"soong-android",
"soong-cc",
"soong-java",
+ "soong-rust",
],
srcs: [
"sysprop_library.go",
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 766f3e7..2258232 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -21,6 +21,7 @@
"io"
"os"
"path"
+ "strings"
"sync"
"github.com/google/blueprint"
@@ -29,6 +30,7 @@
"android/soong/android"
"android/soong/cc"
"android/soong/java"
+ "android/soong/rust"
)
type dependencyTag struct {
@@ -51,7 +53,16 @@
genSrcjars android.Paths
}
+type syspropRustGenRule struct {
+ android.ModuleBase
+
+ properties syspropGenProperties
+
+ genSrcs android.Paths
+}
+
var _ android.OutputFileProducer = (*syspropJavaGenRule)(nil)
+var _ android.OutputFileProducer = (*syspropRustGenRule)(nil)
var (
syspropJava = pctx.AndroidStaticRule("syspropJava",
@@ -64,11 +75,20 @@
"$soongZipCmd",
},
}, "scope")
+ syspropRust = pctx.AndroidStaticRule("syspropRust",
+ blueprint.RuleParams{
+ Command: `rm -rf $out_dir && mkdir -p $out_dir && ` +
+ `$syspropRustCmd --scope $scope --rust-output-dir $out_dir $in`,
+ CommandDeps: []string{
+ "$syspropRustCmd",
+ },
+ }, "scope", "out_dir")
)
func init() {
pctx.HostBinToolVariable("soongZipCmd", "soong_zip")
pctx.HostBinToolVariable("syspropJavaCmd", "sysprop_java")
+ pctx.HostBinToolVariable("syspropRustCmd", "sysprop_rust")
}
// syspropJavaGenRule module generates srcjar containing generated java APIs.
@@ -122,6 +142,56 @@
return g
}
+// syspropRustGenRule module generates rust source files containing generated rust APIs.
+// It also depends on check api rule, so api check has to pass to use sysprop_library.
+func (g *syspropRustGenRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ var checkApiFileTimeStamp android.WritablePath
+
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ if m, ok := dep.(*syspropLibrary); ok {
+ checkApiFileTimeStamp = m.checkApiFileTimeStamp
+ }
+ })
+
+ for _, syspropFile := range android.PathsForModuleSrc(ctx, g.properties.Srcs) {
+ syspropDir := strings.TrimSuffix(syspropFile.String(), syspropFile.Ext())
+ outputDir := android.PathForModuleGen(ctx, syspropDir, "src")
+ libPath := android.PathForModuleGen(ctx, syspropDir, "src", "lib.rs")
+ parsersPath := android.PathForModuleGen(ctx, syspropDir, "src", "gen_parsers_and_formatters.rs")
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: syspropRust,
+ Description: "sysprop_rust " + syspropFile.Rel(),
+ Outputs: android.WritablePaths{libPath, parsersPath},
+ Input: syspropFile,
+ Implicit: checkApiFileTimeStamp,
+ Args: map[string]string{
+ "scope": g.properties.Scope,
+ "out_dir": outputDir.String(),
+ },
+ })
+
+ g.genSrcs = append(g.genSrcs, libPath, parsersPath)
+ }
+}
+
+func (g *syspropRustGenRule) DepsMutator(ctx android.BottomUpMutatorContext) {
+ // Add a dependency from the stubs to sysprop library so that the generator rule can depend on
+ // the check API rule of the sysprop library.
+ ctx.AddFarVariationDependencies(nil, nil, proptools.String(g.properties.Check_api))
+}
+
+func (g *syspropRustGenRule) OutputFiles(_ string) (android.Paths, error) {
+ return g.genSrcs, nil
+}
+
+func syspropRustGenFactory() android.Module {
+ g := &syspropRustGenRule{}
+ g.AddProperties(&g.properties)
+ android.InitAndroidModule(g)
+ return g
+}
+
type syspropLibrary struct {
android.ModuleBase
android.ApexModuleBase
@@ -180,6 +250,12 @@
// Forwarded to java_library.min_sdk_version
Min_sdk_version *string
}
+
+ Rust struct {
+ // Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
+ // Forwarded to rust_library.min_sdk_version
+ Min_sdk_version *string
+ }
}
var (
@@ -233,6 +309,21 @@
return m.BaseModuleName() + "_java_gen_public"
}
+func (m *syspropLibrary) rustGenModuleName() string {
+ return m.rustCrateName() + "_rust_gen"
+}
+
+func (m *syspropLibrary) rustGenStubName() string {
+ return "lib" + m.rustCrateName() + "_rust"
+}
+
+func (m *syspropLibrary) rustCrateName() string {
+ moduleName := strings.ToLower(m.BaseModuleName())
+ moduleName = strings.ReplaceAll(moduleName, "-", "_")
+ moduleName = strings.ReplaceAll(moduleName, ".", "_")
+ return moduleName
+}
+
func (m *syspropLibrary) BaseModuleName() string {
return m.ModuleBase.Name()
}
@@ -436,6 +527,18 @@
Min_sdk_version *string
}
+type rustLibraryProperties struct {
+ Name *string
+ Srcs []string
+ Installable *bool
+ Crate_name string
+ Rustlibs []string
+ Vendor_available *bool
+ Product_available *bool
+ Apex_available []string
+ Min_sdk_version *string
+}
+
func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) {
if len(m.properties.Srcs) == 0 {
ctx.PropertyErrorf("srcs", "sysprop_library must specify srcs")
@@ -564,6 +667,28 @@
})
}
+ // Generate a Rust implementation library.
+ ctx.CreateModule(syspropRustGenFactory, &syspropGenProperties{
+ Srcs: m.properties.Srcs,
+ Scope: scope,
+ Name: proptools.StringPtr(m.rustGenModuleName()),
+ Check_api: proptools.StringPtr(ctx.ModuleName()),
+ })
+ rustProps := rustLibraryProperties{
+ Name: proptools.StringPtr(m.rustGenStubName()),
+ Srcs: []string{":" + m.rustGenModuleName()},
+ Installable: proptools.BoolPtr(false),
+ Crate_name: m.rustCrateName(),
+ Rustlibs: []string{
+ "librustutils",
+ },
+ Vendor_available: m.properties.Vendor_available,
+ Product_available: m.properties.Product_available,
+ Apex_available: m.ApexProperties.Apex_available,
+ Min_sdk_version: proptools.StringPtr("29"),
+ }
+ ctx.CreateModule(rust.RustLibraryFactory, &rustProps)
+
// syspropLibraries will be used by property_contexts to check types.
// Record absolute paths of sysprop_library to prevent soong_namespace problem.
if m.ExportedToMake() {
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index e5b3dea..9dd696f 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -22,6 +22,7 @@
"android/soong/android"
"android/soong/cc"
"android/soong/java"
+ "android/soong/rust"
"github.com/google/blueprint/proptools"
)
@@ -46,18 +47,6 @@
recovery_available: true,
}
- cc_library {
- name: "liblog",
- no_libcrt: true,
- nocrt: true,
- system_shared_libs: [],
- recovery_available: true,
- host_supported: true,
- llndk: {
- symbol_file: "liblog.map.txt",
- }
- }
-
java_library {
name: "sysprop-library-stub-platform",
sdk_version: "core_current",
@@ -74,6 +63,15 @@
product_specific: true,
sdk_version: "core_current",
}
+
+ rust_library {
+ name: "librustutils",
+ crate_name: "rustutils",
+ srcs: ["librustutils/lib.rs"],
+ product_available: true,
+ vendor_available: true,
+ min_sdk_version: "29",
+ }
`
mockFS := android.MockFS{
@@ -115,11 +113,14 @@
"android/sysprop/PlatformProperties.sysprop": nil,
"com/android/VendorProperties.sysprop": nil,
"com/android2/OdmProperties.sysprop": nil,
+
+ "librustutils/lib.rs": nil,
}
result := android.GroupFixturePreparers(
cc.PrepareForTestWithCcDefaultModules,
java.PrepareForTestWithJavaDefaultModules,
+ rust.PrepareForTestWithRustDefaultModules,
PrepareForTestWithSyspropBuildComponents,
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.DeviceSystemSdkVersions = []string{"28"}
@@ -356,6 +357,10 @@
javaModule := result.ModuleForTests("sysprop-platform", "android_common").Module().(*java.Library)
propFromJava := javaModule.ApexProperties.Apex_available
android.AssertDeepEquals(t, "apex_available forwarding to java module", expected, propFromJava)
+
+ rustModule := result.ModuleForTests("libsysprop_platform_rust", "android_arm64_armv8-a_rlib_rlib-std").Module().(*rust.Module)
+ propFromRust := rustModule.ApexProperties.Apex_available
+ android.AssertDeepEquals(t, "apex_available forwarding to rust module", expected, propFromRust)
}
func TestMinSdkVersionIsForwarded(t *testing.T) {
@@ -371,6 +376,9 @@
java: {
min_sdk_version: "30",
},
+ rust: {
+ min_sdk_version: "29",
+ }
}
`)
@@ -381,4 +389,8 @@
javaModule := result.ModuleForTests("sysprop-platform", "android_common").Module().(*java.Library)
propFromJava := javaModule.MinSdkVersionString()
android.AssertStringEquals(t, "min_sdk_version forwarding to java module", "30", propFromJava)
+
+ rustModule := result.ModuleForTests("libsysprop_platform_rust", "android_arm64_armv8-a_rlib_rlib-std").Module().(*rust.Module)
+ propFromRust := proptools.String(rustModule.Properties.Min_sdk_version)
+ android.AssertStringEquals(t, "min_sdk_version forwarding to rust module", "29", propFromRust)
}
diff --git a/tradefed/Android.bp b/tradefed/Android.bp
index f0336a3..e852584 100644
--- a/tradefed/Android.bp
+++ b/tradefed/Android.bp
@@ -13,6 +13,7 @@
"autogen.go",
"config.go",
"makevars.go",
+ "providers.go",
],
pluginFor: ["soong_build"],
}
diff --git a/tradefed/providers.go b/tradefed/providers.go
new file mode 100644
index 0000000..f41e09e
--- /dev/null
+++ b/tradefed/providers.go
@@ -0,0 +1,21 @@
+package tradefed
+
+import (
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+)
+
+// Output files we need from a base test that we derive from.
+type BaseTestProviderData struct {
+ // data files and apps for android_test
+ InstalledFiles android.Paths
+ // apk for android_test
+ OutputFile android.Path
+ // Either handwritten or generated TF xml.
+ TestConfig android.Path
+ // Other modules we require to be installed to run tests. We expect base to build them.
+ HostRequiredModuleNames []string
+}
+
+var BaseTestProviderKey = blueprint.NewProvider[BaseTestProviderData]()
diff --git a/tradefed_modules/Android.bp b/tradefed_modules/Android.bp
new file mode 100644
index 0000000..9969ae2
--- /dev/null
+++ b/tradefed_modules/Android.bp
@@ -0,0 +1,21 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-tradefed-modules",
+ pkgPath: "android/soong/tradefed_modules",
+ deps: [
+ "blueprint",
+ "soong-android",
+ "soong-java",
+ "soong-tradefed",
+ ],
+ srcs: [
+ "test_module_config.go",
+ ],
+ testSrcs: [
+ "test_module_config_test.go",
+ ],
+ pluginFor: ["soong_build"],
+}
diff --git a/tradefed_modules/test_module_config.go b/tradefed_modules/test_module_config.go
new file mode 100644
index 0000000..ba6ab94
--- /dev/null
+++ b/tradefed_modules/test_module_config.go
@@ -0,0 +1,219 @@
+package tradefed_modules
+
+import (
+ "android/soong/android"
+ "android/soong/tradefed"
+ "encoding/json"
+ "fmt"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+func init() {
+ RegisterTestModuleConfigBuildComponents(android.InitRegistrationContext)
+}
+
+// Register the license_kind module type.
+func RegisterTestModuleConfigBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("test_module_config", TestModuleConfigFactory)
+}
+
+type testModuleConfigModule struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+ base android.Module
+
+ tradefedProperties
+
+ // Our updated testConfig.
+ testConfig android.OutputPath
+ manifest android.InstallPath
+ provider tradefed.BaseTestProviderData
+}
+
+// Properties to list in Android.bp for this module.
+type tradefedProperties struct {
+ // Module name of the base test that we will run.
+ Base *string `android:"path,arch_variant"`
+
+ // Tradefed Options to add to tradefed xml when not one of the include or exclude filter or property.
+ // Sample: [{name: "TestRunnerOptionName", value: "OptionValue" }]
+ Options []tradefed.Option
+
+ // List of tradefed include annotations to add to tradefed xml, like "android.platform.test.annotations.Presubmit".
+ // Tests will be restricted to those matching an include_annotation or include_filter.
+ Include_annotations []string
+
+ // List of tradefed include annotations to add to tradefed xml, like "android.support.test.filters.FlakyTest".
+ // Tests matching an exclude annotation or filter will be skipped.
+ Exclude_annotations []string
+
+ // List of tradefed include filters to add to tradefed xml, like "fully.qualified.class#method".
+ // Tests will be restricted to those matching an include_annotation or include_filter.
+ Include_filters []string
+
+ // List of tradefed exclude filters to add to tradefed xml, like "fully.qualified.class#method".
+ // Tests matching an exclude annotation or filter will be skipped.
+ Exclude_filters []string
+
+ // List of compatibility suites (for example "cts", "vts") that the module should be
+ // installed into.
+ Test_suites []string
+}
+
+type dependencyTag struct {
+ blueprint.BaseDependencyTag
+ name string
+}
+
+var (
+ testModuleConfigTag = dependencyTag{name: "TestModuleConfigBase"}
+ pctx = android.NewPackageContext("android/soong/tradefed_modules")
+)
+
+func (m *testModuleConfigModule) InstallInTestcases() bool {
+ return true
+}
+
+func (m *testModuleConfigModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+ ctx.AddDependency(ctx.Module(), testModuleConfigTag, *m.Base)
+}
+
+// Takes base's Tradefed Config xml file and generates a new one with the test properties
+// appeneded from this module.
+// Rewrite the name of the apk in "test-file-name" to be our module's name, rather than the original one.
+func (m *testModuleConfigModule) fixTestConfig(ctx android.ModuleContext, baseTestConfig android.Path) android.OutputPath {
+ // Test safe to do when no test_runner_options, but check for that earlier?
+ fixedConfig := android.PathForModuleOut(ctx, "test_config_fixer", ctx.ModuleName()+".config")
+ rule := android.NewRuleBuilder(pctx, ctx)
+ command := rule.Command().BuiltTool("test_config_fixer").Input(baseTestConfig).Output(fixedConfig)
+ options := m.composeOptions()
+ if len(options) == 0 {
+ ctx.ModuleErrorf("Test options must be given when using test_module_config. Set include/exclude filter or annotation.")
+ }
+ xmlTestModuleConfigSnippet, _ := json.Marshal(options)
+ escaped := proptools.NinjaAndShellEscape(string(xmlTestModuleConfigSnippet))
+ command.FlagWithArg("--test-file-name=", ctx.ModuleName()+".apk").
+ FlagWithArg("--orig-test-file-name=", *m.tradefedProperties.Base+".apk").
+ FlagWithArg("--test-runner-options=", escaped)
+ rule.Build("fix_test_config", "fix test config")
+ return fixedConfig.OutputPath
+}
+
+// Convert --exclude_filters: ["filter1", "filter2"] ->
+// [ Option{Name: "exclude-filters", Value: "filter1"}, Option{Name: "exclude-filters", Value: "filter2"},
+// ... + include + annotations ]
+func (m *testModuleConfigModule) composeOptions() []tradefed.Option {
+ options := m.Options
+ for _, e := range m.Exclude_filters {
+ options = append(options, tradefed.Option{Name: "exclude-filter", Value: e})
+ }
+ for _, i := range m.Include_filters {
+ options = append(options, tradefed.Option{Name: "include-filter", Value: i})
+ }
+ for _, e := range m.Exclude_annotations {
+ options = append(options, tradefed.Option{Name: "exclude-annotation", Value: e})
+ }
+ for _, i := range m.Include_annotations {
+ options = append(options, tradefed.Option{Name: "include-annotation", Value: i})
+ }
+ return options
+}
+
+// Files to write and where they come from:
+// 1) test_module_config.manifest
+// - Leave a trail of where we got files from in case other tools need it.
+//
+// 2) $Module.config
+// - comes from base's module.config (AndroidTest.xml), and then we add our test_options.
+// provider.TestConfig
+// [rules via soong_app_prebuilt]
+//
+// 3) $ARCH/$Module.apk
+// - comes from base
+// provider.OutputFile
+// [rules via soong_app_prebuilt]
+//
+// 4) [bases data]
+// - We copy all of bases data (like helper apks) to our install directory too.
+// Since we call AndroidMkEntries on base, it will write out LOCAL_COMPATIBILITY_SUPPORT_FILES
+// with this data and app_prebuilt.mk will generate the rules to copy it from base.
+// We have no direct rules here to add to ninja.
+//
+// If we change to symlinks, this all needs to change.
+func (m *testModuleConfigModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+
+ ctx.VisitDirectDepsWithTag(testModuleConfigTag, func(dep android.Module) {
+ if provider, ok := android.OtherModuleProvider(ctx, dep, tradefed.BaseTestProviderKey); ok {
+ m.base = dep
+ m.provider = provider
+ } else {
+ ctx.ModuleErrorf("The base module '%s' does not provide test BaseTestProviderData. Only 'android_test' modules are supported.", dep.Name())
+ return
+ }
+ })
+
+ // 1) A manifest file listing the base.
+ installDir := android.PathForModuleInstall(ctx, ctx.ModuleName())
+ out := android.PathForModuleOut(ctx, "test_module_config.manifest")
+ android.WriteFileRule(ctx, out, fmt.Sprintf("{%q: %q}", "base", *m.tradefedProperties.Base))
+ ctx.InstallFile(installDir, out.Base(), out)
+
+ // 2) Module.config / AndroidTest.xml
+ // Note, there is still a "test-tag" element with base's module name, but
+ // Tradefed team says its ignored anyway.
+ m.testConfig = m.fixTestConfig(ctx, m.provider.TestConfig)
+
+ // 3) Write ARCH/Module.apk in testcases.
+ // Handled by soong_app_prebuilt and OutputFile in entries.
+ // Nothing to do here.
+
+ // 4) Copy base's data files.
+ // Handled by soong_app_prebuilt and LOCAL_COMPATIBILITY_SUPPORT_FILES.
+ // Nothing to do here.
+}
+
+func TestModuleConfigFactory() android.Module {
+ module := &testModuleConfigModule{}
+
+ module.AddProperties(&module.tradefedProperties)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+
+ return module
+}
+
+// Implements android.AndroidMkEntriesProvider
+var _ android.AndroidMkEntriesProvider = (*testModuleConfigModule)(nil)
+
+func (m *testModuleConfigModule) AndroidMkEntries() []android.AndroidMkEntries {
+ // We rely on base writing LOCAL_COMPATIBILITY_SUPPORT_FILES for its data files
+ entriesList := m.base.(android.AndroidMkEntriesProvider).AndroidMkEntries()
+ entries := &entriesList[0]
+ entries.OutputFile = android.OptionalPathForPath(m.provider.OutputFile)
+ entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE", m.Name()) // out module name, not base's
+
+ // Out update config file with extra options.
+ entries.SetPath("LOCAL_FULL_TEST_CONFIG", m.testConfig)
+ entries.SetString("LOCAL_MODULE_TAGS", "tests")
+ // Required for atest to run additional tradefed testtypes
+ entries.AddStrings("LOCAL_HOST_REQUIRED_MODULES", m.provider.HostRequiredModuleNames...)
+
+ // Clear the JNI symbols because they belong to base not us. Either transform the names in the string
+ // or clear the variable because we don't need it, we are copying bases libraries not generating
+ // new ones.
+ entries.SetString("LOCAL_SOONG_JNI_LIBS_SYMBOLS", "")
+
+ // Don't append to base's test-suites, only use the ones we define, so clear it before
+ // appending to it.
+ entries.SetString("LOCAL_COMPATIBILITY_SUITE", "")
+ if len(m.tradefedProperties.Test_suites) > 0 {
+ entries.AddCompatibilityTestSuites(m.tradefedProperties.Test_suites...)
+ } else {
+ entries.AddCompatibilityTestSuites("null-suite")
+ }
+ })
+ return entriesList
+}
diff --git a/tradefed_modules/test_module_config_test.go b/tradefed_modules/test_module_config_test.go
new file mode 100644
index 0000000..ff53043
--- /dev/null
+++ b/tradefed_modules/test_module_config_test.go
@@ -0,0 +1,204 @@
+// Copyright 2024 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 tradefed_modules
+
+import (
+ "android/soong/android"
+ "android/soong/java"
+ "strings"
+ "testing"
+)
+
+const bp = `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ }
+
+ android_test_helper_app {
+ name: "HelperApp",
+ srcs: ["helper.java"],
+ }
+
+ android_test {
+ name: "base",
+ sdk_version: "current",
+ data: [":HelperApp", "data/testfile"],
+ }
+
+ test_module_config {
+ name: "derived_test",
+ base: "base",
+ exclude_filters: ["android.test.example.devcodelab.DevCodelabTest#testHelloFail"],
+ include_annotations: ["android.platform.test.annotations.LargeTest"],
+ }
+
+`
+
+// Ensure we create files needed and set the AndroidMkEntries needed
+func TestModuleConfigAndroidTest(t *testing.T) {
+
+ ctx := android.GroupFixturePreparers(
+ java.PrepareForTestWithJavaDefaultModules,
+ android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
+ ).RunTestWithBp(t, bp)
+
+ derived := ctx.ModuleForTests("derived_test", "android_common")
+ // Assert there are rules to create these files.
+ derived.Output("test_module_config.manifest")
+ derived.Output("test_config_fixer/derived_test.config")
+
+ // Ensure some basic rules exist.
+ ctx.ModuleForTests("base", "android_common").Output("package-res.apk")
+ entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, derived.Module())[0]
+
+ // Ensure some entries from base are there, specifically support files for data and helper apps.
+ assertEntryPairValues(t, entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"], []string{"HelperApp.apk", "data/testfile"})
+
+ // And some new derived entries are there.
+ android.AssertArrayString(t, "", entries.EntryMap["LOCAL_MODULE_TAGS"], []string{"tests"})
+
+ // And ones we override
+ android.AssertArrayString(t, "", entries.EntryMap["LOCAL_SOONG_JNI_LIBS_SYMBOLS"], []string{""})
+
+ android.AssertStringMatches(t, "", entries.EntryMap["LOCAL_FULL_TEST_CONFIG"][0], "derived_test/android_common/test_config_fixer/derived_test.config")
+}
+
+// Make sure we call test-config-fixer with the right args.
+func TestModuleConfigOptions(t *testing.T) {
+
+ ctx := android.GroupFixturePreparers(
+ java.PrepareForTestWithJavaDefaultModules,
+ android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
+ ).RunTestWithBp(t, bp)
+
+ // Check that we generate a rule to make a new AndroidTest.xml/Module.config file.
+ derived := ctx.ModuleForTests("derived_test", "android_common")
+ rule_cmd := derived.Rule("fix_test_config").RuleParams.Command
+ android.AssertStringDoesContain(t, "Bad FixConfig rule inputs", rule_cmd,
+ `--test-file-name=derived_test.apk --orig-test-file-name=base.apk --test-runner-options='[{"Name":"exclude-filter","Key":"","Value":"android.test.example.devcodelab.DevCodelabTest#testHelloFail"},{"Name":"include-annotation","Key":"","Value":"android.platform.test.annotations.LargeTest"}]'`)
+}
+
+// Ensure we error for a base we don't support.
+func TestModuleConfigBadBaseShouldFail(t *testing.T) {
+ badBp := `
+ java_test_host {
+ name: "base",
+ srcs: ["a.java"],
+ }
+
+ test_module_config {
+ name: "derived_test",
+ base: "base",
+ exclude_filters: ["android.test.example.devcodelab.DevCodelabTest#testHelloFail"],
+ include_annotations: ["android.platform.test.annotations.LargeTest"],
+ }`
+
+ ctx := android.GroupFixturePreparers(
+ java.PrepareForTestWithJavaDefaultModules,
+ android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
+ ).ExtendWithErrorHandler(
+ android.FixtureExpectsAtLeastOneErrorMatchingPattern("does not provide test BaseTestProviderData")).
+ RunTestWithBp(t, badBp)
+
+ ctx.ModuleForTests("derived_test", "android_common")
+}
+
+// Ensure we error for a base we don't support.
+func TestModuleConfigNoFiltersOrAnnotationsShouldFail(t *testing.T) {
+ badBp := `
+ android_test {
+ name: "base",
+ sdk_version: "current",
+ srcs: ["a.java"],
+ }
+
+ test_module_config {
+ name: "derived_test",
+ base: "base",
+ }`
+
+ ctx := android.GroupFixturePreparers(
+ java.PrepareForTestWithJavaDefaultModules,
+ android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
+ ).ExtendWithErrorHandler(
+ android.FixtureExpectsAtLeastOneErrorMatchingPattern("Test options must be given")).
+ RunTestWithBp(t, badBp)
+
+ ctx.ModuleForTests("derived_test", "android_common")
+}
+
+func TestModuleConfigMultipleDerivedTestsWriteDistinctMakeEntries(t *testing.T) {
+ multiBp := `
+ android_test {
+ name: "base",
+ sdk_version: "current",
+ srcs: ["a.java"],
+ }
+
+ test_module_config {
+ name: "derived_test",
+ base: "base",
+ include_annotations: ["android.platform.test.annotations.LargeTest"],
+ }
+
+ test_module_config {
+ name: "another_derived_test",
+ base: "base",
+ include_annotations: ["android.platform.test.annotations.LargeTest"],
+ }`
+
+ ctx := android.GroupFixturePreparers(
+ java.PrepareForTestWithJavaDefaultModules,
+ android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
+ ).RunTestWithBp(t, multiBp)
+
+ {
+ derived := ctx.ModuleForTests("derived_test", "android_common")
+ entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, derived.Module())[0]
+ // All these should be the same in both derived tests
+ assertEntryPairValues(t, entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"], []string{"HelperApp.apk", "data/testfile"})
+ android.AssertArrayString(t, "", entries.EntryMap["LOCAL_SOONG_JNI_LIBS_SYMBOLS"], []string{""})
+ // Except this one, which points to the updated tradefed xml file.
+ android.AssertStringMatches(t, "", entries.EntryMap["LOCAL_FULL_TEST_CONFIG"][0], "derived_test/android_common/test_config_fixer/derived_test.config")
+ // And this one, the module name.
+ android.AssertArrayString(t, "", entries.EntryMap["LOCAL_MODULE"], []string{"derived_test"})
+ }
+
+ {
+ derived := ctx.ModuleForTests("another_derived_test", "android_common")
+ entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, derived.Module())[0]
+ // All these should be the same in both derived tests
+ assertEntryPairValues(t, entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"], []string{"HelperApp.apk", "data/testfile"})
+ android.AssertArrayString(t, "", entries.EntryMap["LOCAL_SOONG_JNI_LIBS_SYMBOLS"], []string{""})
+ // Except this one, which points to the updated tradefed xml file.
+ android.AssertStringMatches(t, "", entries.EntryMap["LOCAL_FULL_TEST_CONFIG"][0], "another_derived_test/android_common/test_config_fixer/another_derived_test.config")
+ // And this one, the module name.
+ android.AssertArrayString(t, "", entries.EntryMap["LOCAL_MODULE"], []string{"another_derived_test"})
+ }
+}
+
+// Use for situations where the entries map contains pairs: [srcPath:installedPath1, srcPath2:installedPath2]
+// and we want to compare the RHS of the pairs, i.e. installedPath1, installedPath2
+func assertEntryPairValues(t *testing.T, actual []string, expected []string) {
+ for i, e := range actual {
+ parts := strings.Split(e, ":")
+ if len(parts) != 2 {
+ t.Errorf("Expected entry to have a value delimited by :, received: %s", e)
+ return
+ }
+ android.AssertStringEquals(t, "", parts[1], expected[i])
+ }
+}
diff --git a/ui/build/config.go b/ui/build/config.go
index e29d239..3143b6b 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -75,7 +75,6 @@
queryview bool
reportMkMetrics bool // Collect and report mk2bp migration progress metrics.
soongDocs bool
- multitreeBuild bool // This is a multitree build.
skipConfig bool
skipKati bool
skipKatiNinja bool
@@ -387,22 +386,21 @@
// Configure Java-related variables, including adding it to $PATH
java8Home := filepath.Join("prebuilts/jdk/jdk8", ret.HostPrebuiltTag())
- java17Home := filepath.Join("prebuilts/jdk/jdk17", ret.HostPrebuiltTag())
java21Home := filepath.Join("prebuilts/jdk/jdk21", ret.HostPrebuiltTag())
javaHome := func() string {
if override, ok := ret.environ.Get("OVERRIDE_ANDROID_JAVA_HOME"); ok {
return override
}
- if ret.environ.IsEnvTrue("EXPERIMENTAL_USE_OPENJDK21_TOOLCHAIN") {
- return java21Home
- }
if toolchain11, ok := ret.environ.Get("EXPERIMENTAL_USE_OPENJDK11_TOOLCHAIN"); ok && toolchain11 != "true" {
- ctx.Fatalln("The environment variable EXPERIMENTAL_USE_OPENJDK11_TOOLCHAIN is no longer supported. An OpenJDK 11 toolchain is now the global default.")
+ ctx.Fatalln("The environment variable EXPERIMENTAL_USE_OPENJDK11_TOOLCHAIN is no longer supported. An OpenJDK 21 toolchain is now the global default.")
}
if toolchain17, ok := ret.environ.Get("EXPERIMENTAL_USE_OPENJDK17_TOOLCHAIN"); ok && toolchain17 != "true" {
- ctx.Fatalln("The environment variable EXPERIMENTAL_USE_OPENJDK17_TOOLCHAIN is no longer supported. An OpenJDK 17 toolchain is now the global default.")
+ ctx.Fatalln("The environment variable EXPERIMENTAL_USE_OPENJDK17_TOOLCHAIN is no longer supported. An OpenJDK 21 toolchain is now the global default.")
}
- return java17Home
+ if toolchain21, ok := ret.environ.Get("EXPERIMENTAL_USE_OPENJDK21_TOOLCHAIN"); ok && toolchain21 != "true" {
+ ctx.Fatalln("The environment variable EXPERIMENTAL_USE_OPENJDK21_TOOLCHAIN is no longer supported. An OpenJDK 21 toolchain is now the global default.")
+ }
+ return java21Home
}()
absJavaHome := absPath(ctx, javaHome)
@@ -424,10 +422,6 @@
// zip files produced by soong_zip. Disable zipbomb detection.
ret.environ.Set("UNZIP_DISABLE_ZIPBOMB_DETECTION", "TRUE")
- if ret.MultitreeBuild() {
- ret.environ.Set("MULTITREE_BUILD", "true")
- }
-
outDir := ret.OutDir()
buildDateTimeFile := filepath.Join(outDir, "build_date.txt")
if buildDateTime, ok := ret.environ.Get("BUILD_DATETIME"); ok && buildDateTime != "" {
@@ -789,8 +783,6 @@
c.skipMetricsUpload = true
} else if arg == "--mk-metrics" {
c.reportMkMetrics = true
- } else if arg == "--multitree-build" {
- c.multitreeBuild = true
} else if arg == "--search-api-dir" {
c.searchApiDir = true
} else if strings.HasPrefix(arg, "--ninja_weight_source=") {
@@ -1095,10 +1087,6 @@
return c.verbose
}
-func (c *configImpl) MultitreeBuild() bool {
- return c.multitreeBuild
-}
-
func (c *configImpl) NinjaWeightListSource() NinjaWeightListSource {
return c.ninjaWeightListSource
}
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index 5182b12..b1222fe 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -860,23 +860,24 @@
}
func TestGetConfigArgsBuildModulesInDirectory(t *testing.T) {
- tests := []buildActionTestCase{{
- description: "normal execution in a directory",
- dirsInTrees: []string{"0/1/2"},
- buildFiles: []string{"0/1/2/Android.mk"},
- args: []string{"fake-module"},
- curDir: "0/1/2",
- tidyOnly: "",
- expectedArgs: []string{"fake-module", "MODULES-IN-0-1-2"},
- }, {
- description: "build file in parent directory",
- dirsInTrees: []string{"0/1/2"},
- buildFiles: []string{"0/1/Android.mk"},
- args: []string{},
- curDir: "0/1/2",
- tidyOnly: "",
- expectedArgs: []string{"MODULES-IN-0-1"},
- },
+ tests := []buildActionTestCase{
+ {
+ description: "normal execution in a directory",
+ dirsInTrees: []string{"0/1/2"},
+ buildFiles: []string{"0/1/2/Android.mk"},
+ args: []string{"fake-module"},
+ curDir: "0/1/2",
+ tidyOnly: "",
+ expectedArgs: []string{"fake-module", "MODULES-IN-0-1-2"},
+ }, {
+ description: "build file in parent directory",
+ dirsInTrees: []string{"0/1/2"},
+ buildFiles: []string{"0/1/Android.mk"},
+ args: []string{},
+ curDir: "0/1/2",
+ tidyOnly: "",
+ expectedArgs: []string{"MODULES-IN-0-1"},
+ },
{
description: "build file in parent directory, multiple module names passed in",
dirsInTrees: []string{"0/1/2"},
@@ -903,15 +904,6 @@
tidyOnly: "",
expectedArgs: []string{},
}, {
- description: "multitree build action executed at root directory",
- dirsInTrees: []string{},
- buildFiles: []string{},
- rootSymlink: false,
- args: []string{"--multitree-build"},
- curDir: ".",
- tidyOnly: "",
- expectedArgs: []string{"--multitree-build"},
- }, {
description: "build action executed at root directory in symlink",
dirsInTrees: []string{},
buildFiles: []string{},
@@ -953,7 +945,8 @@
curDir: "",
tidyOnly: "",
expectedArgs: []string{"-j", "-k", "fake_module"},
- }}
+ },
+ }
for _, tt := range tests {
t.Run("build action BUILD_MODULES_IN_DIR, "+tt.description, func(t *testing.T) {
testGetConfigArgs(t, tt, BUILD_MODULES_IN_A_DIRECTORY)
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index fa04207..5142a41 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -163,7 +163,7 @@
return
}
fmt.Fprintln(ctx.Writer, "")
- fmt.Fprintln(ctx.Writer, "\033[33mWARNING: Missing LOAS credentials, please run `gcert`. This will result in failing builds in the future, see go/rbe-android-default-announcement.\033[0m")
+ fmt.Fprintln(ctx.Writer, "\033[33mWARNING: Missing LOAS credentials, please run `gcert`. This is required for a successful build execution. See go/rbe-android-default-announcement for more information.\033[0m")
fmt.Fprintln(ctx.Writer, "")
}
diff --git a/ui/build/soong.go b/ui/build/soong.go
index a201ac5..79584c6 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -197,9 +197,6 @@
commonArgs = append(commonArgs, "-t")
}
- if pb.config.multitreeBuild {
- commonArgs = append(commonArgs, "--multitree-build")
- }
if pb.config.buildFromSourceStub {
commonArgs = append(commonArgs, "--build-from-source-stub")
}
@@ -305,9 +302,6 @@
if config.EmptyNinjaFile() {
mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--empty-ninja-file")
}
- if config.MultitreeBuild() {
- mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--multitree-build")
- }
if config.buildFromSourceStub {
mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--build-from-source-stub")
}