Merge "Add a new x86(_64) arch variant "goldmont-without-xsaves"" into main
diff --git a/OWNERS b/OWNERS
index 58edc89..01025fb 100644
--- a/OWNERS
+++ b/OWNERS
@@ -12,4 +12,6 @@
mrziwang@google.com
spandandas@google.com
weiwli@google.com
-yudiliu@google.com
\ No newline at end of file
+yudiliu@google.com
+
+per-file build/soong/ui/build/androidmk_denylist.go = joeo@google.com, weiwli@google.com
\ No newline at end of file
diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go
index 697dc22..b55d7bf 100644
--- a/aconfig/aconfig_declarations.go
+++ b/aconfig/aconfig_declarations.go
@@ -112,38 +112,17 @@
return sb.String()
}
-// Provider published by aconfig_value_set
-type DeclarationsProviderData struct {
- Package string
- Container string
- IntermediateCacheOutputPath android.WritablePath
- IntermediateDumpOutputPath android.WritablePath
-}
-
-var DeclarationsProviderKey = blueprint.NewProvider(DeclarationsProviderData{})
-
-// This is used to collect the aconfig declarations info on the transitive closure,
-// the data is keyed on the container.
-type TransitiveDeclarationsInfo struct {
- AconfigFiles map[string]android.Paths
-}
-
-var TransitiveDeclarationsInfoProvider = blueprint.NewProvider(TransitiveDeclarationsInfo{})
-
func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
valuesFiles := make([]android.Path, 0)
ctx.VisitDirectDeps(func(dep android.Module) {
- if !ctx.OtherModuleHasProvider(dep, valueSetProviderKey) {
- // Other modules get injected as dependencies too, for example the license modules
- return
- }
- depData := ctx.OtherModuleProvider(dep, valueSetProviderKey).(valueSetProviderData)
- paths, ok := depData.AvailablePackages[module.properties.Package]
- if ok {
- valuesFiles = append(valuesFiles, paths...)
- for _, path := range paths {
- module.properties.Values = append(module.properties.Values, path.String())
+ if depData, ok := android.OtherModuleProvider(ctx, dep, valueSetProviderKey); ok {
+ paths, ok := depData.AvailablePackages[module.properties.Package]
+ if ok {
+ valuesFiles = append(valuesFiles, paths...)
+ for _, path := range paths {
+ module.properties.Values = append(module.properties.Values, path.String())
+ }
}
}
})
@@ -177,7 +156,7 @@
Description: "aconfig_text",
})
- ctx.SetProvider(DeclarationsProviderKey, DeclarationsProviderData{
+ android.SetProvider(ctx, android.AconfigDeclarationsProviderKey, android.AconfigDeclarationsProviderData{
Package: module.properties.Package,
Container: module.properties.Container,
IntermediateCacheOutputPath: intermediateCacheFilePath,
@@ -185,48 +164,18 @@
})
}
-func CollectDependencyAconfigFiles(ctx android.ModuleContext, mergedAconfigFiles *map[string]android.Paths) {
- if *mergedAconfigFiles == nil {
- *mergedAconfigFiles = make(map[string]android.Paths)
- }
- ctx.VisitDirectDeps(func(module android.Module) {
- if dep := ctx.OtherModuleProvider(module, DeclarationsProviderKey).(DeclarationsProviderData); dep.IntermediateCacheOutputPath != nil {
- (*mergedAconfigFiles)[dep.Container] = append((*mergedAconfigFiles)[dep.Container], dep.IntermediateCacheOutputPath)
- return
- }
- if dep := ctx.OtherModuleProvider(module, TransitiveDeclarationsInfoProvider).(TransitiveDeclarationsInfo); len(dep.AconfigFiles) > 0 {
- for container, v := range dep.AconfigFiles {
- (*mergedAconfigFiles)[container] = append((*mergedAconfigFiles)[container], v...)
- }
- }
- })
- for container, aconfigFiles := range *mergedAconfigFiles {
- (*mergedAconfigFiles)[container] = mergeAconfigFiles(ctx, aconfigFiles)
+func SetAconfigFileMkEntries(m *android.ModuleBase, entries *android.AndroidMkEntries, aconfigFiles map[string]android.Paths) {
+ // TODO(b/311155208): The default container here should be system.
+ container := ""
+
+ if m.SocSpecific() {
+ container = "vendor"
+ } else if m.ProductSpecific() {
+ container = "product"
+ } else if m.SystemExtSpecific() {
+ container = "system_ext"
}
- ctx.SetProvider(TransitiveDeclarationsInfoProvider, TransitiveDeclarationsInfo{
- AconfigFiles: *mergedAconfigFiles,
- })
-}
-
-func mergeAconfigFiles(ctx android.ModuleContext, inputs android.Paths) android.Paths {
- inputs = android.LastUniquePaths(inputs)
- if len(inputs) == 1 {
- return android.Paths{inputs[0]}
- }
-
- output := android.PathForModuleOut(ctx, "aconfig_merged.pb")
-
- ctx.Build(pctx, android.BuildParams{
- Rule: mergeAconfigFilesRule,
- Description: "merge aconfig files",
- Inputs: inputs,
- Output: output,
- Args: map[string]string{
- "flags": android.JoinWithPrefix(inputs.Strings(), "--cache "),
- },
- })
-
- return android.Paths{output}
+ entries.SetPaths("LOCAL_ACONFIG_FILES", aconfigFiles[container])
}
diff --git a/aconfig/aconfig_declarations_test.go b/aconfig/aconfig_declarations_test.go
index 9035c71..d508af7 100644
--- a/aconfig/aconfig_declarations_test.go
+++ b/aconfig/aconfig_declarations_test.go
@@ -38,7 +38,7 @@
module := result.ModuleForTests("module_name", "").Module().(*DeclarationsModule)
// Check that the provider has the right contents
- depData := result.ModuleProvider(module, DeclarationsProviderKey).(DeclarationsProviderData)
+ depData, _ := android.SingletonModuleProvider(result, module, android.AconfigDeclarationsProviderKey)
android.AssertStringEquals(t, "package", depData.Package, "com.example.package")
android.AssertStringEquals(t, "container", depData.Container, "com.android.foo")
if !strings.HasSuffix(depData.IntermediateCacheOutputPath.String(), "/intermediate.pb") {
diff --git a/aconfig/aconfig_value_set.go b/aconfig/aconfig_value_set.go
index 94c322a..7ba76c0 100644
--- a/aconfig/aconfig_value_set.go
+++ b/aconfig/aconfig_value_set.go
@@ -54,7 +54,7 @@
AvailablePackages map[string]android.Paths
}
-var valueSetProviderKey = blueprint.NewProvider(valueSetProviderData{})
+var valueSetProviderKey = blueprint.NewProvider[valueSetProviderData]()
func (module *ValueSetModule) DepsMutator(ctx android.BottomUpMutatorContext) {
deps := ctx.AddDependency(ctx.Module(), valueSetTag, module.properties.Values...)
@@ -73,18 +73,14 @@
// to append values to their aconfig actions.
packages := make(map[string]android.Paths)
ctx.VisitDirectDeps(func(dep android.Module) {
- if !ctx.OtherModuleHasProvider(dep, valuesProviderKey) {
- // Other modules get injected as dependencies too, for example the license modules
- return
+ if depData, ok := android.OtherModuleProvider(ctx, dep, valuesProviderKey); ok {
+ srcs := make([]android.Path, len(depData.Values))
+ copy(srcs, depData.Values)
+ packages[depData.Package] = srcs
}
- depData := ctx.OtherModuleProvider(dep, valuesProviderKey).(valuesProviderData)
-
- srcs := make([]android.Path, len(depData.Values))
- copy(srcs, depData.Values)
- packages[depData.Package] = srcs
})
- ctx.SetProvider(valueSetProviderKey, valueSetProviderData{
+ android.SetProvider(ctx, valueSetProviderKey, valueSetProviderData{
AvailablePackages: packages,
})
}
diff --git a/aconfig/aconfig_value_set_test.go b/aconfig/aconfig_value_set_test.go
index 9127872..7d18999 100644
--- a/aconfig/aconfig_value_set_test.go
+++ b/aconfig/aconfig_value_set_test.go
@@ -38,6 +38,6 @@
module := result.ModuleForTests("module_name", "").Module().(*ValueSetModule)
// Check that the provider has the right contents
- depData := result.ModuleProvider(module, valueSetProviderKey).(valueSetProviderData)
+ depData, _ := android.SingletonModuleProvider(result, module, valueSetProviderKey)
android.AssertStringEquals(t, "AvailablePackages", "blah.aconfig_values", depData.AvailablePackages["foo.package"][0].String())
}
diff --git a/aconfig/aconfig_values.go b/aconfig/aconfig_values.go
index 621aae8..239b10c 100644
--- a/aconfig/aconfig_values.go
+++ b/aconfig/aconfig_values.go
@@ -52,7 +52,7 @@
Values android.Paths
}
-var valuesProviderKey = blueprint.NewProvider(valuesProviderData{})
+var valuesProviderKey = blueprint.NewProvider[valuesProviderData]()
func (module *ValuesModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if len(module.properties.Package) == 0 {
@@ -64,5 +64,5 @@
Package: module.properties.Package,
Values: android.PathsForModuleSrc(ctx, module.properties.Srcs),
}
- ctx.SetProvider(valuesProviderKey, providerData)
+ android.SetProvider(ctx, valuesProviderKey, providerData)
}
diff --git a/aconfig/aconfig_values_test.go b/aconfig/aconfig_values_test.go
index ab457f0..526579c 100644
--- a/aconfig/aconfig_values_test.go
+++ b/aconfig/aconfig_values_test.go
@@ -33,7 +33,7 @@
module := result.ModuleForTests("module_name", "").Module().(*ValuesModule)
// Check that the provider has the right contents
- depData := result.ModuleProvider(module, valuesProviderKey).(valuesProviderData)
+ depData, _ := android.SingletonModuleProvider(result, module, valuesProviderKey)
android.AssertStringEquals(t, "package", "foo.package", depData.Package)
android.AssertPathsEndWith(t, "srcs", []string{"blah.aconfig_values"}, depData.Values)
}
diff --git a/aconfig/all_aconfig_declarations.go b/aconfig/all_aconfig_declarations.go
index 2686e76..36bea0e 100644
--- a/aconfig/all_aconfig_declarations.go
+++ b/aconfig/all_aconfig_declarations.go
@@ -37,10 +37,10 @@
// Find all of the aconfig_declarations modules
var cacheFiles android.Paths
ctx.VisitAllModules(func(module android.Module) {
- if !ctx.ModuleHasProvider(module, DeclarationsProviderKey) {
+ decl, ok := android.SingletonModuleProvider(ctx, module, android.AconfigDeclarationsProviderKey)
+ if !ok {
return
}
- decl := ctx.ModuleProvider(module, DeclarationsProviderKey).(DeclarationsProviderData)
cacheFiles = append(cacheFiles, decl.IntermediateCacheOutputPath)
})
diff --git a/aconfig/codegen/cc_aconfig_library.go b/aconfig/codegen/cc_aconfig_library.go
index 30f6863..8df353d 100644
--- a/aconfig/codegen/cc_aconfig_library.go
+++ b/aconfig/codegen/cc_aconfig_library.go
@@ -15,7 +15,6 @@
package codegen
import (
- "android/soong/aconfig"
"android/soong/android"
"android/soong/cc"
@@ -41,6 +40,7 @@
// default mode is "production", the other accepted modes are:
// "test": to generate test mode version of the library
// "exported": to generate exported mode version of the library
+ // "force-read-only": to generate force-read-only mode version of the library
// an error will be thrown if the mode is not supported
Mode *string
}
@@ -92,7 +92,7 @@
if len(declarationsModules) != 1 {
panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
}
- declarations := ctx.OtherModuleProvider(declarationsModules[0], aconfig.DeclarationsProviderKey).(aconfig.DeclarationsProviderData)
+ declarations, _ := android.OtherModuleProvider(ctx, declarationsModules[0], android.AconfigDeclarationsProviderKey)
// Figure out the generated file paths. This has to match aconfig's codegen_cpp.rs.
this.generatedDir = android.PathForModuleGen(ctx)
@@ -122,7 +122,7 @@
if len(declarationsModules) != 1 {
panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
}
- declarations := ctx.OtherModuleProvider(declarationsModules[0], aconfig.DeclarationsProviderKey).(aconfig.DeclarationsProviderData)
+ declarations, _ := android.OtherModuleProvider(ctx, declarationsModules[0], android.AconfigDeclarationsProviderKey)
mode := proptools.StringDefault(this.properties.Mode, "production")
if !isModeSupported(mode) {
diff --git a/aconfig/codegen/cc_aconfig_library_test.go b/aconfig/codegen/cc_aconfig_library_test.go
index 0c8a969..d762e9b 100644
--- a/aconfig/codegen/cc_aconfig_library_test.go
+++ b/aconfig/codegen/cc_aconfig_library_test.go
@@ -29,6 +29,7 @@
{"mode: `production`,", "production"},
{"mode: `test`,", "test"},
{"mode: `exported`,", "exported"},
+ {"mode: `force-read-only`,", "force-read-only"},
}
func TestCCCodegenMode(t *testing.T) {
@@ -104,3 +105,62 @@
}
`, bpMode))
}
+
+func TestAndroidMkCcLibrary(t *testing.T) {
+ bp := `
+ aconfig_declarations {
+ name: "my_aconfig_declarations_foo",
+ package: "com.example.package",
+ srcs: ["foo.aconfig"],
+ container: "vendor",
+ }
+
+ cc_aconfig_library {
+ name: "my_cc_aconfig_library_foo",
+ aconfig_declarations: "my_aconfig_declarations_foo",
+ vendor_available: true,
+ }
+
+ aconfig_declarations {
+ name: "my_aconfig_declarations_bar",
+ package: "com.example.package",
+ srcs: ["bar.aconfig"],
+ }
+
+ cc_aconfig_library {
+ name: "my_cc_aconfig_library_bar",
+ aconfig_declarations: "my_aconfig_declarations_bar",
+ vendor_available: true,
+ }
+
+ cc_library {
+ name: "my_cc_library",
+ srcs: [
+ "src/foo.cc",
+ ],
+ static_libs: [
+ "my_cc_aconfig_library_foo",
+ "my_cc_aconfig_library_bar",
+ ],
+ vendor: true,
+ }
+
+ cc_library {
+ name: "server_configurable_flags",
+ srcs: ["server_configurable_flags.cc"],
+ vendor_available: true,
+ }
+ `
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithAconfigBuildComponents,
+ cc.PrepareForTestWithCcDefaultModules).
+ ExtendWithErrorHandler(android.FixtureExpectsNoErrors).RunTestWithBp(t, bp)
+
+ module := result.ModuleForTests("my_cc_library", "android_vendor_arm64_armv8-a_shared").Module()
+
+ entry := android.AndroidMkEntriesForTest(t, result.TestContext, module)[0]
+
+ makeVar := entry.EntryMap["LOCAL_ACONFIG_FILES"]
+ android.AssertIntEquals(t, "len(LOCAL_ACONFIG_FILES)", 1, len(makeVar))
+ android.EnsureListContainsSuffix(t, makeVar, "my_aconfig_declarations_foo/intermediate.pb")
+}
diff --git a/aconfig/codegen/java_aconfig_library.go b/aconfig/codegen/java_aconfig_library.go
index 202e358..e6817e0 100644
--- a/aconfig/codegen/java_aconfig_library.go
+++ b/aconfig/codegen/java_aconfig_library.go
@@ -17,7 +17,6 @@
import (
"fmt"
- "android/soong/aconfig"
"android/soong/android"
"android/soong/java"
@@ -31,7 +30,7 @@
var declarationsTag = declarationsTagType{}
-var aconfigSupportedModes = []string{"production", "test", "exported"}
+var aconfigSupportedModes = []string{"production", "test", "exported", "force-read-only"}
type JavaAconfigDeclarationsLibraryProperties struct {
// name of the aconfig_declarations module to generate a library for
@@ -40,6 +39,7 @@
// default mode is "production", the other accepted modes are:
// "test": to generate test mode version of the library
// "exported": to generate exported mode version of the library
+ // "force-read-only": to generate force-read-only mode version of the library
// an error will be thrown if the mode is not supported
Mode *string
}
@@ -62,10 +62,18 @@
ctx.AddDependency(ctx.Module(), declarationsTag, declarations)
}
- // Add aconfig-annotations-lib as a dependency for the optimization / code stripping annotations
- module.AddSharedLibrary("aconfig-annotations-lib")
- // TODO(b/303773055): Remove the annotation after access issue is resolved.
- module.AddSharedLibrary("unsupportedappusage")
+ // "libcore_aconfig_flags_lib" module has a circular dependency because the shared libraries
+ // are built on core_current and the module is used to flag the APIs in the core_current.
+ // http://b/316554963#comment2 has the details of the circular dependency chain.
+ // If a java_aconfig_library uses "none" sdk_version, it should include and build these
+ // annotation files as the shared library themselves.
+ var addLibraries bool = module.Library.Module.SdkVersion(ctx).Kind != android.SdkNone
+ if addLibraries {
+ // Add aconfig-annotations-lib as a dependency for the optimization / code stripping annotations
+ module.AddSharedLibrary("aconfig-annotations-lib")
+ // TODO(b/303773055): Remove the annotation after access issue is resolved.
+ module.AddSharedLibrary("unsupportedappusage")
+ }
}
func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuildActions(module *java.GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path {
@@ -74,7 +82,7 @@
if len(declarationsModules) != 1 {
panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
}
- declarations := ctx.OtherModuleProvider(declarationsModules[0], aconfig.DeclarationsProviderKey).(aconfig.DeclarationsProviderData)
+ declarations, _ := android.OtherModuleProvider(ctx, declarationsModules[0], android.AconfigDeclarationsProviderKey)
// Generate the action to build the srcjar
srcJarPath := android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar")
diff --git a/aconfig/codegen/java_aconfig_library_test.go b/aconfig/codegen/java_aconfig_library_test.go
index 2523abc..8d54b5b 100644
--- a/aconfig/codegen/java_aconfig_library_test.go
+++ b/aconfig/codegen/java_aconfig_library_test.go
@@ -227,6 +227,10 @@
testCodegenMode(t, "mode: `exported`,", "exported")
}
+func TestForceReadOnlyMode(t *testing.T) {
+ testCodegenMode(t, "mode: `force-read-only`,", "force-read-only")
+}
+
func TestUnsupportedMode(t *testing.T) {
testCodegenModeWithError(t, "mode: `unsupported`,", "mode: \"unsupported\" is not a supported mode")
}
diff --git a/aconfig/codegen/rust_aconfig_library.go b/aconfig/codegen/rust_aconfig_library.go
index e587056..2ab54b6 100644
--- a/aconfig/codegen/rust_aconfig_library.go
+++ b/aconfig/codegen/rust_aconfig_library.go
@@ -3,7 +3,6 @@
import (
"fmt"
- "android/soong/aconfig"
"android/soong/android"
"android/soong/rust"
@@ -24,6 +23,7 @@
// default mode is "production", the other accepted modes are:
// "test": to generate test mode version of the library
// "exported": to generate exported mode version of the library
+ // "force-read-only": to generate force-read-only mode version of the library
// an error will be thrown if the mode is not supported
Mode *string
}
@@ -65,7 +65,7 @@
if len(declarationsModules) != 1 {
panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
}
- declarations := ctx.OtherModuleProvider(declarationsModules[0], aconfig.DeclarationsProviderKey).(aconfig.DeclarationsProviderData)
+ declarations, _ := android.OtherModuleProvider(ctx, declarationsModules[0], android.AconfigDeclarationsProviderKey)
mode := proptools.StringDefault(a.Properties.Mode, "production")
if !isModeSupported(mode) {
diff --git a/aconfig/codegen/rust_aconfig_library_test.go b/aconfig/codegen/rust_aconfig_library_test.go
index c09f701..60bc9f7 100644
--- a/aconfig/codegen/rust_aconfig_library_test.go
+++ b/aconfig/codegen/rust_aconfig_library_test.go
@@ -72,6 +72,7 @@
{"mode: `production`,", "production"},
{"mode: `test`,", "test"},
{"mode: `exported`,", "exported"},
+ {"mode: `force-read-only`,", "force-read-only"},
}
func TestRustCodegenMode(t *testing.T) {
diff --git a/aconfig/exported_java_aconfig_library.go b/aconfig/exported_java_aconfig_library.go
index 45c5e39..291938f 100644
--- a/aconfig/exported_java_aconfig_library.go
+++ b/aconfig/exported_java_aconfig_library.go
@@ -30,10 +30,10 @@
// Find all of the aconfig_declarations modules
var cacheFiles android.Paths
ctx.VisitAllModules(func(module android.Module) {
- if !ctx.ModuleHasProvider(module, DeclarationsProviderKey) {
+ decl, ok := android.SingletonModuleProvider(ctx, module, android.AconfigDeclarationsProviderKey)
+ if !ok {
return
}
- decl := ctx.ModuleProvider(module, DeclarationsProviderKey).(DeclarationsProviderData)
cacheFiles = append(cacheFiles, decl.IntermediateCacheOutputPath)
})
diff --git a/aconfig/init.go b/aconfig/init.go
index 05fab4c..3e9d297 100644
--- a/aconfig/init.go
+++ b/aconfig/init.go
@@ -43,7 +43,7 @@
// For create-device-config-sysprops: Generate aconfig flag value map text file
aconfigTextRule = pctx.AndroidStaticRule("aconfig_text",
blueprint.RuleParams{
- Command: `${aconfig} dump --format bool` +
+ Command: `${aconfig} dump-cache --format='{fully_qualified_name}={state:bool}'` +
` --cache ${in}` +
` --out ${out}.tmp` +
` && ( if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`,
@@ -56,24 +56,27 @@
// For all_aconfig_declarations: Combine all parsed_flags proto files
AllDeclarationsRule = pctx.AndroidStaticRule("All_aconfig_declarations_dump",
blueprint.RuleParams{
- Command: `${aconfig} dump --format protobuf --out ${out} ${cache_files}`,
+ Command: `${aconfig} dump-cache --format protobuf --out ${out} ${cache_files}`,
CommandDeps: []string{
"${aconfig}",
},
}, "cache_files")
- mergeAconfigFilesRule = pctx.AndroidStaticRule("mergeAconfigFilesRule",
- blueprint.RuleParams{
- Command: `${aconfig} dump --dedup --format protobuf --out $out $flags`,
- CommandDeps: []string{"${aconfig}"},
- }, "flags")
// For exported_java_aconfig_library: Generate a JAR from all
// java_aconfig_libraries to be consumed by apps built outside the
// platform
exportedJavaRule = pctx.AndroidStaticRule("exported_java_aconfig_library",
+ // For each aconfig cache file, if the cache contains any
+ // exported flags, generate Java flag lookup code for the
+ // exported flags (only). Finally collect all generated code
+ // into the ${out} JAR file.
blueprint.RuleParams{
Command: `rm -rf ${out}.tmp` +
- `&& for cache in ${cache_files}; do ${aconfig} create-java-lib --cache $$cache --out ${out}.tmp; done` +
+ `&& for cache in ${cache_files}; do ` +
+ ` if [ -n "$$(${aconfig} dump-cache --cache $$cache --filter=is_exported:true --format='{fully_qualified_name}')" ]; then ` +
+ ` ${aconfig} create-java-lib --cache $$cache --mode=exported --out ${out}.tmp; ` +
+ ` fi ` +
+ `done` +
`&& $soong_zip -write_if_changed -jar -o ${out} -C ${out}.tmp -D ${out}.tmp` +
`&& rm -rf ${out}.tmp`,
CommandDeps: []string{
diff --git a/aidl_library/aidl_library.go b/aidl_library/aidl_library.go
index b49c516..0141545 100644
--- a/aidl_library/aidl_library.go
+++ b/aidl_library/aidl_library.go
@@ -64,7 +64,7 @@
}
// AidlLibraryProvider provides the srcs and the transitive include dirs
-var AidlLibraryProvider = blueprint.NewProvider(AidlLibraryInfo{})
+var AidlLibraryProvider = blueprint.NewProvider[AidlLibraryInfo]()
func (lib *AidlLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
includeDirsDepSetBuilder := android.NewDepSetBuilder[android.Path](android.PREORDER)
@@ -99,14 +99,13 @@
includeDirsDepSetBuilder.Direct(includeDir)
for _, dep := range ctx.GetDirectDepsWithTag(aidlLibraryTag) {
- if ctx.OtherModuleHasProvider(dep, AidlLibraryProvider) {
- info := ctx.OtherModuleProvider(dep, AidlLibraryProvider).(AidlLibraryInfo)
+ if info, ok := android.OtherModuleProvider(ctx, dep, AidlLibraryProvider); ok {
includeDirsDepSetBuilder.Transitive(&info.IncludeDirs)
hdrsDepSetBuilder.Transitive(&info.Hdrs)
}
}
- ctx.SetProvider(AidlLibraryProvider, AidlLibraryInfo{
+ android.SetProvider(ctx, AidlLibraryProvider, AidlLibraryInfo{
Srcs: srcs,
IncludeDirs: *includeDirsDepSetBuilder.Build(),
Hdrs: *hdrsDepSetBuilder.Build(),
diff --git a/aidl_library/aidl_library_test.go b/aidl_library/aidl_library_test.go
index 0205629..01eab0e 100644
--- a/aidl_library/aidl_library_test.go
+++ b/aidl_library/aidl_library_test.go
@@ -46,7 +46,7 @@
).RunTest(t).TestContext
foo := ctx.ModuleForTests("foo", "").Module().(*AidlLibrary)
- actualInfo := ctx.ModuleProvider(foo, AidlLibraryProvider).(AidlLibraryInfo)
+ actualInfo, _ := android.SingletonModuleProvider(ctx, foo, AidlLibraryProvider)
android.AssertArrayString(
t,
@@ -95,7 +95,7 @@
).RunTest(t).TestContext
foo := ctx.ModuleForTests("foo", "").Module().(*AidlLibrary)
- actualInfo := ctx.ModuleProvider(foo, AidlLibraryProvider).(AidlLibraryInfo)
+ actualInfo, _ := android.SingletonModuleProvider(ctx, foo, AidlLibraryProvider)
android.AssertArrayString(
t,
diff --git a/android/Android.bp b/android/Android.bp
index 2ac1d5f..e40e462 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -27,6 +27,7 @@
"androidmk-parser",
],
srcs: [
+ "aconfig_providers.go",
"androidmk.go",
"apex.go",
"apex_contributions.go",
@@ -62,6 +63,7 @@
"metrics.go",
"module.go",
"module_context.go",
+ "module_info_json.go",
"mutator.go",
"namespace.go",
"neverallow.go",
@@ -79,6 +81,8 @@
"prebuilt.go",
"prebuilt_build_tool.go",
"proto.go",
+ "provider.go",
+ "raw_files.go",
"register.go",
"rule_builder.go",
"sandbox.go",
diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go
new file mode 100644
index 0000000..ddebec3
--- /dev/null
+++ b/android/aconfig_providers.go
@@ -0,0 +1,92 @@
+// 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 android
+
+import (
+ "github.com/google/blueprint"
+)
+
+var (
+ mergeAconfigFilesRule = pctx.AndroidStaticRule("mergeAconfigFilesRule",
+ blueprint.RuleParams{
+ Command: `${aconfig} dump --dedup --format protobuf --out $out $flags`,
+ CommandDeps: []string{"${aconfig}"},
+ }, "flags")
+ _ = pctx.HostBinToolVariable("aconfig", "aconfig")
+)
+
+// Provider published by aconfig_value_set
+type AconfigDeclarationsProviderData struct {
+ Package string
+ Container string
+ IntermediateCacheOutputPath WritablePath
+ IntermediateDumpOutputPath WritablePath
+}
+
+var AconfigDeclarationsProviderKey = blueprint.NewProvider[AconfigDeclarationsProviderData]()
+
+// This is used to collect the aconfig declarations info on the transitive closure,
+// the data is keyed on the container.
+type AconfigTransitiveDeclarationsInfo struct {
+ AconfigFiles map[string]Paths
+}
+
+var AconfigTransitiveDeclarationsInfoProvider = blueprint.NewProvider[AconfigTransitiveDeclarationsInfo]()
+
+func CollectDependencyAconfigFiles(ctx ModuleContext, mergedAconfigFiles *map[string]Paths) {
+ if *mergedAconfigFiles == nil {
+ *mergedAconfigFiles = make(map[string]Paths)
+ }
+ ctx.VisitDirectDeps(func(module Module) {
+ if dep, _ := OtherModuleProvider(ctx, module, AconfigDeclarationsProviderKey); dep.IntermediateCacheOutputPath != nil {
+ (*mergedAconfigFiles)[dep.Container] = append((*mergedAconfigFiles)[dep.Container], dep.IntermediateCacheOutputPath)
+ return
+ }
+ if dep, _ := OtherModuleProvider(ctx, module, AconfigTransitiveDeclarationsInfoProvider); len(dep.AconfigFiles) > 0 {
+ for container, v := range dep.AconfigFiles {
+ (*mergedAconfigFiles)[container] = append((*mergedAconfigFiles)[container], v...)
+ }
+ }
+ })
+
+ for container, aconfigFiles := range *mergedAconfigFiles {
+ (*mergedAconfigFiles)[container] = mergeAconfigFiles(ctx, aconfigFiles)
+ }
+
+ SetProvider(ctx, AconfigTransitiveDeclarationsInfoProvider, AconfigTransitiveDeclarationsInfo{
+ AconfigFiles: *mergedAconfigFiles,
+ })
+}
+
+func mergeAconfigFiles(ctx ModuleContext, inputs Paths) Paths {
+ inputs = LastUniquePaths(inputs)
+ if len(inputs) == 1 {
+ return Paths{inputs[0]}
+ }
+
+ output := PathForModuleOut(ctx, "aconfig_merged.pb")
+
+ ctx.Build(pctx, BuildParams{
+ Rule: mergeAconfigFilesRule,
+ Description: "merge aconfig files",
+ Inputs: inputs,
+ Output: output,
+ Args: map[string]string{
+ "flags": JoinWithPrefix(inputs.Strings(), "--cache "),
+ },
+ })
+
+ return Paths{output}
+}
diff --git a/android/androidmk.go b/android/androidmk.go
index c4b93c7..235d7c0 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -30,6 +30,7 @@
"reflect"
"runtime"
"sort"
+ "strconv"
"strings"
"github.com/google/blueprint"
@@ -159,7 +160,7 @@
}
type AndroidMkExtraEntriesContext interface {
- Provider(provider blueprint.ProviderKey) interface{}
+ Provider(provider blueprint.AnyProviderKey) (any, bool)
}
type androidMkExtraEntriesContext struct {
@@ -167,8 +168,8 @@
mod blueprint.Module
}
-func (a *androidMkExtraEntriesContext) Provider(provider blueprint.ProviderKey) interface{} {
- return a.ctx.ModuleProvider(a.mod, provider)
+func (a *androidMkExtraEntriesContext) Provider(provider blueprint.AnyProviderKey) (any, bool) {
+ return a.ctx.moduleProvider(a.mod, provider)
}
type AndroidMkExtraEntriesFunc func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries)
@@ -275,14 +276,17 @@
}
// AddCompatibilityTestSuites adds the supplied test suites to the EntryMap, with special handling
-// for partial MTS test suites.
+// for partial MTS and MCTS test suites.
func (a *AndroidMkEntries) AddCompatibilityTestSuites(suites ...string) {
- // MTS supports a full test suite and partial per-module MTS test suites, with naming mts-${MODULE}.
- // To reduce repetition, if we find a partial MTS test suite without an full MTS test suite,
+ // M(C)TS supports a full test suite and partial per-module MTS test suites, with naming mts-${MODULE}.
+ // To reduce repetition, if we find a partial M(C)TS test suite without an full M(C)TS test suite,
// we add the full test suite to our list.
if PrefixInList(suites, "mts-") && !InList("mts", suites) {
suites = append(suites, "mts")
}
+ if PrefixInList(suites, "mcts-") && !InList("mcts", suites) {
+ suites = append(suites, "mcts")
+ }
a.AddStrings("LOCAL_COMPATIBILITY_SUITE", suites...)
}
@@ -492,8 +496,7 @@
ModuleDir(module blueprint.Module) string
ModuleSubDir(module blueprint.Module) string
Config() Config
- ModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{}
- ModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool
+ moduleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
ModuleType(module blueprint.Module) string
}
@@ -623,11 +626,14 @@
}
}
- if ctx.ModuleHasProvider(mod, LicenseMetadataProvider) {
- licenseMetadata := ctx.ModuleProvider(mod, LicenseMetadataProvider).(*LicenseMetadataInfo)
+ if licenseMetadata, ok := SingletonModuleProvider(ctx, mod, LicenseMetadataProvider); ok {
a.SetPath("LOCAL_SOONG_LICENSE_METADATA", licenseMetadata.LicenseMetadataPath)
}
+ if _, ok := SingletonModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
+ a.SetBool("LOCAL_SOONG_MODULE_INFO_JSON", true)
+ }
+
extraCtx := &androidMkExtraEntriesContext{
ctx: ctx,
mod: mod,
@@ -645,14 +651,14 @@
}
}
+func (a *AndroidMkEntries) disabled() bool {
+ return a.Disabled || !a.OutputFile.Valid()
+}
+
// write flushes the AndroidMkEntries's in-struct data populated by AndroidMkEntries into the
// given Writer object.
func (a *AndroidMkEntries) write(w io.Writer) {
- if a.Disabled {
- return
- }
-
- if !a.OutputFile.Valid() {
+ if a.disabled() {
return
}
@@ -698,7 +704,9 @@
return
}
- err := translateAndroidMk(ctx, absolutePath(transMk.String()), androidMkModulesList)
+ moduleInfoJSON := PathForOutput(ctx, "module-info"+String(ctx.Config().productVariables.Make_suffix)+".json")
+
+ err := translateAndroidMk(ctx, absolutePath(transMk.String()), moduleInfoJSON, androidMkModulesList)
if err != nil {
ctx.Errorf(err.Error())
}
@@ -709,14 +717,16 @@
})
}
-func translateAndroidMk(ctx SingletonContext, absMkFile string, mods []blueprint.Module) error {
+func translateAndroidMk(ctx SingletonContext, absMkFile string, moduleInfoJSONPath WritablePath, mods []blueprint.Module) error {
buf := &bytes.Buffer{}
+ var moduleInfoJSONs []*ModuleInfoJSON
+
fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))")
typeStats := make(map[string]int)
for _, mod := range mods {
- err := translateAndroidMkModule(ctx, buf, mod)
+ err := translateAndroidMkModule(ctx, buf, &moduleInfoJSONs, mod)
if err != nil {
os.Remove(absMkFile)
return err
@@ -738,10 +748,36 @@
fmt.Fprintf(buf, "STATS.SOONG_MODULE_TYPE.%s := %d\n", mod_type, typeStats[mod_type])
}
- return pathtools.WriteFileIfChanged(absMkFile, buf.Bytes(), 0666)
+ err := pathtools.WriteFileIfChanged(absMkFile, buf.Bytes(), 0666)
+ if err != nil {
+ return err
+ }
+
+ return writeModuleInfoJSON(ctx, moduleInfoJSONs, moduleInfoJSONPath)
}
-func translateAndroidMkModule(ctx SingletonContext, w io.Writer, mod blueprint.Module) error {
+func writeModuleInfoJSON(ctx SingletonContext, moduleInfoJSONs []*ModuleInfoJSON, moduleInfoJSONPath WritablePath) error {
+ moduleInfoJSONBuf := &strings.Builder{}
+ moduleInfoJSONBuf.WriteString("[")
+ for i, moduleInfoJSON := range moduleInfoJSONs {
+ if i != 0 {
+ moduleInfoJSONBuf.WriteString(",\n")
+ }
+ moduleInfoJSONBuf.WriteString("{")
+ moduleInfoJSONBuf.WriteString(strconv.Quote(moduleInfoJSON.core.RegisterName))
+ moduleInfoJSONBuf.WriteString(":")
+ err := encodeModuleInfoJSON(moduleInfoJSONBuf, moduleInfoJSON)
+ moduleInfoJSONBuf.WriteString("}")
+ if err != nil {
+ return err
+ }
+ }
+ moduleInfoJSONBuf.WriteString("]")
+ WriteFileRule(ctx, moduleInfoJSONPath, moduleInfoJSONBuf.String())
+ return nil
+}
+
+func translateAndroidMkModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON, mod blueprint.Module) error {
defer func() {
if r := recover(); r != nil {
panic(fmt.Errorf("%s in translateAndroidMkModule for module %s variant %s",
@@ -750,17 +786,23 @@
}()
// Additional cases here require review for correct license propagation to make.
+ var err error
switch x := mod.(type) {
case AndroidMkDataProvider:
- return translateAndroidModule(ctx, w, mod, x)
+ err = translateAndroidModule(ctx, w, moduleInfoJSONs, mod, x)
case bootstrap.GoBinaryTool:
- return translateGoBinaryModule(ctx, w, mod, x)
+ err = translateGoBinaryModule(ctx, w, mod, x)
case AndroidMkEntriesProvider:
- return translateAndroidMkEntriesModule(ctx, w, mod, x)
+ err = translateAndroidMkEntriesModule(ctx, w, moduleInfoJSONs, mod, x)
default:
// Not exported to make so no make variables to set.
- return nil
}
+
+ if err != nil {
+ return err
+ }
+
+ return err
}
// A simple, special Android.mk entry output func to make it possible to build blueprint tools using
@@ -803,8 +845,8 @@
// A support func for the deprecated AndroidMkDataProvider interface. Use AndroidMkEntryProvider
// instead.
-func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
- provider AndroidMkDataProvider) error {
+func translateAndroidModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON,
+ mod blueprint.Module, provider AndroidMkDataProvider) error {
amod := mod.(Module).base()
if shouldSkipAndroidMkProcessing(amod) {
@@ -854,6 +896,7 @@
case "*java.SystemModules": // doesn't go through base_rules
case "*java.systemModulesImport": // doesn't go through base_rules
case "*phony.phony": // license properties written
+ case "*phony.PhonyRule": // writes phony deps and acts like `.PHONY`
case "*selinux.selinuxContextsModule": // license properties written
case "*sysprop.syspropLibrary": // license properties written
default:
@@ -866,17 +909,19 @@
WriteAndroidMkData(w, data)
}
+ if !data.Entries.disabled() {
+ if moduleInfoJSON, ok := SingletonModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
+ *moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON)
+ }
+ }
+
return nil
}
// A support func for the deprecated AndroidMkDataProvider interface. Use AndroidMkEntryProvider
// instead.
func WriteAndroidMkData(w io.Writer, data AndroidMkData) {
- if data.Disabled {
- return
- }
-
- if !data.OutputFile.Valid() {
+ if data.Entries.disabled() {
return
}
@@ -891,18 +936,26 @@
fmt.Fprintln(w, "include "+data.Include)
}
-func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
- provider AndroidMkEntriesProvider) error {
+func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON,
+ mod blueprint.Module, provider AndroidMkEntriesProvider) error {
if shouldSkipAndroidMkProcessing(mod.(Module).base()) {
return nil
}
+ entriesList := provider.AndroidMkEntries()
+
// Any new or special cases here need review to verify correct propagation of license information.
- for _, entries := range provider.AndroidMkEntries() {
+ for _, entries := range entriesList {
entries.fillInEntries(ctx, mod)
entries.write(w)
}
+ if len(entriesList) > 0 && !entriesList[0].disabled() {
+ if moduleInfoJSON, ok := SingletonModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
+ *moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON)
+ }
+ }
+
return nil
}
diff --git a/android/apex.go b/android/apex.go
index c6d9940..c1e7a5c 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -89,7 +89,7 @@
TestApexes []string
}
-var ApexInfoProvider = blueprint.NewMutatorProvider(ApexInfo{}, "apex")
+var ApexInfoProvider = blueprint.NewMutatorProvider[ApexInfo]("apex")
func (i ApexInfo) AddJSONData(d *map[string]interface{}) {
(*d)["Apex"] = map[string]interface{}{
@@ -145,7 +145,7 @@
ApexContents []*ApexContents
}
-var ApexTestForInfoProvider = blueprint.NewMutatorProvider(ApexTestForInfo{}, "apex_test_for")
+var ApexTestForInfoProvider = blueprint.NewMutatorProvider[ApexTestForInfo]("apex_test_for")
// DepIsInSameApex defines an interface that should be used to determine whether a given dependency
// should be considered as part of the same APEX as the current module or not. Note: this was
@@ -954,3 +954,18 @@
// Return true if the apex bundle is an apex_test
IsTestApex() bool
}
+
+var ApexExportsInfoProvider = blueprint.NewProvider[ApexExportsInfo]()
+
+// ApexExportsInfo contains information about the artifacts provided by apexes to dexpreopt and hiddenapi
+type ApexExportsInfo struct {
+ // Canonical name of this APEX. Used to determine the path to the activated APEX on
+ // device (/apex/<apex_name>)
+ ApexName string
+
+ // Path to the image profile file on host (or empty, if profile is not generated).
+ ProfilePathOnHost Path
+
+ // Map from the apex library name (without prebuilt_ prefix) to the dex file path on host
+ LibraryNameToDexJarPathOnHost map[string]Path
+}
diff --git a/android/apex_contributions.go b/android/apex_contributions.go
index f13659a..a309640 100644
--- a/android/apex_contributions.go
+++ b/android/apex_contributions.go
@@ -119,12 +119,12 @@
ctx.ModuleErrorf("%s is not an apex_contributions module\n", child.Name())
}
})
- ctx.SetProvider(PrebuiltSelectionInfoProvider, p)
+ SetProvider(ctx, PrebuiltSelectionInfoProvider, p)
}
// A provider containing metadata about whether source or prebuilt should be used
// This provider will be used in prebuilt_select mutator to redirect deps
-var PrebuiltSelectionInfoProvider = blueprint.NewMutatorProvider(PrebuiltSelectionInfoMap{}, "prebuilt_select")
+var PrebuiltSelectionInfoProvider = blueprint.NewMutatorProvider[PrebuiltSelectionInfoMap]("prebuilt_select")
// Map of baseModuleName to the selected source or prebuilt
type PrebuiltSelectionInfoMap map[string]PrebuiltSelectionInfo
@@ -164,6 +164,18 @@
}
}
+// Return the list of soong modules selected for this api domain
+// In the case of apexes, it is the canonical name of the apex on device (/apex/<apex_name>)
+func (p *PrebuiltSelectionInfoMap) GetSelectedModulesForApiDomain(apiDomain string) []string {
+ selected := []string{}
+ for _, entry := range *p {
+ if entry.apiDomain == apiDomain {
+ selected = append(selected, entry.selectedModuleName)
+ }
+ }
+ return selected
+}
+
// This module type does not have any build actions.
func (a *allApexContributions) GenerateAndroidBuildActions(ctx ModuleContext) {
}
diff --git a/android/arch.go b/android/arch.go
index 7436660..c39db02 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -446,8 +446,10 @@
}
}
+ createCommonOSVariant := base.commonProperties.CreateCommonOSVariant
+
// If there are no supported OSes then disable the module.
- if len(moduleOSList) == 0 {
+ if len(moduleOSList) == 0 && !createCommonOSVariant {
base.Disable()
return
}
@@ -458,7 +460,6 @@
osNames[i] = os.String()
}
- createCommonOSVariant := base.commonProperties.CreateCommonOSVariant
if createCommonOSVariant {
// A CommonOS variant was requested so add it to the list of OS variants to
// create. It needs to be added to the end because it needs to depend on the
diff --git a/android/base_module_context.go b/android/base_module_context.go
index 4312e9b..3dfe123 100644
--- a/android/base_module_context.go
+++ b/android/base_module_context.go
@@ -75,30 +75,28 @@
// It is intended for use inside the visit functions of Visit* and WalkDeps.
OtherModuleType(m blueprint.Module) string
- // OtherModuleProvider returns the value for a provider for the given module. If the value is
- // not set it returns the zero value of the type of the provider, so the return value can always
- // be type asserted to the type of the provider. The value returned may be a deep copy of the
- // value originally passed to SetProvider.
- OtherModuleProvider(m blueprint.Module, provider blueprint.ProviderKey) interface{}
-
- // OtherModuleHasProvider returns true if the provider for the given module has been set.
- OtherModuleHasProvider(m blueprint.Module, provider blueprint.ProviderKey) bool
+ // otherModuleProvider returns the value for a provider for the given module. If the value is
+ // not set it returns nil and false. The value returned may be a deep copy of the value originally
+ // passed to SetProvider.
+ //
+ // This method shouldn't be used directly, prefer the type-safe android.OtherModuleProvider instead.
+ otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
// Provider returns the value for a provider for the current module. If the value is
- // not set it returns the zero value of the type of the provider, so the return value can always
- // be type asserted to the type of the provider. It panics if called before the appropriate
+ // not set it returns nil and false. It panics if called before the appropriate
// mutator or GenerateBuildActions pass for the provider. The value returned may be a deep
// copy of the value originally passed to SetProvider.
- Provider(provider blueprint.ProviderKey) interface{}
+ //
+ // This method shouldn't be used directly, prefer the type-safe android.ModuleProvider instead.
+ provider(provider blueprint.AnyProviderKey) (any, bool)
- // HasProvider returns true if the provider for the current module has been set.
- HasProvider(provider blueprint.ProviderKey) bool
-
- // SetProvider sets the value for a provider for the current module. It panics if not called
+ // setProvider sets the value for a provider for the current module. It panics if not called
// during the appropriate mutator or GenerateBuildActions pass for the provider, if the value
// is not of the appropriate type, or if the value has already been set. The value should not
// be modified after being passed to SetProvider.
- SetProvider(provider blueprint.ProviderKey, value interface{})
+ //
+ // This method shouldn't be used directly, prefer the type-safe android.SetProvider instead.
+ setProvider(provider blueprint.AnyProviderKey, value any)
GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module
@@ -260,19 +258,16 @@
func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string {
return b.bp.OtherModuleType(m)
}
-func (b *baseModuleContext) OtherModuleProvider(m blueprint.Module, provider blueprint.ProviderKey) interface{} {
+
+func (b *baseModuleContext) otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
return b.bp.OtherModuleProvider(m, provider)
}
-func (b *baseModuleContext) OtherModuleHasProvider(m blueprint.Module, provider blueprint.ProviderKey) bool {
- return b.bp.OtherModuleHasProvider(m, provider)
-}
-func (b *baseModuleContext) Provider(provider blueprint.ProviderKey) interface{} {
+
+func (b *baseModuleContext) provider(provider blueprint.AnyProviderKey) (any, bool) {
return b.bp.Provider(provider)
}
-func (b *baseModuleContext) HasProvider(provider blueprint.ProviderKey) bool {
- return b.bp.HasProvider(provider)
-}
-func (b *baseModuleContext) SetProvider(provider blueprint.ProviderKey, value interface{}) {
+
+func (b *baseModuleContext) setProvider(provider blueprint.AnyProviderKey, value any) {
b.bp.SetProvider(provider, value)
}
diff --git a/android/config.go b/android/config.go
index 312a5da..24b9b8a 100644
--- a/android/config.go
+++ b/android/config.go
@@ -18,6 +18,7 @@
// product variables necessary for soong_build's operation.
import (
+ "android/soong/shared"
"encoding/json"
"fmt"
"os"
@@ -118,6 +119,11 @@
return c.soongOutDir
}
+// tempDir returns the path to out/soong/.temp, which is cleared at the beginning of every build.
+func (c Config) tempDir() string {
+ return shared.TempDirForOutDir(c.soongOutDir)
+}
+
func (c Config) OutDir() string {
return c.outDir
}
diff --git a/android/deapexer.go b/android/deapexer.go
index 6a93f60..2704b3e 100644
--- a/android/deapexer.go
+++ b/android/deapexer.go
@@ -15,6 +15,7 @@
package android
import (
+ "fmt"
"strings"
"github.com/google/blueprint"
@@ -78,6 +79,10 @@
//
// See Prebuilt.ApexInfoMutator for more information.
exports map[string]WritablePath
+
+ // name of the java libraries exported from the apex
+ // e.g. core-libart
+ exportedModuleNames []string
}
// ApexModuleName returns the name of the APEX module that provided the info.
@@ -96,18 +101,23 @@
return path
}
+func (i DeapexerInfo) GetExportedModuleNames() []string {
+ return i.exportedModuleNames
+}
+
// Provider that can be used from within the `GenerateAndroidBuildActions` of a module that depends
// on a `deapexer` module to retrieve its `DeapexerInfo`.
-var DeapexerProvider = blueprint.NewProvider(DeapexerInfo{})
+var DeapexerProvider = blueprint.NewProvider[DeapexerInfo]()
// NewDeapexerInfo creates and initializes a DeapexerInfo that is suitable
// for use with a prebuilt_apex module.
//
// See apex/deapexer.go for more information.
-func NewDeapexerInfo(apexModuleName string, exports map[string]WritablePath) DeapexerInfo {
+func NewDeapexerInfo(apexModuleName string, exports map[string]WritablePath, moduleNames []string) DeapexerInfo {
return DeapexerInfo{
- apexModuleName: apexModuleName,
- exports: exports,
+ apexModuleName: apexModuleName,
+ exports: exports,
+ exportedModuleNames: moduleNames,
}
}
@@ -146,11 +156,17 @@
// FindDeapexerProviderForModule searches through the direct dependencies of the current context
// module for a DeapexerTag dependency and returns its DeapexerInfo. If a single nonambiguous
-// deapexer module isn't found then errors are reported with ctx.ModuleErrorf and nil is returned.
-func FindDeapexerProviderForModule(ctx ModuleContext) *DeapexerInfo {
+// deapexer module isn't found then it returns it an error
+// clients should check the value of error and call ctx.ModuleErrof if a non nil error is received
+func FindDeapexerProviderForModule(ctx ModuleContext) (*DeapexerInfo, error) {
var di *DeapexerInfo
+ var err error
ctx.VisitDirectDepsWithTag(DeapexerTag, func(m Module) {
- c := ctx.OtherModuleProvider(m, DeapexerProvider).(DeapexerInfo)
+ if err != nil {
+ // An err has been found. Do not visit further.
+ return
+ }
+ c, _ := OtherModuleProvider(ctx, m, DeapexerProvider)
p := &c
if di != nil {
// If two DeapexerInfo providers have been found then check if they are
@@ -159,17 +175,18 @@
di = selected
return
}
- ctx.ModuleErrorf("Multiple installable prebuilt APEXes provide ambiguous deapexers: %s and %s",
- di.ApexModuleName(), p.ApexModuleName())
+ err = fmt.Errorf("Multiple installable prebuilt APEXes provide ambiguous deapexers: %s and %s", di.ApexModuleName(), p.ApexModuleName())
}
di = p
})
- if di != nil {
- return di
+ if err != nil {
+ return nil, err
}
- ai := ctx.Provider(ApexInfoProvider).(ApexInfo)
- ctx.ModuleErrorf("No prebuilt APEX provides a deapexer module for APEX variant %s", ai.ApexVariationName)
- return nil
+ if di != nil {
+ return di, nil
+ }
+ ai, _ := ModuleProvider(ctx, ApexInfoProvider)
+ return nil, fmt.Errorf("No prebuilt APEX provides a deapexer module for APEX variant %s", ai.ApexVariationName)
}
// removeCompressedApexSuffix removes the _compressed suffix from the name if present.
diff --git a/android/defs.go b/android/defs.go
index 03968c1..a988964 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -15,13 +15,8 @@
package android
import (
- "fmt"
- "strings"
- "testing"
-
"github.com/google/blueprint"
"github.com/google/blueprint/bootstrap"
- "github.com/google/blueprint/proptools"
)
var (
@@ -72,8 +67,7 @@
Command: "if ! cmp -s $in $out; then cp $in $out; fi",
Description: "cp if changed $out",
Restat: true,
- },
- "cpFlags")
+ })
CpExecutable = pctx.AndroidStaticRule("CpExecutable",
blueprint.RuleParams{
@@ -146,106 +140,6 @@
return BazelToolchainVars(config, exportedVars)
}
-var (
- // echoEscaper escapes a string such that passing it to "echo -e" will produce the input value.
- echoEscaper = strings.NewReplacer(
- `\`, `\\`, // First escape existing backslashes so they aren't interpreted by `echo -e`.
- "\n", `\n`, // Then replace newlines with \n
- )
-
- // echoEscaper reverses echoEscaper.
- echoUnescaper = strings.NewReplacer(
- `\n`, "\n",
- `\\`, `\`,
- )
-
- // shellUnescaper reverses the replacer in proptools.ShellEscape
- shellUnescaper = strings.NewReplacer(`'\''`, `'`)
-)
-
-func buildWriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
- content = echoEscaper.Replace(content)
- content = proptools.NinjaEscape(proptools.ShellEscapeIncludingSpaces(content))
- if content == "" {
- content = "''"
- }
- ctx.Build(pctx, BuildParams{
- Rule: writeFile,
- Output: outputFile,
- Description: "write " + outputFile.Base(),
- Args: map[string]string{
- "content": content,
- },
- })
-}
-
-// WriteFileRule creates a ninja rule to write contents to a file. The contents will be escaped
-// so that the file contains exactly the contents passed to the function, plus a trailing newline.
-func WriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
- WriteFileRuleVerbatim(ctx, outputFile, content+"\n")
-}
-
-// WriteFileRuleVerbatim creates a ninja rule to write contents to a file. The contents will be
-// escaped so that the file contains exactly the contents passed to the function.
-func WriteFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) {
- // This is MAX_ARG_STRLEN subtracted with some safety to account for shell escapes
- const SHARD_SIZE = 131072 - 10000
-
- if len(content) > SHARD_SIZE {
- var chunks WritablePaths
- for i, c := range ShardString(content, SHARD_SIZE) {
- tempPath := outputFile.ReplaceExtension(ctx, fmt.Sprintf("%s.%d", outputFile.Ext(), i))
- buildWriteFileRule(ctx, tempPath, c)
- chunks = append(chunks, tempPath)
- }
- ctx.Build(pctx, BuildParams{
- Rule: Cat,
- Inputs: chunks.Paths(),
- Output: outputFile,
- Description: "Merging to " + outputFile.Base(),
- })
- return
- }
- buildWriteFileRule(ctx, outputFile, content)
-}
-
-// WriteExecutableFileRuleVerbatim is the same as WriteFileRuleVerbatim, but runs chmod +x on the result
-func WriteExecutableFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) {
- intermediate := PathForIntermediates(ctx, "write_executable_file_intermediates").Join(ctx, outputFile.String())
- WriteFileRuleVerbatim(ctx, intermediate, content)
- ctx.Build(pctx, BuildParams{
- Rule: CpExecutable,
- Output: outputFile,
- Input: intermediate,
- })
-}
-
-// shellUnescape reverses proptools.ShellEscape
-func shellUnescape(s string) string {
- // Remove leading and trailing quotes if present
- if len(s) >= 2 && s[0] == '\'' {
- s = s[1 : len(s)-1]
- }
- s = shellUnescaper.Replace(s)
- return s
-}
-
-// ContentFromFileRuleForTests returns the content that was passed to a WriteFileRule for use
-// in tests.
-func ContentFromFileRuleForTests(t *testing.T, ctx *TestContext, params TestingBuildParams) string {
- t.Helper()
- if g, w := params.Rule, writeFile; g != w {
- t.Errorf("expected params.Rule to be %q, was %q", w, g)
- return ""
- }
-
- content := params.Args["content"]
- content = shellUnescape(content)
- content = echoUnescaper.Replace(content)
-
- return content
-}
-
// GlobToListFileRule creates a rule that writes a list of files matching a pattern to a file.
func GlobToListFileRule(ctx ModuleContext, pattern string, excludes []string, file WritablePath) {
bootstrap.GlobFile(ctx.blueprintModuleContext(), pattern, excludes, file.String())
diff --git a/android/filegroup.go b/android/filegroup.go
index 04bd8a8..0aabb68 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -92,7 +92,7 @@
if fg.properties.Path != nil {
fg.srcs = PathsWithModuleSrcSubDir(ctx, fg.srcs, String(fg.properties.Path))
}
- ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: fg.srcs.Strings()})
+ SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: fg.srcs.Strings()})
}
func (fg *fileGroup) Srcs() Paths {
diff --git a/android/license_metadata.go b/android/license_metadata.go
index 609ca79..463fd07 100644
--- a/android/license_metadata.go
+++ b/android/license_metadata.go
@@ -78,8 +78,7 @@
return
}
- if ctx.OtherModuleHasProvider(dep, LicenseMetadataProvider) {
- info := ctx.OtherModuleProvider(dep, LicenseMetadataProvider).(*LicenseMetadataInfo)
+ if info, ok := OtherModuleProvider(ctx, dep, LicenseMetadataProvider); ok {
allDepMetadataFiles = append(allDepMetadataFiles, info.LicenseMetadataPath)
if isContainer || isInstallDepNeeded(dep, ctx.OtherModuleDependencyTag(dep)) {
allDepMetadataDepSets = append(allDepMetadataDepSets, info.LicenseMetadataDepSet)
@@ -175,7 +174,7 @@
},
})
- ctx.SetProvider(LicenseMetadataProvider, &LicenseMetadataInfo{
+ SetProvider(ctx, LicenseMetadataProvider, &LicenseMetadataInfo{
LicenseMetadataPath: licenseMetadataFile,
LicenseMetadataDepSet: NewDepSet(TOPOLOGICAL, Paths{licenseMetadataFile}, allDepMetadataDepSets),
})
@@ -200,7 +199,7 @@
}
// LicenseMetadataProvider is used to propagate license metadata paths between modules.
-var LicenseMetadataProvider = blueprint.NewProvider(&LicenseMetadataInfo{})
+var LicenseMetadataProvider = blueprint.NewProvider[*LicenseMetadataInfo]()
// LicenseMetadataInfo stores the license metadata path for a module.
type LicenseMetadataInfo struct {
diff --git a/android/licenses.go b/android/licenses.go
index c6b3243..be1eede 100644
--- a/android/licenses.go
+++ b/android/licenses.go
@@ -230,7 +230,7 @@
licenseInfo := LicenseInfo{
Licenses: licenses,
}
- ctx.SetProvider(LicenseInfoProvider, licenseInfo)
+ SetProvider(ctx, LicenseInfoProvider, licenseInfo)
}
// Update a property string array with a distinct union of its values and a list of new values.
@@ -322,7 +322,7 @@
Licenses []string
}
-var LicenseInfoProvider = blueprint.NewProvider(LicenseInfo{})
+var LicenseInfoProvider = blueprint.NewProvider[LicenseInfo]()
func init() {
RegisterMakeVarsProvider(pctx, licensesMakeVarsProvider)
diff --git a/android/makevars.go b/android/makevars.go
index 0800190..4039e7e 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -16,9 +16,11 @@
import (
"bytes"
+ "cmp"
"fmt"
"path/filepath"
"runtime"
+ "slices"
"sort"
"strings"
@@ -92,7 +94,7 @@
ModuleDir(module blueprint.Module) string
ModuleSubDir(module blueprint.Module) string
ModuleType(module blueprint.Module) string
- ModuleProvider(module blueprint.Module, key blueprint.ProviderKey) interface{}
+ moduleProvider(module blueprint.Module, key blueprint.AnyProviderKey) (any, bool)
BlueprintFile(module blueprint.Module) string
ModuleErrorf(module blueprint.Module, format string, args ...interface{})
@@ -242,6 +244,8 @@
var dists []dist
var phonies []phony
var katiInstalls []katiInstall
+ var katiInitRcInstalls []katiInstall
+ var katiVintfManifestInstalls []katiInstall
var katiSymlinks []katiInstall
providers := append([]makeVarsProvider(nil), makeVarsInitProviders...)
@@ -275,10 +279,33 @@
if m.ExportedToMake() {
katiInstalls = append(katiInstalls, m.base().katiInstalls...)
+ katiInitRcInstalls = append(katiInitRcInstalls, m.base().katiInitRcInstalls...)
+ katiVintfManifestInstalls = append(katiVintfManifestInstalls, m.base().katiVintfInstalls...)
katiSymlinks = append(katiSymlinks, m.base().katiSymlinks...)
}
})
+ compareKatiInstalls := func(a, b katiInstall) int {
+ aTo, bTo := a.to.String(), b.to.String()
+ if cmpTo := cmp.Compare(aTo, bTo); cmpTo != 0 {
+ return cmpTo
+ }
+
+ aFrom, bFrom := a.from.String(), b.from.String()
+ return cmp.Compare(aFrom, bFrom)
+ }
+
+ slices.SortFunc(katiInitRcInstalls, compareKatiInstalls)
+ katiInitRcInstalls = slices.CompactFunc(katiInitRcInstalls, func(a, b katiInstall) bool {
+ return compareKatiInstalls(a, b) == 0
+ })
+ katiInstalls = append(katiInstalls, katiInitRcInstalls...)
+
+ slices.SortFunc(katiVintfManifestInstalls, compareKatiInstalls)
+ katiVintfManifestInstalls = slices.CompactFunc(katiVintfManifestInstalls, func(a, b katiInstall) bool {
+ return compareKatiInstalls(a, b) == 0
+ })
+
if ctx.Failed() {
return
}
@@ -316,7 +343,7 @@
ctx.Errorf(err.Error())
}
- installsBytes := s.writeInstalls(katiInstalls, katiSymlinks)
+ installsBytes := s.writeInstalls(katiInstalls, katiSymlinks, katiVintfManifestInstalls)
if err := pathtools.WriteFileIfChanged(installsFile, installsBytes, 0666); err != nil {
ctx.Errorf(err.Error())
}
@@ -438,7 +465,7 @@
// writeInstalls writes the list of install rules generated by Soong to a makefile. The rules
// are exported to Make instead of written directly to the ninja file so that main.mk can add
// the dependencies from the `required` property that are hard to resolve in Soong.
-func (s *makeVarsSingleton) writeInstalls(installs, symlinks []katiInstall) []byte {
+func (s *makeVarsSingleton) writeInstalls(installs, symlinks, katiVintfManifestInstalls []katiInstall) []byte {
buf := &bytes.Buffer{}
fmt.Fprint(buf, `# Autogenerated file
@@ -486,9 +513,9 @@
for _, symlink := range symlinks {
fmt.Fprintf(buf, "%s:", symlink.to.String())
if symlink.from != nil {
- // The symlink doesn't need updating when the target is modified, but we sometimes
- // have a dependency on a symlink to a binary instead of to the binary directly, and
- // the mtime of the symlink must be updated when the binary is modified, so use a
+ // The katiVintfManifestInstall doesn't need updating when the target is modified, but we sometimes
+ // have a dependency on a katiVintfManifestInstall to a binary instead of to the binary directly, and
+ // the mtime of the katiVintfManifestInstall must be updated when the binary is modified, so use a
// normal dependency here instead of an order-only dependency.
fmt.Fprintf(buf, " %s", symlink.from.String())
}
@@ -507,7 +534,7 @@
if symlink.from != nil {
rel, err := filepath.Rel(filepath.Dir(symlink.to.String()), symlink.from.String())
if err != nil {
- panic(fmt.Errorf("failed to find relative path for symlink from %q to %q: %w",
+ panic(fmt.Errorf("failed to find relative path for katiVintfManifestInstall from %q to %q: %w",
symlink.from.String(), symlink.to.String(), err))
}
fromStr = rel
@@ -521,6 +548,19 @@
fmt.Fprintln(buf)
}
+ for _, install := range katiVintfManifestInstalls {
+ // Write a rule for each vintf install request that calls the copy-vintf-manifest-chedk make function.
+ fmt.Fprintf(buf, "$(eval $(call copy-vintf-manifest-checked, %s, %s))\n", install.from.String(), install.to.String())
+
+ if len(install.implicitDeps) > 0 {
+ panic(fmt.Errorf("unsupported implicitDeps %q in vintf install rule %q", install.implicitDeps, install.to))
+ }
+ if len(install.orderOnlyDeps) > 0 {
+ panic(fmt.Errorf("unsupported orderOnlyDeps %q in vintf install rule %q", install.orderOnlyDeps, install.to))
+ }
+
+ fmt.Fprintln(buf)
+ }
return buf.Bytes()
}
diff --git a/android/module.go b/android/module.go
index f571157..1a428e5 100644
--- a/android/module.go
+++ b/android/module.go
@@ -23,6 +23,7 @@
"net/url"
"path/filepath"
"reflect"
+ "slices"
"sort"
"strings"
@@ -77,6 +78,8 @@
InstallInDebugRamdisk() bool
InstallInRecovery() bool
InstallInRoot() bool
+ InstallInOdm() bool
+ InstallInProduct() bool
InstallInVendor() bool
InstallForceOS() (*OsType, *ArchType)
PartitionTag(DeviceConfig) string
@@ -837,8 +840,12 @@
// katiInstalls tracks the install rules that were created by Soong but are being exported
// to Make to convert to ninja rules so that Make can add additional dependencies.
katiInstalls katiInstalls
- katiSymlinks katiInstalls
- testData []DataPath
+ // katiInitRcInstalls and katiVintfInstalls track the install rules created by Soong that are
+ // allowed to have duplicates across modules and variants.
+ katiInitRcInstalls katiInstalls
+ katiVintfInstalls katiInstalls
+ katiSymlinks katiInstalls
+ testData []DataPath
// The files to copy to the dist as explicitly specified in the .bp file.
distFiles TaggedDistFiles
@@ -861,12 +868,19 @@
initRcPaths Paths
vintfFragmentsPaths Paths
+ installedInitRcPaths InstallPaths
+ installedVintfFragmentsPaths InstallPaths
+
// set of dependency module:location mappings used to populate the license metadata for
// apex containers.
licenseInstallMap []string
// The path to the generated license metadata file for the module.
licenseMetadataFile WritablePath
+
+ // moduleInfoJSON can be filled out by GenerateAndroidBuildActions to write a JSON file that will
+ // be included in the final module-info.json produced by Make.
+ moduleInfoJSON *ModuleInfoJSON
}
func (m *ModuleBase) AddJSONData(d *map[string]interface{}) {
@@ -1399,6 +1413,14 @@
return Bool(m.commonProperties.Recovery)
}
+func (m *ModuleBase) InstallInOdm() bool {
+ return false
+}
+
+func (m *ModuleBase) InstallInProduct() bool {
+ return false
+}
+
func (m *ModuleBase) InstallInVendor() bool {
return Bool(m.commonProperties.Vendor) || Bool(m.commonProperties.Soc_specific) || Bool(m.commonProperties.Proprietary)
}
@@ -1648,7 +1670,7 @@
if !ctx.PrimaryArch() {
suffix = append(suffix, ctx.Arch().ArchType.String())
}
- if apexInfo := ctx.Provider(ApexInfoProvider).(ApexInfo); !apexInfo.IsForPlatform() {
+ if apexInfo, _ := ModuleProvider(ctx, ApexInfoProvider); !apexInfo.IsForPlatform() {
suffix = append(suffix, apexInfo.ApexVariationName)
}
@@ -1674,6 +1696,41 @@
}
})
+ if m.Device() {
+ // Handle any init.rc and vintf fragment files requested by the module. All files installed by this
+ // module will automatically have a dependency on the installed init.rc or vintf fragment file.
+ // The same init.rc or vintf fragment file may be requested by multiple modules or variants,
+ // so instead of installing them now just compute the install path and store it for later.
+ // The full list of all init.rc and vintf fragment install rules will be deduplicated later
+ // so only a single rule is created for each init.rc or vintf fragment file.
+
+ if !m.InVendorRamdisk() {
+ m.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc)
+ rcDir := PathForModuleInstall(ctx, "etc", "init")
+ for _, src := range m.initRcPaths {
+ installedInitRc := rcDir.Join(ctx, src.Base())
+ m.katiInitRcInstalls = append(m.katiInitRcInstalls, katiInstall{
+ from: src,
+ to: installedInitRc,
+ })
+ ctx.PackageFile(rcDir, src.Base(), src)
+ m.installedInitRcPaths = append(m.installedInitRcPaths, installedInitRc)
+ }
+ }
+
+ m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments)
+ vintfDir := PathForModuleInstall(ctx, "etc", "vintf", "manifest")
+ for _, src := range m.vintfFragmentsPaths {
+ installedVintfFragment := vintfDir.Join(ctx, src.Base())
+ m.katiVintfInstalls = append(m.katiVintfInstalls, katiInstall{
+ from: src,
+ to: installedVintfFragment,
+ })
+ ctx.PackageFile(vintfDir, src.Base(), src)
+ m.installedVintfFragmentsPaths = append(m.installedVintfFragmentsPaths, installedVintfFragment)
+ }
+ }
+
licensesPropertyFlattener(ctx)
if ctx.Failed() {
return
@@ -1684,18 +1741,6 @@
return
}
- m.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc)
- rcDir := PathForModuleInstall(ctx, "etc", "init")
- for _, src := range m.initRcPaths {
- ctx.PackageFile(rcDir, filepath.Base(src.String()), src)
- }
-
- m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments)
- vintfDir := PathForModuleInstall(ctx, "etc", "vintf", "manifest")
- for _, src := range m.vintfFragmentsPaths {
- ctx.PackageFile(vintfDir, filepath.Base(src.String()), src)
- }
-
// Create the set of tagged dist files after calling GenerateAndroidBuildActions
// as GenerateTaggedDistFiles() calls OutputFiles(tag) and so relies on the
// output paths being set which must be done before or during
@@ -1731,11 +1776,90 @@
buildLicenseMetadata(ctx, m.licenseMetadataFile)
+ if m.moduleInfoJSON != nil {
+ var installed InstallPaths
+ installed = append(installed, m.katiInstalls.InstallPaths()...)
+ installed = append(installed, m.katiSymlinks.InstallPaths()...)
+ installed = append(installed, m.katiInitRcInstalls.InstallPaths()...)
+ installed = append(installed, m.katiVintfInstalls.InstallPaths()...)
+ installedStrings := installed.Strings()
+
+ var targetRequired, hostRequired []string
+ if ctx.Host() {
+ targetRequired = m.commonProperties.Target_required
+ } else {
+ hostRequired = m.commonProperties.Host_required
+ }
+
+ var data []string
+ for _, d := range m.testData {
+ data = append(data, d.ToRelativeInstallPath())
+ }
+
+ if m.moduleInfoJSON.Uninstallable {
+ installedStrings = nil
+ if len(m.moduleInfoJSON.CompatibilitySuites) == 1 && m.moduleInfoJSON.CompatibilitySuites[0] == "null-suite" {
+ m.moduleInfoJSON.CompatibilitySuites = nil
+ m.moduleInfoJSON.TestConfig = nil
+ m.moduleInfoJSON.AutoTestConfig = nil
+ data = nil
+ }
+ }
+
+ m.moduleInfoJSON.core = CoreModuleInfoJSON{
+ RegisterName: m.moduleInfoRegisterName(ctx, m.moduleInfoJSON.SubName),
+ Path: []string{ctx.ModuleDir()},
+ Installed: installedStrings,
+ ModuleName: m.BaseModuleName() + m.moduleInfoJSON.SubName,
+ SupportedVariants: []string{m.moduleInfoVariant(ctx)},
+ TargetDependencies: targetRequired,
+ HostDependencies: hostRequired,
+ Data: data,
+ }
+ SetProvider(ctx, ModuleInfoJSONProvider, m.moduleInfoJSON)
+ }
+
m.buildParams = ctx.buildParams
m.ruleParams = ctx.ruleParams
m.variables = ctx.variables
}
+func (m *ModuleBase) moduleInfoRegisterName(ctx ModuleContext, subName string) string {
+ name := m.BaseModuleName()
+
+ prefix := ""
+ if ctx.Host() {
+ if ctx.Os() != ctx.Config().BuildOS {
+ prefix = "host_cross_"
+ }
+ }
+ suffix := ""
+ arches := slices.Clone(ctx.Config().Targets[ctx.Os()])
+ arches = slices.DeleteFunc(arches, func(target Target) bool {
+ return target.NativeBridge != ctx.Target().NativeBridge
+ })
+ if len(arches) > 0 && ctx.Arch().ArchType != arches[0].Arch.ArchType {
+ if ctx.Arch().ArchType.Multilib == "lib32" {
+ suffix = "_32"
+ } else {
+ suffix = "_64"
+ }
+ }
+ return prefix + name + subName + suffix
+}
+
+func (m *ModuleBase) moduleInfoVariant(ctx ModuleContext) string {
+ variant := "DEVICE"
+ if ctx.Host() {
+ if ctx.Os() != ctx.Config().BuildOS {
+ variant = "HOST_CROSS"
+ } else {
+ variant = "HOST"
+ }
+ }
+ return variant
+}
+
// Check the supplied dist structure to make sure that it is valid.
//
// property - the base property, e.g. dist or dists[1], which is combined with the
diff --git a/android/module_context.go b/android/module_context.go
index 39986df..e772f8b 100644
--- a/android/module_context.go
+++ b/android/module_context.go
@@ -181,6 +181,8 @@
InstallInDebugRamdisk() bool
InstallInRecovery() bool
InstallInRoot() bool
+ InstallInOdm() bool
+ InstallInProduct() bool
InstallInVendor() bool
InstallForceOS() (*OsType, *ArchType)
@@ -208,6 +210,11 @@
// LicenseMetadataFile returns the path where the license metadata for this module will be
// generated.
LicenseMetadataFile() Path
+
+ // ModuleInfoJSON returns a pointer to the ModuleInfoJSON struct that can be filled out by
+ // 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
}
type moduleContext struct {
@@ -438,6 +445,14 @@
return m.module.InstallForceOS()
}
+func (m *moduleContext) InstallInOdm() bool {
+ return m.module.InstallInOdm()
+}
+
+func (m *moduleContext) InstallInProduct() bool {
+ return m.module.InstallInProduct()
+}
+
func (m *moduleContext) InstallInVendor() bool {
return m.module.InstallInVendor()
}
@@ -508,6 +523,8 @@
if !m.skipInstall() {
deps = append(deps, InstallPaths(m.module.base().installFilesDepSet.ToList())...)
+ deps = append(deps, m.module.base().installedInitRcPaths...)
+ deps = append(deps, m.module.base().installedVintfFragmentsPaths...)
var implicitDeps, orderOnlyDeps Paths
@@ -685,6 +702,15 @@
return m.module.base().licenseMetadataFile
}
+func (m *moduleContext) ModuleInfoJSON() *ModuleInfoJSON {
+ if moduleInfoJSON := m.module.base().moduleInfoJSON; moduleInfoJSON != nil {
+ return moduleInfoJSON
+ }
+ moduleInfoJSON := &ModuleInfoJSON{}
+ m.module.base().moduleInfoJSON = moduleInfoJSON
+ return moduleInfoJSON
+}
+
// Returns a list of paths expanded from globs and modules referenced using ":module" syntax. The property must
// be tagged with `android:"path" to support automatic source module dependency resolution.
//
diff --git a/android/module_info_json.go b/android/module_info_json.go
new file mode 100644
index 0000000..1c0a38e
--- /dev/null
+++ b/android/module_info_json.go
@@ -0,0 +1,103 @@
+package android
+
+import (
+ "encoding/json"
+ "io"
+ "slices"
+
+ "github.com/google/blueprint"
+)
+
+type CoreModuleInfoJSON struct {
+ RegisterName string `json:"-"`
+ Path []string `json:"path,omitempty"` // $(sort $(ALL_MODULES.$(m).PATH))
+ Installed []string `json:"installed,omitempty"` // $(sort $(ALL_MODULES.$(m).INSTALLED))
+ ModuleName string `json:"module_name,omitempty"` // $(ALL_MODULES.$(m).MODULE_NAME)
+ SupportedVariants []string `json:"supported_variants,omitempty"` // $(sort $(ALL_MODULES.$(m).SUPPORTED_VARIANTS))
+ HostDependencies []string `json:"host_dependencies,omitempty"` // $(sort $(ALL_MODULES.$(m).HOST_REQUIRED_FROM_TARGET))
+ TargetDependencies []string `json:"target_dependencies,omitempty"` // $(sort $(ALL_MODULES.$(m).TARGET_REQUIRED_FROM_HOST))
+ Data []string `json:"data,omitempty"` // $(sort $(ALL_MODULES.$(m).TEST_DATA))
+}
+
+type ModuleInfoJSON struct {
+ core CoreModuleInfoJSON
+ SubName string `json:"-"`
+ Uninstallable bool `json:"-"`
+ Class []string `json:"class,omitempty"` // $(sort $(ALL_MODULES.$(m).CLASS))
+ Tags []string `json:"tags,omitempty"` // $(sort $(ALL_MODULES.$(m).TAGS))
+ Dependencies []string `json:"dependencies,omitempty"` // $(sort $(ALL_DEPS.$(m).ALL_DEPS))
+ SharedLibs []string `json:"shared_libs,omitempty"` // $(sort $(ALL_MODULES.$(m).SHARED_LIBS))
+ StaticLibs []string `json:"static_libs,omitempty"` // $(sort $(ALL_MODULES.$(m).STATIC_LIBS))
+ SystemSharedLibs []string `json:"system_shared_libs,omitempty"` // $(sort $(ALL_MODULES.$(m).SYSTEM_SHARED_LIBS))
+ Srcs []string `json:"srcs,omitempty"` // $(sort $(ALL_MODULES.$(m).SRCS))
+ SrcJars []string `json:"srcjars,omitempty"` // $(sort $(ALL_MODULES.$(m).SRCJARS))
+ ClassesJar []string `json:"classes_jar,omitempty"` // $(sort $(ALL_MODULES.$(m).CLASSES_JAR))
+ TestMainlineModules []string `json:"test_mainline_modules,omitempty"` // $(sort $(ALL_MODULES.$(m).TEST_MAINLINE_MODULES))
+ IsUnitTest bool `json:"is_unit_test,omitempty"` // $(ALL_MODULES.$(m).IS_UNIT_TEST)
+ TestOptionsTags []string `json:"test_options_tags,omitempty"` // $(sort $(ALL_MODULES.$(m).TEST_OPTIONS_TAGS))
+ RuntimeDependencies []string `json:"runtime_dependencies,omitempty"` // $(sort $(ALL_MODULES.$(m).LOCAL_RUNTIME_LIBRARIES))
+ StaticDependencies []string `json:"static_dependencies,omitempty"` // $(sort $(ALL_MODULES.$(m).LOCAL_STATIC_LIBRARIES))
+ DataDependencies []string `json:"data_dependencies,omitempty"` // $(sort $(ALL_MODULES.$(m).TEST_DATA_BINS))
+
+ CompatibilitySuites []string `json:"compatibility_suites,omitempty"` // $(sort $(ALL_MODULES.$(m).COMPATIBILITY_SUITES))
+ AutoTestConfig []string `json:"auto_test_config,omitempty"` // $(ALL_MODULES.$(m).auto_test_config)
+ TestConfig []string `json:"test_config,omitempty"` // $(strip $(ALL_MODULES.$(m).TEST_CONFIG) $(ALL_MODULES.$(m).EXTRA_TEST_CONFIGS)
+}
+
+//ALL_DEPS.$(LOCAL_MODULE).ALL_DEPS := $(sort \
+//$(ALL_DEPS.$(LOCAL_MODULE).ALL_DEPS) \
+//$(LOCAL_STATIC_LIBRARIES) \
+//$(LOCAL_WHOLE_STATIC_LIBRARIES) \
+//$(LOCAL_SHARED_LIBRARIES) \
+//$(LOCAL_DYLIB_LIBRARIES) \
+//$(LOCAL_RLIB_LIBRARIES) \
+//$(LOCAL_PROC_MACRO_LIBRARIES) \
+//$(LOCAL_HEADER_LIBRARIES) \
+//$(LOCAL_STATIC_JAVA_LIBRARIES) \
+//$(LOCAL_JAVA_LIBRARIES) \
+//$(LOCAL_JNI_SHARED_LIBRARIES))
+
+type combinedModuleInfoJSON struct {
+ *CoreModuleInfoJSON
+ *ModuleInfoJSON
+}
+
+func encodeModuleInfoJSON(w io.Writer, moduleInfoJSON *ModuleInfoJSON) error {
+ moduleInfoJSONCopy := *moduleInfoJSON
+
+ sortAndUnique := func(s *[]string) {
+ *s = slices.Clone(*s)
+ slices.Sort(*s)
+ *s = slices.Compact(*s)
+ }
+
+ sortAndUnique(&moduleInfoJSONCopy.core.Path)
+ sortAndUnique(&moduleInfoJSONCopy.core.Installed)
+ sortAndUnique(&moduleInfoJSONCopy.core.SupportedVariants)
+ sortAndUnique(&moduleInfoJSONCopy.core.HostDependencies)
+ sortAndUnique(&moduleInfoJSONCopy.core.TargetDependencies)
+ sortAndUnique(&moduleInfoJSONCopy.core.Data)
+
+ sortAndUnique(&moduleInfoJSONCopy.Class)
+ sortAndUnique(&moduleInfoJSONCopy.Tags)
+ sortAndUnique(&moduleInfoJSONCopy.Dependencies)
+ sortAndUnique(&moduleInfoJSONCopy.SharedLibs)
+ sortAndUnique(&moduleInfoJSONCopy.StaticLibs)
+ sortAndUnique(&moduleInfoJSONCopy.SystemSharedLibs)
+ sortAndUnique(&moduleInfoJSONCopy.Srcs)
+ sortAndUnique(&moduleInfoJSONCopy.SrcJars)
+ sortAndUnique(&moduleInfoJSONCopy.ClassesJar)
+ sortAndUnique(&moduleInfoJSONCopy.TestMainlineModules)
+ sortAndUnique(&moduleInfoJSONCopy.TestOptionsTags)
+ sortAndUnique(&moduleInfoJSONCopy.RuntimeDependencies)
+ sortAndUnique(&moduleInfoJSONCopy.StaticDependencies)
+ sortAndUnique(&moduleInfoJSONCopy.DataDependencies)
+ sortAndUnique(&moduleInfoJSONCopy.CompatibilitySuites)
+ sortAndUnique(&moduleInfoJSONCopy.AutoTestConfig)
+ sortAndUnique(&moduleInfoJSONCopy.TestConfig)
+
+ encoder := json.NewEncoder(w)
+ return encoder.Encode(combinedModuleInfoJSON{&moduleInfoJSONCopy.core, &moduleInfoJSONCopy})
+}
+
+var ModuleInfoJSONProvider = blueprint.NewProvider[*ModuleInfoJSON]()
diff --git a/android/mutator.go b/android/mutator.go
index 0d391a4..93c519d 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -325,7 +325,7 @@
// if the value is not of the appropriate type, or if the module is not a newly created
// variant of the current module. The value should not be modified after being passed to
// SetVariationProvider.
- SetVariationProvider(module blueprint.Module, provider blueprint.ProviderKey, value interface{})
+ SetVariationProvider(module blueprint.Module, provider blueprint.AnyProviderKey, value interface{})
}
type bottomUpMutatorContext struct {
@@ -746,6 +746,6 @@
b.bp.CreateAliasVariation(fromVariationName, toVariationName)
}
-func (b *bottomUpMutatorContext) SetVariationProvider(module blueprint.Module, provider blueprint.ProviderKey, value interface{}) {
+func (b *bottomUpMutatorContext) SetVariationProvider(module blueprint.Module, provider blueprint.AnyProviderKey, value interface{}) {
b.bp.SetVariationProvider(module, provider, value)
}
diff --git a/android/packaging.go b/android/packaging.go
index 503bb97..8873540 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -17,6 +17,7 @@
import (
"fmt"
"path/filepath"
+ "strings"
"github.com/google/blueprint"
)
@@ -239,7 +240,14 @@
// CopySpecsToDir is a helper that will add commands to the rule builder to copy the PackagingSpec
// entries into the specified directory.
func (p *PackagingBase) CopySpecsToDir(ctx ModuleContext, builder *RuleBuilder, specs map[string]PackagingSpec, dir WritablePath) (entries []string) {
+ if len(specs) == 0 {
+ return entries
+ }
seenDir := make(map[string]bool)
+ preparerPath := PathForModuleOut(ctx, "preparer.sh")
+ cmd := builder.Command().Tool(preparerPath)
+ var sb strings.Builder
+ sb.WriteString("set -e\n")
for _, k := range SortedKeys(specs) {
ps := specs[k]
destPath := filepath.Join(dir.String(), ps.relPathInPackage)
@@ -247,18 +255,21 @@
entries = append(entries, ps.relPathInPackage)
if _, ok := seenDir[destDir]; !ok {
seenDir[destDir] = true
- builder.Command().Text("mkdir").Flag("-p").Text(destDir)
+ sb.WriteString(fmt.Sprintf("mkdir -p %s\n", destDir))
}
if ps.symlinkTarget == "" {
- builder.Command().Text("cp").Input(ps.srcPath).Text(destPath)
+ cmd.Implicit(ps.srcPath)
+ sb.WriteString(fmt.Sprintf("cp %s %s\n", ps.srcPath, destPath))
} else {
- builder.Command().Text("ln").Flag("-sf").Text(ps.symlinkTarget).Text(destPath)
+ sb.WriteString(fmt.Sprintf("ln -sf %s %s\n", ps.symlinkTarget, destPath))
}
if ps.executable {
- builder.Command().Text("chmod").Flag("a+x").Text(destPath)
+ sb.WriteString(fmt.Sprintf("chmod a+x %s\n", destPath))
}
}
+ WriteExecutableFileRuleVerbatim(ctx, preparerPath, sb.String())
+
return entries
}
diff --git a/android/paths.go b/android/paths.go
index 3f35449..6aabe4f 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -111,6 +111,9 @@
InstallInDebugRamdisk() bool
InstallInRecovery() bool
InstallInRoot() bool
+ InstallInOdm() bool
+ InstallInProduct() bool
+ InstallInVendor() bool
InstallForceOS() (*OsType, *ArchType)
}
@@ -152,6 +155,18 @@
return ctx.Module().InstallInRoot()
}
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallInOdm() bool {
+ return ctx.Module().InstallInOdm()
+}
+
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallInProduct() bool {
+ return ctx.Module().InstallInProduct()
+}
+
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallInVendor() bool {
+ return ctx.Module().InstallInVendor()
+}
+
func (ctx *baseModuleContextToModuleInstallPathContext) InstallForceOS() (*OsType, *ArchType) {
return ctx.Module().InstallForceOS()
}
@@ -1866,11 +1881,11 @@
// the layout of recovery partion is the same as that of system partition
partition = "recovery/root/system"
}
- } else if ctx.SocSpecific() {
+ } else if ctx.SocSpecific() || ctx.InstallInVendor() {
partition = ctx.DeviceConfig().VendorPath()
- } else if ctx.DeviceSpecific() {
+ } else if ctx.DeviceSpecific() || ctx.InstallInOdm() {
partition = ctx.DeviceConfig().OdmPath()
- } else if ctx.ProductSpecific() {
+ } else if ctx.ProductSpecific() || ctx.InstallInProduct() {
partition = ctx.DeviceConfig().ProductPath()
} else if ctx.SystemExtSpecific() {
partition = ctx.DeviceConfig().SystemExtPath()
@@ -2066,6 +2081,9 @@
inDebugRamdisk bool
inRecovery bool
inRoot bool
+ inOdm bool
+ inProduct bool
+ inVendor bool
forceOS *OsType
forceArch *ArchType
}
@@ -2108,6 +2126,18 @@
return m.inRoot
}
+func (m testModuleInstallPathContext) InstallInOdm() bool {
+ return m.inOdm
+}
+
+func (m testModuleInstallPathContext) InstallInProduct() bool {
+ return m.inProduct
+}
+
+func (m testModuleInstallPathContext) InstallInVendor() bool {
+ return m.inVendor
+}
+
func (m testModuleInstallPathContext) InstallForceOS() (*OsType, *ArchType) {
return m.forceOS, m.forceArch
}
diff --git a/android/prebuilt.go b/android/prebuilt.go
index a32a37d..6a417a8 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -461,8 +461,8 @@
// Propagate the provider received from `all_apex_contributions`
// to the source module
ctx.VisitDirectDepsWithTag(acDepTag, func(am Module) {
- psi := ctx.OtherModuleProvider(am, PrebuiltSelectionInfoProvider).(PrebuiltSelectionInfoMap)
- ctx.SetProvider(PrebuiltSelectionInfoProvider, psi)
+ psi, _ := OtherModuleProvider(ctx, am, PrebuiltSelectionInfoProvider)
+ SetProvider(ctx, PrebuiltSelectionInfoProvider, psi)
})
} else if s, ok := ctx.Module().(Module); ok {
@@ -548,9 +548,7 @@
// Use `all_apex_contributions` for source vs prebuilt selection.
psi := PrebuiltSelectionInfoMap{}
ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(am Module) {
- if ctx.OtherModuleHasProvider(am, PrebuiltSelectionInfoProvider) {
- psi = ctx.OtherModuleProvider(am, PrebuiltSelectionInfoProvider).(PrebuiltSelectionInfoMap)
- }
+ psi, _ = OtherModuleProvider(ctx, am, PrebuiltSelectionInfoProvider)
})
// If the source module is explicitly listed in the metadata module, use that
diff --git a/android/provider.go b/android/provider.go
new file mode 100644
index 0000000..3b9c5d2
--- /dev/null
+++ b/android/provider.go
@@ -0,0 +1,120 @@
+package android
+
+import (
+ "github.com/google/blueprint"
+)
+
+// OtherModuleProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or
+// TopDownMutatorContext for use in OtherModuleProvider.
+type OtherModuleProviderContext interface {
+ otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
+}
+
+var _ OtherModuleProviderContext = BaseModuleContext(nil)
+var _ OtherModuleProviderContext = ModuleContext(nil)
+var _ OtherModuleProviderContext = BottomUpMutatorContext(nil)
+var _ OtherModuleProviderContext = TopDownMutatorContext(nil)
+
+// OtherModuleProvider reads the provider for the given module. If the provider has been set the value is
+// returned and the boolean is true. If it has not been set the zero value of the provider's type is returned
+// and the boolean is false. The value returned may be a deep copy of the value originally passed to SetProvider.
+//
+// OtherModuleProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or
+// TopDownMutatorContext.
+func OtherModuleProvider[K any](ctx OtherModuleProviderContext, module blueprint.Module, provider blueprint.ProviderKey[K]) (K, bool) {
+ value, ok := ctx.otherModuleProvider(module, provider)
+ if !ok {
+ var k K
+ return k, false
+ }
+ return value.(K), ok
+}
+
+// ModuleProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or
+// TopDownMutatorContext for use in ModuleProvider.
+type ModuleProviderContext interface {
+ provider(provider blueprint.AnyProviderKey) (any, bool)
+}
+
+var _ ModuleProviderContext = BaseModuleContext(nil)
+var _ ModuleProviderContext = ModuleContext(nil)
+var _ ModuleProviderContext = BottomUpMutatorContext(nil)
+var _ ModuleProviderContext = TopDownMutatorContext(nil)
+
+// ModuleProvider reads the provider for the current module. If the provider has been set the value is
+// returned and the boolean is true. If it has not been set the zero value of the provider's type is returned
+// and the boolean is false. The value returned may be a deep copy of the value originally passed to SetProvider.
+//
+// ModuleProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or
+// TopDownMutatorContext.
+func ModuleProvider[K any](ctx ModuleProviderContext, provider blueprint.ProviderKey[K]) (K, bool) {
+ value, ok := ctx.provider(provider)
+ if !ok {
+ var k K
+ return k, false
+ }
+ return value.(K), ok
+}
+
+type SingletonModuleProviderContext interface {
+ moduleProvider(blueprint.Module, blueprint.AnyProviderKey) (any, bool)
+}
+
+var _ SingletonModuleProviderContext = SingletonContext(nil)
+var _ SingletonModuleProviderContext = (*TestContext)(nil)
+
+// SingletonModuleProvider wraps blueprint.SingletonModuleProvider to provide a type-safe method to retrieve the value
+// of the given provider from a module using a SingletonContext. If the provider has not been set the first return
+// value will be the zero value of the provider's type, and the second return value will be false. If the provider has
+// been set the second return value will be true.
+func SingletonModuleProvider[K any](ctx SingletonModuleProviderContext, module blueprint.Module, provider blueprint.ProviderKey[K]) (K, bool) {
+ value, ok := ctx.moduleProvider(module, provider)
+ if !ok {
+ var k K
+ return k, false
+ }
+ return value.(K), ok
+}
+
+// SetProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or
+// TopDownMutatorContext for use in SetProvider.
+type SetProviderContext interface {
+ setProvider(provider blueprint.AnyProviderKey, value any)
+}
+
+var _ SetProviderContext = BaseModuleContext(nil)
+var _ SetProviderContext = ModuleContext(nil)
+var _ SetProviderContext = BottomUpMutatorContext(nil)
+var _ SetProviderContext = TopDownMutatorContext(nil)
+
+// SetProvider sets the value for a provider for the current module. It panics if not called
+// during the appropriate mutator or GenerateBuildActions pass for the provider, if the value
+// is not of the appropriate type, or if the value has already been set. The value should not
+// be modified after being passed to SetProvider.
+//
+// SetProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or
+// TopDownMutatorContext.
+func SetProvider[K any](ctx SetProviderContext, provider blueprint.ProviderKey[K], value K) {
+ ctx.setProvider(provider, value)
+}
+
+var _ OtherModuleProviderContext = (*otherModuleProviderAdaptor)(nil)
+
+// An OtherModuleProviderFunc can be passed to NewOtherModuleProviderAdaptor to create an OtherModuleProviderContext
+// for use in tests.
+type OtherModuleProviderFunc func(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
+
+type otherModuleProviderAdaptor struct {
+ otherModuleProviderFunc OtherModuleProviderFunc
+}
+
+func (p *otherModuleProviderAdaptor) otherModuleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
+ return p.otherModuleProviderFunc(module, provider)
+}
+
+// NewOtherModuleProviderAdaptor returns an OtherModuleProviderContext that proxies calls to otherModuleProvider to
+// the provided OtherModuleProviderFunc. It can be used in tests to unit test methods that need to call
+// android.OtherModuleProvider.
+func NewOtherModuleProviderAdaptor(otherModuleProviderFunc OtherModuleProviderFunc) OtherModuleProviderContext {
+ return &otherModuleProviderAdaptor{otherModuleProviderFunc}
+}
diff --git a/android/raw_files.go b/android/raw_files.go
new file mode 100644
index 0000000..9d7f5e8
--- /dev/null
+++ b/android/raw_files.go
@@ -0,0 +1,279 @@
+// 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 android
+
+import (
+ "crypto/sha1"
+ "encoding/hex"
+ "fmt"
+ "github.com/google/blueprint"
+ "io"
+ "io/fs"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "github.com/google/blueprint/proptools"
+)
+
+// WriteFileRule creates a ninja rule to write contents to a file by immediately writing the
+// contents, plus a trailing newline, to a file in out/soong/raw-${TARGET_PRODUCT}, and then creating
+// a ninja rule to copy the file into place.
+func WriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
+ writeFileRule(ctx, outputFile, content, true, false)
+}
+
+// WriteFileRuleVerbatim creates a ninja rule to write contents to a file by immediately writing the
+// contents to a file in out/soong/raw-${TARGET_PRODUCT}, and then creating a ninja rule to copy the file into place.
+func WriteFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) {
+ writeFileRule(ctx, outputFile, content, false, false)
+}
+
+// WriteExecutableFileRuleVerbatim is the same as WriteFileRuleVerbatim, but runs chmod +x on the result
+func WriteExecutableFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) {
+ writeFileRule(ctx, outputFile, content, false, true)
+}
+
+// tempFile provides a testable wrapper around a file in out/soong/.temp. It writes to a temporary file when
+// not in tests, but writes to a buffer in memory when used in tests.
+type tempFile struct {
+ // tempFile contains wraps an io.Writer, which will be file if testMode is false, or testBuf if it is true.
+ io.Writer
+
+ file *os.File
+ testBuf *strings.Builder
+}
+
+func newTempFile(ctx BuilderContext, pattern string, testMode bool) *tempFile {
+ if testMode {
+ testBuf := &strings.Builder{}
+ return &tempFile{
+ Writer: testBuf,
+ testBuf: testBuf,
+ }
+ } else {
+ f, err := os.CreateTemp(absolutePath(ctx.Config().tempDir()), pattern)
+ if err != nil {
+ panic(fmt.Errorf("failed to open temporary raw file: %w", err))
+ }
+ return &tempFile{
+ Writer: f,
+ file: f,
+ }
+ }
+}
+
+func (t *tempFile) close() error {
+ if t.file != nil {
+ return t.file.Close()
+ }
+ return nil
+}
+
+func (t *tempFile) name() string {
+ if t.file != nil {
+ return t.file.Name()
+ }
+ return "temp_file_in_test"
+}
+
+func (t *tempFile) rename(to string) {
+ if t.file != nil {
+ os.MkdirAll(filepath.Dir(to), 0777)
+ err := os.Rename(t.file.Name(), to)
+ if err != nil {
+ panic(fmt.Errorf("failed to rename %s to %s: %w", t.file.Name(), to, err))
+ }
+ }
+}
+
+func (t *tempFile) remove() error {
+ if t.file != nil {
+ return os.Remove(t.file.Name())
+ }
+ return nil
+}
+
+func writeContentToTempFileAndHash(ctx BuilderContext, content string, newline bool) (*tempFile, string) {
+ tempFile := newTempFile(ctx, "raw", ctx.Config().captureBuild)
+ defer tempFile.close()
+
+ hash := sha1.New()
+ w := io.MultiWriter(tempFile, hash)
+
+ _, err := io.WriteString(w, content)
+ if err == nil && newline {
+ _, err = io.WriteString(w, "\n")
+ }
+ if err != nil {
+ panic(fmt.Errorf("failed to write to temporary raw file %s: %w", tempFile.name(), err))
+ }
+ return tempFile, hex.EncodeToString(hash.Sum(nil))
+}
+
+func writeFileRule(ctx BuilderContext, outputFile WritablePath, content string, newline bool, executable bool) {
+ // Write the contents to a temporary file while computing its hash.
+ tempFile, hash := writeContentToTempFileAndHash(ctx, content, newline)
+
+ // Shard the final location of the raw file into a subdirectory based on the first two characters of the
+ // hash to avoid making the raw directory too large and slowing down accesses.
+ relPath := filepath.Join(hash[0:2], hash)
+
+ // These files are written during soong_build. If something outside the build deleted them there would be no
+ // trigger to rerun soong_build, and the build would break with dependencies on missing files. Writing them
+ // to their final locations would risk having them deleted when cleaning a module, and would also pollute the
+ // output directory with files for modules that have never been built.
+ // Instead, the files are written to a separate "raw" directory next to the build.ninja file, and a ninja
+ // rule is created to copy the files into their final location as needed.
+ // Obsolete files written by previous runs of soong_build must be cleaned up to avoid continually growing
+ // disk usage as the hashes of the files change over time. The cleanup must not remove files that were
+ // created by previous runs of soong_build for other products, as the build.ninja files for those products
+ // may still exist and still reference those files. The raw files from different products are kept
+ // separate by appending the Make_suffix to the directory name.
+ rawPath := PathForOutput(ctx, "raw"+proptools.String(ctx.Config().productVariables.Make_suffix), relPath)
+
+ rawFileInfo := rawFileInfo{
+ relPath: relPath,
+ }
+
+ if ctx.Config().captureBuild {
+ // When running tests tempFile won't write to disk, instead store the contents for later retrieval by
+ // ContentFromFileRuleForTests.
+ rawFileInfo.contentForTests = tempFile.testBuf.String()
+ }
+
+ rawFileSet := getRawFileSet(ctx.Config())
+ if _, exists := rawFileSet.LoadOrStore(hash, rawFileInfo); exists {
+ // If a raw file with this hash has already been created delete the temporary file.
+ tempFile.remove()
+ } else {
+ // If this is the first time this hash has been seen then move it from the temporary directory
+ // to the raw directory. If the file already exists in the raw directory assume it has the correct
+ // contents.
+ absRawPath := absolutePath(rawPath.String())
+ _, err := os.Stat(absRawPath)
+ if os.IsNotExist(err) {
+ tempFile.rename(absRawPath)
+ } else if err != nil {
+ panic(fmt.Errorf("failed to stat %q: %w", absRawPath, err))
+ } else {
+ tempFile.remove()
+ }
+ }
+
+ // Emit a rule to copy the file from raw directory to the final requested location in the output tree.
+ // Restat is used to ensure that two different products that produce identical files copied from their
+ // own raw directories they don't cause everything downstream to rebuild.
+ rule := rawFileCopy
+ if executable {
+ rule = rawFileCopyExecutable
+ }
+ ctx.Build(pctx, BuildParams{
+ Rule: rule,
+ Input: rawPath,
+ Output: outputFile,
+ Description: "raw " + outputFile.Base(),
+ })
+}
+
+var (
+ rawFileCopy = pctx.AndroidStaticRule("rawFileCopy",
+ blueprint.RuleParams{
+ Command: "if ! cmp -s $in $out; then cp $in $out; fi",
+ Description: "copy raw file $out",
+ Restat: true,
+ })
+ rawFileCopyExecutable = pctx.AndroidStaticRule("rawFileCopyExecutable",
+ blueprint.RuleParams{
+ Command: "if ! cmp -s $in $out; then cp $in $out; fi && chmod +x $out",
+ Description: "copy raw exectuable file $out",
+ Restat: true,
+ })
+)
+
+type rawFileInfo struct {
+ relPath string
+ contentForTests string
+}
+
+var rawFileSetKey OnceKey = NewOnceKey("raw file set")
+
+func getRawFileSet(config Config) *SyncMap[string, rawFileInfo] {
+ return config.Once(rawFileSetKey, func() any {
+ return &SyncMap[string, rawFileInfo]{}
+ }).(*SyncMap[string, rawFileInfo])
+}
+
+// ContentFromFileRuleForTests returns the content that was passed to a WriteFileRule for use
+// in tests.
+func ContentFromFileRuleForTests(t *testing.T, ctx *TestContext, params TestingBuildParams) string {
+ t.Helper()
+ if params.Rule != rawFileCopy && params.Rule != rawFileCopyExecutable {
+ t.Errorf("expected params.Rule to be rawFileCopy or rawFileCopyExecutable, was %q", params.Rule)
+ return ""
+ }
+
+ key := filepath.Base(params.Input.String())
+ rawFileSet := getRawFileSet(ctx.Config())
+ rawFileInfo, _ := rawFileSet.Load(key)
+
+ return rawFileInfo.contentForTests
+}
+
+func rawFilesSingletonFactory() Singleton {
+ return &rawFilesSingleton{}
+}
+
+type rawFilesSingleton struct{}
+
+func (rawFilesSingleton) GenerateBuildActions(ctx SingletonContext) {
+ if ctx.Config().captureBuild {
+ // Nothing to do when running in tests, no temporary files were created.
+ return
+ }
+ rawFileSet := getRawFileSet(ctx.Config())
+ rawFilesDir := PathForOutput(ctx, "raw"+proptools.String(ctx.Config().productVariables.Make_suffix)).String()
+ absRawFilesDir := absolutePath(rawFilesDir)
+ err := filepath.WalkDir(absRawFilesDir, func(path string, d fs.DirEntry, err error) error {
+ if err != nil {
+ return err
+ }
+ if d.IsDir() {
+ // Ignore obsolete directories for now.
+ return nil
+ }
+
+ // Assume the basename of the file is a hash
+ key := filepath.Base(path)
+ relPath, err := filepath.Rel(absRawFilesDir, path)
+ if err != nil {
+ return err
+ }
+
+ // Check if a file with the same hash was written by this run of soong_build. If the file was not written,
+ // or if a file with the same hash was written but to a different path in the raw directory, then delete it.
+ // Checking that the path matches allows changing the structure of the raw directory, for example to increase
+ // the sharding.
+ rawFileInfo, written := rawFileSet.Load(key)
+ if !written || rawFileInfo.relPath != relPath {
+ os.Remove(path)
+ }
+ return nil
+ })
+ if err != nil {
+ panic(fmt.Errorf("failed to clean %q: %w", rawFilesDir, err))
+ }
+}
diff --git a/android/register.go b/android/register.go
index cd968cd..d00c15f 100644
--- a/android/register.go
+++ b/android/register.go
@@ -191,8 +191,9 @@
// Register makevars after other singletons so they can export values through makevars
singleton{parallel: false, name: "makevars", factory: makeVarsSingletonFunc},
- // Register env and ninjadeps last so that they can track all used environment variables and
+ // Register rawfiles and ninjadeps last so that they can track all used environment variables and
// Ninja file dependencies stored in the config.
+ singleton{parallel: false, name: "rawfiles", factory: rawFilesSingletonFactory},
singleton{parallel: false, name: "ninjadeps", factory: ninjaDepsSingletonFactory},
)
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 1a491f7..1454357 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -590,7 +590,7 @@
To: proto.String(sboxOutSubDir),
},
{
- From: proto.String(PathForOutput(r.ctx).String()),
+ From: proto.String(r.ctx.Config().OutDir()),
To: proto.String(sboxOutSubDir),
},
},
@@ -891,7 +891,7 @@
// When sandboxing inputs all inputs have to be copied into the sandbox. Input files that
// are outputs of other rules could be an arbitrary absolute path if OUT_DIR is set, so they
// will be copied to relative paths under __SBOX_OUT_DIR__/out.
- rel, isRelOut, _ := maybeRelErr(PathForOutput(r.ctx).String(), path.String())
+ rel, isRelOut, _ := maybeRelErr(r.ctx.Config().OutDir(), path.String())
if isRelOut {
return filepath.Join(sboxOutSubDir, rel), true
}
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index 63c3527..9e5f12d 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -474,7 +474,7 @@
wantCommands := []string{
"__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile " +
"FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output " +
- "FlagWithRspFileInputList=__SBOX_SANDBOX_DIR__/out/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
+ "FlagWithRspFileInputList=__SBOX_SANDBOX_DIR__/out/soong/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
"__SBOX_SANDBOX_DIR__/out/SymlinkOutput Text __SBOX_SANDBOX_DIR__/tools/src/Tool after command2 old cmd",
"command2 __SBOX_SANDBOX_DIR__/out/depfile2 input2 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/tools/src/tool2",
"command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3 input3 __SBOX_SANDBOX_DIR__/out/output2",
@@ -816,13 +816,13 @@
func TestRuleBuilderWithNinjaVarEscaping(t *testing.T) {
bp := `
rule_builder_test {
- name: "foo_sbox_escaped_ninja",
+ name: "foo_sbox_escaped",
flags: ["${cmdFlags}"],
sbox: true,
sbox_inputs: true,
}
rule_builder_test {
- name: "foo_sbox",
+ name: "foo_sbox_unescaped",
flags: ["${cmdFlags}"],
sbox: true,
sbox_inputs: true,
@@ -834,15 +834,16 @@
FixtureWithRootAndroidBp(bp),
).RunTest(t)
- escapedNinjaMod := result.ModuleForTests("foo_sbox_escaped_ninja", "").Rule("writeFile")
+ escapedNinjaMod := result.ModuleForTests("foo_sbox_escaped", "").Output("sbox.textproto")
+ AssertStringEquals(t, "expected rule", "android/soong/android.rawFileCopy", escapedNinjaMod.Rule.String())
AssertStringDoesContain(
t,
"",
- escapedNinjaMod.BuildParams.Args["content"],
- "$${cmdFlags}",
+ ContentFromFileRuleForTests(t, result.TestContext, escapedNinjaMod),
+ "${cmdFlags}",
)
- unescapedNinjaMod := result.ModuleForTests("foo_sbox", "").Rule("unescapedWriteFile")
+ unescapedNinjaMod := result.ModuleForTests("foo_sbox_unescaped", "").Rule("unescapedWriteFile")
AssertStringDoesContain(
t,
"",
diff --git a/android/sdk.go b/android/sdk.go
index 6b598ab..6d5293e 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -860,11 +860,11 @@
Components []string
}
-var ExportedComponentsInfoProvider = blueprint.NewProvider(ExportedComponentsInfo{})
+var ExportedComponentsInfoProvider = blueprint.NewProvider[ExportedComponentsInfo]()
// AdditionalSdkInfo contains additional properties to add to the generated SDK info file.
type AdditionalSdkInfo struct {
Properties map[string]interface{}
}
-var AdditionalSdkInfoProvider = blueprint.NewProvider(AdditionalSdkInfo{})
+var AdditionalSdkInfoProvider = blueprint.NewProvider[AdditionalSdkInfo]()
diff --git a/android/singleton.go b/android/singleton.go
index 7c6cf4f..47cfb28 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -20,6 +20,8 @@
// SingletonContext
type SingletonContext interface {
+ blueprintSingletonContext() blueprint.SingletonContext
+
Config() Config
DeviceConfig() DeviceConfig
@@ -33,15 +35,7 @@
// Allows generating build actions for `referer` based on the metadata for `name` deferred until the singleton context.
ModuleVariantsFromName(referer Module, name string) []Module
- // ModuleProvider returns the value, if any, for the provider for a module. If the value for the
- // provider was not set it returns the zero value of the type of the provider, which means the
- // return value can always be type-asserted to the type of the provider. The return value should
- // always be considered read-only. It panics if called before the appropriate mutator or
- // GenerateBuildActions pass for the provider on the module.
- ModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{}
-
- // ModuleHasProvider returns true if the provider for the given module has been set.
- ModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool
+ moduleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
ModuleErrorf(module blueprint.Module, format string, args ...interface{})
Errorf(format string, args ...interface{})
@@ -135,6 +129,10 @@
ruleParams map[blueprint.Rule]blueprint.RuleParams
}
+func (s *singletonContextAdaptor) blueprintSingletonContext() blueprint.SingletonContext {
+ return s.SingletonContext
+}
+
func (s *singletonContextAdaptor) Config() Config {
return s.SingletonContext.Config().(Config)
}
@@ -282,3 +280,7 @@
}
return result
}
+
+func (s *singletonContextAdaptor) moduleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
+ return s.SingletonContext.ModuleProvider(module, provider)
+}
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
index 79bdeb8..a6b2c51 100644
--- a/android/soong_config_modules_test.go
+++ b/android/soong_config_modules_test.go
@@ -376,8 +376,7 @@
prepareForSoongConfigTestModule,
FixtureWithRootAndroidBp(bp),
).ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern([]string{
- // TODO(b/171232169): improve the error message for non-existent properties
- `unrecognized property "soong_config_variables`,
+ `unrecognized property "soong_config_variables.feature1.made_up_property`,
})).RunTest(t)
}
diff --git a/android/testing.go b/android/testing.go
index fa4dffd..3d0300a 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -203,7 +203,7 @@
ctx.PreArchMutators(f)
}
-func (ctx *TestContext) ModuleProvider(m blueprint.Module, p blueprint.ProviderKey) interface{} {
+func (ctx *TestContext) moduleProvider(m blueprint.Module, p blueprint.AnyProviderKey) (any, bool) {
return ctx.Context.ModuleProvider(m, p)
}
@@ -225,6 +225,12 @@
ctx.bp2buildPreArch = append(ctx.bp2buildPreArch, f)
}
+func (ctx *TestContext) OtherModuleProviderAdaptor() OtherModuleProviderContext {
+ return NewOtherModuleProviderAdaptor(func(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
+ return ctx.moduleProvider(module, provider)
+ })
+}
+
// registeredComponentOrder defines the order in which a sortableComponent type is registered at
// runtime and provides support for reordering the components registered for a test in the same
// way.
diff --git a/android/util.go b/android/util.go
index ae1c657..51313ce 100644
--- a/android/util.go
+++ b/android/util.go
@@ -22,6 +22,7 @@
"runtime"
"sort"
"strings"
+ "sync"
)
// CopyOf returns a new slice that has the same contents as s.
@@ -597,3 +598,32 @@
set[item] = true
}
}
+
+// SyncMap is a wrapper around sync.Map that provides type safety via generics.
+type SyncMap[K comparable, V any] struct {
+ sync.Map
+}
+
+// Load returns the value stored in the map for a key, or the zero value if no
+// value is present.
+// The ok result indicates whether value was found in the map.
+func (m *SyncMap[K, V]) Load(key K) (value V, ok bool) {
+ v, ok := m.Map.Load(key)
+ if !ok {
+ return *new(V), false
+ }
+ return v.(V), true
+}
+
+// Store sets the value for a key.
+func (m *SyncMap[K, V]) Store(key K, value V) {
+ m.Map.Store(key, value)
+}
+
+// LoadOrStore returns the existing value for the key if present.
+// Otherwise, it stores and returns the given value.
+// The loaded result is true if the value was loaded, false if stored.
+func (m *SyncMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) {
+ v, loaded := m.Map.LoadOrStore(key, value)
+ return v.(V), loaded
+}
diff --git a/apex/apex.go b/apex/apex.go
index 38a166e..42a7d73 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -24,7 +24,6 @@
"sort"
"strings"
- "android/soong/aconfig"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -720,7 +719,7 @@
// getImageVariationPair returns a pair for the image variation name as its
// prefix and suffix. The prefix indicates whether it's core/vendor/product and the
-// suffix indicates the vndk version when it's vendor or product.
+// suffix indicates the vndk version for vendor/product if vndk is enabled.
// getImageVariation can simply join the result of this function to get the
// image variation name.
func (a *apexBundle) getImageVariationPair(deviceConfig android.DeviceConfig) (string, string) {
@@ -728,8 +727,8 @@
return cc.VendorVariationPrefix, a.vndkVersion(deviceConfig)
}
- var prefix string
- var vndkVersion string
+ prefix := android.CoreVariation
+ vndkVersion := ""
if deviceConfig.VndkVersion() != "" {
if a.SocSpecific() || a.DeviceSpecific() {
prefix = cc.VendorVariationPrefix
@@ -738,15 +737,18 @@
prefix = cc.ProductVariationPrefix
vndkVersion = deviceConfig.PlatformVndkVersion()
}
+ } else {
+ if a.SocSpecific() || a.DeviceSpecific() {
+ prefix = cc.VendorVariation
+ } else if a.ProductSpecific() {
+ prefix = cc.ProductVariation
+ }
}
if vndkVersion == "current" {
vndkVersion = deviceConfig.PlatformVndkVersion()
}
- if vndkVersion != "" {
- return prefix, vndkVersion
- }
- return android.CoreVariation, "" // The usual case
+ return prefix, vndkVersion
}
// getImageVariation returns the image variant name for this apexBundle. In most cases, it's simply
@@ -912,13 +914,13 @@
ProvidedLibs []string
}
-var DCLAInfoProvider = blueprint.NewMutatorProvider(DCLAInfo{}, "apex_info")
+var DCLAInfoProvider = blueprint.NewMutatorProvider[DCLAInfo]("apex_info")
type ApexBundleInfo struct {
Contents *android.ApexContents
}
-var ApexBundleInfoProvider = blueprint.NewMutatorProvider(ApexBundleInfo{}, "apex_info")
+var ApexBundleInfoProvider = blueprint.NewMutatorProvider[ApexBundleInfo]("apex_info")
var _ ApexInfoMutator = (*apexBundle)(nil)
@@ -1020,7 +1022,7 @@
// The membership information is saved for later access
apexContents := android.NewApexContents(contents)
- mctx.SetProvider(ApexBundleInfoProvider, ApexBundleInfo{
+ android.SetProvider(mctx, ApexBundleInfoProvider, ApexBundleInfo{
Contents: apexContents,
})
@@ -1058,7 +1060,7 @@
})
if a.dynamic_common_lib_apex() {
- mctx.SetProvider(DCLAInfoProvider, DCLAInfo{
+ android.SetProvider(mctx, DCLAInfoProvider, DCLAInfo{
ProvidedLibs: a.properties.Native_shared_libs,
})
}
@@ -1201,10 +1203,10 @@
if _, ok := mctx.Module().(android.ApexModule); ok {
var contents []*android.ApexContents
for _, testFor := range mctx.GetDirectDepsWithTag(testForTag) {
- abInfo := mctx.OtherModuleProvider(testFor, ApexBundleInfoProvider).(ApexBundleInfo)
+ abInfo, _ := android.OtherModuleProvider(mctx, testFor, ApexBundleInfoProvider)
contents = append(contents, abInfo.Contents)
}
- mctx.SetProvider(android.ApexTestForInfoProvider, android.ApexTestForInfo{
+ android.SetProvider(mctx, android.ApexTestForInfoProvider, android.ApexTestForInfo{
ApexContents: contents,
})
}
@@ -1465,7 +1467,7 @@
panic(fmt.Errorf("expected exactly at most one dcla dependency, got %d", len(dclaModules)))
}
if len(dclaModules) > 0 {
- DCLAInfo := ctx.OtherModuleProvider(dclaModules[0], DCLAInfoProvider).(DCLAInfo)
+ DCLAInfo, _ := android.OtherModuleProvider(ctx, dclaModules[0], DCLAInfoProvider)
return DCLAInfo.ProvidedLibs
}
return []string{}
@@ -1783,7 +1785,7 @@
return false
}
- ai := ctx.OtherModuleProvider(child, android.ApexInfoProvider).(android.ApexInfo)
+ ai, _ := android.OtherModuleProvider(ctx, child, android.ApexInfoProvider)
externalDep := !android.InList(ctx.ModuleName(), ai.InApexVariants)
// Visit actually
@@ -2150,7 +2152,7 @@
af := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs)
af.transitiveDep = true
- abInfo := ctx.Provider(ApexBundleInfoProvider).(ApexBundleInfo)
+ abInfo, _ := android.ModuleProvider(ctx, ApexBundleInfoProvider)
if !abInfo.Contents.DirectlyInApex(depName) && (ch.IsStubs() || ch.HasStubsVariants()) {
// If the dependency is a stubs lib, don't include it in this APEX,
// but make sure that the lib is installed on the device.
@@ -2272,7 +2274,7 @@
}
func addAconfigFiles(vctx *visitorContext, ctx android.ModuleContext, module blueprint.Module) {
- dep := ctx.OtherModuleProvider(module, aconfig.TransitiveDeclarationsInfoProvider).(aconfig.TransitiveDeclarationsInfo)
+ dep, _ := android.OtherModuleProvider(ctx, module, android.AconfigTransitiveDeclarationsInfoProvider)
if len(dep.AconfigFiles) > 0 && dep.AconfigFiles[ctx.ModuleName()] != nil {
vctx.aconfigFiles = append(vctx.aconfigFiles, dep.AconfigFiles[ctx.ModuleName()]...)
}
@@ -2371,12 +2373,31 @@
a.buildApex(ctx)
a.buildApexDependencyInfo(ctx)
a.buildLintReports(ctx)
+
+ // Set a provider for dexpreopt of bootjars
+ a.provideApexExportsInfo(ctx)
+}
+
+// Set a provider containing information about the jars and .prof provided by the apex
+// Apexes built from source retrieve this information by visiting `bootclasspath_fragments`
+// Used by dex_bootjars to generate the boot image
+func (a *apexBundle) provideApexExportsInfo(ctx android.ModuleContext) {
+ ctx.VisitDirectDepsWithTag(bcpfTag, func(child android.Module) {
+ if info, ok := android.OtherModuleProvider(ctx, child, java.BootclasspathFragmentApexContentInfoProvider); ok {
+ exports := android.ApexExportsInfo{
+ ApexName: a.ApexVariationName(),
+ ProfilePathOnHost: info.ProfilePathOnHost(),
+ LibraryNameToDexJarPathOnHost: info.DexBootJarPathMap(),
+ }
+ android.SetProvider(ctx, android.ApexExportsInfoProvider, exports)
+ }
+ })
}
// apexBootclasspathFragmentFiles returns the list of apexFile structures defining the files that
// the bootclasspath_fragment contributes to the apex.
func apexBootclasspathFragmentFiles(ctx android.ModuleContext, module blueprint.Module) []apexFile {
- bootclasspathFragmentInfo := ctx.OtherModuleProvider(module, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo)
+ bootclasspathFragmentInfo, _ := android.OtherModuleProvider(ctx, module, java.BootclasspathFragmentApexContentInfoProvider)
var filesToAdd []apexFile
// Add classpaths.proto config.
@@ -2425,7 +2446,7 @@
// apexClasspathFragmentProtoFile returns *apexFile structure defining the classpath.proto config that
// the module contributes to the apex; or nil if the proto config was not generated.
func apexClasspathFragmentProtoFile(ctx android.ModuleContext, module blueprint.Module) *apexFile {
- info := ctx.OtherModuleProvider(module, java.ClasspathFragmentProtoContentInfoProvider).(java.ClasspathFragmentProtoContentInfo)
+ info, _ := android.OtherModuleProvider(ctx, module, java.ClasspathFragmentProtoContentInfoProvider)
if !info.ClasspathFragmentProtoGenerated {
return nil
}
@@ -2437,7 +2458,7 @@
// apexFileForBootclasspathFragmentContentModule creates an apexFile for a bootclasspath_fragment
// content module, i.e. a library that is part of the bootclasspath.
func apexFileForBootclasspathFragmentContentModule(ctx android.ModuleContext, fragmentModule blueprint.Module, javaModule javaModule) apexFile {
- bootclasspathFragmentInfo := ctx.OtherModuleProvider(fragmentModule, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo)
+ bootclasspathFragmentInfo, _ := android.OtherModuleProvider(ctx, fragmentModule, java.BootclasspathFragmentApexContentInfoProvider)
// Get the dexBootJar from the bootclasspath_fragment as that is responsible for performing the
// hidden API encpding.
@@ -2589,7 +2610,7 @@
return
}
- abInfo := ctx.Provider(ApexBundleInfoProvider).(ApexBundleInfo)
+ abInfo, _ := android.ModuleProvider(ctx, ApexBundleInfoProvider)
a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
if ccm, ok := to.(*cc.Module); ok {
@@ -2650,7 +2671,7 @@
func (a *apexBundle) checkClasspathFragments(ctx android.ModuleContext) {
ctx.VisitDirectDeps(func(module android.Module) {
if tag := ctx.OtherModuleDependencyTag(module); tag == bcpfTag || tag == sscpfTag {
- info := ctx.OtherModuleProvider(module, java.ClasspathFragmentProtoContentInfoProvider).(java.ClasspathFragmentProtoContentInfo)
+ info, _ := android.OtherModuleProvider(ctx, module, java.ClasspathFragmentProtoContentInfoProvider)
if !info.ClasspathFragmentProtoGenerated {
ctx.OtherModuleErrorf(module, "is included in updatable apex %v, it must not set generate_classpaths_proto to false", ctx.ModuleName())
}
@@ -2835,17 +2856,6 @@
//
// Module separator
//
- m["com.android.mediaprovider"] = []string{
- "MediaProvider",
- "MediaProviderGoogle",
- "fmtlib_ndk",
- "libbase_ndk",
- "libfuse",
- "libfuse_jni",
- }
- //
- // Module separator
- //
m["com.android.runtime"] = []string{
"libdebuggerd",
"libdebuggerd_common_headers",
@@ -2867,14 +2877,6 @@
//
// Module separator
//
- m["com.android.tethering"] = []string{
- "android.hardware.tetheroffload.config-V1.0-java",
- "android.hardware.tetheroffload.control-V1.0-java",
- "net-utils-framework-common",
- }
- //
- // Module separator
- //
m["com.android.wifi"] = []string{
"PlatformProperties",
"android.hardware.wifi-V1.0-java",
@@ -2898,15 +2900,6 @@
"wifi-nano-protos",
"wifi-service-pre-jarjar",
}
- //
- // Module separator
- //
- m[android.AvailableToAnyApex] = []string{
- "libprofile-clang-extras",
- "libprofile-clang-extras_ndk",
- "libprofile-extras",
- "libprofile-extras_ndk",
- }
return m
}
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index a63344f..25c0cc4 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -83,7 +83,7 @@
updatableFlatLists := android.Paths{}
ctx.VisitAllModules(func(module android.Module) {
if binaryInfo, ok := module.(android.ApexBundleDepsInfoIntf); ok {
- apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.SingletonModuleProvider(ctx, module, android.ApexInfoProvider)
if path := binaryInfo.FlatListPath(); path != nil {
if binaryInfo.Updatable() || apexInfo.Updatable {
updatableFlatLists = append(updatableFlatLists, path)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index abf6b15..1b9fa19 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -3725,7 +3725,7 @@
}
func ensureExactDeapexedContents(t *testing.T, ctx *android.TestContext, moduleName string, variant string, files []string) {
- deapexer := ctx.ModuleForTests(moduleName+".deapexer", variant).Rule("deapexer")
+ deapexer := ctx.ModuleForTests(moduleName+".deapexer", variant).Description("deapex")
outputs := make([]string, 0, len(deapexer.ImplicitOutputs)+1)
if deapexer.Output != nil {
outputs = append(outputs, deapexer.Output.String())
@@ -8408,30 +8408,39 @@
func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) {
preparers := android.GroupFixturePreparers(
java.PrepareForTestWithJavaDefaultModules,
+ prepareForTestWithBootclasspathFragment,
+ dexpreopt.FixtureSetTestOnlyArtBootImageJars("com.android.art:libfoo"),
PrepareForTestWithApexBuildComponents,
).
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
- "Multiple installable prebuilt APEXes provide ambiguous deapexers: com.android.myapex and com.mycompany.android.myapex"))
+ "Multiple installable prebuilt APEXes provide ambiguous deapexers: com.android.art and com.mycompany.android.art"))
bpBase := `
apex_set {
- name: "com.android.myapex",
+ name: "com.android.art",
installable: true,
- exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
+ exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
set: "myapex.apks",
}
apex_set {
- name: "com.mycompany.android.myapex",
- apex_name: "com.android.myapex",
+ name: "com.mycompany.android.art",
+ apex_name: "com.android.art",
installable: true,
- exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
+ exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
set: "company-myapex.apks",
}
prebuilt_bootclasspath_fragment {
- name: "my-bootclasspath-fragment",
- apex_available: ["com.android.myapex"],
+ name: "art-bootclasspath-fragment",
+ apex_available: ["com.android.art"],
+ hidden_api: {
+ annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
+ metadata: "my-bootclasspath-fragment/metadata.csv",
+ index: "my-bootclasspath-fragment/index.csv",
+ stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
+ all_flags: "my-bootclasspath-fragment/all-flags.csv",
+ },
%s
}
`
@@ -8441,7 +8450,7 @@
java_import {
name: "libfoo",
jars: ["libfoo.jar"],
- apex_available: ["com.android.myapex"],
+ apex_available: ["com.android.art"],
}
`)
})
@@ -8453,7 +8462,8 @@
public: {
jars: ["libbar.jar"],
},
- apex_available: ["com.android.myapex"],
+ shared_library: false,
+ apex_available: ["com.android.art"],
}
`)
})
@@ -8468,7 +8478,8 @@
public: {
jars: ["libbar.jar"],
},
- apex_available: ["com.android.myapex"],
+ shared_library: false,
+ apex_available: ["com.android.art"],
}
`)
})
@@ -11404,3 +11415,181 @@
android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb")
ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb")
}
+
+// Test that the boot jars come from the _selected_ apex prebuilt
+// RELEASE_APEX_CONTIRBUTIONS_* build flags will be used to select the correct prebuilt for a specific release config
+func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) {
+ checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, stem string, bootDexJarPath string) {
+ t.Helper()
+ s := ctx.ModuleForTests("dex_bootjars", "android_common")
+ foundLibfooJar := false
+ base := stem + ".jar"
+ for _, output := range s.AllOutputs() {
+ if filepath.Base(output) == base {
+ foundLibfooJar = true
+ buildRule := s.Output(output)
+ android.AssertStringEquals(t, "boot dex jar path", bootDexJarPath, buildRule.Input.String())
+ }
+ }
+ if !foundLibfooJar {
+ t.Errorf("Rule for libfoo.jar missing in dex_bootjars singleton outputs %q", android.StringPathsRelativeToTop(ctx.Config().SoongOutDir(), s.AllOutputs()))
+ }
+ }
+
+ // Check that the boot jars of the selected apex are run through boot_jars_package_check
+ // This validates that the jars on the bootclasspath do not contain packages outside an allowlist
+ checkBootJarsPackageCheck := func(t *testing.T, ctx *android.TestContext, expectedBootJar string) {
+ platformBcp := ctx.ModuleForTests("platform-bootclasspath", "android_common")
+ bootJarsCheckRule := platformBcp.Rule("boot_jars_package_check")
+ android.AssertStringMatches(t, "Could not find the correct boot dex jar in package check rule", bootJarsCheckRule.RuleParams.Command, "build/soong/scripts/check_boot_jars/package_allowed_list.txt.*"+expectedBootJar)
+ }
+
+ // Check that the boot jars used to generate the monolithic hiddenapi flags come from the selected apex
+ checkBootJarsForMonolithicHiddenapi := func(t *testing.T, ctx *android.TestContext, expectedBootJar string) {
+ monolithicHiddenapiFlagsCmd := ctx.ModuleForTests("platform-bootclasspath", "android_common").Output("out/soong/hiddenapi/hiddenapi-stub-flags.txt").RuleParams.Command
+ android.AssertStringMatches(t, "Could not find the correct boot dex jar in monolithic hiddenapi flags generation command", monolithicHiddenapiFlagsCmd, "--boot-dex="+expectedBootJar)
+ }
+
+ bp := `
+ // Source APEX.
+
+ java_library {
+ name: "framework-foo",
+ srcs: ["foo.java"],
+ installable: true,
+ apex_available: [
+ "com.android.foo",
+ ],
+ }
+
+ bootclasspath_fragment {
+ name: "foo-bootclasspath-fragment",
+ contents: ["framework-foo"],
+ apex_available: [
+ "com.android.foo",
+ ],
+ hidden_api: {
+ split_packages: ["*"],
+ },
+ }
+
+ apex_key {
+ name: "com.android.foo.key",
+ public_key: "com.android.foo.avbpubkey",
+ private_key: "com.android.foo.pem",
+ }
+
+ apex {
+ name: "com.android.foo",
+ key: "com.android.foo.key",
+ bootclasspath_fragments: ["foo-bootclasspath-fragment"],
+ updatable: false,
+ }
+
+ // Prebuilt APEX.
+
+ java_sdk_library_import {
+ name: "framework-foo",
+ public: {
+ jars: ["foo.jar"],
+ },
+ apex_available: ["com.android.foo"],
+ shared_library: false,
+ }
+
+ prebuilt_bootclasspath_fragment {
+ name: "foo-bootclasspath-fragment",
+ contents: ["framework-foo"],
+ hidden_api: {
+ annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
+ metadata: "my-bootclasspath-fragment/metadata.csv",
+ index: "my-bootclasspath-fragment/index.csv",
+ stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
+ all_flags: "my-bootclasspath-fragment/all-flags.csv",
+ },
+ apex_available: [
+ "com.android.foo",
+ ],
+ }
+
+ prebuilt_apex {
+ name: "com.android.foo",
+ apex_name: "com.android.foo",
+ src: "com.android.foo-arm.apex",
+ exported_bootclasspath_fragments: ["foo-bootclasspath-fragment"],
+ }
+
+ // Another Prebuilt ART APEX
+ prebuilt_apex {
+ name: "com.android.foo.v2",
+ apex_name: "com.android.foo", // Used to determine the API domain
+ src: "com.android.foo-arm.apex",
+ exported_bootclasspath_fragments: ["foo-bootclasspath-fragment"],
+ }
+
+ // APEX contribution modules
+
+ apex_contributions {
+ name: "foo.source.contributions",
+ api_domain: "com.android.foo",
+ contents: ["com.android.foo"],
+ }
+
+ apex_contributions {
+ name: "foo.prebuilt.contributions",
+ api_domain: "com.android.foo",
+ contents: ["prebuilt_com.android.foo"],
+ }
+
+ apex_contributions {
+ name: "foo.prebuilt.v2.contributions",
+ api_domain: "com.android.foo",
+ contents: ["com.android.foo.v2"], // prebuilt_ prefix is missing because of prebuilt_rename mutator
+ }
+ `
+
+ testCases := []struct {
+ desc string
+ selectedApexContributions string
+ expectedBootJar string
+ }{
+ {
+ desc: "Source apex com.android.foo is selected, bootjar should come from source java library",
+ selectedApexContributions: "foo.source.contributions",
+ expectedBootJar: "out/soong/.intermediates/foo-bootclasspath-fragment/android_common_apex10000/hiddenapi-modular/encoded/framework-foo.jar",
+ },
+ {
+ desc: "Prebuilt apex prebuilt_com.android.foo is selected, profile should come from .prof deapexed from the prebuilt",
+ selectedApexContributions: "foo.prebuilt.contributions",
+ expectedBootJar: "out/soong/.intermediates/com.android.foo.deapexer/android_common/deapexer/javalib/framework-foo.jar",
+ },
+ {
+ desc: "Prebuilt apex prebuilt_com.android.foo.v2 is selected, profile should come from .prof deapexed from the prebuilt",
+ selectedApexContributions: "foo.prebuilt.v2.contributions",
+ expectedBootJar: "out/soong/.intermediates/com.android.foo.v2.deapexer/android_common/deapexer/javalib/framework-foo.jar",
+ },
+ }
+
+ fragment := java.ApexVariantReference{
+ Apex: proptools.StringPtr("com.android.foo"),
+ Module: proptools.StringPtr("foo-bootclasspath-fragment"),
+ }
+
+ for _, tc := range testCases {
+ preparer := android.GroupFixturePreparers(
+ java.FixtureConfigureApexBootJars("com.android.foo:framework-foo"),
+ android.FixtureMergeMockFs(map[string][]byte{
+ "system/sepolicy/apex/com.android.foo-file_contexts": nil,
+ }),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BuildFlags = map[string]string{
+ "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": tc.selectedApexContributions,
+ }
+ }),
+ )
+ ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
+ checkBootDexJarPath(t, ctx, "framework-foo", tc.expectedBootJar)
+ checkBootJarsPackageCheck(t, ctx, tc.expectedBootJar)
+ checkBootJarsForMonolithicHiddenapi(t, ctx, tc.expectedBootJar)
+ }
+}
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 43be310..159e9e1 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -152,7 +152,7 @@
// Check stub dex paths exported by art.
artFragment := result.Module("art-bootclasspath-fragment", "android_common")
- artInfo := result.ModuleProvider(artFragment, java.HiddenAPIInfoProvider).(java.HiddenAPIInfo)
+ artInfo, _ := android.SingletonModuleProvider(result, artFragment, java.HiddenAPIInfoProvider)
bazPublicStubs := "out/soong/.intermediates/baz.stubs/android_common/dex/baz.stubs.jar"
bazSystemStubs := "out/soong/.intermediates/baz.stubs.system/android_common/dex/baz.stubs.system.jar"
@@ -165,7 +165,7 @@
// Check stub dex paths exported by other.
otherFragment := result.Module("other-bootclasspath-fragment", "android_common")
- otherInfo := result.ModuleProvider(otherFragment, java.HiddenAPIInfoProvider).(java.HiddenAPIInfo)
+ otherInfo, _ := android.SingletonModuleProvider(result, otherFragment, java.HiddenAPIInfoProvider)
fooPublicStubs := "out/soong/.intermediates/foo.stubs/android_common/dex/foo.stubs.jar"
fooSystemStubs := "out/soong/.intermediates/foo.stubs.system/android_common/dex/foo.stubs.system.jar"
@@ -530,6 +530,8 @@
java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
`com.android.art.apex.selector`,
+ `com.android.art.deapexer`,
+ `dex2oatd`,
`prebuilt_art-bootclasspath-fragment`,
})
@@ -655,7 +657,7 @@
// Make sure that the fragment provides the hidden API encoded dex jars to the APEX.
fragment := result.Module("mybootclasspathfragment", "android_common_apex10000")
- info := result.ModuleProvider(fragment, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo)
+ info, _ := android.SingletonModuleProvider(result, fragment, java.BootclasspathFragmentApexContentInfoProvider)
checkFragmentExportedDexJar := func(name string, expectedDexJar string) {
module := result.Module(name, "android_common_apex10000")
diff --git a/apex/classpath_element_test.go b/apex/classpath_element_test.go
index 9142eed..b9a9198 100644
--- a/apex/classpath_element_test.go
+++ b/apex/classpath_element_test.go
@@ -20,7 +20,6 @@
"android/soong/android"
"android/soong/java"
- "github.com/google/blueprint"
)
// Contains tests for java.CreateClasspathElements logic from java/classpath_element.go that
@@ -28,19 +27,12 @@
// testClasspathElementContext is a ClasspathElementContext suitable for use in tests.
type testClasspathElementContext struct {
+ android.OtherModuleProviderContext
testContext *android.TestContext
module android.Module
errs []error
}
-func (t *testClasspathElementContext) OtherModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool {
- return t.testContext.ModuleHasProvider(module, provider)
-}
-
-func (t *testClasspathElementContext) OtherModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{} {
- return t.testContext.ModuleProvider(module, provider)
-}
-
func (t *testClasspathElementContext) ModuleErrorf(fmt string, args ...interface{}) {
t.errs = append(t.errs, t.testContext.ModuleErrorf(t.module, fmt, args...))
}
@@ -238,7 +230,11 @@
}
newCtx := func() *testClasspathElementContext {
- return &testClasspathElementContext{testContext: result.TestContext, module: bootclasspath}
+ return &testClasspathElementContext{
+ OtherModuleProviderContext: result.TestContext.OtherModuleProviderAdaptor(),
+ testContext: result.TestContext,
+ module: bootclasspath,
+ }
}
// Verify that CreateClasspathElements works when given valid input.
diff --git a/apex/deapexer.go b/apex/deapexer.go
index 3b7c77d..5ff622c 100644
--- a/apex/deapexer.go
+++ b/apex/deapexer.go
@@ -98,6 +98,7 @@
func (p *Deapexer) DepsMutator(ctx android.BottomUpMutatorContext) {
// Add dependencies from the java modules to which this exports files from the `.apex` file onto
// this module so that they can access the `DeapexerInfo` object that this provides.
+ // TODO: b/308174306 - Once all the mainline modules have been flagged, drop this dependency edge
for _, lib := range p.properties.CommonModules {
dep := prebuiltApexExportedModuleName(ctx, lib)
ctx.AddReverseDependency(ctx.Module(), android.DeapexerTag, dep)
@@ -126,8 +127,8 @@
// apex relative path to extracted file path available for other modules.
if len(exports) > 0 {
// Make the information available for other modules.
- di := android.NewDeapexerInfo(apexModuleName(ctx.ModuleName()), exports)
- ctx.SetProvider(android.DeapexerProvider, di)
+ di := android.NewDeapexerInfo(apexModuleName(ctx.ModuleName()), exports, p.properties.CommonModules)
+ android.SetProvider(ctx, android.DeapexerProvider, di)
// Create a sorted list of the files that this exports.
exportedPaths = android.SortedUniquePaths(exportedPaths)
diff --git a/apex/dexpreopt_bootjars_test.go b/apex/dexpreopt_bootjars_test.go
index 2e828ca..34ccdd7 100644
--- a/apex/dexpreopt_bootjars_test.go
+++ b/apex/dexpreopt_bootjars_test.go
@@ -252,3 +252,162 @@
testDexpreoptBoot(t, ruleFile, expectedInputs, expectedOutputs, false)
}
+
+// Multiple ART apexes might exist in the tree.
+// The profile should correspond to the apex selected using release build flags
+func TestDexpreoptProfileWithMultiplePrebuiltArtApexes(t *testing.T) {
+ ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art"
+ bp := `
+ // Platform.
+
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ fragments: [
+ {
+ apex: "com.android.art",
+ module: "art-bootclasspath-fragment",
+ },
+ ],
+ }
+
+ // Source ART APEX.
+
+ java_library {
+ name: "core-oj",
+ srcs: ["core-oj.java"],
+ installable: true,
+ apex_available: [
+ "com.android.art",
+ ],
+ }
+
+ bootclasspath_fragment {
+ name: "art-bootclasspath-fragment",
+ image_name: "art",
+ contents: ["core-oj"],
+ apex_available: [
+ "com.android.art",
+ ],
+ hidden_api: {
+ split_packages: ["*"],
+ },
+ }
+
+ apex_key {
+ name: "com.android.art.key",
+ public_key: "com.android.art.avbpubkey",
+ private_key: "com.android.art.pem",
+ }
+
+ apex {
+ name: "com.android.art",
+ key: "com.android.art.key",
+ bootclasspath_fragments: ["art-bootclasspath-fragment"],
+ updatable: false,
+ }
+
+ // Prebuilt ART APEX.
+
+ java_import {
+ name: "core-oj",
+ jars: ["core-oj.jar"],
+ apex_available: [
+ "com.android.art",
+ ],
+ }
+
+ prebuilt_bootclasspath_fragment {
+ name: "art-bootclasspath-fragment",
+ image_name: "art",
+ contents: ["core-oj"],
+ hidden_api: {
+ annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
+ metadata: "my-bootclasspath-fragment/metadata.csv",
+ index: "my-bootclasspath-fragment/index.csv",
+ stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
+ all_flags: "my-bootclasspath-fragment/all-flags.csv",
+ },
+ apex_available: [
+ "com.android.art",
+ ],
+ }
+
+ prebuilt_apex {
+ name: "com.android.art",
+ apex_name: "com.android.art",
+ src: "com.android.art-arm.apex",
+ exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
+ }
+
+ // Another Prebuilt ART APEX
+ prebuilt_apex {
+ name: "com.android.art.v2",
+ apex_name: "com.android.art", // Used to determine the API domain
+ src: "com.android.art-arm.apex",
+ exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
+ }
+
+ // APEX contribution modules
+
+ apex_contributions {
+ name: "art.source.contributions",
+ api_domain: "com.android.art",
+ contents: ["com.android.art"],
+ }
+
+ apex_contributions {
+ name: "art.prebuilt.contributions",
+ api_domain: "com.android.art",
+ contents: ["prebuilt_com.android.art"],
+ }
+
+ apex_contributions {
+ name: "art.prebuilt.v2.contributions",
+ api_domain: "com.android.art",
+ contents: ["com.android.art.v2"], // prebuilt_ prefix is missing because of prebuilt_rename mutator
+ }
+
+ `
+
+ testCases := []struct {
+ desc string
+ selectedArtApexContributions string
+ expectedProfile string
+ }{
+ {
+ desc: "Source apex com.android.art is selected, profile should come from source java library",
+ selectedArtApexContributions: "art.source.contributions",
+ expectedProfile: "out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/art-bootclasspath-fragment/boot.prof",
+ },
+ {
+ desc: "Prebuilt apex prebuilt_com.android.art is selected, profile should come from .prof deapexed from the prebuilt",
+ selectedArtApexContributions: "art.prebuilt.contributions",
+ expectedProfile: "out/soong/.intermediates/com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof",
+ },
+ {
+ desc: "Prebuilt apex prebuilt_com.android.art.v2 is selected, profile should come from .prof deapexed from the prebuilt",
+ selectedArtApexContributions: "art.prebuilt.v2.contributions",
+ expectedProfile: "out/soong/.intermediates/com.android.art.v2.deapexer/android_common/deapexer/etc/boot-image.prof",
+ },
+ }
+ for _, tc := range testCases {
+ result := android.GroupFixturePreparers(
+ java.PrepareForTestWithDexpreopt,
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureConfigureBootJars("com.android.art:core-oj"),
+ PrepareForTestWithApexBuildComponents,
+ prepareForTestWithArtApex,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BuildFlags = map[string]string{
+ "RELEASE_APEX_CONTRIBUTIONS_ART": tc.selectedArtApexContributions,
+ }
+ }),
+ ).RunTestWithBp(t, bp)
+
+ dexBootJars := result.ModuleForTests("dex_bootjars", "android_common")
+ rule := dexBootJars.Output(ruleFile)
+
+ inputs := rule.Implicits.Strings()
+ android.AssertStringListContains(t, tc.desc, inputs, tc.expectedProfile)
+ }
+}
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 05bb136..01b616b 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -152,7 +152,7 @@
).RunTest(t)
pbcp := result.Module("platform-bootclasspath", "android_common")
- info := result.ModuleProvider(pbcp, java.MonolithicHiddenAPIInfoProvider).(java.MonolithicHiddenAPIInfo)
+ info, _ := android.SingletonModuleProvider(result, pbcp, java.MonolithicHiddenAPIInfoProvider)
for _, category := range java.HiddenAPIFlagFileCategories {
name := category.PropertyName
@@ -234,7 +234,7 @@
)
pbcp := result.Module("myplatform-bootclasspath", "android_common")
- info := result.ModuleProvider(pbcp, java.MonolithicHiddenAPIInfoProvider).(java.MonolithicHiddenAPIInfo)
+ info, _ := android.SingletonModuleProvider(result, pbcp, java.MonolithicHiddenAPIInfoProvider)
android.AssertArrayString(t, "stub flags", []string{"prebuilt-stub-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop())
android.AssertArrayString(t, "all flags", []string{"prebuilt-all-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop())
@@ -382,6 +382,9 @@
// Make sure that the myplatform-bootclasspath has the correct dependencies.
CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
+ // source vs prebuilt selection metadata module
+ `platform:all_apex_contributions`,
+
// The following are stubs.
`platform:android_stubs_current`,
`platform:android_system_stubs_current`,
@@ -534,6 +537,9 @@
// Make sure that the myplatform-bootclasspath has the correct dependencies.
CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
+ // source vs prebuilt selection metadata module
+ `platform:all_apex_contributions`,
+
// The following are stubs.
"platform:prebuilt_sdk_public_current_android",
"platform:prebuilt_sdk_system_current_android",
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 7d339d5..188875a 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -22,6 +22,7 @@
"strings"
"android/soong/android"
+ "android/soong/dexpreopt"
"android/soong/java"
"android/soong/provenance"
@@ -50,6 +51,7 @@
type prebuiltCommon struct {
android.ModuleBase
+ java.Dexpreopter
prebuilt android.Prebuilt
// Properties common to both prebuilt_apex and apex_set.
@@ -170,50 +172,42 @@
return proptools.BoolDefault(p.prebuiltCommonProperties.Installable, true)
}
-// initApexFilesForAndroidMk initializes the prebuiltCommon.apexFilesForAndroidMk field from the
-// modules that this depends upon.
+// To satisfy java.DexpreopterInterface
+func (p *prebuiltCommon) IsInstallable() bool {
+ return p.installable()
+}
+
+// initApexFilesForAndroidMk initializes the prebuiltCommon.requiredModuleNames field with the install only deps of the prebuilt apex
func (p *prebuiltCommon) initApexFilesForAndroidMk(ctx android.ModuleContext) {
- // Walk the dependencies of this module looking for the java modules that it exports.
- ctx.WalkDeps(func(child, parent android.Module) bool {
- tag := ctx.OtherModuleDependencyTag(child)
+ // If this apex contains a system server jar, then the dexpreopt artifacts should be added as required
+ for _, install := range p.Dexpreopter.DexpreoptBuiltInstalledForApex() {
+ p.requiredModuleNames = append(p.requiredModuleNames, install.FullModuleName())
+ }
+}
- name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child))
- if java.IsBootclasspathFragmentContentDepTag(tag) ||
- java.IsSystemServerClasspathFragmentContentDepTag(tag) || tag == exportedJavaLibTag {
- // If the exported java module provides a dex jar path then add it to the list of apexFiles.
- path := child.(interface {
- DexJarBuildPath() java.OptionalDexJarPath
- }).DexJarBuildPath()
- if path.IsSet() {
- af := apexFile{
- module: child,
- moduleDir: ctx.OtherModuleDir(child),
- androidMkModuleName: name,
- builtFile: path.Path(),
- class: javaSharedLib,
- }
- if module, ok := child.(java.DexpreopterInterface); ok {
- for _, install := range module.DexpreoptBuiltInstalledForApex() {
- af.requiredModuleNames = append(af.requiredModuleNames, install.FullModuleName())
- }
- }
- p.apexFilesForAndroidMk = append(p.apexFilesForAndroidMk, af)
- }
- } else if tag == exportedBootclasspathFragmentTag {
- _, ok := child.(*java.PrebuiltBootclasspathFragmentModule)
- if !ok {
- ctx.PropertyErrorf("exported_bootclasspath_fragments", "%q is not a prebuilt_bootclasspath_fragment module", name)
- return false
- }
- // Visit the children of the bootclasspath_fragment.
- return true
- } else if tag == exportedSystemserverclasspathFragmentTag {
- // Visit the children of the systemserver_fragment.
- return true
+// If this prebuilt has system server jar, create the rules to dexpreopt it and install it alongside the prebuilt apex
+func (p *prebuiltCommon) dexpreoptSystemServerJars(ctx android.ModuleContext) {
+ // If this apex does not export anything, return
+ if !p.hasExportedDeps() {
+ return
+ }
+ // Use apex_name to determine the api domain of this prebuilt apex
+ apexName := p.ApexVariationName()
+ di, err := android.FindDeapexerProviderForModule(ctx)
+ if err != nil {
+ ctx.ModuleErrorf(err.Error())
+ }
+ dc := dexpreopt.GetGlobalConfig(ctx)
+ systemServerJarList := dc.AllApexSystemServerJars(ctx)
+
+ for i := 0; i < systemServerJarList.Len(); i++ {
+ sscpApex := systemServerJarList.Apex(i)
+ sscpJar := systemServerJarList.Jar(i)
+ if apexName != sscpApex {
+ continue
}
-
- return false
- })
+ p.Dexpreopter.DexpreoptPrebuiltApexSystemServerJars(ctx, sscpJar, di)
+ }
}
func (p *prebuiltCommon) addRequiredModules(entries *android.AndroidMkEntries) {
@@ -248,6 +242,11 @@
},
}
+ // Add the dexpreopt artifacts to androidmk
+ for _, install := range p.Dexpreopter.DexpreoptBuiltInstalledForApex() {
+ entriesList = append(entriesList, install.ToMakeEntries())
+ }
+
// Iterate over the apexFilesForAndroidMk list and create an AndroidMkEntries struct for each
// file. This provides similar behavior to that provided in apexBundle.AndroidMk() as it makes the
// apex specific variants of the exported java modules available for use from within make.
@@ -428,7 +427,7 @@
// Create contents for the prebuilt_apex and store it away for later use.
apexContents := android.NewApexContents(contents)
- mctx.SetProvider(ApexBundleInfoProvider, ApexBundleInfo{
+ android.SetProvider(mctx, ApexBundleInfoProvider, ApexBundleInfo{
Contents: apexContents,
})
@@ -756,12 +755,47 @@
p.prebuiltApexContentsDeps(ctx)
}
+func (p *prebuiltCommon) DepsMutator(ctx android.BottomUpMutatorContext) {
+ if p.hasExportedDeps() {
+ // Create a dependency from the prebuilt apex (prebuilt_apex/apex_set) to the internal deapexer module
+ // The deapexer will return a provider that will be bubbled up to the rdeps of apexes (e.g. dex_bootjars)
+ ctx.AddDependency(ctx.Module(), android.DeapexerTag, deapexerModuleName(p.BaseModuleName()))
+ }
+}
+
var _ ApexInfoMutator = (*Prebuilt)(nil)
func (p *Prebuilt) ApexInfoMutator(mctx android.TopDownMutatorContext) {
p.apexInfoMutator(mctx)
}
+// Set a provider containing information about the jars and .prof provided by the apex
+// Apexes built from prebuilts retrieve this information by visiting its internal deapexer module
+// Used by dex_bootjars to generate the boot image
+func (p *prebuiltCommon) provideApexExportsInfo(ctx android.ModuleContext) {
+ if !p.hasExportedDeps() {
+ // nothing to do
+ return
+ }
+ if di, err := android.FindDeapexerProviderForModule(ctx); err == nil {
+ javaModuleToDexPath := map[string]android.Path{}
+ for _, commonModule := range di.GetExportedModuleNames() {
+ if dex := di.PrebuiltExportPath(java.ApexRootRelativePathToJavaLib(commonModule)); dex != nil {
+ javaModuleToDexPath[commonModule] = dex
+ }
+ }
+
+ exports := android.ApexExportsInfo{
+ ApexName: p.ApexVariationName(),
+ ProfilePathOnHost: di.PrebuiltExportPath(java.ProfileInstallPathInApex),
+ LibraryNameToDexJarPathOnHost: javaModuleToDexPath,
+ }
+ android.SetProvider(ctx, android.ApexExportsInfoProvider, exports)
+ } else {
+ ctx.ModuleErrorf(err.Error())
+ }
+}
+
func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
p.apexKeysPath = writeApexKeys(ctx, p)
// TODO(jungjw): Check the key validity.
@@ -783,6 +817,12 @@
return
}
+ // dexpreopt any system server jars if present
+ p.dexpreoptSystemServerJars(ctx)
+
+ // provide info used for generating the boot image
+ p.provideApexExportsInfo(ctx)
+
// Save the files that need to be made available to Make.
p.initApexFilesForAndroidMk(ctx)
@@ -999,6 +1039,12 @@
return
}
+ // dexpreopt any system server jars if present
+ a.dexpreoptSystemServerJars(ctx)
+
+ // provide info used for generating the boot image
+ a.provideApexExportsInfo(ctx)
+
// Save the files that need to be made available to Make.
a.initApexFilesForAndroidMk(ctx)
diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go
index 40d0581..90fd2ca 100644
--- a/apex/systemserver_classpath_fragment_test.go
+++ b/apex/systemserver_classpath_fragment_test.go
@@ -272,7 +272,9 @@
ctx := result.TestContext
java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{
+ `dex2oatd`,
`myapex.apex.selector`,
+ `myapex.deapexer`,
`prebuilt_mysystemserverclasspathfragment`,
})
diff --git a/bloaty/bloaty.go b/bloaty/bloaty.go
index 3cff60f..43fb71d 100644
--- a/bloaty/bloaty.go
+++ b/bloaty/bloaty.go
@@ -26,7 +26,7 @@
const protoFilename = "binary_sizes.pb.gz"
var (
- fileSizeMeasurerKey blueprint.ProviderKey
+ fileSizeMeasurerKey blueprint.ProviderKey[measuredFiles]
pctx = android.NewPackageContext("android/soong/bloaty")
// bloaty is used to measure a binary section sizes.
@@ -52,7 +52,7 @@
pctx.SourcePathVariable("bloaty", "prebuilts/build-tools/${hostPrebuiltTag}/bin/bloaty")
pctx.HostBinToolVariable("bloatyMerger", "bloaty_merger")
android.RegisterParallelSingletonType("file_metrics", fileSizesSingleton)
- fileSizeMeasurerKey = blueprint.NewProvider(measuredFiles{})
+ fileSizeMeasurerKey = blueprint.NewProvider[measuredFiles]()
}
// measuredFiles contains the paths of the files measured by a module.
@@ -73,7 +73,7 @@
mf.paths = append(mf.paths, p)
}
}
- ctx.SetProvider(fileSizeMeasurerKey, mf)
+ android.SetProvider(ctx, fileSizeMeasurerKey, mf)
}
type sizesSingleton struct{}
@@ -85,10 +85,10 @@
func (singleton *sizesSingleton) GenerateBuildActions(ctx android.SingletonContext) {
var deps android.Paths
ctx.VisitAllModules(func(m android.Module) {
- if !ctx.ModuleHasProvider(m, fileSizeMeasurerKey) {
+ filePaths, ok := android.SingletonModuleProvider(ctx, m, fileSizeMeasurerKey)
+ if !ok {
return
}
- filePaths := ctx.ModuleProvider(m, fileSizeMeasurerKey).(measuredFiles)
for _, path := range filePaths.paths {
filePath := path.(android.ModuleOutPath)
sizeFile := filePath.InSameDir(ctx, filePath.Base()+bloatyDescriptorExt)
diff --git a/bpf/bpf.go b/bpf/bpf.go
index ce57b46..32d62b5 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -203,7 +203,7 @@
}
}
- ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
+ android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
}
func (bpf *bpf) AndroidMk() android.AndroidMkData {
diff --git a/cc/afdo.go b/cc/afdo.go
index bad16a1..79fbae1 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -137,8 +137,7 @@
}
ctx.VisitDirectDepsWithTag(FdoProfileTag, func(m android.Module) {
- if ctx.OtherModuleHasProvider(m, FdoProfileProvider) {
- info := ctx.OtherModuleProvider(m, FdoProfileProvider).(FdoProfileInfo)
+ if info, ok := android.OtherModuleProvider(ctx, m, FdoProfileProvider); ok {
c.afdo.Properties.FdoProfilePath = proptools.StringPtr(info.Path.String())
}
})
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 8cae634..bde096b 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -15,6 +15,7 @@
package cc
import (
+ "android/soong/aconfig"
"github.com/google/blueprint/proptools"
"fmt"
@@ -100,15 +101,6 @@
if len(c.Properties.AndroidMkSharedLibs) > 0 {
entries.AddStrings("LOCAL_SHARED_LIBRARIES", c.Properties.AndroidMkSharedLibs...)
}
- if len(c.Properties.AndroidMkStaticLibs) > 0 {
- entries.AddStrings("LOCAL_STATIC_LIBRARIES", c.Properties.AndroidMkStaticLibs...)
- }
- if len(c.Properties.AndroidMkWholeStaticLibs) > 0 {
- entries.AddStrings("LOCAL_WHOLE_STATIC_LIBRARIES", c.Properties.AndroidMkWholeStaticLibs...)
- }
- if len(c.Properties.AndroidMkHeaderLibs) > 0 {
- entries.AddStrings("LOCAL_HEADER_LIBRARIES", c.Properties.AndroidMkHeaderLibs...)
- }
if len(c.Properties.AndroidMkRuntimeLibs) > 0 {
entries.AddStrings("LOCAL_RUNTIME_LIBRARIES", c.Properties.AndroidMkRuntimeLibs...)
}
@@ -133,8 +125,7 @@
entries.SetString("SOONG_SDK_VARIANT_MODULES",
"$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))")
}
- // TODO(b/311155208): The container here should be system.
- entries.SetPaths("LOCAL_ACONFIG_FILES", c.mergedAconfigFiles[""])
+ aconfig.SetAconfigFileMkEntries(c.AndroidModuleBase(), entries, c.mergedAconfigFiles)
},
},
ExtraFooters: []android.AndroidMkExtraFootersFunc{
diff --git a/cc/binary.go b/cc/binary.go
index 61541ad..7aa8e20 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -541,6 +541,11 @@
return binary.Properties.Overrides
}
+func (binary *binaryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+ moduleInfoJSON.Class = []string{"EXECUTABLES"}
+ binary.baseLinker.moduleInfoJSON(ctx, moduleInfoJSON)
+}
+
var _ overridable = (*binaryDecorator)(nil)
func init() {
diff --git a/cc/cc.go b/cc/cc.go
index 7a06128..c6e21c2 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -25,10 +25,10 @@
"strings"
"android/soong/testing"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
- "android/soong/aconfig"
"android/soong/aidl_library"
"android/soong/android"
"android/soong/cc/config"
@@ -301,8 +301,8 @@
// Set by DepsMutator.
AndroidMkSystemSharedLibs []string `blueprint:"mutated"`
- // The name of the image this module is built for, suffixed with a '.'
- ImageVariationPrefix string `blueprint:"mutated"`
+ // The name of the image this module is built for
+ ImageVariation string `blueprint:"mutated"`
// The VNDK version this module is built against. If empty, the module is not
// build against the VNDK.
@@ -544,6 +544,7 @@
isPreventInstall() bool
isCfiAssemblySupportEnabled() bool
getSharedFlags() *SharedFlags
+ notInPlatform() bool
}
type SharedFlags struct {
@@ -624,6 +625,8 @@
// Get the deps that have been explicitly specified in the properties.
linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps
+
+ moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON)
}
// specifiedDeps is a tuple struct representing dependencies of a linked binary owned by the linker.
@@ -1744,11 +1747,13 @@
}
func (ctx *moduleContextImpl) isForPlatform() bool {
- return ctx.ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
+ apexInfo, _ := android.ModuleProvider(ctx.ctx, android.ApexInfoProvider)
+ return apexInfo.IsForPlatform()
}
func (ctx *moduleContextImpl) apexVariationName() string {
- return ctx.ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).ApexVariationName
+ apexInfo, _ := android.ModuleProvider(ctx.ctx, android.ApexInfoProvider)
+ return apexInfo.ApexVariationName
}
func (ctx *moduleContextImpl) apexSdkVersion() android.ApiLevel {
@@ -1784,6 +1789,10 @@
return ctx.mod.isCfiAssemblySupportEnabled()
}
+func (ctx *moduleContextImpl) notInPlatform() bool {
+ return ctx.mod.NotInPlatform()
+}
+
func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
return &Module{
hod: hod,
@@ -1940,6 +1949,7 @@
"libdl_android": true,
"libm": true,
"libdl": true,
+ "libz": true,
// art apex
"libandroidio": true,
"libdexfile": true,
@@ -1991,7 +2001,7 @@
}
c.Properties.SubName = GetSubnameProperty(actx, c)
- apexInfo := actx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.ModuleProvider(actx, android.ApexInfoProvider)
if !apexInfo.IsForPlatform() {
c.hideApexVariantFromMake = true
}
@@ -2131,13 +2141,46 @@
}
}
if c.testModule {
- ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+ android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
}
- ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: deps.GeneratedSources.Strings()})
+ android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: deps.GeneratedSources.Strings()})
- aconfig.CollectDependencyAconfigFiles(ctx, &c.mergedAconfigFiles)
+ android.CollectDependencyAconfigFiles(ctx, &c.mergedAconfigFiles)
c.maybeInstall(ctx, apexInfo)
+
+ if c.linker != nil {
+ moduleInfoJSON := ctx.ModuleInfoJSON()
+ c.linker.moduleInfoJSON(ctx, moduleInfoJSON)
+ moduleInfoJSON.SharedLibs = c.Properties.AndroidMkSharedLibs
+ moduleInfoJSON.StaticLibs = c.Properties.AndroidMkStaticLibs
+ moduleInfoJSON.SystemSharedLibs = c.Properties.AndroidMkSystemSharedLibs
+ moduleInfoJSON.RuntimeDependencies = c.Properties.AndroidMkRuntimeLibs
+
+ moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, c.Properties.AndroidMkSharedLibs...)
+ moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, c.Properties.AndroidMkStaticLibs...)
+ moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, c.Properties.AndroidMkHeaderLibs...)
+ moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, c.Properties.AndroidMkWholeStaticLibs...)
+
+ if c.sanitize != nil && len(moduleInfoJSON.Class) > 0 &&
+ (moduleInfoJSON.Class[0] == "STATIC_LIBRARIES" || moduleInfoJSON.Class[0] == "HEADER_LIBRARIES") {
+ if Bool(c.sanitize.Properties.SanitizeMutated.Cfi) {
+ moduleInfoJSON.SubName += ".cfi"
+ }
+ if Bool(c.sanitize.Properties.SanitizeMutated.Hwaddress) {
+ moduleInfoJSON.SubName += ".hwasan"
+ }
+ if Bool(c.sanitize.Properties.SanitizeMutated.Scs) {
+ moduleInfoJSON.SubName += ".scs"
+ }
+ }
+ moduleInfoJSON.SubName += c.Properties.SubName
+
+ if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake {
+ moduleInfoJSON.Uninstallable = true
+ }
+
+ }
}
func (c *Module) maybeUnhideFromMake() {
@@ -2368,9 +2411,9 @@
if actx.OtherModuleExists("api_imports") {
apiImportModule = actx.AddDependency(c, nil, "api_imports")
if len(apiImportModule) > 0 && apiImportModule[0] != nil {
- apiInfo := actx.OtherModuleProvider(apiImportModule[0], multitree.ApiImportsProvider).(multitree.ApiImportInfo)
+ apiInfo, _ := android.OtherModuleProvider(actx, apiImportModule[0], multitree.ApiImportsProvider)
apiImportInfo = apiInfo
- actx.SetProvider(multitree.ApiImportsProvider, apiInfo)
+ android.SetProvider(actx, multitree.ApiImportsProvider, apiInfo)
}
}
}
@@ -2385,16 +2428,16 @@
// Only retrieve the snapshot on demand in order to avoid circular dependencies
// between the modules in the snapshot and the snapshot itself.
var snapshotModule []blueprint.Module
- if c.InVendor() && c.VndkVersion() == actx.DeviceConfig().VndkVersion() {
+ if c.InVendor() && c.VndkVersion() == actx.DeviceConfig().VndkVersion() && actx.OtherModuleExists("vendor_snapshot") {
snapshotModule = actx.AddVariationDependencies(nil, nil, "vendor_snapshot")
- } else if recoverySnapshotVersion := actx.DeviceConfig().RecoverySnapshotVersion(); recoverySnapshotVersion != "current" && recoverySnapshotVersion != "" && c.InRecovery() {
+ } else if recoverySnapshotVersion := actx.DeviceConfig().RecoverySnapshotVersion(); recoverySnapshotVersion != "current" && recoverySnapshotVersion != "" && c.InRecovery() && actx.OtherModuleExists("recovery_snapshot") {
snapshotModule = actx.AddVariationDependencies(nil, nil, "recovery_snapshot")
}
if len(snapshotModule) > 0 && snapshotModule[0] != nil {
- snapshot := actx.OtherModuleProvider(snapshotModule[0], SnapshotInfoProvider).(SnapshotInfo)
+ snapshot, _ := android.OtherModuleProvider(actx, snapshotModule[0], SnapshotInfoProvider)
*snapshotInfo = &snapshot
// republish the snapshot for use in later mutators on this module
- actx.SetProvider(SnapshotInfoProvider, snapshot)
+ android.SetProvider(actx, SnapshotInfoProvider, snapshot)
}
}
if *snapshotInfo == nil {
@@ -2982,7 +3025,7 @@
depPaths.ReexportedGeneratedHeaders = append(depPaths.ReexportedGeneratedHeaders, exporter.GeneratedHeaders...)
}
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
c.apexSdkVersion = findApexSdkVersion(ctx, apexInfo)
skipModuleList := map[string]bool{}
@@ -2992,7 +3035,7 @@
ctx.VisitDirectDeps(func(dep android.Module) {
if dep.Name() == "api_imports" {
- apiImportInfo = ctx.OtherModuleProvider(dep, multitree.ApiImportsProvider).(multitree.ApiImportInfo)
+ apiImportInfo, _ = android.OtherModuleProvider(ctx, dep, multitree.ApiImportsProvider)
hasApiImportInfo = true
}
})
@@ -3043,12 +3086,10 @@
}
if depTag == aidlLibraryTag {
- if ctx.OtherModuleHasProvider(dep, aidl_library.AidlLibraryProvider) {
+ if aidlLibraryInfo, ok := android.OtherModuleProvider(ctx, dep, aidl_library.AidlLibraryProvider); ok {
depPaths.AidlLibraryInfos = append(
depPaths.AidlLibraryInfos,
- ctx.OtherModuleProvider(
- dep,
- aidl_library.AidlLibraryProvider).(aidl_library.AidlLibraryInfo),
+ aidlLibraryInfo,
)
}
}
@@ -3113,10 +3154,10 @@
// version mutator, so the stubs variant is created from the shared variant that
// already has the reuseObjTag dependency on the static variant.
if !c.library.buildStubs() {
- staticAnalogue := ctx.OtherModuleProvider(dep, StaticLibraryInfoProvider).(StaticLibraryInfo)
+ staticAnalogue, _ := android.OtherModuleProvider(ctx, dep, StaticLibraryInfoProvider)
objs := staticAnalogue.ReuseObjects
depPaths.Objs = depPaths.Objs.Append(objs)
- depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo)
+ depExporterInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider)
reexportExporter(depExporterInfo)
}
return
@@ -3137,7 +3178,7 @@
return
}
- depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo)
+ depExporterInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider)
var ptr *android.Paths
var depPtr *android.Paths
@@ -3146,7 +3187,7 @@
switch {
case libDepTag.header():
- if !ctx.OtherModuleHasProvider(dep, HeaderLibraryInfoProvider) {
+ if _, isHeaderLib := android.OtherModuleProvider(ctx, dep, HeaderLibraryInfoProvider); !isHeaderLib {
if !ctx.Config().AllowMissingDependencies() {
ctx.ModuleErrorf("module %q is not a header library", depName)
} else {
@@ -3155,7 +3196,7 @@
return
}
case libDepTag.shared():
- if !ctx.OtherModuleHasProvider(dep, SharedLibraryInfoProvider) {
+ if _, isSharedLib := android.OtherModuleProvider(ctx, dep, SharedLibraryInfoProvider); !isSharedLib {
if !ctx.Config().AllowMissingDependencies() {
ctx.ModuleErrorf("module %q is not a shared library", depName)
} else {
@@ -3192,7 +3233,8 @@
panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order))
}
case libDepTag.static():
- if !ctx.OtherModuleHasProvider(dep, StaticLibraryInfoProvider) {
+ staticLibraryInfo, isStaticLib := android.OtherModuleProvider(ctx, dep, StaticLibraryInfoProvider)
+ if !isStaticLib {
if !ctx.Config().AllowMissingDependencies() {
ctx.ModuleErrorf("module %q is not a static library", depName)
} else {
@@ -3207,7 +3249,6 @@
break
}
- staticLibraryInfo := ctx.OtherModuleProvider(dep, StaticLibraryInfoProvider).(StaticLibraryInfo)
linkFile = android.OptionalPathForPath(staticLibraryInfo.StaticLibrary)
if libDepTag.wholeStatic {
ptr = &depPaths.WholeStaticLibs
@@ -3317,7 +3358,7 @@
if lib.buildStubs() && dep.(android.ApexModule).InAnyApex() {
// Add the dependency to the APEX(es) providing the library so that
// m <module> can trigger building the APEXes as well.
- depApexInfo := ctx.OtherModuleProvider(dep, android.ApexInfoProvider).(android.ApexInfo)
+ depApexInfo, _ := android.OtherModuleProvider(ctx, dep, android.ApexInfoProvider)
for _, an := range depApexInfo.InApexVariants {
c.Properties.ApexesProvidingSharedLibs = append(
c.Properties.ApexesProvidingSharedLibs, an)
@@ -3402,7 +3443,7 @@
bootstrap = linkable.Bootstrap()
}
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
useStubs := false
@@ -3436,7 +3477,7 @@
// Another exception: if this module is a test for an APEX, then
// it is linked with the non-stub variant of a module in the APEX
// as if this is part of the APEX.
- testFor := ctx.Provider(android.ApexTestForInfoProvider).(android.ApexTestForInfo)
+ testFor, _ := android.ModuleProvider(ctx, android.ApexTestForInfoProvider)
for _, apexContents := range testFor.ApexContents {
if apexContents.DirectlyInApex(depName) {
useStubs = false
@@ -3482,9 +3523,9 @@
panic(fmt.Errorf("Unexpected dependency tag: %T", depTag))
}
- sharedLibraryInfo := ctx.OtherModuleProvider(dep, SharedLibraryInfoProvider).(SharedLibraryInfo)
- depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo)
- sharedLibraryStubsInfo := ctx.OtherModuleProvider(dep, SharedLibraryStubsProvider).(SharedLibraryStubsInfo)
+ sharedLibraryInfo, _ := android.OtherModuleProvider(ctx, dep, SharedLibraryInfoProvider)
+ depExporterInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider)
+ sharedLibraryStubsInfo, _ := android.OtherModuleProvider(ctx, dep, SharedLibraryStubsProvider)
if !libDepTag.explicitlyVersioned && len(sharedLibraryStubsInfo.SharedStubLibraries) > 0 {
// when to use (unspecified) stubs, use the latest one.
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 3631f19..321bd38 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -26,6 +26,8 @@
"android/soong/aidl_library"
"android/soong/android"
+
+ "github.com/google/blueprint"
)
func init() {
@@ -45,6 +47,14 @@
}),
)
+// TODO(b/316829758) Update prepareForCcTest with this configuration and remove prepareForCcTestWithoutVndk
+var prepareForCcTestWithoutVndk = android.GroupFixturePreparers(
+ PrepareForIntegrationTestWithCc,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.VendorApiLevel = StringPtr("202404")
+ }),
+)
+
var apexVariationName = "apex28"
var apexVersion = "28"
@@ -194,13 +204,13 @@
}
}
socSpecific := func(m *Module) bool {
- return m.SocSpecific() || m.socSpecificModuleContext()
+ return m.SocSpecific() || m.InstallInVendor()
}
deviceSpecific := func(m *Module) bool {
- return m.DeviceSpecific() || m.deviceSpecificModuleContext()
+ return m.DeviceSpecific() || m.InstallInOdm()
}
productSpecific := func(m *Module) bool {
- return m.ProductSpecific() || m.productSpecificModuleContext()
+ return m.ProductSpecific() || m.InstallInProduct()
}
systemExtSpecific := func(m *Module) bool {
return m.SystemExtSpecific()
@@ -2544,8 +2554,8 @@
variant := "android_arm64_armv8-a_static"
moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
- actual := android.Paths(ctx.ModuleProvider(moduleA, StaticLibraryInfoProvider).(StaticLibraryInfo).
- TransitiveStaticLibrariesForOrdering.ToList()).RelativeToTop()
+ staticLibInfo, _ := android.SingletonModuleProvider(ctx, moduleA, StaticLibraryInfoProvider)
+ actual := android.Paths(staticLibInfo.TransitiveStaticLibrariesForOrdering.ToList()).RelativeToTop()
expected := GetOutputPaths(ctx, variant, []string{"a", "c", "b", "d"})
if !reflect.DeepEqual(actual, expected) {
@@ -2580,8 +2590,8 @@
variant := "android_arm64_armv8-a_static"
moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
- actual := android.Paths(ctx.ModuleProvider(moduleA, StaticLibraryInfoProvider).(StaticLibraryInfo).
- TransitiveStaticLibrariesForOrdering.ToList()).RelativeToTop()
+ staticLibInfo, _ := android.SingletonModuleProvider(ctx, moduleA, StaticLibraryInfoProvider)
+ actual := android.Paths(staticLibInfo.TransitiveStaticLibrariesForOrdering.ToList()).RelativeToTop()
expected := GetOutputPaths(ctx, variant, []string{"a", "c", "b"})
if !reflect.DeepEqual(actual, expected) {
@@ -2640,6 +2650,7 @@
name: "libexternal_headers",
export_include_dirs: ["include"],
vendor_available: true,
+ product_available: true,
}
cc_library_headers {
name: "libexternal_llndk_headers",
@@ -2681,7 +2692,7 @@
checkExportedIncludeDirs := func(module, variant string, expectedDirs ...string) {
t.Helper()
m := result.ModuleForTests(module, variant).Module()
- f := result.ModuleProvider(m, FlagExporterInfoProvider).(FlagExporterInfo)
+ f, _ := android.SingletonModuleProvider(result, m, FlagExporterInfoProvider)
android.AssertPathsRelativeToTopEquals(t, "exported include dirs for "+module+"["+variant+"]",
expectedDirs, f.IncludeDirs)
}
@@ -4113,7 +4124,7 @@
checkIncludeDirs := func(t *testing.T, ctx *android.TestContext, module android.Module, checkers ...exportedChecker) {
t.Helper()
- exported := ctx.ModuleProvider(module, FlagExporterInfoProvider).(FlagExporterInfo)
+ exported, _ := android.SingletonModuleProvider(ctx, module, FlagExporterInfoProvider)
name := module.Name()
for _, checker := range checkers {
@@ -4784,3 +4795,51 @@
return
}
}
+
+// TODO(b/316829758) Remove this test and do not set VNDK version from other tests
+func TestImageVariantsWithoutVndk(t *testing.T) {
+ t.Parallel()
+
+ bp := `
+ cc_binary {
+ name: "binfoo",
+ srcs: ["binfoo.cc"],
+ vendor_available: true,
+ product_available: true,
+ shared_libs: ["libbar"]
+ }
+ cc_library {
+ name: "libbar",
+ srcs: ["libbar.cc"],
+ vendor_available: true,
+ product_available: true,
+ }
+ `
+
+ ctx := prepareForCcTestWithoutVndk.RunTestWithBp(t, bp)
+
+ hasDep := func(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
+ }
+
+ testDepWithVariant := func(imageVariant string) {
+ imageVariantStr := ""
+ if imageVariant != "core" {
+ imageVariantStr = "_" + imageVariant
+ }
+ binFooModule := ctx.ModuleForTests("binfoo", "android"+imageVariantStr+"_arm64_armv8-a").Module()
+ libBarModule := ctx.ModuleForTests("libbar", "android"+imageVariantStr+"_arm64_armv8-a_shared").Module()
+ android.AssertBoolEquals(t, "binfoo should have dependency on libbar with image variant "+imageVariant, true, hasDep(binFooModule, libBarModule))
+ }
+
+ testDepWithVariant("core")
+ testDepWithVariant("vendor")
+ testDepWithVariant("product")
+}
diff --git a/cc/fdo_profile.go b/cc/fdo_profile.go
index 02f68b5..0893da5 100644
--- a/cc/fdo_profile.go
+++ b/cc/fdo_profile.go
@@ -43,7 +43,7 @@
}
// FdoProfileProvider is used to provide path to an fdo profile
-var FdoProfileProvider = blueprint.NewMutatorProvider(FdoProfileInfo{}, "fdo_profile")
+var FdoProfileProvider = blueprint.NewMutatorProvider[FdoProfileInfo]("fdo_profile")
// FdoProfileMutatorInterface is the interface implemented by fdo_profile module type
// module types that can depend on an fdo_profile module
@@ -62,7 +62,7 @@
func (fp *fdoProfile) fdoProfileMutator(ctx android.BottomUpMutatorContext) {
if fp.properties.Profile != nil {
path := android.PathForModuleSrc(ctx, *fp.properties.Profile)
- ctx.SetProvider(FdoProfileProvider, FdoProfileInfo{
+ android.SetProvider(ctx, FdoProfileProvider, FdoProfileInfo{
Path: path,
})
}
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 6b3a739..2436f33 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -144,25 +144,35 @@
}
func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags {
+ subdir := "lib"
+ if ctx.inVendor() {
+ subdir = "lib/vendor"
+ }
+
flags = fuzz.binaryDecorator.linkerFlags(ctx, flags)
// RunPaths on devices isn't instantiated by the base linker. `../lib` for
// installed fuzz targets (both host and device), and `./lib` for fuzz
// target packages.
- flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/lib`)
+ flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/`+subdir)
// When running on device, fuzz targets with vendor: true set will be in
// fuzzer_name/vendor/fuzzer_name (note the extra 'vendor' and thus need to
// link with libraries in ../../lib/. Non-vendor binaries only need to look
// one level up, in ../lib/.
if ctx.inVendor() {
- flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../../lib`)
+ flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../../`+subdir)
} else {
- flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../lib`)
+ flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../`+subdir)
}
return flags
}
+func (fuzz *fuzzBinary) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+ fuzz.binaryDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+ moduleInfoJSON.Class = []string{"EXECUTABLES"}
+}
+
// IsValidSharedDependency takes a module and determines if it is a unique shared library
// that should be installed in the fuzz target output directories. This function
// returns true, unless:
@@ -216,19 +226,27 @@
}
func SharedLibraryInstallLocation(
- libraryBase string, isHost bool, fuzzDir string, archString string) string {
+ libraryBase string, isHost bool, isVendor bool, fuzzDir string, archString string) string {
installLocation := "$(PRODUCT_OUT)/data"
if isHost {
installLocation = "$(HOST_OUT)"
}
+ subdir := "lib"
+ if isVendor {
+ subdir = "lib/vendor"
+ }
installLocation = filepath.Join(
- installLocation, fuzzDir, archString, "lib", libraryBase)
+ installLocation, fuzzDir, archString, subdir, libraryBase)
return installLocation
}
// Get the device-only shared library symbols install directory.
-func SharedLibrarySymbolsInstallLocation(libraryBase string, fuzzDir string, archString string) string {
- return filepath.Join("$(PRODUCT_OUT)/symbols/data/", fuzzDir, archString, "/lib/", libraryBase)
+func SharedLibrarySymbolsInstallLocation(libraryBase string, isVendor bool, fuzzDir string, archString string) string {
+ subdir := "lib"
+ if isVendor {
+ subdir = "lib/vendor"
+ }
+ return filepath.Join("$(PRODUCT_OUT)/symbols/data/", fuzzDir, archString, subdir, libraryBase)
}
func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) {
@@ -239,16 +257,29 @@
// Grab the list of required shared libraries.
fuzzBin.sharedLibraries, _ = CollectAllSharedDependencies(ctx)
+ // TODO: does not mirror Android linkernamespaces
+ // the logic here has special cases for vendor, but it would need more work to
+ // work in arbitrary partitions, so just surface errors early for a few cases
+ //
+ // Even without these, there are certain situations across linkernamespaces
+ // that this won't support. For instance, you might have:
+ //
+ // my_fuzzer (vendor) -> libbinder_ndk (core) -> libbinder (vendor)
+ //
+ // This dependency chain wouldn't be possible to express in the current
+ // logic because all the deps currently match the variant of the source
+ // module.
+
for _, ruleBuilderInstall := range fuzzBin.sharedLibraries {
install := ruleBuilderInstall.To
fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
SharedLibraryInstallLocation(
- install, ctx.Host(), installBase, ctx.Arch().ArchType.String()))
+ install, ctx.Host(), ctx.inVendor(), installBase, ctx.Arch().ArchType.String()))
// Also add the dependency on the shared library symbols dir.
if !ctx.Host() {
fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
- SharedLibrarySymbolsInstallLocation(install, installBase, ctx.Arch().ArchType.String()))
+ SharedLibrarySymbolsInstallLocation(install, ctx.inVendor(), installBase, ctx.Arch().ArchType.String()))
}
}
@@ -407,6 +438,10 @@
}
sharedLibsInstallDirPrefix := "lib"
+ if ccModule.InVendor() {
+ sharedLibsInstallDirPrefix = "lib/vendor"
+ }
+
if !ccModule.IsFuzzModule() {
return
}
@@ -499,7 +534,7 @@
// install it to the output directory. Setup the install destination here,
// which will be used by $(copy-many-files) in the Make backend.
installDestination := SharedLibraryInstallLocation(
- install, module.Host(), fuzzDir, archString)
+ install, module.Host(), module.InVendor(), fuzzDir, archString)
if (*sharedLibraryInstalled)[installDestination] {
continue
}
@@ -517,7 +552,7 @@
// we want symbolization tools (like `stack`) to be able to find the symbols
// in $ANDROID_PRODUCT_OUT/symbols automagically.
if !module.Host() {
- symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(install, fuzzDir, archString)
+ symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(install, module.InVendor(), fuzzDir, archString)
symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$")
s.SharedLibInstallStrings = append(s.SharedLibInstallStrings,
library.String()+":"+symbolsInstallDestination)
@@ -544,7 +579,8 @@
if !IsValidSharedDependency(dep) {
return
}
- if !ctx.OtherModuleHasProvider(dep, SharedLibraryInfoProvider) {
+ sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, dep, SharedLibraryInfoProvider)
+ if !hasSharedLibraryInfo {
return
}
if seen[ctx.OtherModuleName(dep)] {
@@ -553,7 +589,6 @@
seen[ctx.OtherModuleName(dep)] = true
deps = append(deps, dep)
- sharedLibraryInfo := ctx.OtherModuleProvider(dep, SharedLibraryInfoProvider).(SharedLibraryInfo)
installDestination := sharedLibraryInfo.SharedLibrary.Base()
ruleBuilderInstall := android.RuleBuilderInstall{android.OutputFileForModule(ctx, dep, "unstripped"), installDestination}
sharedLibraries = append(sharedLibraries, ruleBuilderInstall)
@@ -574,14 +609,14 @@
if !IsValidSharedDependency(child) {
return false
}
- if !ctx.OtherModuleHasProvider(child, SharedLibraryInfoProvider) {
+ sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, child, SharedLibraryInfoProvider)
+ if !hasSharedLibraryInfo {
return false
}
if !seen[ctx.OtherModuleName(child)] {
seen[ctx.OtherModuleName(child)] = true
deps = append(deps, child)
- sharedLibraryInfo := ctx.OtherModuleProvider(child, SharedLibraryInfoProvider).(SharedLibraryInfo)
installDestination := sharedLibraryInfo.SharedLibrary.Base()
ruleBuilderInstall := android.RuleBuilderInstall{android.OutputFileForModule(ctx, child, "unstripped"), installDestination}
sharedLibraries = append(sharedLibraries, ruleBuilderInstall)
diff --git a/cc/image.go b/cc/image.go
index 4f36111..9eec255 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -42,27 +42,23 @@
)
const (
+ // VendorVariation is the variant name used for /vendor code that does not
+ // compile against the VNDK.
+ VendorVariation = "vendor"
+
// VendorVariationPrefix is the variant prefix used for /vendor code that compiles
// against the VNDK.
VendorVariationPrefix = "vendor."
+ // ProductVariation is the variant name used for /product code that does not
+ // compile against the VNDK.
+ ProductVariation = "product"
+
// ProductVariationPrefix is the variant prefix used for /product code that compiles
// against the VNDK.
ProductVariationPrefix = "product."
)
-func (ctx *moduleContext) ProductSpecific() bool {
- return ctx.ModuleContext.ProductSpecific() || ctx.mod.productSpecificModuleContext()
-}
-
-func (ctx *moduleContext) SocSpecific() bool {
- return ctx.ModuleContext.SocSpecific() || ctx.mod.socSpecificModuleContext()
-}
-
-func (ctx *moduleContext) DeviceSpecific() bool {
- return ctx.ModuleContext.DeviceSpecific() || ctx.mod.deviceSpecificModuleContext()
-}
-
func (ctx *moduleContextImpl) inProduct() bool {
return ctx.mod.InProduct()
}
@@ -83,20 +79,20 @@
return ctx.mod.InRecovery()
}
-func (c *Module) productSpecificModuleContext() bool {
+func (c *Module) InstallInProduct() bool {
// Additionally check if this module is inProduct() that means it is a "product" variant of a
// module. As well as product specific modules, product variants must be installed to /product.
return c.InProduct()
}
-func (c *Module) socSpecificModuleContext() bool {
+func (c *Module) InstallInVendor() bool {
// Additionally check if this module is inVendor() that means it is a "vendor" variant of a
// module. As well as SoC specific modules, vendor variants must be installed to /vendor
// unless they have "odm_available: true".
return c.HasVendorVariant() && c.InVendor() && !c.VendorVariantToOdm()
}
-func (c *Module) deviceSpecificModuleContext() bool {
+func (c *Module) InstallInOdm() bool {
// Some vendor variants want to be installed to /odm by setting "odm_available: true".
return c.InVendor() && c.VendorVariantToOdm()
}
@@ -124,12 +120,12 @@
// Returns true if the module is "product" variant. Usually these modules are installed in /product
func (c *Module) InProduct() bool {
- return c.Properties.ImageVariationPrefix == ProductVariationPrefix
+ return c.Properties.ImageVariation == ProductVariation
}
// Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor
func (c *Module) InVendor() bool {
- return c.Properties.ImageVariationPrefix == VendorVariationPrefix
+ return c.Properties.ImageVariation == VendorVariation
}
func (c *Module) InRamdisk() bool {
@@ -451,10 +447,8 @@
// and vendor and product variants will be created with LLNDK stubs.
// The LLNDK libraries need vendor variants even if there is no VNDK.
coreVariantNeeded = true
- if platformVndkVersion != "" {
- vendorVariants = append(vendorVariants, platformVndkVersion)
- productVariants = append(productVariants, platformVndkVersion)
- }
+ vendorVariants = append(vendorVariants, platformVndkVersion)
+ productVariants = append(productVariants, platformVndkVersion)
// Generate vendor variants for boardVndkVersion only if the VNDK snapshot does not
// provide the LLNDK stub libraries.
if needVndkVersionVendorVariantForLlndk {
@@ -465,13 +459,7 @@
// for system and product.
coreVariantNeeded = true
vendorVariants = append(vendorVariants, boardVndkVersion)
- if platformVndkVersion != "" {
- productVariants = append(productVariants, platformVndkVersion)
- }
- } else if boardVndkVersion == "" {
- // If the device isn't compiling against the VNDK, we always
- // use the core mode.
- coreVariantNeeded = true
+ productVariants = append(productVariants, platformVndkVersion)
} else if m.IsSnapshotPrebuilt() {
// Make vendor variants only for the versions in BOARD_VNDK_VERSION and
// PRODUCT_EXTRA_VNDK_VERSIONS.
@@ -569,11 +557,19 @@
}
for _, variant := range android.FirstUniqueStrings(vendorVariants) {
- m.AppendExtraVariant(VendorVariationPrefix + variant)
+ if variant == "" {
+ m.AppendExtraVariant(VendorVariation)
+ } else {
+ m.AppendExtraVariant(VendorVariationPrefix + variant)
+ }
}
for _, variant := range android.FirstUniqueStrings(productVariants) {
- m.AppendExtraVariant(ProductVariationPrefix + variant)
+ if variant == "" {
+ m.AppendExtraVariant(ProductVariation)
+ } else {
+ m.AppendExtraVariant(ProductVariationPrefix + variant)
+ }
}
m.SetRamdiskVariantNeeded(ramdiskVariantNeeded)
@@ -684,9 +680,12 @@
} else if variant == android.RecoveryVariation {
m.MakeAsPlatform()
squashRecoverySrcs(m)
- } else if strings.HasPrefix(variant, VendorVariationPrefix) {
- m.Properties.ImageVariationPrefix = VendorVariationPrefix
- m.Properties.VndkVersion = strings.TrimPrefix(variant, VendorVariationPrefix)
+ } else if strings.HasPrefix(variant, VendorVariation) {
+ m.Properties.ImageVariation = VendorVariation
+
+ if strings.HasPrefix(variant, VendorVariationPrefix) {
+ m.Properties.VndkVersion = strings.TrimPrefix(variant, VendorVariationPrefix)
+ }
squashVendorSrcs(m)
// Makefile shouldn't know vendor modules other than BOARD_VNDK_VERSION.
@@ -696,9 +695,11 @@
m.Properties.HideFromMake = true
m.HideFromMake()
}
- } else if strings.HasPrefix(variant, ProductVariationPrefix) {
- m.Properties.ImageVariationPrefix = ProductVariationPrefix
- m.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix)
+ } else if strings.HasPrefix(variant, ProductVariation) {
+ m.Properties.ImageVariation = ProductVariation
+ if strings.HasPrefix(variant, ProductVariationPrefix) {
+ m.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix)
+ }
squashProductSrcs(m)
}
diff --git a/cc/library.go b/cc/library.go
index 4d5a254..592f70f 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -341,7 +341,7 @@
}
func (f *flagExporter) setProvider(ctx android.ModuleContext) {
- ctx.SetProvider(FlagExporterInfoProvider, FlagExporterInfo{
+ android.SetProvider(ctx, FlagExporterInfoProvider, FlagExporterInfo{
// Comes from Export_include_dirs property, and those of exported transitive deps
IncludeDirs: android.FirstUniquePaths(f.dirs),
// Comes from Export_system_include_dirs property, and those of exported transitive deps
@@ -1041,6 +1041,40 @@
return specifiedDeps
}
+func (library *libraryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+ if library.static() {
+ moduleInfoJSON.Class = []string{"STATIC_LIBRARIES"}
+ moduleInfoJSON.Uninstallable = true
+ } else if library.shared() {
+ moduleInfoJSON.Class = []string{"SHARED_LIBRARIES"}
+ } else if library.header() {
+ moduleInfoJSON.Class = []string{"HEADER_LIBRARIES"}
+ moduleInfoJSON.Uninstallable = true
+ }
+
+ if library.buildStubs() && library.stubsVersion() != "" {
+ moduleInfoJSON.SubName += "." + library.stubsVersion()
+ }
+
+ // If a library providing a stub is included in an APEX, the private APIs of the library
+ // is accessible only inside the APEX. From outside of the APEX, clients can only use the
+ // public APIs via the stub. To enforce this, the (latest version of the) stub gets the
+ // name of the library. The impl library instead gets the `.bootstrap` suffix to so that
+ // they can be exceptionally used directly when APEXes are not available (e.g. during the
+ // very early stage in the boot process).
+ if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.notInPlatform() &&
+ !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() && !ctx.useVndk() && !ctx.static() {
+ if library.buildStubs() && library.isLatestStubVersion() {
+ moduleInfoJSON.SubName = ""
+ }
+ if !library.buildStubs() {
+ moduleInfoJSON.SubName = ".bootstrap"
+ }
+ }
+
+ library.baseLinker.moduleInfoJSON(ctx, moduleInfoJSON)
+}
+
func (library *libraryDecorator) linkStatic(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
@@ -1071,7 +1105,7 @@
ctx.CheckbuildFile(outputFile)
if library.static() {
- ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+ android.SetProvider(ctx, StaticLibraryInfoProvider, StaticLibraryInfo{
StaticLibrary: outputFile,
ReuseObjects: library.reuseObjects,
Objects: library.objects,
@@ -1085,7 +1119,7 @@
}
if library.header() {
- ctx.SetProvider(HeaderLibraryInfoProvider, HeaderLibraryInfo{})
+ android.SetProvider(ctx, HeaderLibraryInfoProvider, HeaderLibraryInfo{})
}
return outputFile
@@ -1235,11 +1269,11 @@
var transitiveStaticLibrariesForOrdering *android.DepSet[android.Path]
if static := ctx.GetDirectDepsWithTag(staticVariantTag); len(static) > 0 {
- s := ctx.OtherModuleProvider(static[0], StaticLibraryInfoProvider).(StaticLibraryInfo)
+ s, _ := android.OtherModuleProvider(ctx, static[0], StaticLibraryInfoProvider)
transitiveStaticLibrariesForOrdering = s.TransitiveStaticLibrariesForOrdering
}
- ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+ android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
TableOfContents: android.OptionalPathForPath(tocFile),
SharedLibrary: unstrippedOutputFile,
TransitiveStaticLibrariesForOrdering: transitiveStaticLibrariesForOrdering,
@@ -1256,15 +1290,15 @@
if len(stubs) > 0 {
var stubsInfo []SharedStubLibrary
for _, stub := range stubs {
- stubInfo := ctx.OtherModuleProvider(stub, SharedLibraryInfoProvider).(SharedLibraryInfo)
- flagInfo := ctx.OtherModuleProvider(stub, FlagExporterInfoProvider).(FlagExporterInfo)
+ stubInfo, _ := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider)
+ flagInfo, _ := android.OtherModuleProvider(ctx, stub, FlagExporterInfoProvider)
stubsInfo = append(stubsInfo, SharedStubLibrary{
Version: moduleLibraryInterface(stub).stubsVersion(),
SharedLibraryInfo: stubInfo,
FlagExporterInfo: flagInfo,
})
}
- ctx.SetProvider(SharedLibraryStubsProvider, SharedLibraryStubsInfo{
+ android.SetProvider(ctx, SharedLibraryStubsProvider, SharedLibraryStubsInfo{
SharedStubLibraries: stubsInfo,
IsLLNDK: ctx.IsLlndk(),
})
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 52e78d7..a65b1ba 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -511,7 +511,7 @@
}
}
- exportedInfo := ctx.SdkModuleContext().OtherModuleProvider(variant, FlagExporterInfoProvider).(FlagExporterInfo)
+ exportedInfo, _ := android.OtherModuleProvider(ctx.SdkModuleContext(), variant, FlagExporterInfoProvider)
// Separate out the generated include dirs (which are arch specific) from the
// include dirs (which may not be).
diff --git a/cc/library_stub.go b/cc/library_stub.go
index 18d3f21..1183b29 100644
--- a/cc/library_stub.go
+++ b/cc/library_stub.go
@@ -244,7 +244,7 @@
},
})
- ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+ android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
SharedLibrary: outputFile,
Target: ctx.Target(),
@@ -262,15 +262,15 @@
if len(stubs) > 0 {
var stubsInfo []SharedStubLibrary
for _, stub := range stubs {
- stubInfo := ctx.OtherModuleProvider(stub, SharedLibraryInfoProvider).(SharedLibraryInfo)
- flagInfo := ctx.OtherModuleProvider(stub, FlagExporterInfoProvider).(FlagExporterInfo)
+ stubInfo, _ := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider)
+ flagInfo, _ := android.OtherModuleProvider(ctx, stub, FlagExporterInfoProvider)
stubsInfo = append(stubsInfo, SharedStubLibrary{
Version: moduleLibraryInterface(stub).stubsVersion(),
SharedLibraryInfo: stubInfo,
FlagExporterInfo: flagInfo,
})
}
- ctx.SetProvider(SharedLibraryStubsProvider, SharedLibraryStubsInfo{
+ android.SetProvider(ctx, SharedLibraryStubsProvider, SharedLibraryStubsInfo{
SharedStubLibraries: stubsInfo,
IsLLNDK: ctx.IsLlndk(),
diff --git a/cc/linkable.go b/cc/linkable.go
index 994517c..a009c6c 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -368,7 +368,7 @@
TransitiveStaticLibrariesForOrdering *android.DepSet[android.Path]
}
-var SharedLibraryInfoProvider = blueprint.NewProvider(SharedLibraryInfo{})
+var SharedLibraryInfoProvider = blueprint.NewProvider[SharedLibraryInfo]()
// SharedStubLibrary is a struct containing information about a stub shared library.
// Stub libraries are used for cross-APEX dependencies; when a library is to depend on a shared
@@ -391,7 +391,7 @@
IsLLNDK bool
}
-var SharedLibraryStubsProvider = blueprint.NewProvider(SharedLibraryStubsInfo{})
+var SharedLibraryStubsProvider = blueprint.NewProvider[SharedLibraryStubsInfo]()
// StaticLibraryInfo is a provider to propagate information about a static C++ library.
type StaticLibraryInfo struct {
@@ -410,14 +410,14 @@
TransitiveStaticLibrariesForOrdering *android.DepSet[android.Path]
}
-var StaticLibraryInfoProvider = blueprint.NewProvider(StaticLibraryInfo{})
+var StaticLibraryInfoProvider = blueprint.NewProvider[StaticLibraryInfo]()
// HeaderLibraryInfo is a marker provider that identifies a module as a header library.
type HeaderLibraryInfo struct {
}
// HeaderLibraryInfoProvider is a marker provider that identifies a module as a header library.
-var HeaderLibraryInfoProvider = blueprint.NewProvider(HeaderLibraryInfo{})
+var HeaderLibraryInfoProvider = blueprint.NewProvider[HeaderLibraryInfo]()
// FlagExporterInfo is a provider to propagate transitive library information
// pertaining to exported include paths and flags.
@@ -429,4 +429,4 @@
GeneratedHeaders android.Paths
}
-var FlagExporterInfoProvider = blueprint.NewProvider(FlagExporterInfo{})
+var FlagExporterInfoProvider = blueprint.NewProvider[FlagExporterInfo]()
diff --git a/cc/linker.go b/cc/linker.go
index 357d1ce..85c128e 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -648,6 +648,9 @@
return specifiedDeps
}
+func (linker *baseLinker) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+}
+
// Injecting version symbols
// Some host modules want a version number, but we don't want to rebuild it every time. Optionally add a step
// after linking that injects a constant placeholder with the current version number.
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 98fb334..183e818 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -486,6 +486,12 @@
}
}
+func (linker *stubDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+ linker.libraryDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+ // Overwrites the SubName computed by libraryDecorator
+ moduleInfoJSON.SubName = ndkLibrarySuffix + "." + linker.apiLevel.String()
+}
+
func (linker *stubDecorator) Name(name string) string {
return name + ndkLibrarySuffix
}
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index 842bdf6..f503982 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -117,13 +117,13 @@
if ndk.static() {
depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(lib).Build()
- ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+ android.SetProvider(ctx, StaticLibraryInfoProvider, StaticLibraryInfo{
StaticLibrary: lib,
TransitiveStaticLibrariesForOrdering: depSet,
})
} else {
- ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+ android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
SharedLibrary: lib,
Target: ctx.Target(),
})
diff --git a/cc/object.go b/cc/object.go
index 0dba99f..6c0391f 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -238,3 +238,8 @@
func (object *objectLinker) isCrt() bool {
return Bool(object.Properties.Crt)
}
+
+func (object *objectLinker) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+ object.baseLinker.moduleInfoJSON(ctx, moduleInfoJSON)
+ moduleInfoJSON.Class = []string{"STATIC_LIBRARIES"}
+}
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index f68fa24..e721c53 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -132,7 +132,7 @@
if p.static() {
depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(in).Build()
- ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+ android.SetProvider(ctx, StaticLibraryInfoProvider, StaticLibraryInfo{
StaticLibrary: in,
TransitiveStaticLibrariesForOrdering: depSet,
@@ -190,7 +190,7 @@
},
})
- ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+ android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
SharedLibrary: outputFile,
Target: ctx.Target(),
@@ -213,7 +213,7 @@
}
if p.header() {
- ctx.SetProvider(HeaderLibraryInfoProvider, HeaderLibraryInfo{})
+ android.SetProvider(ctx, HeaderLibraryInfoProvider, HeaderLibraryInfo{})
// Need to return an output path so that the AndroidMk logic doesn't skip
// the prebuilt header. For compatibility, in case Android.mk files use a
diff --git a/cc/sabi.go b/cc/sabi.go
index 4cd776a..1310685 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -194,8 +194,8 @@
return false
}
- isPlatformVariant := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
- if isPlatformVariant {
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+ if apexInfo.IsForPlatform() {
// Bionic libraries that are installed to the bootstrap directory are not ABI checked.
// Only the runtime APEX variants, which are the implementation libraries of bionic NDK stubs,
// are checked.
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 31c0500..52b5be9 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -1627,7 +1627,7 @@
addStaticDeps := func(dep string, hideSymbols bool) {
// If we're using snapshots, redirect to snapshot whenever possible
- snapshot := mctx.Provider(SnapshotInfoProvider).(SnapshotInfo)
+ snapshot, _ := android.ModuleProvider(mctx, SnapshotInfoProvider)
if lib, ok := snapshot.StaticLibs[dep]; ok {
dep = lib
}
@@ -1714,7 +1714,7 @@
addStaticDeps(runtimeSharedLibrary, true)
} else if !c.static() && !c.Header() {
// If we're using snapshots, redirect to snapshot whenever possible
- snapshot := mctx.Provider(SnapshotInfoProvider).(SnapshotInfo)
+ snapshot, _ := android.ModuleProvider(mctx, SnapshotInfoProvider)
if lib, ok := snapshot.SharedLibs[runtimeSharedLibrary]; ok {
runtimeSharedLibrary = lib
}
diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go
index 31e668e..44f38e1 100644
--- a/cc/sanitize_test.go
+++ b/cc/sanitize_test.go
@@ -22,8 +22,6 @@
"testing"
"android/soong/android"
-
- "github.com/google/blueprint"
)
var prepareForAsanTest = android.FixtureAddFile("asan/Android.bp", []byte(`
@@ -49,7 +47,7 @@
`))
type providerInterface interface {
- ModuleProvider(blueprint.Module, blueprint.ProviderKey) interface{}
+ android.SingletonModuleProviderContext
}
// expectSharedLinkDep verifies that the from module links against the to module as a
@@ -57,7 +55,7 @@
func expectSharedLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) {
t.Helper()
fromLink := from.Description("link")
- toInfo := ctx.ModuleProvider(to.Module(), SharedLibraryInfoProvider).(SharedLibraryInfo)
+ toInfo, _ := android.SingletonModuleProvider(ctx, to.Module(), SharedLibraryInfoProvider)
if g, w := fromLink.OrderOnly.Strings(), toInfo.SharedLibrary.RelativeToTop().String(); !android.InList(w, g) {
t.Errorf("%s should link against %s, expected %q, got %q",
@@ -70,7 +68,7 @@
func expectNoSharedLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) {
t.Helper()
fromLink := from.Description("link")
- toInfo := ctx.ModuleProvider(to.Module(), SharedLibraryInfoProvider).(SharedLibraryInfo)
+ toInfo, _ := android.SingletonModuleProvider(ctx, to.Module(), SharedLibraryInfoProvider)
if g, w := fromLink.OrderOnly.Strings(), toInfo.SharedLibrary.RelativeToTop().String(); android.InList(w, g) {
t.Errorf("%s should not link against %s, expected %q, got %q",
@@ -83,7 +81,7 @@
func expectStaticLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) {
t.Helper()
fromLink := from.Description("link")
- toInfo := ctx.ModuleProvider(to.Module(), StaticLibraryInfoProvider).(StaticLibraryInfo)
+ toInfo, _ := android.SingletonModuleProvider(ctx, to.Module(), StaticLibraryInfoProvider)
if g, w := fromLink.Implicits.Strings(), toInfo.StaticLibrary.RelativeToTop().String(); !android.InList(w, g) {
t.Errorf("%s should link against %s, expected %q, got %q",
@@ -97,7 +95,7 @@
func expectNoStaticLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) {
t.Helper()
fromLink := from.Description("link")
- toInfo := ctx.ModuleProvider(to.Module(), StaticLibraryInfoProvider).(StaticLibraryInfo)
+ toInfo, _ := android.SingletonModuleProvider(ctx, to.Module(), StaticLibraryInfoProvider)
if g, w := fromLink.Implicits.Strings(), toInfo.StaticLibrary.RelativeToTop().String(); android.InList(w, g) {
t.Errorf("%s should not link against %s, expected %q, got %q",
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index e29c446..e769fe9 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -194,7 +194,7 @@
sharedLibs[k] = v
}
- ctx.SetProvider(SnapshotInfoProvider, SnapshotInfo{
+ android.SetProvider(ctx, SnapshotInfoProvider, SnapshotInfo{
HeaderLibs: headers,
Binaries: binaries,
Objects: objects,
@@ -209,7 +209,7 @@
HeaderLibs, Binaries, Objects, StaticLibs, SharedLibs, Rlibs, Dylibs map[string]string
}
-var SnapshotInfoProvider = blueprint.NewMutatorProvider(SnapshotInfo{}, "deps")
+var SnapshotInfoProvider = blueprint.NewMutatorProvider[SnapshotInfo]("deps")
var _ android.ImageInterface = (*snapshotModule)(nil)
@@ -494,7 +494,7 @@
p.tocFile = android.OptionalPathForPath(tocFile)
TransformSharedObjectToToc(ctx, in, tocFile)
- ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+ android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
SharedLibrary: in,
Target: ctx.Target(),
@@ -504,7 +504,7 @@
if p.static() {
depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(in).Build()
- ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+ android.SetProvider(ctx, StaticLibraryInfoProvider, StaticLibraryInfo{
StaticLibrary: in,
TransitiveStaticLibrariesForOrdering: depSet,
diff --git a/cc/symbolfile/__init__.py b/cc/symbolfile/__init__.py
index 94c8567..345e9f9 100644
--- a/cc/symbolfile/__init__.py
+++ b/cc/symbolfile/__init__.py
@@ -46,6 +46,15 @@
Arch('x86_64'),
)
+# TODO: it would be nice to dedupe with 'has_*_tag' property methods
+SUPPORTED_TAGS = ALL_ARCHITECTURES + (
+ Tag('apex'),
+ Tag('llndk'),
+ Tag('platform-only'),
+ Tag('systemapi'),
+ Tag('var'),
+ Tag('weak'),
+)
# Arbitrary magic number. We use the same one in api-level.h for this purpose.
FUTURE_API_LEVEL = 10000
@@ -136,6 +145,8 @@
def is_api_level_tag(tag: Tag) -> bool:
"""Returns true if this tag has an API level that may need decoding."""
+ if tag.startswith('llndk-deprecated='):
+ return True
if tag.startswith('introduced='):
return True
if tag.startswith('introduced-'):
@@ -170,6 +181,9 @@
ParseError: An unknown version name was found in a tag.
"""
if not is_api_level_tag(tag):
+ if tag not in SUPPORTED_TAGS:
+ raise ParseError(f'Unsupported tag: {tag}')
+
return tag
name, value = split_tag(tag)
diff --git a/cc/symbolfile/test_symbolfile.py b/cc/symbolfile/test_symbolfile.py
index 856b9d7..83becc2 100644
--- a/cc/symbolfile/test_symbolfile.py
+++ b/cc/symbolfile/test_symbolfile.py
@@ -40,10 +40,20 @@
self.assertEqual(Tags(), symbolfile.get_tags('foo bar baz', {}))
def test_get_tags(self) -> None:
- self.assertEqual(Tags.from_strs(['foo', 'bar']),
- symbolfile.get_tags('# foo bar', {}))
- self.assertEqual(Tags.from_strs(['bar', 'baz']),
- symbolfile.get_tags('foo # bar baz', {}))
+ self.assertEqual(Tags.from_strs(['llndk', 'apex']),
+ symbolfile.get_tags('# llndk apex', {}))
+ self.assertEqual(Tags.from_strs(['llndk', 'apex']),
+ symbolfile.get_tags('foo # llndk apex', {}))
+
+ def test_get_unrecognized_tags(self) -> None:
+ with self.assertRaises(symbolfile.ParseError):
+ symbolfile.get_tags('# bar', {})
+ with self.assertRaises(symbolfile.ParseError):
+ symbolfile.get_tags('foo # bar', {})
+ with self.assertRaises(symbolfile.ParseError):
+ symbolfile.get_tags('# #', {})
+ with self.assertRaises(symbolfile.ParseError):
+ symbolfile.get_tags('# apex # llndk', {})
def test_split_tag(self) -> None:
self.assertTupleEqual(('foo', 'bar'),
@@ -425,13 +435,13 @@
def test_parse_version(self) -> None:
input_file = io.StringIO(textwrap.dedent("""\
- VERSION_1 { # foo bar
+ VERSION_1 { # weak introduced=35
baz;
- qux; # woodly doodly
+ qux; # apex llndk
};
VERSION_2 {
- } VERSION_1; # asdf
+ } VERSION_1; # not-a-tag
"""))
parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
@@ -439,11 +449,11 @@
version = parser.parse_version()
self.assertEqual('VERSION_1', version.name)
self.assertIsNone(version.base)
- self.assertEqual(Tags.from_strs(['foo', 'bar']), version.tags)
+ self.assertEqual(Tags.from_strs(['weak', 'introduced=35']), version.tags)
expected_symbols = [
Symbol('baz', Tags()),
- Symbol('qux', Tags.from_strs(['woodly', 'doodly'])),
+ Symbol('qux', Tags.from_strs(['apex', 'llndk'])),
]
self.assertEqual(expected_symbols, version.symbols)
@@ -476,7 +486,7 @@
def test_parse_symbol(self) -> None:
input_file = io.StringIO(textwrap.dedent("""\
foo;
- bar; # baz qux
+ bar; # llndk apex
"""))
parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
@@ -488,7 +498,7 @@
parser.next_line()
symbol = parser.parse_symbol()
self.assertEqual('bar', symbol.name)
- self.assertEqual(Tags.from_strs(['baz', 'qux']), symbol.tags)
+ self.assertEqual(Tags.from_strs(['llndk', 'apex']), symbol.tags)
def test_wildcard_symbol_global(self) -> None:
input_file = io.StringIO(textwrap.dedent("""\
@@ -537,13 +547,13 @@
hidden1;
global:
foo;
- bar; # baz
+ bar; # llndk
};
- VERSION_2 { # wasd
+ VERSION_2 { # weak
# Implicit global scope.
woodly;
- doodly; # asdf
+ doodly; # llndk
local:
qwerty;
} VERSION_1;
@@ -554,12 +564,12 @@
expected = [
symbolfile.Version('VERSION_1', None, Tags(), [
Symbol('foo', Tags()),
- Symbol('bar', Tags.from_strs(['baz'])),
+ Symbol('bar', Tags.from_strs(['llndk'])),
]),
symbolfile.Version(
- 'VERSION_2', 'VERSION_1', Tags.from_strs(['wasd']), [
+ 'VERSION_2', 'VERSION_1', Tags.from_strs(['weak']), [
Symbol('woodly', Tags()),
- Symbol('doodly', Tags.from_strs(['asdf'])),
+ Symbol('doodly', Tags.from_strs(['llndk'])),
]),
]
diff --git a/cc/test.go b/cc/test.go
index d02145b..347d7c9 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -321,6 +321,13 @@
return []interface{}{&test.InstallerProperties}
}
+func (test *testDecorator) moduleInfoJSON(ctx android.ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+ if android.PrefixInList(moduleInfoJSON.CompatibilitySuites, "mts-") &&
+ !android.InList("mts", moduleInfoJSON.CompatibilitySuites) {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "mts")
+ }
+}
+
func NewTestInstaller() *baseInstaller {
return NewBaseInstaller("nativetest", "nativetest64", InstallInData)
}
@@ -355,6 +362,38 @@
return flags
}
+func (test *testBinary) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+ if ctx.Host() && Bool(test.Properties.Test_options.Unit_test) {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "host-unit-tests")
+ }
+ moduleInfoJSON.TestOptionsTags = append(moduleInfoJSON.TestOptionsTags, test.Properties.Test_options.Tags...)
+ moduleInfoJSON.TestMainlineModules = append(moduleInfoJSON.TestMainlineModules, test.Properties.Test_mainline_modules...)
+ if test.testConfig != nil {
+ if _, ok := test.testConfig.(android.WritablePath); ok {
+ moduleInfoJSON.AutoTestConfig = []string{"true"}
+ }
+ moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, test.testConfig.String())
+ }
+ moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, test.extraTestConfigs.Strings()...)
+
+ if Bool(test.Properties.Test_per_src) {
+ moduleInfoJSON.SubName = "_" + String(test.binaryDecorator.Properties.Stem)
+ }
+
+ moduleInfoJSON.DataDependencies = append(moduleInfoJSON.DataDependencies, test.Properties.Data_bins...)
+
+ if len(test.InstallerProperties.Test_suites) > 0 {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, test.InstallerProperties.Test_suites...)
+ } else {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite")
+ }
+
+ test.binaryDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+ test.testDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+ moduleInfoJSON.Class = []string{"NATIVE_TESTS"}
+
+}
+
func (test *testBinary) installerProps() []interface{} {
return append(test.baseInstaller.installerProps(), test.testDecorator.installerProps()...)
}
@@ -532,6 +571,15 @@
return flags
}
+func (test *testLibrary) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+ if len(test.InstallerProperties.Test_suites) > 0 {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, test.InstallerProperties.Test_suites...)
+ }
+
+ test.libraryDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+ test.testDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+}
+
func (test *testLibrary) installerProps() []interface{} {
return append(test.baseInstaller.installerProps(), test.testDecorator.installerProps()...)
}
@@ -626,6 +674,29 @@
benchmark.binaryDecorator.baseInstaller.install(ctx, file)
}
+func (benchmark *benchmarkDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+ benchmark.binaryDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+
+ moduleInfoJSON.Class = []string{"NATIVE_TESTS"}
+ if len(benchmark.Properties.Test_suites) > 0 {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, benchmark.Properties.Test_suites...)
+ } else {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite")
+ }
+
+ if android.PrefixInList(moduleInfoJSON.CompatibilitySuites, "mts-") &&
+ !android.InList("mts", moduleInfoJSON.CompatibilitySuites) {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "mts")
+ }
+
+ if benchmark.testConfig != nil {
+ if _, ok := benchmark.testConfig.(android.WritablePath); ok {
+ moduleInfoJSON.AutoTestConfig = []string{"true"}
+ }
+ moduleInfoJSON.TestConfig = []string{benchmark.testConfig.String()}
+ }
+}
+
func NewBenchmark(hod android.HostOrDeviceSupported) *Module {
module, binary := newBinary(hod)
module.multilib = android.MultilibBoth
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index e8e930e..a33ed5f 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -275,7 +275,7 @@
var propOut string
if m.IsSnapshotLibrary() {
- exporterInfo := ctx.ModuleProvider(m.Module(), FlagExporterInfoProvider).(FlagExporterInfo)
+ exporterInfo, _ := android.SingletonModuleProvider(ctx, m.Module(), FlagExporterInfoProvider)
// library flags
prop.ExportedFlags = exporterInfo.Flags
@@ -407,7 +407,7 @@
moduleDir := ctx.ModuleDir(module)
inProprietaryPath := s.Image.IsProprietaryPath(moduleDir, ctx.DeviceConfig())
- apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.SingletonModuleProvider(ctx, module, android.ApexInfoProvider)
if s.Image.ExcludeFromSnapshot(m) {
if inProprietaryPath {
diff --git a/cc/vndk.go b/cc/vndk.go
index a849455..b2c6e0d 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -772,7 +772,7 @@
prop.MinSdkVersion = m.MinSdkVersion()
if ctx.Config().VndkSnapshotBuildArtifacts() {
- exportedInfo := ctx.ModuleProvider(m, FlagExporterInfoProvider).(FlagExporterInfo)
+ exportedInfo, _ := android.SingletonModuleProvider(ctx, m, FlagExporterInfoProvider)
prop.ExportedFlags = exportedInfo.Flags
prop.ExportedDirs = exportedInfo.IncludeDirs.Strings()
prop.ExportedSystemDirs = exportedInfo.SystemIncludeDirs.Strings()
@@ -797,7 +797,7 @@
return
}
- apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.SingletonModuleProvider(ctx, module, android.ApexInfoProvider)
vndkType, ok := isVndkSnapshotAware(ctx.DeviceConfig(), m, apexInfo)
if !ok {
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 5e526db..eb1790f 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -171,7 +171,7 @@
p.androidMkSuffix = ""
}
- ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+ android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
SharedLibrary: in,
Target: ctx.Target(),
@@ -187,6 +187,11 @@
return nil
}
+func (p *vndkPrebuiltLibraryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+ p.libraryDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+ moduleInfoJSON.SubName += p.androidMkSuffix
+}
+
func (p *vndkPrebuiltLibraryDecorator) MatchesWithDevice(config android.DeviceConfig) bool {
arches := config.Arches()
if len(arches) == 0 || arches[0].ArchType.String() != p.arch() {
diff --git a/cmd/merge_module_info_json/Android.bp b/cmd/merge_module_info_json/Android.bp
new file mode 100644
index 0000000..1ae6a47
--- /dev/null
+++ b/cmd/merge_module_info_json/Android.bp
@@ -0,0 +1,30 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+blueprint_go_binary {
+ name: "merge_module_info_json",
+ srcs: [
+ "merge_module_info_json.go",
+ ],
+ deps: [
+ "soong-response",
+ ],
+ testSrcs: [
+ "merge_module_info_json_test.go",
+ ],
+}
diff --git a/cmd/merge_module_info_json/merge_module_info_json.go b/cmd/merge_module_info_json/merge_module_info_json.go
new file mode 100644
index 0000000..0143984
--- /dev/null
+++ b/cmd/merge_module_info_json/merge_module_info_json.go
@@ -0,0 +1,223 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// merge_module_info_json is a utility that merges module_info.json files generated by
+// Soong and Make.
+
+package main
+
+import (
+ "android/soong/response"
+ "cmp"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "os"
+ "slices"
+)
+
+var (
+ out = flag.String("o", "", "output file")
+ listFile = flag.String("l", "", "input file list file")
+)
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: %s -o <output file> <input files>\n", os.Args[0])
+ flag.PrintDefaults()
+ fmt.Fprintln(os.Stderr, "merge_module_info_json reads input files that each contain an array of json objects")
+ fmt.Fprintln(os.Stderr, "and writes them out as a single json array to the output file.")
+
+ os.Exit(2)
+}
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+
+ if *out == "" {
+ fmt.Fprintf(os.Stderr, "%s: error: -o is required\n", os.Args[0])
+ usage()
+ }
+
+ inputs := flag.Args()
+ if *listFile != "" {
+ listFileInputs, err := readListFile(*listFile)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "failed to read list file %s: %s", *listFile, err)
+ os.Exit(1)
+ }
+ inputs = append(inputs, listFileInputs...)
+ }
+
+ err := mergeJsonObjects(*out, inputs)
+
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: error: %s\n", os.Args[0], err.Error())
+ os.Exit(1)
+ }
+}
+
+func readListFile(file string) ([]string, error) {
+ f, err := os.Open(*listFile)
+ if err != nil {
+ return nil, err
+ }
+ return response.ReadRspFile(f)
+}
+
+func mergeJsonObjects(output string, inputs []string) error {
+ combined := make(map[string]any)
+ for _, input := range inputs {
+ objects, err := decodeObjectFromJson(input)
+ if err != nil {
+ return err
+ }
+
+ for _, object := range objects {
+ for k, v := range object {
+ if old, exists := combined[k]; exists {
+ v = combine(old, v)
+ }
+ combined[k] = v
+ }
+ }
+ }
+
+ f, err := os.Create(output)
+ if err != nil {
+ return fmt.Errorf("failed to open output file: %w", err)
+ }
+ encoder := json.NewEncoder(f)
+ encoder.SetIndent("", " ")
+ err = encoder.Encode(combined)
+ if err != nil {
+ return fmt.Errorf("failed to encode to output file: %w", err)
+ }
+
+ return nil
+}
+
+func decodeObjectFromJson(input string) ([]map[string]any, error) {
+ f, err := os.Open(input)
+ if err != nil {
+ return nil, fmt.Errorf("failed to open input file: %w", err)
+ }
+
+ decoder := json.NewDecoder(f)
+ var object any
+ err = decoder.Decode(&object)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse input file %q: %w", input, err)
+ }
+
+ switch o := object.(type) {
+ case []any:
+ var ret []map[string]any
+ for _, arrayElement := range o {
+ if m, ok := arrayElement.(map[string]any); ok {
+ ret = append(ret, m)
+ } else {
+ return nil, fmt.Errorf("unknown JSON type in array %T", arrayElement)
+ }
+ }
+ return ret, nil
+
+ case map[string]any:
+ return []map[string]any{o}, nil
+ }
+
+ return nil, fmt.Errorf("unknown JSON type %T", object)
+}
+
+func combine(old, new any) any {
+ // fmt.Printf("%#v %#v\n", old, new)
+ switch oldTyped := old.(type) {
+ case map[string]any:
+ if newObject, ok := new.(map[string]any); ok {
+ return combineObjects(oldTyped, newObject)
+ } else {
+ panic(fmt.Errorf("expected map[string]any, got %#v", new))
+ }
+ case []any:
+ if newArray, ok := new.([]any); ok {
+ return combineArrays(oldTyped, newArray)
+ } else {
+ panic(fmt.Errorf("expected []any, got %#v", new))
+ }
+ case string:
+ if newString, ok := new.(string); ok {
+ if oldTyped != newString {
+ panic(fmt.Errorf("strings %q and %q don't match", oldTyped, newString))
+ }
+ return oldTyped
+ } else {
+ panic(fmt.Errorf("expected []any, got %#v", new))
+ }
+ default:
+ panic(fmt.Errorf("can't combine type %T", old))
+ }
+}
+
+func combineObjects(old, new map[string]any) map[string]any {
+ for k, newField := range new {
+ // HACK: Don't merge "test_config" field. This matches the behavior in base_rules.mk that overwrites
+ // instead of appending ALL_MODULES.$(my_register_name).TEST_CONFIG, keeping the
+ if k == "test_config" {
+ old[k] = newField
+ continue
+ }
+ if oldField, exists := old[k]; exists {
+ oldField = combine(oldField, newField)
+ old[k] = oldField
+ } else {
+ old[k] = newField
+ }
+ }
+
+ return old
+}
+
+func combineArrays(old, new []any) []any {
+ containsNonStrings := false
+ for _, oldElement := range old {
+ switch oldElement.(type) {
+ case string:
+ default:
+ containsNonStrings = true
+ }
+ }
+ for _, newElement := range new {
+ found := false
+ for _, oldElement := range old {
+ if oldElement == newElement {
+ found = true
+ break
+ }
+ }
+ if !found {
+ switch newElement.(type) {
+ case string:
+ default:
+ containsNonStrings = true
+ }
+ old = append(old, newElement)
+ }
+ }
+ if !containsNonStrings {
+ slices.SortFunc(old, func(a, b any) int {
+ return cmp.Compare(a.(string), b.(string))
+ })
+ }
+ return old
+}
diff --git a/cmd/merge_module_info_json/merge_module_info_json_test.go b/cmd/merge_module_info_json/merge_module_info_json_test.go
new file mode 100644
index 0000000..dbf1aa1
--- /dev/null
+++ b/cmd/merge_module_info_json/merge_module_info_json_test.go
@@ -0,0 +1,58 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+ "reflect"
+ "testing"
+)
+
+func Test_combine(t *testing.T) {
+ tests := []struct {
+ name string
+ old any
+ new any
+ want any
+ }{
+ {
+ name: "objects",
+ old: map[string]any{
+ "foo": "bar",
+ "baz": []any{"a"},
+ },
+ new: map[string]any{
+ "foo": "bar",
+ "baz": []any{"b"},
+ },
+ want: map[string]any{
+ "foo": "bar",
+ "baz": []any{"a", "b"},
+ },
+ },
+ {
+ name: "arrays",
+ old: []any{"foo", "bar"},
+ new: []any{"foo", "baz"},
+ want: []any{"bar", "baz", "foo"},
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := combine(tt.old, tt.new); !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("combine() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index 3364f50..e69a930 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -22,6 +22,7 @@
"flag"
"fmt"
"io"
+ "io/fs"
"io/ioutil"
"os"
"os/exec"
@@ -478,7 +479,8 @@
// copyOneFile copies a file and its permissions. If forceExecutable is true it adds u+x to the
// permissions. If exists is allowFromNotExists it returns nil if the from path doesn't exist.
// If write is onlyWriteIfChanged then the output file is compared to the input file and not written to
-// if it is the same, avoiding updating the timestamp.
+// if it is the same, avoiding updating the timestamp. If from is a symlink, the symlink itself
+// will be copied, instead of what it points to.
func copyOneFile(from string, to string, forceExecutable bool, exists existsType,
write writeType) error {
err := os.MkdirAll(filepath.Dir(to), 0777)
@@ -486,7 +488,7 @@
return err
}
- stat, err := os.Stat(from)
+ stat, err := os.Lstat(from)
if err != nil {
if os.IsNotExist(err) && exists == allowFromNotExists {
return nil
@@ -494,6 +496,25 @@
return err
}
+ if stat.Mode()&fs.ModeSymlink != 0 {
+ linkTarget, err := os.Readlink(from)
+ if err != nil {
+ return err
+ }
+ if write == onlyWriteIfChanged {
+ toLinkTarget, err := os.Readlink(to)
+ if err == nil && toLinkTarget == linkTarget {
+ return nil
+ }
+ }
+ err = os.Remove(to)
+ if err != nil && !os.IsNotExist(err) {
+ return err
+ }
+
+ return os.Symlink(linkTarget, to)
+ }
+
perm := stat.Mode()
if forceExecutable {
perm = perm | 0100 // u+x
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 7742492..4727566 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -28,6 +28,7 @@
"android/soong/android/allowlists"
"android/soong/bp2build"
"android/soong/shared"
+
"github.com/google/blueprint"
"github.com/google/blueprint/bootstrap"
"github.com/google/blueprint/deptools"
@@ -196,7 +197,7 @@
ctx.Context.PrintJSONGraphAndActions(graphFile, actionsFile)
}
-func writeBuildGlobsNinjaFile(ctx *android.Context) []string {
+func writeBuildGlobsNinjaFile(ctx *android.Context) {
ctx.EventHandler.Begin("globs_ninja_file")
defer ctx.EventHandler.End("globs_ninja_file")
@@ -208,7 +209,6 @@
SrcDir: ctx.SrcDir(),
}, ctx.Config())
maybeQuit(err, "")
- return bootstrap.GlobFileListFiles(globDir)
}
func writeDepFile(outputFile string, eventHandler *metrics.EventHandler, ninjaDeps []string) {
@@ -238,8 +238,7 @@
maybeQuit(err, "")
ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
- globListFiles := writeBuildGlobsNinjaFile(ctx)
- ninjaDeps = append(ninjaDeps, globListFiles...)
+ writeBuildGlobsNinjaFile(ctx)
// Convert the Soong module graph into Bazel BUILD files.
switch ctx.Config().BuildMode {
diff --git a/docs/map_files.md b/docs/map_files.md
index 35e8cbb..37f91ec 100644
--- a/docs/map_files.md
+++ b/docs/map_files.md
@@ -134,6 +134,9 @@
Historically this annotation was spelled `vndk`, but it has always meant LL-NDK.
+When an llndk API is deprecated, the `llndk` tag is dropped and
+`llndk-deprecate=<V>` is added.
+
### platform-only
Indicates that the version or symbol is public in the implementation library but
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
index 8abf73e..cbefa45 100644
--- a/genrule/allowlists.go
+++ b/genrule/allowlists.go
@@ -23,10 +23,7 @@
SandboxingDenyModuleList = []string{
// go/keep-sorted start
- "CtsApkVerityTestDebugFiles",
"aidl_camera_build_version",
- "camera-its",
- "chre_atoms_log.h",
// go/keep-sorted end
}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 0512c15..87f6392 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -393,7 +393,7 @@
return srcFiles
}
srcFiles := addLabelsForInputs("srcs", g.properties.Srcs, g.properties.Exclude_srcs)
- ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcFiles.Strings()})
+ android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcFiles.Strings()})
var copyFrom android.Paths
var outputFiles android.WritablePaths
diff --git a/java/aar.go b/java/aar.go
index af99cd0..2ad8fdf 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -805,7 +805,8 @@
},
)
- a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+ a.hideApexVariantFromMake = !apexInfo.IsForPlatform()
a.stem = proptools.StringDefault(a.overridableDeviceProperties.Stem, ctx.ModuleName())
@@ -825,7 +826,7 @@
a.linter.resources = a.aapt.resourceFiles
proguardSpecInfo := a.collectProguardSpecInfo(ctx)
- ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
+ android.SetProvider(ctx, ProguardSpecInfoProvider, proguardSpecInfo)
exportedProguardFlagsFiles := proguardSpecInfo.ProguardFlagsFiles.ToList()
a.extraProguardFlagsFiles = append(a.extraProguardFlagsFiles, exportedProguardFlagsFiles...)
a.extraProguardFlagsFiles = append(a.extraProguardFlagsFiles, a.proguardOptionsFile)
@@ -860,12 +861,12 @@
prebuiltJniPackages := android.Paths{}
ctx.VisitDirectDeps(func(module android.Module) {
- if info, ok := ctx.OtherModuleProvider(module, JniPackageProvider).(JniPackageInfo); ok {
+ if info, ok := android.OtherModuleProvider(ctx, module, JniPackageProvider); ok {
prebuiltJniPackages = append(prebuiltJniPackages, info.JniPackages...)
}
})
if len(prebuiltJniPackages) > 0 {
- ctx.SetProvider(JniPackageProvider, JniPackageInfo{
+ android.SetProvider(ctx, JniPackageProvider, JniPackageInfo{
JniPackages: prebuiltJniPackages,
})
}
@@ -1069,7 +1070,7 @@
JniPackages android.Paths
}
-var JniPackageProvider = blueprint.NewProvider(JniPackageInfo{})
+var JniPackageProvider = blueprint.NewProvider[JniPackageInfo]()
// Unzip an AAR and extract the JNI libs for $archString.
var extractJNI = pctx.AndroidStaticRule("extractJNI",
@@ -1106,7 +1107,8 @@
a.sdkVersion = a.SdkVersion(ctx)
a.minSdkVersion = a.MinSdkVersion(ctx)
- a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+ a.hideApexVariantFromMake = !apexInfo.IsForPlatform()
aarName := ctx.ModuleName() + ".aar"
a.aarPath = android.PathForModuleSrc(ctx, a.properties.Aars[0])
@@ -1123,7 +1125,7 @@
aarRTxt := extractedAARDir.Join(ctx, "R.txt")
a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip")
a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
- ctx.SetProvider(ProguardSpecInfoProvider, ProguardSpecInfo{
+ android.SetProvider(ctx, ProguardSpecInfoProvider, ProguardSpecInfo{
ProguardFlagsFiles: android.NewDepSet[android.Path](
android.POSTORDER,
android.Paths{a.proguardFlags},
@@ -1228,7 +1230,7 @@
a.transitiveAaptResourcePackagesFile = transitiveAaptResourcePackagesFile
a.collectTransitiveHeaderJars(ctx)
- ctx.SetProvider(JavaInfoProvider, JavaInfo{
+ android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
HeaderJars: android.PathsIfNonNil(a.classpathFile),
TransitiveLibsHeaderJars: a.transitiveLibsHeaderJars,
TransitiveStaticLibsHeaderJars: a.transitiveStaticLibsHeaderJars,
@@ -1256,11 +1258,11 @@
},
})
}
-
- ctx.SetProvider(JniPackageProvider, JniPackageInfo{
- JniPackages: a.jniPackages,
- })
}
+
+ android.SetProvider(ctx, JniPackageProvider, JniPackageInfo{
+ JniPackages: a.jniPackages,
+ })
}
func (a *AARImport) HeaderJars() android.Paths {
diff --git a/java/aar_test.go b/java/aar_test.go
index 8afa039..4d4e5d0 100644
--- a/java/aar_test.go
+++ b/java/aar_test.go
@@ -52,7 +52,7 @@
appMod := ctx.Module(tc.name, "android_common")
appTestMod := ctx.ModuleForTests(tc.name, "android_common")
- info, ok := ctx.ModuleProvider(appMod, JniPackageProvider).(JniPackageInfo)
+ info, ok := android.SingletonModuleProvider(ctx, appMod, JniPackageProvider)
if !ok {
t.Errorf("expected android_library_import to have JniPackageProvider")
}
diff --git a/java/androidmk.go b/java/androidmk.go
index a3f94cd..cbf9abb 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -19,6 +19,7 @@
"io"
"strings"
+ "android/soong/aconfig"
"android/soong/android"
"github.com/google/blueprint/proptools"
@@ -128,9 +129,7 @@
if library.dexpreopter.configPath != nil {
entries.SetPath("LOCAL_SOONG_DEXPREOPT_CONFIG", library.dexpreopter.configPath)
}
- // TODO(b/311155208): The container here should be system.
-
- entries.SetPaths("LOCAL_ACONFIG_FILES", library.mergedAconfigFiles[""])
+ aconfig.SetAconfigFileMkEntries(&library.ModuleBase, entries, library.mergedAconfigFiles)
},
},
})
@@ -208,11 +207,7 @@
func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries {
if prebuilt.hideApexVariantFromMake {
- // For a library imported from a prebuilt APEX, we don't need a Make module for itself, as we
- // don't need to install it. However, we need to add its dexpreopt outputs as sub-modules, if it
- // is preopted.
- dexpreoptEntries := prebuilt.dexpreopter.AndroidMkEntriesForApex()
- return append(dexpreoptEntries, android.AndroidMkEntries{Disabled: true})
+ return []android.AndroidMkEntries{}
}
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
@@ -307,8 +302,7 @@
if len(binary.dexpreopter.builtInstalled) > 0 {
entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", binary.dexpreopter.builtInstalled)
}
- // TODO(b/311155208): The container here should be system.
- entries.SetPaths("LOCAL_ACONFIG_FILES", binary.mergedAconfigFiles[""])
+ aconfig.SetAconfigFileMkEntries(&binary.ModuleBase, entries, binary.mergedAconfigFiles)
},
},
ExtraFooters: []android.AndroidMkExtraFootersFunc{
@@ -461,8 +455,7 @@
entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", app.linter.reports)
if app.Name() != "framework-res" {
- // TODO(b/311155208): The container here should be system.
- entries.SetPaths("LOCAL_ACONFIG_FILES", app.mergedAconfigFiles[""])
+ aconfig.SetAconfigFileMkEntries(&app.ModuleBase, entries, app.mergedAconfigFiles)
}
},
},
@@ -540,8 +533,7 @@
entries.SetPath("LOCAL_FULL_MANIFEST_FILE", a.mergedManifestFile)
entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", a.combinedExportedProguardFlagsFile)
entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", true)
- // TODO(b/311155208): The container here should be system.
- entries.SetPaths("LOCAL_ACONFIG_FILES", a.mergedAconfigFiles[""])
+ aconfig.SetAconfigFileMkEntries(&a.ModuleBase, entries, a.mergedAconfigFiles)
})
return entriesList
diff --git a/java/app.go b/java/app.go
index d5c4eba..8b28dac 100755
--- a/java/app.go
+++ b/java/app.go
@@ -22,7 +22,6 @@
"path/filepath"
"strings"
- "android/soong/aconfig"
"android/soong/testing"
"github.com/google/blueprint"
@@ -139,12 +138,6 @@
// PRODUCT_CHARACTERISTICS.
Generate_product_characteristics_rro *bool
- // A list of files or dependencies to make available to the build sandbox. This is
- // useful if source files are symlinks, the targets of the symlinks must be listed here.
- // Note that currently not all actions implemented by android_apps are sandboxed, so you
- // may only see this being necessary in lint builds.
- Compile_data []string
-
ProductCharacteristicsRROPackageName *string `blueprint:"mutated"`
ProductCharacteristicsRROManifestModuleName *string `blueprint:"mutated"`
}
@@ -417,7 +410,7 @@
ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.MinSdkVersion(ctx), err)
}
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
return (minSdkVersion.FinalOrFutureInt() >= 23 && Bool(a.appProperties.Use_embedded_native_libs)) ||
!apexInfo.IsForPlatform()
}
@@ -442,7 +435,7 @@
}
func (a *AndroidApp) shouldEmbedJnis(ctx android.BaseModuleContext) bool {
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
return ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs) ||
!apexInfo.IsForPlatform() || a.appProperties.AlwaysPackageNativeLibs
}
@@ -515,7 +508,7 @@
var aconfigTextFilePaths android.Paths
ctx.VisitDirectDepsWithTag(aconfigDeclarationTag, func(dep android.Module) {
- if provider, ok := ctx.OtherModuleProvider(dep, aconfig.DeclarationsProviderKey).(aconfig.DeclarationsProviderData); ok {
+ if provider, ok := android.OtherModuleProvider(ctx, dep, android.AconfigDeclarationsProviderKey); ok {
aconfigTextFilePaths = append(aconfigTextFilePaths, provider.IntermediateDumpOutputPath)
} else {
ctx.ModuleErrorf("Only aconfig_declarations module type is allowed for "+
@@ -543,7 +536,7 @@
func (a *AndroidApp) proguardBuildActions(ctx android.ModuleContext) {
var staticLibProguardFlagFiles android.Paths
ctx.VisitDirectDeps(func(m android.Module) {
- depProguardInfo := ctx.OtherModuleProvider(m, ProguardSpecInfoProvider).(ProguardSpecInfo)
+ depProguardInfo, _ := android.OtherModuleProvider(ctx, m, ProguardSpecInfoProvider)
staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, depProguardInfo.UnconditionallyExportedProguardFlags.ToList()...)
if ctx.OtherModuleDependencyTag(m) == staticLibTag {
staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, depProguardInfo.ProguardFlagsFiles.ToList()...)
@@ -751,7 +744,8 @@
func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
var apkDeps android.Paths
- if !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() {
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+ if !apexInfo.IsForPlatform() {
a.hideApexVariantFromMake = true
}
@@ -824,7 +818,6 @@
a.linter.mergedManifest = a.aapt.mergedManifestFile
a.linter.manifest = a.aapt.manifestPath
a.linter.resources = a.aapt.resourceFiles
- a.linter.compile_data = android.PathsForModuleSrc(ctx, a.appProperties.Compile_data)
a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps()
dexJarFile, packageResources := a.dexBuildActions(ctx)
@@ -897,8 +890,6 @@
a.privAppAllowlist = android.OptionalPathForPath(allowlist)
}
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
-
// Install the app package.
shouldInstallAppPackage := (Bool(a.Module.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() && !a.appProperties.PreventInstall
if shouldInstallAppPackage {
@@ -982,7 +973,7 @@
return shouldCollectRecursiveNativeDeps
}
- if info, ok := ctx.OtherModuleProvider(module, JniPackageProvider).(JniPackageInfo); ok {
+ if info, ok := android.OtherModuleProvider(ctx, module, JniPackageProvider); ok {
prebuiltJniPackages = append(prebuiltJniPackages, info.JniPackages...)
}
@@ -1302,7 +1293,7 @@
a.testConfig = a.FixTestConfig(ctx, testConfig)
a.extraTestConfigs = android.PathsForModuleSrc(ctx, a.testProperties.Test_options.Extra_test_configs)
a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
- ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+ android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
}
func (a *AndroidTest) FixTestConfig(ctx android.ModuleContext, testConfig android.Path) android.Path {
diff --git a/java/app_import.go b/java/app_import.go
index c5d09fd..ff0f5fe 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -257,7 +257,7 @@
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.")
}
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
if !apexInfo.IsForPlatform() {
a.hideApexVariantFromMake = true
}
diff --git a/java/app_import_test.go b/java/app_import_test.go
index 8f29bb3..ef4626e 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -40,8 +40,8 @@
variant := ctx.ModuleForTests("foo", "android_common")
// Check dexpreopt outputs.
- if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
- variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
+ if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule == nil ||
+ variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule == nil {
t.Errorf("can't find dexpreopt outputs")
}
@@ -74,8 +74,8 @@
variant := ctx.ModuleForTests("foo", "android_common")
// Check dexpreopt outputs. They shouldn't exist.
- if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule != nil ||
- variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule != nil {
+ if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule != nil ||
+ variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule != nil {
t.Errorf("dexpreopt shouldn't have run.")
}
@@ -101,8 +101,8 @@
variant := ctx.ModuleForTests("foo", "android_common")
// Check dexpreopt outputs.
- if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
- variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
+ if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule == nil ||
+ variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule == nil {
t.Errorf("can't find dexpreopt outputs")
}
// Make sure signing was skipped and aligning was done.
@@ -210,8 +210,8 @@
variant := ctx.ModuleForTests("foo", "android_common")
// Check dexpreopt outputs.
- if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
- variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
+ if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule == nil ||
+ variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule == nil {
t.Errorf("can't find dexpreopt outputs")
}
diff --git a/java/app_test.go b/java/app_test.go
index 0936b28..3ee94d5 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -2109,7 +2109,7 @@
Output("libjni.so").Output.String()
sdkJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared").
Output("libjni.so").Output.String()
- vendorJNI := ctx.ModuleForTests("libvendorjni", "android_arm64_armv8-a_shared").
+ vendorJNI := ctx.ModuleForTests("libvendorjni", "android_vendor_arm64_armv8-a_shared").
Output("libvendorjni.so").Output.String()
for _, test := range testCases {
@@ -3357,7 +3357,7 @@
cmd := app.Rule("dexpreopt").RuleParams.Command
android.AssertStringDoesContain(t, "dexpreopt app cmd context", cmd, "--context-json=")
android.AssertStringDoesContain(t, "dexpreopt app cmd product_packages", cmd,
- "--product-packages=out/soong/.intermediates/app/android_common/dexpreopt/product_packages.txt")
+ "--product-packages=out/soong/.intermediates/app/android_common/dexpreopt/app/product_packages.txt")
}
func TestDexpreoptBcp(t *testing.T) {
diff --git a/java/base.go b/java/base.go
index cdb58a2..51471ea 100644
--- a/java/base.go
+++ b/java/base.go
@@ -24,7 +24,6 @@
"github.com/google/blueprint/pathtools"
"github.com/google/blueprint/proptools"
- "android/soong/aconfig"
"android/soong/android"
"android/soong/dexpreopt"
"android/soong/java/config"
@@ -195,6 +194,12 @@
// If true, then only the headers are built and not the implementation jar.
Headers_only *bool
+
+ // A list of files or dependencies to make available to the build sandbox. This is
+ // useful if source files are symlinks, the targets of the symlinks must be listed here.
+ // Note that currently not all actions implemented by android_apps are sandboxed, so you
+ // may only see this being necessary in lint builds.
+ Compile_data []string `android:"path"`
}
// Properties that are specific to device modules. Host module factories should not add these when
@@ -612,7 +617,7 @@
// Populate with package rules from the properties.
hiddenAPIInfo.extractPackageRulesFromProperties(&j.deviceProperties.HiddenAPIPackageProperties)
- ctx.SetProvider(hiddenAPIPropertyInfoProvider, hiddenAPIInfo)
+ android.SetProvider(ctx, hiddenAPIPropertyInfoProvider, hiddenAPIInfo)
}
func (j *Module) OutputFiles(tag string) (android.Paths, error) {
@@ -679,7 +684,7 @@
// Force enable the instrumentation for java code that is built for APEXes ...
// except for the jacocoagent itself (because instrumenting jacocoagent using jacocoagent
// doesn't make sense) or framework libraries (e.g. libraries found in the InstrumentFrameworkModules list) unless EMMA_INSTRUMENT_FRAMEWORK is true.
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
isJacocoAgent := ctx.ModuleName() == "jacocoagent"
if j.DirectlyInAnyApex() && !isJacocoAgent && !apexInfo.IsForPlatform() {
if !inList(ctx.ModuleName(), config.InstrumentFrameworkModules) {
@@ -1137,7 +1142,7 @@
uniqueSrcFiles = append(uniqueSrcFiles, uniqueJavaFiles...)
uniqueSrcFiles = append(uniqueSrcFiles, uniqueKtFiles...)
j.uniqueSrcFiles = uniqueSrcFiles
- ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: uniqueSrcFiles.Strings()})
+ android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: uniqueSrcFiles.Strings()})
// We don't currently run annotation processors in turbine, which means we can't use turbine
// generated header jars when an annotation processor that generates API is enabled. One
@@ -1172,7 +1177,7 @@
return
}
- ctx.SetProvider(JavaInfoProvider, JavaInfo{
+ android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
HeaderJars: android.PathsIfNonNil(j.headerJarFile),
TransitiveLibsHeaderJars: j.transitiveLibsHeaderJars,
TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
@@ -1566,7 +1571,7 @@
// Enable dex compilation for the APEX variants, unless it is disabled explicitly
compileDex := j.dexProperties.Compile_dex
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
if j.DirectlyInAnyApex() && !apexInfo.IsForPlatform() {
if compileDex == nil {
compileDex = proptools.BoolPtr(true)
@@ -1639,30 +1644,11 @@
}
if ctx.Device() {
- lintSDKVersion := func(apiLevel android.ApiLevel) int {
+ lintSDKVersion := func(apiLevel android.ApiLevel) android.ApiLevel {
if !apiLevel.IsPreview() {
- return apiLevel.FinalInt()
+ return apiLevel
} else {
- // When running metalava, we pass --version-codename. When that value
- // is not REL, metalava will add 1 to the --current-version argument.
- // On old branches, PLATFORM_SDK_VERSION is the latest version (for that
- // branch) and the codename is REL, except potentially on the most
- // recent non-master branch. On that branch, it goes through two other
- // phases before it gets to the phase previously described:
- // - PLATFORM_SDK_VERSION has not been updated yet, and the codename
- // is not rel. This happens for most of the internal branch's life
- // while the branch has been cut but is still under active development.
- // - PLATFORM_SDK_VERSION has been set, but the codename is still not
- // REL. This happens briefly during the release process. During this
- // state the code to add --current-version is commented out, and then
- // that commenting out is reverted after the codename is set to REL.
- // On the master branch, the PLATFORM_SDK_VERSION always represents a
- // prior version and the codename is always non-REL.
- //
- // We need to add one here to match metalava adding 1. Technically
- // this means that in the state described in the second bullet point
- // above, this number is 1 higher than it should be.
- return ctx.Config().PlatformSdkVersion().FinalInt() + 1
+ return ctx.Config().DefaultAppTargetSdk(ctx)
}
}
@@ -1677,6 +1663,7 @@
j.linter.compileSdkKind = j.SdkVersion(ctx).Kind
j.linter.javaLanguageLevel = flags.javaVersion.String()
j.linter.kotlinLanguageLevel = "1.3"
+ j.linter.compile_data = android.PathsForModuleSrc(ctx, j.properties.Compile_data)
if !apexInfo.IsForPlatform() && ctx.Config().UnbundledBuildApps() {
j.linter.buildModuleReportZip = true
}
@@ -1687,9 +1674,9 @@
ctx.CheckbuildFile(outputFile)
- aconfig.CollectDependencyAconfigFiles(ctx, &j.mergedAconfigFiles)
+ android.CollectDependencyAconfigFiles(ctx, &j.mergedAconfigFiles)
- ctx.SetProvider(JavaInfoProvider, JavaInfo{
+ android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
HeaderJars: android.PathsIfNonNil(j.headerJarFile),
TransitiveLibsHeaderJars: j.transitiveLibsHeaderJars,
TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
@@ -1719,7 +1706,7 @@
transitiveProguardFlags := []*android.DepSet[android.Path]{}
ctx.VisitDirectDeps(func(m android.Module) {
- depProguardInfo := ctx.OtherModuleProvider(m, ProguardSpecInfoProvider).(ProguardSpecInfo)
+ depProguardInfo, _ := android.OtherModuleProvider(ctx, m, ProguardSpecInfoProvider)
depTag := ctx.OtherModuleDependencyTag(m)
if depProguardInfo.UnconditionallyExportedProguardFlags != nil {
@@ -1905,7 +1892,7 @@
return
}
- dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+ dep, _ := android.OtherModuleProvider(ctx, module, JavaInfoProvider)
tag := ctx.OtherModuleDependencyTag(module)
_, isUsesLibDep := tag.(usesLibraryDependencyTag)
if tag == libTag || tag == r8LibraryJarTag || isUsesLibDep {
@@ -2030,7 +2017,7 @@
ctx.VisitDirectDeps(func(module android.Module) {
tag := ctx.OtherModuleDependencyTag(module)
if tag == staticLibTag {
- depInfo := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+ depInfo, _ := android.OtherModuleProvider(ctx, module, JavaInfoProvider)
if depInfo.TransitiveSrcFiles != nil {
fromDeps = append(fromDeps, depInfo.TransitiveSrcFiles)
}
@@ -2202,15 +2189,14 @@
case staticLibTag:
ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
}
- } else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
- dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
- if sdkLinkType != javaPlatform &&
- ctx.OtherModuleHasProvider(module, SyspropPublicStubInfoProvider) {
- // dep is a sysprop implementation library, but this module is not linking against
- // the platform, so it gets the sysprop public stubs library instead. Replace
- // dep with the JavaInfo from the SyspropPublicStubInfoProvider.
- syspropDep := ctx.OtherModuleProvider(module, SyspropPublicStubInfoProvider).(SyspropPublicStubInfo)
- dep = syspropDep.JavaInfo
+ } else if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
+ if sdkLinkType != javaPlatform {
+ if syspropDep, ok := android.OtherModuleProvider(ctx, module, SyspropPublicStubInfoProvider); ok {
+ // dep is a sysprop implementation library, but this module is not linking against
+ // the platform, so it gets the sysprop public stubs library instead. Replace
+ // dep with the JavaInfo from the SyspropPublicStubInfoProvider.
+ dep = syspropDep.JavaInfo
+ }
}
switch tag {
case bootClasspathTag:
@@ -2282,7 +2268,7 @@
case syspropPublicStubDepTag:
// This is a sysprop implementation library, forward the JavaInfoProvider from
// the corresponding sysprop public stub library as SyspropPublicStubInfoProvider.
- ctx.SetProvider(SyspropPublicStubInfoProvider, SyspropPublicStubInfo{
+ android.SetProvider(ctx, SyspropPublicStubInfoProvider, SyspropPublicStubInfo{
JavaInfo: dep,
})
}
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 191a65e..ae24404 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -240,7 +240,8 @@
sourceOnlyProperties SourceOnlyBootclasspathProperties
// Path to the boot image profile.
- profilePath android.WritablePath
+ profilePath android.WritablePath
+ profilePathErr error
}
// commonBootclasspathFragment defines the methods that are implemented by both source and prebuilt
@@ -352,7 +353,7 @@
}
}
-var BootclasspathFragmentApexContentInfoProvider = blueprint.NewProvider(BootclasspathFragmentApexContentInfo{})
+var BootclasspathFragmentApexContentInfoProvider = blueprint.NewProvider[BootclasspathFragmentApexContentInfo]()
// BootclasspathFragmentApexContentInfo contains the bootclasspath_fragments contributions to the
// apex contents.
@@ -384,6 +385,10 @@
}
}
+func (i BootclasspathFragmentApexContentInfo) DexBootJarPathMap() bootDexJarByModule {
+ return i.contentModuleDexJarPaths
+}
+
func (i BootclasspathFragmentApexContentInfo) ProfilePathOnHost() android.Path {
return i.profilePathOnHost
}
@@ -500,7 +505,7 @@
if ctx.Module() != ctx.FinalModule() {
b.HideFromMake()
}
- ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+ android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
}
// getProfileProviderApex returns the name of the apex that provides a boot image profile, or an
@@ -512,7 +517,7 @@
}
// Bootclasspath fragment modules that are for the platform do not produce boot related files.
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
for _, apex := range apexInfo.InApexVariants {
if isProfileProviderApex(ctx, apex) {
return apex
@@ -533,11 +538,11 @@
if profile != nil {
info.profilePathOnHost = profile
- info.profileInstallPathInApex = profileInstallPathInApex
+ info.profileInstallPathInApex = ProfileInstallPathInApex
}
// Make the apex content info available for other modules.
- ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, info)
+ android.SetProvider(ctx, BootclasspathFragmentApexContentInfoProvider, info)
}
// generateClasspathProtoBuildActions generates all required build actions for classpath.proto config
@@ -623,7 +628,7 @@
hiddenAPIInfo.HiddenAPIFlagOutput = output.HiddenAPIFlagOutput
// Provide it for use by other modules.
- ctx.SetProvider(HiddenAPIInfoProvider, hiddenAPIInfo)
+ android.SetProvider(ctx, HiddenAPIInfoProvider, hiddenAPIInfo)
return output
}
@@ -744,7 +749,7 @@
}
// Make the information available for the sdk snapshot.
- ctx.SetProvider(HiddenAPIInfoForSdkProvider, HiddenAPIInfoForSdk{
+ android.SetProvider(ctx, HiddenAPIInfoForSdkProvider, HiddenAPIInfoForSdk{
FlagFilesByCategory: flagFilesByCategory,
HiddenAPIFlagOutput: flagOutput,
})
@@ -876,7 +881,7 @@
// Get the hidden API information from the module.
mctx := ctx.SdkModuleContext()
- hiddenAPIInfo := mctx.OtherModuleProvider(module, HiddenAPIInfoForSdkProvider).(HiddenAPIInfoForSdk)
+ hiddenAPIInfo, _ := android.OtherModuleProvider(mctx, module, HiddenAPIInfoForSdkProvider)
b.Flag_files_by_category = hiddenAPIInfo.FlagFilesByCategory
// Copy all the generated file paths.
@@ -1033,10 +1038,6 @@
return android.PathForModuleSrc(ctx, *src)
}
- // Retrieve the dex files directly from the content modules. They in turn should retrieve the
- // encoded dex jars from the prebuilt .apex files.
- encodedBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, contents)
-
output := HiddenAPIOutput{
HiddenAPIFlagOutput: HiddenAPIFlagOutput{
AnnotationFlagsPath: pathForSrc("hidden_api.annotation_flags", module.prebuiltProperties.Hidden_api.Annotation_flags),
@@ -1047,8 +1048,6 @@
StubFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Stub_flags, nil),
AllFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.All_flags, nil),
},
-
- EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
}
// TODO: Temporarily fallback to stub_flags/all_flags properties until prebuilts have been updated.
@@ -1065,15 +1064,21 @@
return nil
}
- di := android.FindDeapexerProviderForModule(ctx)
- if di == nil {
+ di, err := android.FindDeapexerProviderForModule(ctx)
+ if err != nil {
+ // An error was found, possibly due to multiple apexes in the tree that export this library
+ // Defer the error till a client tries to call getProfilePath
+ module.profilePathErr = err
return nil // An error has been reported by FindDeapexerProviderForModule.
}
- return di.PrebuiltExportPath(profileInstallPathInApex)
+ return di.PrebuiltExportPath(ProfileInstallPathInApex)
}
func (b *PrebuiltBootclasspathFragmentModule) getProfilePath() android.Path {
+ if b.profilePathErr != nil {
+ panic(b.profilePathErr.Error())
+ }
return b.profilePath
}
@@ -1087,7 +1092,7 @@
func (module *PrebuiltBootclasspathFragmentModule) RequiredFilesFromPrebuiltApex(ctx android.BaseModuleContext) []string {
for _, apex := range module.ApexProperties.Apex_available {
if isProfileProviderApex(ctx, apex) {
- return []string{profileInstallPathInApex}
+ return []string{ProfileInstallPathInApex}
}
}
return nil
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index 828de21..216c3b3 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -272,7 +272,7 @@
`)
fragment := result.Module("myfragment", "android_common")
- info := result.ModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
+ info, _ := android.SingletonModuleProvider(result, fragment, HiddenAPIInfoProvider)
stubsJar := "out/soong/.intermediates/mystublib/android_common/dex/mystublib.jar"
@@ -456,7 +456,7 @@
// Make sure that the library exports hidden API properties for use by the bootclasspath_fragment.
library := result.Module("mynewlibrary", "android_common")
- info := result.ModuleProvider(library, hiddenAPIPropertyInfoProvider).(HiddenAPIPropertyInfo)
+ info, _ := android.SingletonModuleProvider(result, library, hiddenAPIPropertyInfoProvider)
android.AssertArrayString(t, "split packages", []string{"sdklibrary", "newlibrary"}, info.SplitPackages)
android.AssertArrayString(t, "package prefixes", []string{"newlibrary.all.mine"}, info.PackagePrefixes)
android.AssertArrayString(t, "single packages", []string{"newlibrary.mine"}, info.SinglePackages)
diff --git a/java/classpath_element.go b/java/classpath_element.go
index 4962916..abbcae7 100644
--- a/java/classpath_element.go
+++ b/java/classpath_element.go
@@ -21,7 +21,6 @@
"strings"
"android/soong/android"
- "github.com/google/blueprint"
)
// Supports constructing a list of ClasspathElement from a set of fragments and modules.
@@ -72,8 +71,7 @@
// ClasspathElementContext defines the context methods needed by CreateClasspathElements
type ClasspathElementContext interface {
- OtherModuleHasProvider(m blueprint.Module, provider blueprint.ProviderKey) bool
- OtherModuleProvider(m blueprint.Module, provider blueprint.ProviderKey) interface{}
+ android.OtherModuleProviderContext
ModuleErrorf(fmt string, args ...interface{})
}
@@ -123,12 +121,12 @@
// associated with a particular apex.
apexToFragment := map[string]android.Module{}
for _, fragment := range fragments {
- if !ctx.OtherModuleHasProvider(fragment, android.ApexInfoProvider) {
+ apexInfo, ok := android.OtherModuleProvider(ctx, fragment, android.ApexInfoProvider)
+ if !ok {
ctx.ModuleErrorf("fragment %s is not part of an apex", fragment)
continue
}
- apexInfo := ctx.OtherModuleProvider(fragment, android.ApexInfoProvider).(android.ApexInfo)
for _, apex := range apexInfo.InApexVariants {
if existing, ok := apexToFragment[apex]; ok {
ctx.ModuleErrorf("apex %s has multiple fragments, %s and %s", apex, fragment, existing)
@@ -146,8 +144,7 @@
// Iterate over the libraries to construct the ClasspathElements list.
for _, library := range libraries {
var element ClasspathElement
- if ctx.OtherModuleHasProvider(library, android.ApexInfoProvider) {
- apexInfo := ctx.OtherModuleProvider(library, android.ApexInfoProvider).(android.ApexInfo)
+ if apexInfo, ok := android.OtherModuleProvider(ctx, library, android.ApexInfoProvider); ok {
var fragment android.Module
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index bc9de50..2017801 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -178,7 +178,7 @@
ClasspathFragmentProtoInstallDir: c.installDirPath,
ClasspathFragmentProtoOutput: c.outputFilepath,
}
- ctx.SetProvider(ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo)
+ android.SetProvider(ctx, ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo)
}
func writeClasspathsTextproto(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
@@ -211,7 +211,7 @@
}}
}
-var ClasspathFragmentProtoContentInfoProvider = blueprint.NewProvider(ClasspathFragmentProtoContentInfo{})
+var ClasspathFragmentProtoContentInfoProvider = blueprint.NewProvider[ClasspathFragmentProtoContentInfo]()
type ClasspathFragmentProtoContentInfo struct {
// Whether the classpaths.proto config is generated for the fragment.
diff --git a/java/code_metadata_test.go b/java/code_metadata_test.go
index 4b05d9e..0ef348a 100644
--- a/java/code_metadata_test.go
+++ b/java/code_metadata_test.go
@@ -25,14 +25,10 @@
}`
result := runCodeMetadataTest(t, android.FixtureExpectsNoErrors, bp)
- module := result.ModuleForTests(
- "module-name", "",
- ).Module().(*soongTesting.CodeMetadataModule)
+ module := result.ModuleForTests("module-name", "")
// Check that the provider has the right contents
- data := result.ModuleProvider(
- module, soongTesting.CodeMetadataProviderKey,
- ).(soongTesting.CodeMetadataProviderData)
+ data, _ := android.SingletonModuleProvider(result, module.Module(), soongTesting.CodeMetadataProviderKey)
if !strings.HasSuffix(
data.IntermediatePath.String(), "/intermediateCodeMetadata.pb",
) {
@@ -42,13 +38,8 @@
)
}
- buildParamsSlice := module.BuildParamsForTests()
- var metadata = ""
- for _, params := range buildParamsSlice {
- if params.Rule.String() == "android/soong/android.writeFile" {
- metadata = params.Args["content"]
- }
- }
+ metadata := android.ContentFromFileRuleForTests(t, result.TestContext,
+ module.Output(data.IntermediatePath.String()))
metadataList := make([]*code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership, 0, 2)
teamId := "12345"
@@ -65,9 +56,7 @@
CodeMetadataMetadata := code_metadata_internal_proto.CodeMetadataInternal{TargetOwnershipList: metadataList}
protoData, _ := proto.Marshal(&CodeMetadataMetadata)
- rawData := string(protoData)
- formattedData := strings.ReplaceAll(rawData, "\n", "\\n")
- expectedMetadata := "'" + formattedData + "\\n'"
+ expectedMetadata := string(protoData)
if metadata != expectedMetadata {
t.Errorf(
@@ -114,7 +103,7 @@
}
}
func runCodeMetadataTest(
- t *testing.T, errorHandler android.FixtureErrorHandler, bp string,
+ t *testing.T, errorHandler android.FixtureErrorHandler, bp string,
) *android.TestResult {
return android.GroupFixturePreparers(
soongTesting.PrepareForTestWithTestingBuildComponents, prepareForJavaTest,
diff --git a/java/config/config.go b/java/config/config.go
index d80ed41..6a945ac 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -95,13 +95,11 @@
"-JXX:TieredStopAtLevel=1",
"-JDcom.android.tools.r8.emitRecordAnnotationsInDex",
"-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex",
- "-JDcom.android.tools.r8.emitRecordAnnotationsExInDex",
}, dexerJavaVmFlagsList...))
exportedVars.ExportStringListStaticVariable("R8Flags", append([]string{
"-JXmx4096M",
"-JDcom.android.tools.r8.emitRecordAnnotationsInDex",
"-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex",
- "-JDcom.android.tools.r8.emitRecordAnnotationsExInDex",
}, dexerJavaVmFlagsList...))
exportedVars.ExportStringListStaticVariable("CommonJdkFlags", []string{
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index ee8a15a..834651f 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -97,8 +97,7 @@
}
ctx.VisitDirectDepsWithTag(deviceHostConverterDepTag, func(m android.Module) {
- if ctx.OtherModuleHasProvider(m, JavaInfoProvider) {
- dep := ctx.OtherModuleProvider(m, JavaInfoProvider).(JavaInfo)
+ if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok {
d.headerJars = append(d.headerJars, dep.HeaderJars...)
d.implementationJars = append(d.implementationJars, dep.ImplementationJars...)
d.implementationAndResourceJars = append(d.implementationAndResourceJars, dep.ImplementationAndResourcesJars...)
@@ -131,7 +130,7 @@
d.combinedHeaderJar = d.headerJars[0]
}
- ctx.SetProvider(JavaInfoProvider, JavaInfo{
+ android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
HeaderJars: d.headerJars,
ImplementationAndResourcesJars: d.implementationAndResourceJars,
ImplementationJars: d.implementationJars,
diff --git a/java/dex.go b/java/dex.go
index 6f1c09d..fbb8418 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -223,6 +223,13 @@
if err != nil {
ctx.PropertyErrorf("min_sdk_version", "%s", err)
}
+ if effectiveVersion.FinalOrFutureInt() >= 35 {
+ // V is 35, but we have not bumped the SDK version yet, so check for both.
+ if ctx.Config().PlatformSdkVersion().FinalInt() >= 35 ||
+ ctx.Config().PlatformSdkCodename() == "VanillaIceCream" {
+ flags = append([]string{"-JDcom.android.tools.r8.dexContainerExperiment"}, flags...)
+ }
+ }
// If the specified SDK level is 10000, then configure the compiler to use the
// current platform SDK level and to compile the build as a platform build.
@@ -261,7 +268,7 @@
// See b/20667396
var proguardRaiseDeps classpath
ctx.VisitDirectDepsWithTag(proguardRaiseTag, func(m android.Module) {
- dep := ctx.OtherModuleProvider(m, JavaInfoProvider).(JavaInfo)
+ dep, _ := android.OtherModuleProvider(ctx, m, JavaInfoProvider)
proguardRaiseDeps = append(proguardRaiseDeps, dep.HeaderJars...)
})
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index fe8c5fb..bd3cce4 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -79,18 +79,25 @@
func (install dexpreopterInstall) ToMakeEntries() android.AndroidMkEntries {
return android.AndroidMkEntries{
Class: "ETC",
- SubName: install.SubModuleName(),
OutputFile: android.OptionalPathForPath(install.outputPathOnHost),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE", install.FullModuleName())
entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice)
entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false")
+ // Unset LOCAL_SOONG_INSTALLED_MODULE so that this does not default to the primary .apex file
+ // Without this, installation of the dexpreopt artifacts get skipped
+ entries.SetString("LOCAL_SOONG_INSTALLED_MODULE", "")
},
},
}
}
+type Dexpreopter struct {
+ dexpreopter
+}
+
type dexpreopter struct {
dexpreoptProperties DexpreoptProperties
importDexpreoptProperties ImportDexpreoptProperties
@@ -166,12 +173,12 @@
}
func isApexVariant(ctx android.BaseModuleContext) bool {
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
return !apexInfo.IsForPlatform()
}
func forPrebuiltApex(ctx android.BaseModuleContext) bool {
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
return apexInfo.ForPrebuiltApex
}
@@ -258,6 +265,17 @@
return defaultInstallPath
}
+// DexpreoptPrebuiltApexSystemServerJars generates the dexpreopt artifacts from a jar file that has been deapexed from a prebuilt apex
+func (d *Dexpreopter) DexpreoptPrebuiltApexSystemServerJars(ctx android.ModuleContext, libraryName string, di *android.DeapexerInfo) {
+ // A single prebuilt apex can have multiple apex system jars
+ // initialize the output path for this dex jar
+ dc := dexpreopt.GetGlobalConfig(ctx)
+ d.installPath = android.PathForModuleInPartitionInstall(ctx, "", strings.TrimPrefix(dexpreopt.GetSystemServerDexLocation(ctx, dc, libraryName), "/"))
+ // generate the rules for creating the .odex and .vdex files for this system server jar
+ dexJarFile := di.PrebuiltExportPath(ApexRootRelativePathToJavaLib(libraryName))
+ d.dexpreopt(ctx, dexJarFile)
+}
+
func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.WritablePath) {
global := dexpreopt.GetGlobalConfig(ctx)
@@ -346,11 +364,15 @@
d.dexpreoptProperties.Dex_preopt_result.Profile_guided = profileClassListing.Valid()
+ // A single apex can have multiple system server jars
+ // Use the dexJar to create a unique scope for each
+ dexJarStem := strings.TrimSuffix(dexJarFile.Base(), dexJarFile.Ext())
+
// Full dexpreopt config, used to create dexpreopt build rules.
dexpreoptConfig := &dexpreopt.ModuleConfig{
Name: moduleName(ctx),
DexLocation: dexLocation,
- BuildPath: android.PathForModuleOut(ctx, "dexpreopt", moduleName(ctx)+".jar").OutputPath,
+ BuildPath: android.PathForModuleOut(ctx, "dexpreopt", dexJarStem, moduleName(ctx)+".jar").OutputPath,
DexPath: dexJarFile,
ManifestPath: android.OptionalPathForPath(d.manifestFile),
UncompressedDex: d.uncompressedDex,
@@ -380,7 +402,7 @@
PresignedPrebuilt: d.isPresignedPrebuilt,
}
- d.configPath = android.PathForModuleOut(ctx, "dexpreopt", "dexpreopt.config")
+ d.configPath = android.PathForModuleOut(ctx, "dexpreopt", dexJarStem, "dexpreopt.config")
dexpreopt.WriteModuleConfig(ctx, dexpreoptConfig, d.configPath)
if d.dexpreoptDisabled(ctx) {
@@ -394,7 +416,7 @@
// dependencies to create a per-app list, and use `rsync --checksum` to prevent the file's mtime
// from being changed if the contents don't change. This avoids unnecessary dexpreopt reruns.
productPackages := android.PathForModuleInPartitionInstall(ctx, "", "product_packages.txt")
- appProductPackages := android.PathForModuleOut(ctx, "dexpreopt", "product_packages.txt")
+ appProductPackages := android.PathForModuleOut(ctx, "dexpreopt", dexJarStem, "product_packages.txt")
appProductPackagesStaging := appProductPackages.ReplaceExtension(ctx, "txt.tmp")
clcNames, _ := dexpreopt.ComputeClassLoaderContextDependencies(dexpreoptConfig.ClassLoaderContexts)
sort.Strings(clcNames) // The order needs to be deterministic.
@@ -416,7 +438,7 @@
Text("rsync --checksum").
Input(appProductPackagesStaging).
Output(appProductPackages)
- productPackagesRule.Restat().Build("product_packages", "dexpreopt product_packages")
+ productPackagesRule.Restat().Build("product_packages."+dexJarStem, "dexpreopt product_packages")
dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(
ctx, globalSoong, global, dexpreoptConfig, appProductPackages)
@@ -425,9 +447,11 @@
return
}
- dexpreoptRule.Build("dexpreopt", "dexpreopt")
+ dexpreoptRule.Build("dexpreopt"+"."+dexJarStem, "dexpreopt")
- isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx))
+ // The current ctx might be of a deapexer module created by a prebuilt apex
+ // Use the path of the dex file to determine the library name
+ isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(dexJarStem)
for _, install := range dexpreoptRule.Installs() {
// Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
@@ -452,7 +476,7 @@
// The installs will be handled by Make as sub-modules of the java library.
d.builtInstalledForApex = append(d.builtInstalledForApex, dexpreopterInstall{
name: arch + "-" + installBase,
- moduleName: moduleName(ctx),
+ moduleName: dexJarStem,
outputPathOnHost: install.From,
installDirOnDevice: installPath,
installFileOnDevice: installBase,
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 5fb36df..82cece3 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -21,6 +21,7 @@
"android/soong/android"
"android/soong/dexpreopt"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -224,8 +225,9 @@
}
var (
- dexpreoptBootJarDepTag = bootclasspathDependencyTag{name: "dexpreopt-boot-jar"}
- dexBootJarsFragmentsKey = android.NewOnceKey("dexBootJarsFragments")
+ dexpreoptBootJarDepTag = bootclasspathDependencyTag{name: "dexpreopt-boot-jar"}
+ dexBootJarsFragmentsKey = android.NewOnceKey("dexBootJarsFragments")
+ apexContributionsMetadataDepTag = dependencyTag{name: "all_apex_contributions"}
)
func init() {
@@ -502,6 +504,11 @@
dexpreoptConfigForMake android.WritablePath
}
+func (dbj *dexpreoptBootJars) DepsMutator(ctx android.BottomUpMutatorContext) {
+ // Create a dependency on all_apex_contributions to determine the selected mainline module
+ ctx.AddDependency(ctx.Module(), apexContributionsMetadataDepTag, "all_apex_contributions")
+}
+
func DexpreoptBootJarsMutator(ctx android.BottomUpMutatorContext) {
if _, ok := ctx.Module().(*dexpreoptBootJars); !ok {
return
@@ -520,6 +527,14 @@
}
// For accessing the boot jars.
addDependenciesOntoBootImageModules(ctx, config.modules, dexpreoptBootJarDepTag)
+ // Create a dependency on the apex selected using RELEASE_APEX_CONTRIBUTIONS_*
+ // TODO: b/308174306 - Remove the direct depedendency edge to the java_library (source/prebuilt) once all mainline modules
+ // have been flagged using RELEASE_APEX_CONTRIBUTIONS_*
+ apexes := []string{}
+ for i := 0; i < config.modules.Len(); i++ {
+ apexes = append(apexes, config.modules.Apex(i))
+ }
+ addDependenciesOntoSelectedBootImageApexes(ctx, android.FirstUniqueStrings(apexes)...)
}
if ctx.OtherModuleExists("platform-bootclasspath") {
@@ -532,6 +547,28 @@
}
}
+// Create a dependency from dex_bootjars to the specific apexes selected using all_apex_contributions
+// This dependency will be used to get the path to the deapexed dex boot jars and profile (via a provider)
+func addDependenciesOntoSelectedBootImageApexes(ctx android.BottomUpMutatorContext, apexes ...string) {
+ psi := android.PrebuiltSelectionInfoMap{}
+ ctx.VisitDirectDepsWithTag(apexContributionsMetadataDepTag, func(am android.Module) {
+ if info, exists := android.OtherModuleProvider(ctx, am, android.PrebuiltSelectionInfoProvider); exists {
+ psi = info
+ }
+ })
+ for _, apex := range apexes {
+ for _, selected := range psi.GetSelectedModulesForApiDomain(apex) {
+ // We need to add a dep on only the apex listed in `contents` of the selected apex_contributions module
+ // This is not available in a structured format in `apex_contributions`, so this hack adds a dep on all `contents`
+ // (some modules like art.module.public.api do not have an apex variation since it is a pure stub module that does not get installed)
+ apexVariationOfSelected := append(ctx.Target().Variations(), blueprint.Variation{Mutator: "apex", Variation: apex})
+ if ctx.OtherModuleDependencyVariantExists(apexVariationOfSelected, selected) {
+ ctx.AddFarVariationDependencies(apexVariationOfSelected, dexpreoptBootJarDepTag, selected)
+ }
+ }
+ }
+}
+
func gatherBootclasspathFragments(ctx android.ModuleContext) map[string]android.Module {
return ctx.Config().Once(dexBootJarsFragmentsKey, func() interface{} {
fragments := make(map[string]android.Module)
@@ -544,7 +581,7 @@
return true
}
if tag == bootclasspathFragmentDepTag {
- apexInfo := ctx.OtherModuleProvider(child, android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.OtherModuleProvider(ctx, child, android.ApexInfoProvider)
for _, apex := range apexInfo.InApexVariants {
fragments[apex] = child
}
@@ -662,38 +699,69 @@
// extractEncodedDexJarsFromModulesOrBootclasspathFragments gets the hidden API encoded dex jars for
// the given modules.
func extractEncodedDexJarsFromModulesOrBootclasspathFragments(ctx android.ModuleContext, apexJarModulePairs []apexJarModulePair) bootDexJarByModule {
+ apexNameToApexExportInfoMap := getApexNameToApexExportsInfoMap(ctx)
encodedDexJarsByModuleName := bootDexJarByModule{}
for _, pair := range apexJarModulePairs {
- var path android.Path
- if android.IsConfiguredJarForPlatform(pair.apex) || android.IsModulePrebuilt(pair.jarModule) {
- // This gives us the dex jar with the hidden API flags encoded from the monolithic hidden API
- // files or the dex jar extracted from a prebuilt APEX. We can't use this for a boot jar for
- // a source APEX because there is no guarantee that it is the same as the jar packed into the
- // APEX. In practice, they are the same when we are building from a full source tree, but they
- // are different when we are building from a thin manifest (e.g., master-art), where there is
- // no monolithic hidden API files at all.
- path = retrieveEncodedBootDexJarFromModule(ctx, pair.jarModule)
- } else {
- // Use exactly the same jar that is packed into the APEX.
- fragment := getBootclasspathFragmentByApex(ctx, pair.apex)
- if fragment == nil {
- ctx.ModuleErrorf("Boot jar '%[1]s' is from APEX '%[2]s', but a bootclasspath_fragment for "+
- "APEX '%[2]s' doesn't exist or is not added as a dependency of dex_bootjars",
- pair.jarModule.Name(),
- pair.apex)
- }
- bootclasspathFragmentInfo := ctx.OtherModuleProvider(fragment, BootclasspathFragmentApexContentInfoProvider).(BootclasspathFragmentApexContentInfo)
- jar, err := bootclasspathFragmentInfo.DexBootJarPathForContentModule(pair.jarModule)
- if err != nil {
- ctx.ModuleErrorf("%s", err)
- }
- path = jar
- }
- encodedDexJarsByModuleName.addPath(pair.jarModule, path)
+ dexJarPath := getDexJarForApex(ctx, pair, apexNameToApexExportInfoMap)
+ encodedDexJarsByModuleName.addPath(pair.jarModule, dexJarPath)
}
return encodedDexJarsByModuleName
}
+type apexNameToApexExportsInfoMap map[string]android.ApexExportsInfo
+
+// javaLibraryPathOnHost returns the path to the java library which is exported by the apex for hiddenapi and dexpreopt and a boolean indicating whether the java library exists
+// For prebuilt apexes, this is created by deapexing the prebuilt apex
+func (m *apexNameToApexExportsInfoMap) javaLibraryDexPathOnHost(ctx android.ModuleContext, apex string, javalib string) (android.Path, bool) {
+ if info, exists := (*m)[apex]; exists {
+ if dex, exists := info.LibraryNameToDexJarPathOnHost[javalib]; exists {
+ return dex, true
+ } else {
+ ctx.ModuleErrorf("Apex %s does not provide a dex boot jar for library %s\n", apex, javalib)
+ }
+ }
+ // An apex entry could not be found. Return false.
+ // TODO: b/308174306 - When all the mainline modules have been flagged, make this a hard error
+ return nil, false
+}
+
+// Returns the java libraries exported by the apex for hiddenapi and dexpreopt
+// This information can come from two mechanisms
+// 1. New: Direct deps to _selected_ apexes. The apexes return a ApexExportsInfo
+// 2. Legacy: An edge to java_library or java_import (java_sdk_library) module. For prebuilt apexes, this serves as a hook and is populated by deapexers of prebuilt apxes
+// TODO: b/308174306 - Once all mainline modules have been flagged, drop (2)
+func getDexJarForApex(ctx android.ModuleContext, pair apexJarModulePair, apexNameToApexExportsInfoMap apexNameToApexExportsInfoMap) android.Path {
+ if dex, found := apexNameToApexExportsInfoMap.javaLibraryDexPathOnHost(ctx, pair.apex, android.RemoveOptionalPrebuiltPrefix(pair.jarModule.Name())); found {
+ return dex
+ }
+ // TODO: b/308174306 - Remove the legacy mechanism
+ if android.IsConfiguredJarForPlatform(pair.apex) || android.IsModulePrebuilt(pair.jarModule) {
+ // This gives us the dex jar with the hidden API flags encoded from the monolithic hidden API
+ // files or the dex jar extracted from a prebuilt APEX. We can't use this for a boot jar for
+ // a source APEX because there is no guarantee that it is the same as the jar packed into the
+ // APEX. In practice, they are the same when we are building from a full source tree, but they
+ // are different when we are building from a thin manifest (e.g., master-art), where there is
+ // no monolithic hidden API files at all.
+ return retrieveEncodedBootDexJarFromModule(ctx, pair.jarModule)
+ } else {
+ // Use exactly the same jar that is packed into the APEX.
+ fragment := getBootclasspathFragmentByApex(ctx, pair.apex)
+ if fragment == nil {
+ ctx.ModuleErrorf("Boot jar '%[1]s' is from APEX '%[2]s', but a bootclasspath_fragment for "+
+ "APEX '%[2]s' doesn't exist or is not added as a dependency of dex_bootjars",
+ pair.jarModule.Name(),
+ pair.apex)
+ }
+ bootclasspathFragmentInfo, _ := android.OtherModuleProvider(ctx, fragment, BootclasspathFragmentApexContentInfoProvider)
+ jar, err := bootclasspathFragmentInfo.DexBootJarPathForContentModule(pair.jarModule)
+ if err != nil {
+ ctx.ModuleErrorf("%s", err)
+ }
+ return jar
+ }
+ return nil
+}
+
// copyBootJarsToPredefinedLocations generates commands that will copy boot jars to predefined
// paths in the global config.
func copyBootJarsToPredefinedLocations(ctx android.ModuleContext, srcBootDexJarsByModule bootDexJarByModule, dstBootJarsByModule map[string]android.WritablePath) {
@@ -823,6 +891,37 @@
config *bootImageVariant
}
+// Returns the profile file for an apex
+// This information can come from two mechanisms
+// 1. New: Direct deps to _selected_ apexes. The apexes return a BootclasspathFragmentApexContentInfo
+// 2. Legacy: An edge to bootclasspath_fragment module. For prebuilt apexes, this serves as a hook and is populated by deapexers of prebuilt apxes
+// TODO: b/308174306 - Once all mainline modules have been flagged, drop (2)
+func getProfilePathForApex(ctx android.ModuleContext, apexName string, apexNameToBcpInfoMap map[string]android.ApexExportsInfo) android.Path {
+ if info, exists := apexNameToBcpInfoMap[apexName]; exists {
+ return info.ProfilePathOnHost
+ }
+ // TODO: b/308174306 - Remove the legacy mechanism
+ fragment := getBootclasspathFragmentByApex(ctx, apexName)
+ if fragment == nil {
+ ctx.ModuleErrorf("Boot image config imports profile from '%[2]s', but a "+
+ "bootclasspath_fragment for APEX '%[2]s' doesn't exist or is not added as a "+
+ "dependency of dex_bootjars",
+ apexName)
+ return nil
+ }
+ return fragment.(commonBootclasspathFragment).getProfilePath()
+}
+
+func getApexNameToApexExportsInfoMap(ctx android.ModuleContext) apexNameToApexExportsInfoMap {
+ apexNameToApexExportsInfoMap := apexNameToApexExportsInfoMap{}
+ ctx.VisitDirectDepsWithTag(dexpreoptBootJarDepTag, func(am android.Module) {
+ if info, exists := android.OtherModuleProvider(ctx, am, android.ApexExportsInfoProvider); exists {
+ apexNameToApexExportsInfoMap[info.ApexName] = info
+ }
+ })
+ return apexNameToApexExportsInfoMap
+}
+
// Generate boot image build rules for a specific target.
func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, profile android.Path) bootImageVariantOutputs {
@@ -865,6 +964,8 @@
invocationPath := outputPath.ReplaceExtension(ctx, "invocation")
+ apexNameToApexExportsInfoMap := getApexNameToApexExportsInfoMap(ctx)
+
cmd.Tool(globalSoong.Dex2oat).
Flag("--avoid-storing-invocation").
FlagWithOutput("--write-invocation-to=", invocationPath).ImplicitOutput(invocationPath).
@@ -877,16 +978,7 @@
}
for _, apex := range image.profileImports {
- fragment := getBootclasspathFragmentByApex(ctx, apex)
- if fragment == nil {
- ctx.ModuleErrorf("Boot image config '%[1]s' imports profile from '%[2]s', but a "+
- "bootclasspath_fragment for APEX '%[2]s' doesn't exist or is not added as a "+
- "dependency of dex_bootjars",
- image.name,
- apex)
- return bootImageVariantOutputs{}
- }
- importedProfile := fragment.(commonBootclasspathFragment).getProfilePath()
+ importedProfile := getProfilePathForApex(ctx, apex, apexNameToApexExportsInfoMap)
if importedProfile == nil {
ctx.ModuleErrorf("Boot image config '%[1]s' imports profile from '%[2]s', but '%[2]s' "+
"doesn't provide a profile",
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 2bd696c..254b2c1 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -45,7 +45,7 @@
frameworkBootImageName = "boot"
mainlineBootImageName = "mainline"
bootImageStem = "boot"
- profileInstallPathInApex = "etc/boot-image.prof"
+ ProfileInstallPathInApex = "etc/boot-image.prof"
)
// getImageNames returns an ordered list of image names. The order doesn't matter but needs to be
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index fedd564..73e33f4 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -410,7 +410,7 @@
verifyEntries(t,
"entriesList[0]",
"service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.odex",
- "/dexpreopt/oat/arm64/javalib.odex",
+ "/dexpreopt/service-foo/oat/arm64/javalib.odex",
"/system/framework/oat/arm64",
"apex@com.android.apex1@javalib@service-foo.jar@classes.odex",
entriesList[0])
@@ -418,7 +418,7 @@
verifyEntries(t,
"entriesList[1]",
"service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.vdex",
- "/dexpreopt/oat/arm64/javalib.vdex",
+ "/dexpreopt/service-foo/oat/arm64/javalib.vdex",
"/system/framework/oat/arm64",
"apex@com.android.apex1@javalib@service-foo.jar@classes.vdex",
entriesList[1])
@@ -459,7 +459,7 @@
ctx := result.TestContext
dexpreopt := ctx.ModuleForTests("foo", "android_common").MaybeRule("dexpreopt")
- expected := []string{"out/soong/.intermediates/foo/android_common/dexpreopt/profile.prof"}
+ expected := []string{"out/soong/.intermediates/foo/android_common/dexpreopt/foo/profile.prof"}
android.AssertArrayString(t, "outputs", expected, dexpreopt.AllOutputs())
}
diff --git a/java/droiddoc.go b/java/droiddoc.go
index b0d5376..138c9c3 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -363,8 +363,7 @@
switch tag {
case bootClasspathTag:
- if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
- dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+ if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
deps.bootClasspath = append(deps.bootClasspath, dep.ImplementationJars...)
} else if sm, ok := module.(SystemModulesProvider); ok {
// A system modules dependency has been added to the bootclasspath
@@ -376,8 +375,7 @@
case libTag, sdkLibTag:
if dep, ok := module.(SdkLibraryDependency); ok {
deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...)
- } else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
- dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+ } else if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
deps.classpath = append(deps.classpath, dep.HeaderJars...)
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
} else if dep, ok := module.(android.SourceFileProducer); ok {
@@ -387,8 +385,7 @@
ctx.ModuleErrorf("depends on non-java module %q", otherName)
}
case java9LibTag:
- if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
- dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+ if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...)
} else {
ctx.ModuleErrorf("depends on non-java module %q", otherName)
diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go
index 17cad89..7bcaca1 100644
--- a/java/droidstubs_test.go
+++ b/java/droidstubs_test.go
@@ -213,7 +213,7 @@
}
manifest := android.RuleBuilderSboxProtoForTests(t, ctx, m.Output("metalava.sbox.textproto"))
- if g, w := manifest.Commands[0].GetCommand(), "reference __SBOX_SANDBOX_DIR__/out/.intermediates/foo/gen/foo.txt"; !strings.Contains(g, w) {
+ if g, w := manifest.Commands[0].GetCommand(), "reference __SBOX_SANDBOX_DIR__/out/soong/.intermediates/foo/gen/foo.txt"; !strings.Contains(g, w) {
t.Errorf("Expected command to contain %q, got %q", w, g)
}
}
diff --git a/java/fuzz.go b/java/fuzz.go
index b3c2fd4..dc4c6be 100644
--- a/java/fuzz.go
+++ b/java/fuzz.go
@@ -121,7 +121,7 @@
_, sharedDeps := cc.CollectAllSharedDependencies(ctx)
for _, dep := range sharedDeps {
- sharedLibInfo := ctx.OtherModuleProvider(dep, cc.SharedLibraryInfoProvider).(cc.SharedLibraryInfo)
+ sharedLibInfo, _ := android.OtherModuleProvider(ctx, dep, cc.SharedLibraryInfoProvider)
if sharedLibInfo.SharedLibrary != nil {
arch := "lib"
if sharedLibInfo.Target.Arch.ArchType.Multilib == "lib64" {
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index fe3fe7b..e9ee3a2 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -94,7 +94,7 @@
// processing.
classesJars := android.Paths{classesJar}
ctx.VisitDirectDepsWithTag(hiddenApiAnnotationsTag, func(dep android.Module) {
- javaInfo := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+ javaInfo, _ := android.OtherModuleProvider(ctx, dep, JavaInfoProvider)
classesJars = append(classesJars, javaInfo.ImplementationJars...)
})
h.classesJarPaths = classesJars
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index fbc0197..c3caa08 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -19,6 +19,7 @@
"strings"
"android/soong/android"
+ "android/soong/dexpreopt"
"github.com/google/blueprint"
)
@@ -579,8 +580,7 @@
// Merge all the information from the fragments. The fragments form a DAG so it is possible that
// this will introduce duplicates so they will be resolved after processing all the fragments.
for _, fragment := range fragments {
- if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) {
- info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
+ if info, ok := android.OtherModuleProvider(ctx, fragment, HiddenAPIInfoProvider); ok {
i.TransitiveStubDexJarsByScope.addStubDexJarsByModule(info.TransitiveStubDexJarsByScope)
}
}
@@ -600,7 +600,7 @@
return SignatureCsvSubset{i.FilteredFlagsPath, i.SignaturePatternsPath}
}
-var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{})
+var HiddenAPIInfoProvider = blueprint.NewProvider[HiddenAPIInfo]()
// HiddenAPIInfoForSdk contains information provided by the hidden API processing for use
// by the sdk snapshot.
@@ -617,7 +617,7 @@
}
// Provides hidden API info for the sdk snapshot.
-var HiddenAPIInfoForSdkProvider = blueprint.NewProvider(HiddenAPIInfoForSdk{})
+var HiddenAPIInfoForSdkProvider = blueprint.NewProvider[HiddenAPIInfoForSdk]()
// ModuleStubDexJars contains the stub dex jars provided by a single module.
//
@@ -749,7 +749,7 @@
SplitPackages []string
}
-var hiddenAPIPropertyInfoProvider = blueprint.NewProvider(HiddenAPIPropertyInfo{})
+var hiddenAPIPropertyInfoProvider = blueprint.NewProvider[HiddenAPIPropertyInfo]()
// newHiddenAPIPropertyInfo creates a new initialized HiddenAPIPropertyInfo struct.
func newHiddenAPIPropertyInfo() HiddenAPIPropertyInfo {
@@ -777,8 +777,7 @@
func (i *HiddenAPIPropertyInfo) gatherPropertyInfo(ctx android.ModuleContext, contents []android.Module) {
for _, module := range contents {
- if ctx.OtherModuleHasProvider(module, hiddenAPIPropertyInfoProvider) {
- info := ctx.OtherModuleProvider(module, hiddenAPIPropertyInfoProvider).(HiddenAPIPropertyInfo)
+ if info, ok := android.OtherModuleProvider(ctx, module, hiddenAPIPropertyInfoProvider); ok {
i.FlagFilesByCategory.append(info.FlagFilesByCategory)
i.PackagePrefixes = append(i.PackagePrefixes, info.PackagePrefixes...)
i.SinglePackages = append(i.SinglePackages, info.SinglePackages...)
@@ -949,6 +948,7 @@
HiddenAPIFlagOutput
// The map from base module name to the path to the encoded boot dex file.
+ // This field is not available in prebuilt apexes
EncodedBootDexFilesByModule bootDexJarByModule
}
@@ -1251,9 +1251,27 @@
}
// extractBootDexJarsFromModules extracts the boot dex jars from the supplied modules.
+// This information can come from two mechanisms
+// 1. New: Direct deps to _selected_ apexes. The apexes contain a ApexExportsInfo
+// 2. Legacy: An edge to java_sdk_library(_import) module. For prebuilt apexes, this serves as a hook and is populated by deapexers of prebuilt apxes
+// TODO: b/308174306 - Once all mainline modules have been flagged, drop (2)
func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
bootDexJars := bootDexJarByModule{}
+
+ apexNameToApexExportsInfoMap := getApexNameToApexExportsInfoMap(ctx)
+ // For ART and mainline module jars, query apexNameToApexExportsInfoMap to get the dex file
+ apexJars := dexpreopt.GetGlobalConfig(ctx).ArtApexJars.AppendList(&dexpreopt.GetGlobalConfig(ctx).ApexBootJars)
+ for i := 0; i < apexJars.Len(); i++ {
+ if dex, found := apexNameToApexExportsInfoMap.javaLibraryDexPathOnHost(ctx, apexJars.Apex(i), apexJars.Jar(i)); found {
+ bootDexJars[apexJars.Jar(i)] = dex
+ }
+ }
+
+ // TODO - b/308174306: Drop the legacy mechanism
for _, module := range contents {
+ if _, exists := bootDexJars[android.RemoveOptionalPrebuiltPrefix(module.Name())]; exists {
+ continue
+ }
hiddenAPIModule := hiddenAPIModuleFromModule(ctx, module)
if hiddenAPIModule == nil {
continue
@@ -1404,7 +1422,7 @@
}
if am, ok := module.(android.ApexModule); ok && am.InAnyApex() {
- apexInfo := ctx.OtherModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.OtherModuleProvider(ctx, module, android.ApexInfoProvider)
if apexInfo.IsForPlatform() {
return true
}
diff --git a/java/hiddenapi_monolithic.go b/java/hiddenapi_monolithic.go
index 5956e3c..a61018d 100644
--- a/java/hiddenapi_monolithic.go
+++ b/java/hiddenapi_monolithic.go
@@ -67,8 +67,7 @@
case *ClasspathFragmentElement:
fragment := e.Module()
- if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) {
- info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
+ if info, ok := android.OtherModuleProvider(ctx, fragment, HiddenAPIInfoProvider); ok {
monolithicInfo.append(&info)
} else {
ctx.ModuleErrorf("%s does not provide hidden API information", fragment)
@@ -90,4 +89,4 @@
i.FlagSubsets = append(i.FlagSubsets, other.FlagSubset())
}
-var MonolithicHiddenAPIInfoProvider = blueprint.NewProvider(MonolithicHiddenAPIInfo{})
+var MonolithicHiddenAPIInfoProvider = blueprint.NewProvider[MonolithicHiddenAPIInfo]()
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 8ec1797..8cb78cd 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -162,7 +162,7 @@
return false
}
- apexInfo := ctx.OtherModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.OtherModuleProvider(ctx, module, android.ApexInfoProvider)
// Now match the apex part of the boot image configuration.
requiredApex := configuredBootJars.Apex(index)
diff --git a/java/java.go b/java/java.go
index 9be8bfd..2a4fafa 100644
--- a/java/java.go
+++ b/java/java.go
@@ -239,7 +239,7 @@
UnconditionallyExportedProguardFlags *android.DepSet[android.Path]
}
-var ProguardSpecInfoProvider = blueprint.NewProvider(ProguardSpecInfo{})
+var ProguardSpecInfoProvider = blueprint.NewProvider[ProguardSpecInfo]()
// JavaInfo contains information about a java module for use by modules that depend on it.
type JavaInfo struct {
@@ -295,7 +295,7 @@
JacocoReportClassesFile android.Path
}
-var JavaInfoProvider = blueprint.NewProvider(JavaInfo{})
+var JavaInfoProvider = blueprint.NewProvider[JavaInfo]()
// SyspropPublicStubInfo contains info about the sysprop public stub library that corresponds to
// the sysprop implementation library.
@@ -305,7 +305,7 @@
JavaInfo JavaInfo
}
-var SyspropPublicStubInfoProvider = blueprint.NewProvider(SyspropPublicStubInfo{})
+var SyspropPublicStubInfoProvider = blueprint.NewProvider[SyspropPublicStubInfo]()
// Methods that need to be implemented for a module that is added to apex java_libs property.
type ApexDependency interface {
@@ -647,7 +647,7 @@
func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bool {
// Store uncompressed (and aligned) any dex files from jars in APEXes.
- if apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo); !apexInfo.IsForPlatform() {
+ if apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider); !apexInfo.IsForPlatform() {
return true
}
@@ -687,7 +687,7 @@
j.stem = proptools.StringDefault(j.overridableDeviceProperties.Stem, ctx.ModuleName())
proguardSpecInfo := j.collectProguardSpecInfo(ctx)
- ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
+ android.SetProvider(ctx, ProguardSpecInfoProvider, proguardSpecInfo)
exportedProguardFlagsFiles := proguardSpecInfo.ProguardFlagsFiles.ToList()
j.extraProguardFlagsFiles = append(j.extraProguardFlagsFiles, exportedProguardFlagsFiles...)
@@ -695,7 +695,7 @@
writeCombinedProguardFlagsFile(ctx, combinedExportedProguardFlagFile, exportedProguardFlagsFiles)
j.combinedExportedProguardFlagsFile = combinedExportedProguardFlagFile
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
if !apexInfo.IsForPlatform() {
j.hideApexVariantFromMake = true
}
@@ -1216,12 +1216,12 @@
}
j.Test.generateAndroidBuildActionsWithConfig(ctx, configs)
- ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+ android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
}
func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.generateAndroidBuildActionsWithConfig(ctx, nil)
- ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+ android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
}
func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, configs []tradefed.Config) {
@@ -1257,7 +1257,7 @@
})
ctx.VisitDirectDepsWithTag(jniLibTag, func(dep android.Module) {
- sharedLibInfo := ctx.OtherModuleProvider(dep, cc.SharedLibraryInfoProvider).(cc.SharedLibraryInfo)
+ sharedLibInfo, _ := android.OtherModuleProvider(ctx, dep, cc.SharedLibraryInfoProvider)
if sharedLibInfo.SharedLibrary != nil {
// Copy to an intermediate output directory to append "lib[64]" to the path,
// so that it's compatible with the default rpath values.
@@ -1624,7 +1624,7 @@
ApiSurface string
}
-var JavaApiImportProvider = blueprint.NewProvider(JavaApiImportInfo{})
+var JavaApiImportProvider = blueprint.NewProvider[JavaApiImportInfo]()
func (ap *JavaApiContribution) GenerateAndroidBuildActions(ctx android.ModuleContext) {
var apiFile android.Path = nil
@@ -1632,7 +1632,7 @@
apiFile = android.PathForModuleSrc(ctx, String(apiFileString))
}
- ctx.SetProvider(JavaApiImportProvider, JavaApiImportInfo{
+ android.SetProvider(ctx, JavaApiImportProvider, JavaApiImportInfo{
ApiFile: apiFile,
ApiSurface: proptools.String(ap.properties.Api_surface),
})
@@ -1902,19 +1902,19 @@
tag := ctx.OtherModuleDependencyTag(dep)
switch tag {
case javaApiContributionTag:
- provider := ctx.OtherModuleProvider(dep, JavaApiImportProvider).(JavaApiImportInfo)
+ provider, _ := android.OtherModuleProvider(ctx, dep, JavaApiImportProvider)
if provider.ApiFile == nil && !ctx.Config().AllowMissingDependencies() {
ctx.ModuleErrorf("Error: %s has an empty api file.", dep.Name())
}
srcFilesInfo = append(srcFilesInfo, provider)
case libTag:
- provider := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+ provider, _ := android.OtherModuleProvider(ctx, dep, JavaInfoProvider)
classPaths = append(classPaths, provider.HeaderJars...)
case staticLibTag:
- provider := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+ provider, _ := android.OtherModuleProvider(ctx, dep, JavaInfoProvider)
staticLibs = append(staticLibs, provider.HeaderJars...)
case depApiSrcsTag:
- provider := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+ provider, _ := android.OtherModuleProvider(ctx, dep, JavaInfoProvider)
depApiSrcsStubsJar = provider.HeaderJars[0]
case systemModulesTag:
module := dep.(SystemModulesProvider)
@@ -2002,7 +2002,7 @@
ctx.Phony(ctx.ModuleName(), al.stubsJar)
- ctx.SetProvider(JavaInfoProvider, JavaInfo{
+ android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
HeaderJars: android.PathsIfNonNil(al.stubsJar),
ImplementationAndResourcesJars: android.PathsIfNonNil(al.stubsJar),
ImplementationJars: android.PathsIfNonNil(al.stubsJar),
@@ -2100,6 +2100,7 @@
// output file containing classes.dex and resources
dexJarFile OptionalDexJarPath
+ dexJarFileErr error
dexJarInstallFile android.Path
combinedClasspathFile android.Path
@@ -2188,7 +2189,8 @@
j.sdkVersion = j.SdkVersion(ctx)
j.minSdkVersion = j.MinSdkVersion(ctx)
- if !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() {
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+ if !apexInfo.IsForPlatform() {
j.hideApexVariantFromMake = true
}
@@ -2219,8 +2221,7 @@
j.collectTransitiveHeaderJars(ctx)
ctx.VisitDirectDeps(func(module android.Module) {
tag := ctx.OtherModuleDependencyTag(module)
- if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
- dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+ if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
switch tag {
case libTag, sdkLibTag:
flags.classpath = append(flags.classpath, dep.HeaderJars...)
@@ -2247,18 +2248,21 @@
if ctx.Device() {
// If this is a variant created for a prebuilt_apex then use the dex implementation jar
// obtained from the associated deapexer module.
- ai := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
if ai.ForPrebuiltApex {
// Get the path of the dex implementation jar from the `deapexer` module.
- di := android.FindDeapexerProviderForModule(ctx)
- if di == nil {
- return // An error has been reported by FindDeapexerProviderForModule.
+ di, err := android.FindDeapexerProviderForModule(ctx)
+ if err != nil {
+ // An error was found, possibly due to multiple apexes in the tree that export this library
+ // Defer the error till a client tries to call DexJarBuildPath
+ j.dexJarFileErr = err
+ return
}
- dexJarFileApexRootRelative := apexRootRelativePathToJavaLib(j.BaseModuleName())
+ dexJarFileApexRootRelative := ApexRootRelativePathToJavaLib(j.BaseModuleName())
if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil {
dexJarFile := makeDexJarPathFromPath(dexOutputPath)
j.dexJarFile = dexJarFile
- installPath := android.PathForModuleInPartitionInstall(ctx, "apex", ai.ApexVariationName, apexRootRelativePathToJavaLib(j.BaseModuleName()))
+ installPath := android.PathForModuleInPartitionInstall(ctx, "apex", ai.ApexVariationName, ApexRootRelativePathToJavaLib(j.BaseModuleName()))
j.dexJarInstallFile = installPath
j.dexpreopter.installPath = j.dexpreopter.getInstallPath(ctx, installPath)
@@ -2320,7 +2324,7 @@
}
}
- ctx.SetProvider(JavaInfoProvider, JavaInfo{
+ android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
HeaderJars: android.PathsIfNonNil(j.combinedClasspathFile),
TransitiveLibsHeaderJars: j.transitiveLibsHeaderJars,
TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
@@ -2375,6 +2379,9 @@
}
func (j *Import) DexJarBuildPath() OptionalDexJarPath {
+ if j.dexJarFileErr != nil {
+ panic(j.dexJarFileErr.Error())
+ }
return j.dexJarFile
}
@@ -2415,7 +2422,7 @@
// java_sdk_library_import with the specified base module name requires to be exported from a
// prebuilt_apex/apex_set.
func requiredFilesFromPrebuiltApexForImport(name string, d *dexpreopter) []string {
- dexJarFileApexRootRelative := apexRootRelativePathToJavaLib(name)
+ dexJarFileApexRootRelative := ApexRootRelativePathToJavaLib(name)
// Add the dex implementation jar to the set of exported files.
files := []string{
dexJarFileApexRootRelative,
@@ -2426,9 +2433,9 @@
return files
}
-// apexRootRelativePathToJavaLib returns the path, relative to the root of the apex's contents, for
+// ApexRootRelativePathToJavaLib returns the path, relative to the root of the apex's contents, for
// the java library with the specified name.
-func apexRootRelativePathToJavaLib(name string) string {
+func ApexRootRelativePathToJavaLib(name string) string {
return filepath.Join("javalib", name+".jar")
}
@@ -2570,7 +2577,7 @@
ctx.PropertyErrorf("jars", "exactly one jar must be provided")
}
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
if !apexInfo.IsForPlatform() {
j.hideApexVariantFromMake = true
}
diff --git a/java/java_test.go b/java/java_test.go
index 8e83fc4..b9dc453 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -618,8 +618,6 @@
android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "java_library", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
entries = android.AndroidMkEntriesForTest(t, ctx, barModule.Module())[0]
android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "java_import", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
- entries = android.AndroidMkEntriesForTest(t, ctx, ctx.ModuleForTests("sdklib", "android_common").Module())[0]
- android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "java_sdk_library_import", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
}
func assertDeepEquals(t *testing.T, message string, expected interface{}, actual interface{}) {
@@ -2226,7 +2224,8 @@
}
`)
c := ctx.ModuleForTests("c", "android_common").Module()
- transitiveSrcFiles := android.Paths(ctx.ModuleProvider(c, JavaInfoProvider).(JavaInfo).TransitiveSrcFiles.ToList())
+ javaInfo, _ := android.SingletonModuleProvider(ctx, c, JavaInfoProvider)
+ transitiveSrcFiles := android.Paths(javaInfo.TransitiveSrcFiles.ToList())
android.AssertArrayString(t, "unexpected jar deps", []string{"b.java", "c.java"}, transitiveSrcFiles.Strings())
}
@@ -2432,7 +2431,7 @@
manifest := m.Output("metalava.sbox.textproto")
sboxProto := android.RuleBuilderSboxProtoForTests(t, result.TestContext, manifest)
manifestCommand := sboxProto.Commands[0].GetCommand()
- classPathFlag := "--classpath __SBOX_SANDBOX_DIR__/out/.intermediates/bar/android_common/turbine-combined/bar.jar"
+ classPathFlag := "--classpath __SBOX_SANDBOX_DIR__/out/soong/.intermediates/bar/android_common/turbine-combined/bar.jar"
android.AssertStringDoesContain(t, "command expected to contain classpath flag", manifestCommand, classPathFlag)
}
diff --git a/java/jdeps.go b/java/jdeps.go
index 7e3a14f..91f7ce7 100644
--- a/java/jdeps.go
+++ b/java/jdeps.go
@@ -89,8 +89,7 @@
dpInfo.Classes = append(dpInfo.Classes, data.Class)
}
- if ctx.ModuleHasProvider(module, JavaInfoProvider) {
- dep := ctx.ModuleProvider(module, JavaInfoProvider).(JavaInfo)
+ if dep, ok := android.SingletonModuleProvider(ctx, module, JavaInfoProvider); ok {
dpInfo.Installed_paths = append(dpInfo.Installed_paths, dep.ImplementationJars.Strings()...)
}
dpInfo.Classes = android.FirstUniqueStrings(dpInfo.Classes)
diff --git a/java/lint.go b/java/lint.go
index eb46ea8..e740c3a 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -17,7 +17,6 @@
import (
"fmt"
"sort"
- "strconv"
"strings"
"github.com/google/blueprint/proptools"
@@ -56,7 +55,8 @@
// Modules that provide extra lint checks
Extra_check_modules []string
- // Name of the file that lint uses as the baseline. Defaults to "lint-baseline.xml".
+ // The lint baseline file to use. If specified, lint warnings listed in this file will be
+ // suppressed during lint checks.
Baseline_filename *string
// If true, baselining updatability lint checks (e.g. NewApi) is prohibited. Defaults to false.
@@ -84,9 +84,9 @@
classes android.Path
extraLintCheckJars android.Paths
library bool
- minSdkVersion int
- targetSdkVersion int
- compileSdkVersion int
+ minSdkVersion android.ApiLevel
+ targetSdkVersion android.ApiLevel
+ compileSdkVersion android.ApiLevel
compileSdkKind android.SdkKind
javaLanguageLevel string
kotlinLanguageLevel string
@@ -357,33 +357,20 @@
Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
- Textf(`echo " <uses-sdk android:minSdkVersion='%d' android:targetSdkVersion='%d'/>" &&`,
- l.minSdkVersion, l.targetSdkVersion).
+ Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
+ l.minSdkVersion.String(), l.targetSdkVersion.String()).
Text(`echo "</manifest>"`).
Text(") >").Output(manifestPath)
return manifestPath
}
-func (l *linter) getBaselineFilepath(ctx android.ModuleContext) android.OptionalPath {
- var lintBaseline android.OptionalPath
- if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
- if String(l.properties.Lint.Baseline_filename) != "" {
- // if manually specified, we require the file to exist
- lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
- } else {
- lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
- }
- }
- return lintBaseline
-}
-
func (l *linter) lint(ctx android.ModuleContext) {
if !l.enabled() {
return
}
- if l.minSdkVersion != l.compileSdkVersion {
+ if l.minSdkVersion.CompareTo(l.compileSdkVersion) == -1 {
l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
// Skip lint warning checks for NewApi warnings for libcore where they come from source
// files that reference the API they are adding (b/208656169).
@@ -413,8 +400,7 @@
extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
for _, extraLintCheckModule := range extraLintCheckModules {
- if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
- dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
+ if dep, ok := android.OtherModuleProvider(ctx, extraLintCheckModule, JavaInfoProvider); ok {
l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
} else {
ctx.PropertyErrorf("lint.extra_check_modules",
@@ -498,7 +484,7 @@
FlagWithOutput("--html ", html).
FlagWithOutput("--text ", text).
FlagWithOutput("--xml ", xml).
- FlagWithArg("--compile-sdk-version ", strconv.Itoa(l.compileSdkVersion)).
+ FlagWithArg("--compile-sdk-version ", l.compileSdkVersion.String()).
FlagWithArg("--java-language-level ", l.javaLanguageLevel).
FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
@@ -519,9 +505,8 @@
cmd.FlagWithArg("--check ", checkOnly)
}
- lintBaseline := l.getBaselineFilepath(ctx)
- if lintBaseline.Valid() {
- cmd.FlagWithInput("--baseline ", lintBaseline.Path())
+ if l.properties.Lint.Baseline_filename != nil {
+ cmd.FlagWithInput("--baseline ", android.PathForModuleSrc(ctx, *l.properties.Lint.Baseline_filename))
}
cmd.FlagWithOutput("--write-reference-baseline ", referenceBaseline)
@@ -661,7 +646,7 @@
}
if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
- apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.SingletonModuleProvider(ctx, m, android.ApexInfoProvider)
if apexInfo.IsForPlatform() {
// There are stray platform variants of modules in apexes that are not available for
// the platform, and they sometimes can't be built. Don't depend on them.
diff --git a/java/lint_test.go b/java/lint_test.go
index 5e6b8bc..b7e6aad 100644
--- a/java/lint_test.go
+++ b/java/lint_test.go
@@ -21,7 +21,7 @@
"android/soong/android"
)
-func TestJavaLint(t *testing.T) {
+func TestJavaLintDoesntUseBaselineImplicitly(t *testing.T) {
ctx, _ := testJavaWithFS(t, `
java_library {
name: "foo",
@@ -40,30 +40,8 @@
foo := ctx.ModuleForTests("foo", "android_common")
sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx, foo.Output("lint.sbox.textproto"))
- if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml") {
- t.Error("did not pass --baseline flag")
- }
-}
-
-func TestJavaLintWithoutBaseline(t *testing.T) {
- ctx, _ := testJavaWithFS(t, `
- java_library {
- name: "foo",
- srcs: [
- "a.java",
- "b.java",
- "c.java",
- ],
- min_sdk_version: "29",
- sdk_version: "system_current",
- }
- `, map[string][]byte{})
-
- foo := ctx.ModuleForTests("foo", "android_common")
-
- sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx, foo.Output("lint.sbox.textproto"))
- if strings.Contains(*sboxProto.Commands[0].Command, "--baseline") {
- t.Error("passed --baseline flag for non existent file")
+ if strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml") {
+ t.Error("Passed --baseline flag when baseline_filename was not set")
}
}
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 0d52614..4db426e 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -106,6 +106,9 @@
}
func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+ // Create a dependency on all_apex_contributions to determine the selected mainline module
+ ctx.AddDependency(ctx.Module(), apexContributionsMetadataDepTag, "all_apex_contributions")
+
b.hiddenAPIDepsMutator(ctx)
if !dexpreopt.IsDex2oatNeeded(ctx) {
@@ -130,6 +133,8 @@
func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
// Add dependencies on all the ART jars.
global := dexpreopt.GetGlobalConfig(ctx)
+ addDependenciesOntoSelectedBootImageApexes(ctx, "com.android.art")
+ // TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly
addDependenciesOntoBootImageModules(ctx, global.ArtApexJars, platformBootclasspathArtBootJarDepTag)
// Add dependencies on all the non-updatable jars, which are on the platform or in non-updatable
@@ -138,6 +143,12 @@
// Add dependencies on all the updatable jars, except the ART jars.
apexJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
+ apexes := []string{}
+ for i := 0; i < apexJars.Len(); i++ {
+ apexes = append(apexes, apexJars.Apex(i))
+ }
+ addDependenciesOntoSelectedBootImageApexes(ctx, android.FirstUniqueStrings(apexes)...)
+ // TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly
addDependenciesOntoBootImageModules(ctx, apexJars, platformBootclasspathApexBootJarDepTag)
// Add dependencies on all the fragments.
@@ -180,7 +191,7 @@
var transitiveSrcFiles android.Paths
for _, module := range allModules {
- depInfo := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+ depInfo, _ := android.OtherModuleProvider(ctx, module, JavaInfoProvider)
if depInfo.TransitiveSrcFiles != nil {
transitiveSrcFiles = append(transitiveSrcFiles, depInfo.TransitiveSrcFiles.ToList()...)
}
@@ -219,7 +230,7 @@
// Include jars from APEXes that don't populate their classpath proto config.
remainingJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
for _, fragment := range b.fragments {
- info := ctx.OtherModuleProvider(fragment, ClasspathFragmentProtoContentInfoProvider).(ClasspathFragmentProtoContentInfo)
+ info, _ := android.OtherModuleProvider(ctx, fragment, ClasspathFragmentProtoContentInfoProvider)
if info.ClasspathFragmentProtoGenerated {
remainingJars = remainingJars.RemoveList(info.ClasspathFragmentProtoContents)
}
@@ -241,7 +252,7 @@
func (b *platformBootclasspathModule) checkPlatformModules(ctx android.ModuleContext, modules []android.Module) {
// TODO(satayev): change this check to only allow core-icu4j, all apex jars should not be here.
for _, m := range modules {
- apexInfo := ctx.OtherModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.OtherModuleProvider(ctx, m, android.ApexInfoProvider)
fromUpdatableApex := apexInfo.Updatable
if fromUpdatableApex {
// error: this jar is part of an updatable apex
@@ -255,7 +266,7 @@
// checkApexModules ensures that the apex modules supplied are not from the platform.
func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext, modules []android.Module) {
for _, m := range modules {
- apexInfo := ctx.OtherModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.OtherModuleProvider(ctx, m, android.ApexInfoProvider)
fromUpdatableApex := apexInfo.Updatable
if fromUpdatableApex {
// ok: this jar is part of an updatable apex
@@ -389,7 +400,7 @@
monolithicInfo := newMonolithicHiddenAPIInfo(ctx, temporaryInput.FlagFilesByCategory, classpathElements)
// Store the information for testing.
- ctx.SetProvider(MonolithicHiddenAPIInfoProvider, monolithicInfo)
+ android.SetProvider(ctx, MonolithicHiddenAPIInfoProvider, monolithicInfo)
return monolithicInfo
}
diff --git a/java/robolectric.go b/java/robolectric.go
index 45621fd..9e8850c 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -193,7 +193,7 @@
}
handleLibDeps := func(dep android.Module) {
- m := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+ m, _ := android.OtherModuleProvider(ctx, dep, JavaInfoProvider)
r.libs = append(r.libs, ctx.OtherModuleName(dep))
if !android.InList(ctx.OtherModuleName(dep), config.FrameworkLibraries) {
combinedJarJars = append(combinedJarJars, m.ImplementationAndResourcesJars...)
@@ -254,7 +254,7 @@
}
r.installFile = ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...)
- ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+ android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
}
func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath,
@@ -305,8 +305,7 @@
srcJarDeps := append(android.Paths(nil), instrumentedApp.srcJarDeps...)
for _, m := range ctx.GetDirectDepsWithTag(roboCoverageLibsTag) {
- if ctx.OtherModuleHasProvider(m, JavaInfoProvider) {
- dep := ctx.OtherModuleProvider(m, JavaInfoProvider).(JavaInfo)
+ if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok {
srcJarArgs = append(srcJarArgs, dep.SrcJarArgs...)
srcJarDeps = append(srcJarDeps, dep.SrcJarDeps...)
}
diff --git a/java/sdk.go b/java/sdk.go
index ad71fb2..352b243 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -262,8 +262,7 @@
ctx.VisitAllModules(func(module android.Module) {
// Collect dex jar paths for the modules listed above.
- if ctx.ModuleHasProvider(module, JavaInfoProvider) {
- j := ctx.ModuleProvider(module, JavaInfoProvider).(JavaInfo)
+ if j, ok := android.SingletonModuleProvider(ctx, module, JavaInfoProvider); ok {
name := ctx.ModuleName(module)
if i := android.IndexList(name, stubsModules); i != -1 {
stubsJars[i] = j.HeaderJars
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 176bda0..ef34fb6 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -673,8 +673,7 @@
}
func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error {
- if ctx.OtherModuleHasProvider(dep, JavaInfoProvider) {
- lib := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+ if lib, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok {
paths.stubsHeaderPath = lib.HeaderJars
paths.stubsImplPath = lib.ImplementationJars
@@ -1451,7 +1450,7 @@
// Make the set of components exported by this module available for use elsewhere.
exportedComponentInfo := android.ExportedComponentsInfo{Components: android.SortedKeys(exportedComponents)}
- ctx.SetProvider(android.ExportedComponentsInfoProvider, exportedComponentInfo)
+ android.SetProvider(ctx, android.ExportedComponentsInfoProvider, exportedComponentInfo)
// Provide additional information for inclusion in an sdk's generated .info file.
additionalSdkInfo := map[string]interface{}{}
@@ -1471,7 +1470,7 @@
scopeInfo["latest_removed_api"] = p.Path().String()
}
}
- ctx.SetProvider(android.AdditionalSdkInfoProvider, android.AdditionalSdkInfo{additionalSdkInfo})
+ android.SetProvider(ctx, android.AdditionalSdkInfoProvider, android.AdditionalSdkInfo{additionalSdkInfo})
}
func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries {
@@ -2036,8 +2035,8 @@
// If either this or the other module are on the platform then this will return
// false.
func withinSameApexesAs(ctx android.BaseModuleContext, other android.Module) bool {
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
- otherApexInfo := ctx.OtherModuleProvider(other, android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+ otherApexInfo, _ := android.OtherModuleProvider(ctx, other, android.ApexInfoProvider)
return len(otherApexInfo.InApexVariants) > 0 && reflect.DeepEqual(apexInfo.InApexVariants, otherApexInfo.InApexVariants)
}
@@ -2379,7 +2378,8 @@
xmlPermissionsFileModule *sdkLibraryXml
// Build path to the dex implementation jar obtained from the prebuilt_apex, if any.
- dexJarFile OptionalDexJarPath
+ dexJarFile OptionalDexJarPath
+ dexJarFileErr error
// Expected install file path of the source module(sdk_library)
// or dex implementation jar obtained from the prebuilt_apex, if any.
@@ -2592,14 +2592,6 @@
}
}
-func (module *SdkLibraryImport) AndroidMkEntries() []android.AndroidMkEntries {
- // For an SDK library imported from a prebuilt APEX, we don't need a Make module for itself, as we
- // don't need to install it. However, we need to add its dexpreopt outputs as sub-modules, if it
- // is preopted.
- dexpreoptEntries := module.dexpreopter.AndroidMkEntriesForApex()
- return append(dexpreoptEntries, android.AndroidMkEntries{Disabled: true})
-}
-
var _ android.ApexModule = (*SdkLibraryImport)(nil)
// Implements android.ApexModule
@@ -2693,14 +2685,17 @@
if ctx.Device() {
// If this is a variant created for a prebuilt_apex then use the dex implementation jar
// obtained from the associated deapexer module.
- ai := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
if ai.ForPrebuiltApex {
// Get the path of the dex implementation jar from the `deapexer` module.
- di := android.FindDeapexerProviderForModule(ctx)
- if di == nil {
- return // An error has been reported by FindDeapexerProviderForModule.
+ di, err := android.FindDeapexerProviderForModule(ctx)
+ if err != nil {
+ // An error was found, possibly due to multiple apexes in the tree that export this library
+ // Defer the error till a client tries to call DexJarBuildPath
+ module.dexJarFileErr = err
+ return
}
- dexJarFileApexRootRelative := apexRootRelativePathToJavaLib(module.BaseModuleName())
+ dexJarFileApexRootRelative := ApexRootRelativePathToJavaLib(module.BaseModuleName())
if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil {
dexJarFile := makeDexJarPathFromPath(dexOutputPath)
module.dexJarFile = dexJarFile
@@ -2760,6 +2755,9 @@
func (module *SdkLibraryImport) DexJarBuildPath() OptionalDexJarPath {
// The dex implementation jar extracted from the .apex file should be used in preference to the
// source.
+ if module.dexJarFileErr != nil {
+ panic(module.dexJarFileErr.Error())
+ }
if module.dexJarFile.IsSet() {
return module.dexJarFile
}
@@ -2960,7 +2958,7 @@
// File path to the runtime implementation library
func (module *sdkLibraryXml) implPath(ctx android.ModuleContext) string {
implName := proptools.String(module.properties.Lib_name)
- if apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo); !apexInfo.IsForPlatform() {
+ if apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider); !apexInfo.IsForPlatform() {
// TODO(b/146468504): ApexVariationName() is only a soong module name, not apex name.
// In most cases, this works fine. But when apex_name is set or override_apex is used
// this can be wrong.
@@ -3067,7 +3065,8 @@
}
func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- module.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+ module.hideApexVariantFromMake = !apexInfo.IsForPlatform()
libName := proptools.String(module.properties.Lib_name)
module.selfValidate(ctx)
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index a136818..63419d6 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -132,7 +132,7 @@
result.ModuleForTests("foo.api.system.28", "")
result.ModuleForTests("foo.api.test.28", "")
- exportedComponentsInfo := result.ModuleProvider(foo.Module(), android.ExportedComponentsInfoProvider).(android.ExportedComponentsInfo)
+ exportedComponentsInfo, _ := android.SingletonModuleProvider(result, foo.Module(), android.ExportedComponentsInfoProvider)
expectedFooExportedComponents := []string{
"foo-removed.api.public.latest",
"foo-removed.api.system.latest",
@@ -950,6 +950,7 @@
})
CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{
+ `all_apex_contributions`,
`prebuilt_sdklib.stubs`,
`sdklib.impl`,
// This should be prebuilt_sdklib.stubs but is set to sdklib.stubs because the
@@ -1022,6 +1023,7 @@
})
CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{
+ `all_apex_contributions`,
`dex2oatd`,
`prebuilt_sdklib.stubs`,
`prebuilt_sdklib.stubs.source`,
@@ -1085,9 +1087,6 @@
"prebuilt_sdklib.source_preferred_using_legacy_flags",
],
}
- all_apex_contributions {
- name: "all_apex_contributions",
- }
java_sdk_library {
name: "sdklib.prebuilt_preferred_using_legacy_flags",
srcs: ["a.java"],
@@ -1169,9 +1168,6 @@
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
FixtureWithLastReleaseApis("sdklib.source_preferred_using_legacy_flags", "sdklib.prebuilt_preferred_using_legacy_flags"),
- android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
- android.RegisterApexContributionsBuildComponents(ctx)
- }),
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.BuildFlags = map[string]string{
"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contributions",
diff --git a/java/system_modules.go b/java/system_modules.go
index 0efa1a4..f344648 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -55,7 +55,8 @@
`${config.MergeZipsCmd} -j ${workDir}/module.jar ${workDir}/classes.jar $in && ` +
// Note: The version of the java.base module created must match the version
// of the jlink tool which consumes it.
- `${config.JmodCmd} create --module-version ${config.JlinkVersion} --target-platform android ` +
+ // Use LINUX-OTHER to be compatible with JDK 21+ (b/294137077)
+ `${config.JmodCmd} create --module-version ${config.JlinkVersion} --target-platform LINUX-OTHER ` +
` --class-path ${workDir}/module.jar ${workDir}/jmod/java.base.jmod && ` +
`${config.JlinkCmd} --module-path ${workDir}/jmod --add-modules java.base --output ${outDir} ` +
// Note: The system-modules jlink plugin is disabled because (a) it is not
@@ -159,7 +160,7 @@
var jars android.Paths
ctx.VisitDirectDepsWithTag(systemModulesLibsTag, func(module android.Module) {
- dep, _ := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+ dep, _ := android.OtherModuleProvider(ctx, module, JavaInfoProvider)
jars = append(jars, dep.HeaderJars...)
})
diff --git a/java/system_modules_test.go b/java/system_modules_test.go
index 7b5a386..2ceca5d 100644
--- a/java/system_modules_test.go
+++ b/java/system_modules_test.go
@@ -24,7 +24,7 @@
paths := []string{}
for _, moduleName := range moduleNames {
module := result.Module(moduleName, "android_common")
- info := result.ModuleProvider(module, JavaInfoProvider).(JavaInfo)
+ info, _ := android.SingletonModuleProvider(result, module, JavaInfoProvider)
paths = append(paths, info.HeaderJars.RelativeToTop().Strings()...)
}
return paths
diff --git a/java/test_spec_test.go b/java/test_spec_test.go
index 7f06785..4144dad 100644
--- a/java/test_spec_test.go
+++ b/java/test_spec_test.go
@@ -29,14 +29,10 @@
}`
result := runTestSpecTest(t, android.FixtureExpectsNoErrors, bp)
- module := result.ModuleForTests(
- "module-name", "",
- ).Module().(*soongTesting.TestSpecModule)
+ module := result.ModuleForTests("module-name", "")
// Check that the provider has the right contents
- data := result.ModuleProvider(
- module, soongTesting.TestSpecProviderKey,
- ).(soongTesting.TestSpecProviderData)
+ data, _ := android.SingletonModuleProvider(result, module.Module(), soongTesting.TestSpecProviderKey)
if !strings.HasSuffix(
data.IntermediatePath.String(), "/intermediateTestSpecMetadata.pb",
) {
@@ -46,13 +42,8 @@
)
}
- buildParamsSlice := module.BuildParamsForTests()
- var metadata = ""
- for _, params := range buildParamsSlice {
- if params.Rule.String() == "android/soong/android.writeFile" {
- metadata = params.Args["content"]
- }
- }
+ metadata := android.ContentFromFileRuleForTests(t, result.TestContext,
+ module.Output(data.IntermediatePath.String()))
metadataList := make([]*test_spec_proto.TestSpec_OwnershipMetadata, 0, 2)
teamId := "12345"
@@ -72,9 +63,7 @@
}
testSpecMetadata := test_spec_proto.TestSpec{OwnershipMetadataList: metadataList}
protoData, _ := proto.Marshal(&testSpecMetadata)
- rawData := string(protoData)
- formattedData := strings.ReplaceAll(rawData, "\n", "\\n")
- expectedMetadata := "'" + formattedData + "\\n'"
+ expectedMetadata := string(protoData)
if metadata != expectedMetadata {
t.Errorf(
@@ -122,7 +111,7 @@
}
func runTestSpecTest(
- t *testing.T, errorHandler android.FixtureErrorHandler, bp string,
+ t *testing.T, errorHandler android.FixtureErrorHandler, bp string,
) *android.TestResult {
return android.GroupFixturePreparers(
soongTesting.PrepareForTestWithTestingBuildComponents,
diff --git a/java/testing.go b/java/testing.go
index e883bcb..5959c49 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -383,6 +383,7 @@
RegisterSystemModulesBuildComponents(ctx)
registerSystemserverClasspathBuildComponents(ctx)
registerLintBuildComponents(ctx)
+ android.RegisterApexContributionsBuildComponents(ctx)
}
// gatherRequiredDepsForTest gathers the module definitions used by
@@ -570,6 +571,11 @@
}
`
+ bp += `
+ all_apex_contributions {
+ name: "all_apex_contributions",
+ }
+`
return bp
}
@@ -617,7 +623,7 @@
func CheckClasspathFragmentProtoContentInfoProvider(t *testing.T, result *android.TestResult, generated bool, contents, outputFilename, installDir string) {
t.Helper()
p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
- info := result.ModuleProvider(p, ClasspathFragmentProtoContentInfoProvider).(ClasspathFragmentProtoContentInfo)
+ info, _ := android.SingletonModuleProvider(result, p, ClasspathFragmentProtoContentInfoProvider)
android.AssertBoolEquals(t, "classpath proto generated", generated, info.ClasspathFragmentProtoGenerated)
android.AssertStringEquals(t, "classpath proto contents", contents, info.ClasspathFragmentProtoContents.String())
@@ -637,7 +643,7 @@
func apexNamePairFromModule(ctx *android.TestContext, module android.Module) string {
name := module.Name()
var apex string
- apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.SingletonModuleProvider(ctx, module, android.ApexInfoProvider)
if apexInfo.IsForPlatform() {
apex = "platform"
} else {
diff --git a/multitree/api_imports.go b/multitree/api_imports.go
index 07ec7bc..51b9e07 100644
--- a/multitree/api_imports.go
+++ b/multitree/api_imports.go
@@ -64,7 +64,7 @@
SharedLibs, HeaderLibs, ApexSharedLibs map[string]string
}
-var ApiImportsProvider = blueprint.NewMutatorProvider(ApiImportInfo{}, "deps")
+var ApiImportsProvider = blueprint.NewMutatorProvider[ApiImportInfo]("deps")
// Store module lists into ApiImportInfo and share it over mutator provider.
func (imports *ApiImports) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -81,7 +81,7 @@
headerLibs := generateNameMapWithSuffix(imports.properties.Header_libs)
apexSharedLibs := generateNameMapWithSuffix(imports.properties.Apex_shared_libs)
- ctx.SetProvider(ApiImportsProvider, ApiImportInfo{
+ android.SetProvider(ctx, ApiImportsProvider, ApiImportInfo{
SharedLibs: sharedLibs,
HeaderLibs: headerLibs,
ApexSharedLibs: apexSharedLibs,
diff --git a/phony/phony.go b/phony/phony.go
index a8b651a..bb48788 100644
--- a/phony/phony.go
+++ b/phony/phony.go
@@ -24,6 +24,7 @@
func init() {
android.RegisterModuleType("phony", PhonyFactory)
+ android.RegisterModuleType("phony_rule", PhonyRuleFactory)
}
type phony struct {
@@ -71,3 +72,40 @@
},
}
}
+
+type PhonyRule struct {
+ android.ModuleBase
+
+ properties PhonyProperties
+}
+
+type PhonyProperties struct {
+ // The Phony_deps is the set of all dependencies for this target,
+ // and it can function similarly to .PHONY in a makefile.
+ // Additionally, dependencies within it can even include genrule.
+ Phony_deps []string
+}
+
+// The phony_rule provides functionality similar to the .PHONY in a makefile.
+// It can create a phony target and include relevant dependencies associated with it.
+func PhonyRuleFactory() android.Module {
+ module := &PhonyRule{}
+ android.InitAndroidModule(module)
+ module.AddProperties(&module.properties)
+ return module
+}
+
+func (p *PhonyRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+}
+
+func (p *PhonyRule) AndroidMk() android.AndroidMkData {
+ return android.AndroidMkData{
+ Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+ if len(p.properties.Phony_deps) > 0 {
+ depModulesStr := strings.Join(p.properties.Phony_deps, " ")
+ fmt.Fprintln(w, ".PHONY:", name)
+ fmt.Fprintln(w, name, ":", depModulesStr)
+ }
+ },
+ }
+}
diff --git a/python/python.go b/python/python.go
index 79b1515..d3cbd76 100644
--- a/python/python.go
+++ b/python/python.go
@@ -420,7 +420,7 @@
// GenerateAndroidBuildActions performs build actions common to all Python modules
func (p *PythonLibraryModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
expandedSrcs := android.PathsForModuleSrcExcludes(ctx, p.properties.Srcs, p.properties.Exclude_srcs)
- ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: expandedSrcs.Strings()})
+ android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: expandedSrcs.Strings()})
// expand data files from "data" property.
expandedData := android.PathsForModuleSrc(ctx, p.properties.Data)
diff --git a/python/test.go b/python/test.go
index f15a8fc..782f39f 100644
--- a/python/test.go
+++ b/python/test.go
@@ -208,7 +208,7 @@
installedData := ctx.InstallTestData(installDir, p.data)
p.installedDest = ctx.InstallFile(installDir, p.installSource.Base(), p.installSource, installedData...)
- ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+ android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
}
func (p *PythonTestModule) AndroidMkEntries() []android.AndroidMkEntries {
diff --git a/rust/afdo.go b/rust/afdo.go
index 3534ee6..323ee36 100644
--- a/rust/afdo.go
+++ b/rust/afdo.go
@@ -67,8 +67,7 @@
}
ctx.VisitDirectDepsWithTag(cc.FdoProfileTag, func(m android.Module) {
- if ctx.OtherModuleHasProvider(m, cc.FdoProfileProvider) {
- info := ctx.OtherModuleProvider(m, cc.FdoProfileProvider).(cc.FdoProfileInfo)
+ if info, ok := android.OtherModuleProvider(ctx, m, cc.FdoProfileProvider); ok {
path := info.Path
profileUseFlag := fmt.Sprintf(afdoFlagFormat, path.String())
flags.RustFlags = append(flags.RustFlags, profileUseFlag)
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 733ffc5..c355a56 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -17,6 +17,7 @@
import (
"path/filepath"
+ "android/soong/aconfig"
"android/soong/android"
)
@@ -66,8 +67,7 @@
if mod.UseVndk() {
entries.SetBool("LOCAL_USE_VNDK", true)
}
- // TODO(b/311155208): The container here should be system.
- entries.SetPaths("LOCAL_ACONFIG_FILES", mod.mergedAconfigFiles[""])
+ aconfig.SetAconfigFileMkEntries(mod.AndroidModuleBase(), entries, mod.mergedAconfigFiles)
},
},
}
diff --git a/rust/fuzz.go b/rust/fuzz.go
index bacfa2d..1770d2e 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -142,12 +142,12 @@
fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
cc.SharedLibraryInstallLocation(
- install, ctx.Host(), installBase, ctx.Arch().ArchType.String()))
+ install, ctx.Host(), ctx.InstallInVendor(), installBase, ctx.Arch().ArchType.String()))
// Also add the dependency on the shared library symbols dir.
if !ctx.Host() {
fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
- cc.SharedLibrarySymbolsInstallLocation(install, installBase, ctx.Arch().ArchType.String()))
+ cc.SharedLibrarySymbolsInstallLocation(install, ctx.InstallInVendor(), installBase, ctx.Arch().ArchType.String()))
}
}
diff --git a/rust/image.go b/rust/image.go
index c2e250c..7adf234 100644
--- a/rust/image.go
+++ b/rust/image.go
@@ -117,20 +117,16 @@
return false
}
-func (ctx *moduleContext) SocSpecific() bool {
+func (mod *Module) InstallInVendor() bool {
// Additionally check if this module is inVendor() that means it is a "vendor" variant of a
// module. As well as SoC specific modules, vendor variants must be installed to /vendor
// unless they have "odm_available: true".
- return ctx.ModuleContext.SocSpecific() || (ctx.RustModule().InVendor() && !ctx.RustModule().VendorVariantToOdm())
+ return mod.InVendor() && !mod.VendorVariantToOdm()
}
-func (ctx *moduleContext) DeviceSpecific() bool {
+func (mod *Module) InstallInOdm() bool {
// Some vendor variants want to be installed to /odm by setting "odm_available: true".
- return ctx.ModuleContext.DeviceSpecific() || (ctx.RustModule().InVendor() && ctx.RustModule().VendorVariantToOdm())
-}
-
-func (ctx *moduleContext) SystemExtSpecific() bool {
- return ctx.ModuleContext.SystemExtSpecific()
+ return mod.InVendor() && mod.VendorVariantToOdm()
}
// Returns true when this module creates a vendor variant and wants to install the vendor variant
@@ -188,12 +184,12 @@
}
func (mod *Module) InProduct() bool {
- return mod.Properties.ImageVariationPrefix == cc.ProductVariationPrefix
+ return mod.Properties.ImageVariation == cc.ProductVariation
}
// Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor
func (mod *Module) InVendor() bool {
- return mod.Properties.ImageVariationPrefix == cc.VendorVariationPrefix
+ return mod.Properties.ImageVariation == cc.VendorVariation
}
func (mod *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
@@ -202,9 +198,11 @@
m.MakeAsPlatform()
} else if variant == android.RecoveryVariation {
m.MakeAsPlatform()
- } else if strings.HasPrefix(variant, cc.VendorVariationPrefix) {
- m.Properties.ImageVariationPrefix = cc.VendorVariationPrefix
- m.Properties.VndkVersion = strings.TrimPrefix(variant, cc.VendorVariationPrefix)
+ } else if strings.HasPrefix(variant, cc.VendorVariation) {
+ m.Properties.ImageVariation = cc.VendorVariation
+ if strings.HasPrefix(variant, cc.VendorVariationPrefix) {
+ m.Properties.VndkVersion = strings.TrimPrefix(variant, cc.VendorVariationPrefix)
+ }
// Makefile shouldn't know vendor modules other than BOARD_VNDK_VERSION.
// Hide other vendor variants to avoid collision.
@@ -213,9 +211,11 @@
m.Properties.HideFromMake = true
m.HideFromMake()
}
- } else if strings.HasPrefix(variant, cc.ProductVariationPrefix) {
- m.Properties.ImageVariationPrefix = cc.ProductVariationPrefix
- m.Properties.VndkVersion = strings.TrimPrefix(variant, cc.ProductVariationPrefix)
+ } else if strings.HasPrefix(variant, cc.ProductVariation) {
+ m.Properties.ImageVariation = cc.ProductVariation
+ if strings.HasPrefix(variant, cc.ProductVariationPrefix) {
+ m.Properties.VndkVersion = strings.TrimPrefix(variant, cc.ProductVariationPrefix)
+ }
}
}
diff --git a/rust/library.go b/rust/library.go
index 199ffbb..7f004fc 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -547,7 +547,7 @@
}
if library.static() || library.shared() {
- ctx.SetProvider(cc.FlagExporterInfoProvider, cc.FlagExporterInfo{
+ android.SetProvider(ctx, cc.FlagExporterInfoProvider, cc.FlagExporterInfo{
IncludeDirs: library.includeDirs,
})
}
@@ -559,7 +559,7 @@
library.tocFile = android.OptionalPathForPath(tocFile)
cc.TransformSharedObjectToToc(ctx, outputFile, tocFile)
- ctx.SetProvider(cc.SharedLibraryInfoProvider, cc.SharedLibraryInfo{
+ android.SetProvider(ctx, cc.SharedLibraryInfoProvider, cc.SharedLibraryInfo{
TableOfContents: android.OptionalPathForPath(tocFile),
SharedLibrary: outputFile,
Target: ctx.Target(),
@@ -568,7 +568,7 @@
if library.static() {
depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(outputFile).Build()
- ctx.SetProvider(cc.StaticLibraryInfoProvider, cc.StaticLibraryInfo{
+ android.SetProvider(ctx, cc.StaticLibraryInfoProvider, cc.StaticLibraryInfo{
StaticLibrary: outputFile,
TransitiveStaticLibrariesForOrdering: depSet,
diff --git a/rust/protobuf.go b/rust/protobuf.go
index 8d231bb..0b26b80 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -54,10 +54,6 @@
// List of libraries which export include paths required for this module
Header_libs []string `android:"arch_variant,variant_prepend"`
- // Use protobuf version 3.x. This will be deleted once we migrate all current users
- // of protobuf off of 2.x.
- Use_protobuf3 *bool
-
// List of exported include paths containing proto files for dependent rust_protobuf modules.
Exported_include_dirs []string
}
@@ -74,10 +70,6 @@
protoFlags android.ProtoFlags
}
-func (proto *protobufDecorator) useProtobuf3() bool {
- return Bool(proto.Properties.Use_protobuf3)
-}
-
func (proto *protobufDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path {
var protoFlags android.ProtoFlags
var grpcProtoFlags android.ProtoFlags
@@ -87,12 +79,7 @@
protoFiles := android.PathsForModuleSrc(ctx, proto.Properties.Protos)
grpcFiles := android.PathsForModuleSrc(ctx, proto.Properties.Grpc_protos)
- // For now protobuf2 (the deprecated version) remains the default. This will change in the
- // future as we update the various users.
- protoPluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust-deprecated")
- if proto.useProtobuf3() == true {
- protoPluginPath = ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
- }
+ protoPluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
commonProtoFlags = append(commonProtoFlags, defaultProtobufFlags...)
commonProtoFlags = append(commonProtoFlags, proto.Properties.Proto_flags...)
@@ -186,7 +173,7 @@
// stemFile must be first here as the first path in BaseSourceProvider.OutputFiles is the library entry-point.
proto.BaseSourceProvider.OutputFiles = append(android.Paths{stemFile}, outputs.Paths()...)
- ctx.SetProvider(cc.FlagExporterInfoProvider, cc.FlagExporterInfo{
+ android.SetProvider(ctx, cc.FlagExporterInfoProvider, cc.FlagExporterInfo{
IncludeDirs: android.PathsForModuleSrc(ctx, proto.Properties.Exported_include_dirs),
})
@@ -216,13 +203,7 @@
lines = append(
lines,
"pub mod empty {",
- " pub use protobuf::well_known_types::Empty;",
- "}",
- "pub mod wrappers {",
- " pub use protobuf::well_known_types::{",
- " DoubleValue, FloatValue, Int64Value, UInt64Value, Int32Value, UInt32Value,",
- " BoolValue, StringValue, BytesValue",
- " };",
+ " pub use protobuf::well_known_types::empty::Empty;",
"}")
}
@@ -235,20 +216,10 @@
func (proto *protobufDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps {
deps = proto.BaseSourceProvider.SourceProviderDeps(ctx, deps)
- useProtobuf3 := proto.useProtobuf3()
- if useProtobuf3 == true {
- deps.Rustlibs = append(deps.Rustlibs, "libprotobuf")
- } else {
- deps.Rustlibs = append(deps.Rustlibs, "libprotobuf_deprecated")
- }
+ deps.Rustlibs = append(deps.Rustlibs, "libprotobuf")
deps.HeaderLibs = append(deps.SharedLibs, proto.Properties.Header_libs...)
if len(proto.Properties.Grpc_protos) > 0 {
- if useProtobuf3 == true {
- ctx.PropertyErrorf("protos", "rust_protobuf with grpc_protos defined must currently use "+
- "`use_protobuf3: false,` in the Android.bp file. This is temporary until the "+
- "grpcio crate is updated to use the current version of the protobuf crate.")
- }
deps.Rustlibs = append(deps.Rustlibs, "libgrpcio", "libfutures")
deps.HeaderLibs = append(deps.HeaderLibs, "libprotobuf-cpp-full")
}
diff --git a/rust/protobuf_test.go b/rust/protobuf_test.go
index 9dca029..cae071b 100644
--- a/rust/protobuf_test.go
+++ b/rust/protobuf_test.go
@@ -21,54 +21,6 @@
"android/soong/android"
)
-func TestRustProtobuf(t *testing.T) {
- ctx := testRust(t, `
- rust_protobuf {
- name: "librust_proto",
- protos: ["buf.proto", "proto.proto"],
- crate_name: "rust_proto",
- source_stem: "buf",
- shared_libs: ["libfoo_shared"],
- static_libs: ["libfoo_static"],
- }
- cc_library_shared {
- name: "libfoo_shared",
- export_include_dirs: ["shared_include"],
- }
- cc_library_static {
- name: "libfoo_static",
- export_include_dirs: ["static_include"],
- }
- `)
- // Check that libprotobuf is added as a dependency.
- librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Module().(*Module)
- if !android.InList("libprotobuf_deprecated", librust_proto.Properties.AndroidMkDylibs) {
- t.Errorf("libprotobuf_deprecated dependency missing for rust_protobuf (dependency missing from AndroidMkDylibs)")
- }
-
- // Make sure the correct plugin is being used.
- librust_proto_out := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Output("buf.rs")
- cmd := librust_proto_out.RuleParams.Command
- if w := "protoc-gen-rust-deprecated"; !strings.Contains(cmd, w) {
- t.Errorf("expected %q in %q", w, cmd)
- }
-
- // Check exported include directories
- if w := "-Ishared_include"; !strings.Contains(cmd, w) {
- t.Errorf("expected %q in %q", w, cmd)
- }
- if w := "-Istatic_include"; !strings.Contains(cmd, w) {
- t.Errorf("expected %q in %q", w, cmd)
- }
-
- // Check proto.rs, the second protobuf, is listed as an output
- librust_proto_outputs := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").AllOutputs()
- if android.InList("proto.rs", librust_proto_outputs) {
- t.Errorf("rust_protobuf is not producing multiple outputs; expected 'proto.rs' in list, got: %#v ",
- librust_proto_outputs)
- }
-}
-
func TestRustProtobuf3(t *testing.T) {
ctx := testRust(t, `
rust_protobuf {
@@ -76,7 +28,6 @@
protos: ["buf.proto", "proto.proto"],
crate_name: "rust_proto",
source_stem: "buf",
- use_protobuf3: true,
shared_libs: ["libfoo_shared"],
static_libs: ["libfoo_static"],
}
@@ -125,7 +76,6 @@
protos: ["proto.proto"],
crate_name: "rust_proto",
source_stem: "proto",
- use_protobuf3: true,
rustlibs: ["librust_exported_proto", "libfoo"],
}
rust_protobuf {
@@ -133,7 +83,6 @@
protos: ["proto.proto"],
crate_name: "rust_exported_proto",
source_stem: "exported_proto",
- use_protobuf3: true,
exported_include_dirs: ["proto"]
}
rust_library {
diff --git a/rust/rust.go b/rust/rust.go
index 02ec22d..34ce4c5 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -20,10 +20,10 @@
"android/soong/bloaty"
"android/soong/testing"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
- "android/soong/aconfig"
"android/soong/android"
"android/soong/cc"
cc_config "android/soong/cc/config"
@@ -70,9 +70,9 @@
AndroidMkProcMacroLibs []string `blueprint:"mutated"`
AndroidMkStaticLibs []string `blueprint:"mutated"`
- ImageVariationPrefix string `blueprint:"mutated"`
- VndkVersion string `blueprint:"mutated"`
- SubName string `blueprint:"mutated"`
+ ImageVariation string `blueprint:"mutated"`
+ VndkVersion string `blueprint:"mutated"`
+ SubName string `blueprint:"mutated"`
// SubName is used by CC for tracking image variants / SDK versions. RustSubName is used for Rust-specific
// subnaming which shouldn't be visible to CC modules (such as the rlib stdlinkage subname). This should be
@@ -509,7 +509,7 @@
}
func (flagExporter *flagExporter) setProvider(ctx ModuleContext) {
- ctx.SetProvider(FlagExporterInfoProvider, FlagExporterInfo{
+ android.SetProvider(ctx, FlagExporterInfoProvider, FlagExporterInfo{
LinkDirs: flagExporter.linkDirs,
LinkObjects: flagExporter.linkObjects,
})
@@ -527,7 +527,7 @@
LinkObjects []string // TODO: this should be android.Paths
}
-var FlagExporterInfoProvider = blueprint.NewProvider(FlagExporterInfo{})
+var FlagExporterInfoProvider = blueprint.NewProvider[FlagExporterInfo]()
func (mod *Module) isCoverageVariant() bool {
return mod.coverage.Properties.IsCoverageVariant
@@ -747,7 +747,8 @@
}
func (ctx moduleContext) apexVariationName() string {
- return ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).ApexVariationName
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+ return apexInfo.ApexVariationName
}
var _ cc.LinkableInterface = (*Module)(nil)
@@ -897,7 +898,7 @@
ModuleContext: actx,
}
- apexInfo := actx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.ModuleProvider(actx, android.ApexInfoProvider)
if !apexInfo.IsForPlatform() {
mod.hideApexVariantFromMake = true
}
@@ -950,7 +951,7 @@
sourceLib := sourceMod.(*Module).compiler.(*libraryDecorator)
mod.sourceProvider.setOutputFiles(sourceLib.sourceProvider.Srcs())
}
- ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: mod.sourceProvider.Srcs().Strings()})
+ android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: mod.sourceProvider.Srcs().Strings()})
}
if mod.compiler != nil && !mod.compiler.Disabled() {
@@ -978,7 +979,7 @@
}
}
- apexInfo := actx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.ModuleProvider(actx, android.ApexInfoProvider)
if !proptools.BoolDefault(mod.Installable(), mod.EverInstallable()) && !mod.ProcMacro() {
// If the module has been specifically configure to not be installed then
// hide from make as otherwise it will break when running inside make as the
@@ -1003,10 +1004,10 @@
ctx.Phony("rust", ctx.RustModule().OutputFile().Path())
}
if mod.testModule {
- ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+ android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
}
- aconfig.CollectDependencyAconfigFiles(ctx, &mod.mergedAconfigFiles)
+ android.CollectDependencyAconfigFiles(ctx, &mod.mergedAconfigFiles)
}
func (mod *Module) deps(ctx DepsContext) Deps {
@@ -1148,7 +1149,7 @@
// For the dependency from platform to apex, use the latest stubs
mod.apexSdkVersion = android.FutureApiLevel
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
if !apexInfo.IsForPlatform() {
mod.apexSdkVersion = apexInfo.MinSdkVersion
}
@@ -1167,7 +1168,7 @@
ctx.VisitDirectDeps(func(dep android.Module) {
if dep.Name() == "api_imports" {
- apiImportInfo = ctx.OtherModuleProvider(dep, multitree.ApiImportsProvider).(multitree.ApiImportInfo)
+ apiImportInfo, _ = android.OtherModuleProvider(ctx, dep, multitree.ApiImportsProvider)
hasApiImportInfo = true
}
})
@@ -1278,7 +1279,7 @@
//Append the dependencies exportedDirs, except for proc-macros which target a different arch/OS
if depTag != procMacroDepTag {
- exportedInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo)
+ exportedInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider)
depPaths.linkDirs = append(depPaths.linkDirs, exportedInfo.LinkDirs...)
depPaths.depFlags = append(depPaths.depFlags, exportedInfo.Flags...)
depPaths.linkObjects = append(depPaths.linkObjects, exportedInfo.LinkObjects...)
@@ -1294,7 +1295,7 @@
if depTag == sourceDepTag {
if _, ok := mod.sourceProvider.(*protobufDecorator); ok && mod.Source() {
if _, ok := rustDep.sourceProvider.(*protobufDecorator); ok {
- exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo)
+ exportedInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider)
depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
}
}
@@ -1347,7 +1348,7 @@
depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
- exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo)
+ exportedInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider)
depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...)
depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...)
@@ -1391,7 +1392,7 @@
directAndroidMkSharedLibs = append(directAndroidMkSharedLibs, makeLibName)
exportDep = true
case cc.IsHeaderDepTag(depTag):
- exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo)
+ exportedInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider)
depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...)
depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, exportedInfo.GeneratedHeaders...)
diff --git a/rust/sanitize.go b/rust/sanitize.go
index 0b10435..9dda43f 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -270,7 +270,7 @@
}
// If we're using snapshots, redirect to snapshot whenever possible
// TODO(b/178470649): clean manual snapshot redirections
- snapshot := mctx.Provider(cc.SnapshotInfoProvider).(cc.SnapshotInfo)
+ snapshot, _ := android.ModuleProvider(mctx, cc.SnapshotInfoProvider)
if lib, ok := snapshot.StaticLibs[noteDep]; ok {
noteDep = lib
}
diff --git a/rust/testing.go b/rust/testing.go
index 3fe751e..0b34c97 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -133,12 +133,6 @@
host_supported: true,
}
rust_library {
- name: "libprotobuf_deprecated",
- crate_name: "protobuf",
- srcs: ["foo.rs"],
- host_supported: true,
- }
- rust_library {
name: "libgrpcio",
crate_name: "grpcio",
srcs: ["foo.rs"],
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 97f6ab4..7baaadb 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -254,3 +254,8 @@
"modify_permissions_allowlist.py",
],
}
+
+sh_binary_host {
+ name: "keep-flagged-apis",
+ src: "keep-flagged-apis.sh",
+}
diff --git a/scripts/keep-flagged-apis.sh b/scripts/keep-flagged-apis.sh
new file mode 100755
index 0000000..9c48fdb
--- /dev/null
+++ b/scripts/keep-flagged-apis.sh
@@ -0,0 +1,46 @@
+#!/bin/bash -e
+#
+# 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.
+
+# Convert a list of flags in the input file to a list of metalava options
+# that will keep the APIs for those flags will hiding all other flagged
+# APIs.
+
+FLAGS="$1"
+
+FLAGGED="android.annotation.FlaggedApi"
+
+# Convert the list of feature flags in the input file to Metalava options
+# of the form `--revert-annotation !android.annotation.FlaggedApi("<flag>")`
+# to prevent the annotated APIs from being hidden, i.e. include the annotated
+# APIs in the SDK snapshots. This also preserves the line comments, they will
+# be ignored by Metalava but might be useful when debugging.
+while read -r line; do
+ key=$(echo "$line" | cut -d= -f1)
+ value=$(echo "$line" | cut -d= -f2)
+
+ # Skip if value is not true and line does not start with '#'
+ if [[ ( $value != "true" ) && ( $line =~ ^[^#] )]]; then
+ continue
+ fi
+
+ # Escape and quote the key for sed
+ escaped_key=$(echo "$key" | sed "s/'/\\\'/g; s/ /\\ /g")
+
+ echo $line | sed "s|^[^#].*$|--revert-annotation '!$FLAGGED(\"$escaped_key\")'|"
+done < "$FLAGS"
+
+# Revert all flagged APIs, unless listed above.
+echo "--revert-annotation $FLAGGED"
diff --git a/sdk/Android.bp b/sdk/Android.bp
index f42b478..f436320 100644
--- a/sdk/Android.bp
+++ b/sdk/Android.bp
@@ -18,6 +18,7 @@
"bp.go",
"build_release.go",
"exports.go",
+ "genrule.go",
"member_trait.go",
"member_type.go",
"sdk.go",
@@ -30,6 +31,7 @@
"cc_sdk_test.go",
"compat_config_sdk_test.go",
"exports_test.go",
+ "genrule_test.go",
"java_sdk_test.go",
"license_sdk_test.go",
"member_trait_test.go",
diff --git a/sdk/genrule.go b/sdk/genrule.go
new file mode 100644
index 0000000..347ab05
--- /dev/null
+++ b/sdk/genrule.go
@@ -0,0 +1,44 @@
+// 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 sdk
+
+import (
+ "android/soong/android"
+ "android/soong/genrule"
+)
+
+func init() {
+ registerGenRuleBuildComponents(android.InitRegistrationContext)
+}
+
+func registerGenRuleBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("sdk_genrule", SdkGenruleFactory)
+}
+
+// sdk_genrule_host is a genrule that can depend on sdk and sdk_snapshot module types
+//
+// What this means is that it's a genrule with only the "common_os" variant.
+// sdk modules have 3 variants: host, android, and common_os. The common_os one depends
+// on the host/device ones and packages their result into a final snapshot zip.
+// Genrules probably want access to this snapshot zip when they depend on an sdk module,
+// which means they want to depend on the common_os variant and not the host/android
+// variants.
+func SdkGenruleFactory() android.Module {
+ module := genrule.NewGenRule()
+
+ android.InitCommonOSAndroidMultiTargetsArchModule(module, android.NeitherHostNorDeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+
+ return module
+}
diff --git a/sdk/genrule_test.go b/sdk/genrule_test.go
new file mode 100644
index 0000000..6e52a3d
--- /dev/null
+++ b/sdk/genrule_test.go
@@ -0,0 +1,52 @@
+// Copyright 2018 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 sdk
+
+import (
+ "testing"
+
+ "android/soong/android"
+ "android/soong/genrule"
+ "android/soong/java"
+)
+
+func TestSdkGenrule(t *testing.T) {
+ // Test that an sdk_genrule can depend on an sdk, and that a genrule can depend on an sdk_genrule
+ bp := `
+ sdk {
+ name: "my_sdk",
+ }
+ sdk_genrule {
+ name: "my_sdk_genrule",
+ tool_files: ["tool"],
+ cmd: "$(location tool) $(in) $(out)",
+ srcs: [":my_sdk"],
+ out: ["out"],
+ }
+ genrule {
+ name: "my_regular_genrule",
+ srcs: [":my_sdk_genrule"],
+ out: ["out"],
+ cmd: "cp $(in) $(out)",
+ }
+ `
+ android.GroupFixturePreparers(
+ // if java components aren't registered, the sdk module doesn't create a snapshot for some reason.
+ java.PrepareForTestWithJavaBuildComponents,
+ genrule.PrepareForTestWithGenRuleBuildComponents,
+ PrepareForTestWithSdkBuildComponents,
+ android.FixtureRegisterWithContext(registerGenRuleBuildComponents),
+ ).RunTestWithBp(t, bp)
+}
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 4d4a2a2..fd16ab6 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -222,6 +222,18 @@
}}
}
+func (s *sdk) OutputFiles(tag string) (android.Paths, error) {
+ switch tag {
+ case "":
+ if s.snapshotFile.Valid() {
+ return []android.Path{s.snapshotFile.Path()}, nil
+ }
+ return nil, fmt.Errorf("snapshot file not defined. This is most likely because this isn't the common_os variant of this module")
+ default:
+ return nil, fmt.Errorf("unknown tag %q", tag)
+ }
+}
+
// gatherTraits gathers the traits from the dynamically generated trait specific properties.
//
// Returns a map from member name to the set of required traits.
diff --git a/sdk/update.go b/sdk/update.go
index 4c39fae..095e0c2 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -166,10 +166,7 @@
// Keep track of which multilib variants are used by the sdk.
s.multilibUsages = s.multilibUsages.addArchType(child.Target().Arch.ArchType)
- var exportedComponentsInfo android.ExportedComponentsInfo
- if ctx.OtherModuleHasProvider(child, android.ExportedComponentsInfoProvider) {
- exportedComponentsInfo = ctx.OtherModuleProvider(child, android.ExportedComponentsInfoProvider).(android.ExportedComponentsInfo)
- }
+ exportedComponentsInfo, _ := android.OtherModuleProvider(ctx, child, android.ExportedComponentsInfoProvider)
var container android.Module
if parent != ctx.Module() {
@@ -607,7 +604,7 @@
name: name,
}
- additionalSdkInfo := ctx.OtherModuleProvider(module, android.AdditionalSdkInfoProvider).(android.AdditionalSdkInfo)
+ additionalSdkInfo, _ := android.OtherModuleProvider(ctx, module, android.AdditionalSdkInfoProvider)
info.memberSpecific = additionalSdkInfo.Properties
name2Info[name] = info
@@ -1171,7 +1168,7 @@
// The licenses are the same for all variants.
mctx := s.ctx
- licenseInfo := mctx.OtherModuleProvider(variant, android.LicenseInfoProvider).(android.LicenseInfo)
+ licenseInfo, _ := android.OtherModuleProvider(mctx, variant, android.LicenseInfoProvider)
if len(licenseInfo.Licenses) > 0 {
m.AddPropertyWithTag("licenses", licenseInfo.Licenses, s.OptionalSdkMemberReferencePropertyTag())
}
@@ -1417,7 +1414,7 @@
variantsByApex := make(map[string]android.Module)
conflictDetected := false
for _, variant := range list {
- apexInfo := moduleCtx.OtherModuleProvider(variant, android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.OtherModuleProvider(moduleCtx, variant, android.ApexInfoProvider)
apexVariationName := apexInfo.ApexVariationName
// If there are two variants for a specific APEX variation then there is conflict.
if _, ok := variantsByApex[apexVariationName]; ok {
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 1e27375..97adeed 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -270,7 +270,7 @@
Output: s.outputFilePath,
Input: s.sourceFilePath,
})
- ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: []string{s.sourceFilePath.String()}})
+ android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: []string{s.sourceFilePath.String()}})
}
func (s *ShBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -457,7 +457,7 @@
installedData := ctx.InstallTestData(s.installDir, s.data)
s.installedFile = ctx.InstallExecutable(s.installDir, s.outputFilePath.Base(), s.outputFilePath, installedData...)
- ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+ android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
}
func (s *ShTest) InstallInData() bool {
diff --git a/snapshot/host_fake_snapshot.go b/snapshot/host_fake_snapshot.go
index c4cfbb5..63cd4e1 100644
--- a/snapshot/host_fake_snapshot.go
+++ b/snapshot/host_fake_snapshot.go
@@ -119,7 +119,7 @@
if !module.Enabled() || module.IsHideFromMake() {
return
}
- apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+ apexInfo, _ := android.SingletonModuleProvider(ctx, module, android.ApexInfoProvider)
if !apexInfo.IsForPlatform() {
return
}
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index c89c6b0..4a0796b 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -251,7 +251,7 @@
ctx.PropertyErrorf("srcs", "srcs contains non-sysprop file %q", syspropFile.String())
}
}
- ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
+ android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
if ctx.Failed() {
return
diff --git a/testing/all_code_metadata.go b/testing/all_code_metadata.go
index 16d7aae..12aa7b5 100644
--- a/testing/all_code_metadata.go
+++ b/testing/all_code_metadata.go
@@ -21,14 +21,9 @@
ctx.VisitAllModules(
func(module android.Module) {
- if !ctx.ModuleHasProvider(module, CodeMetadataProviderKey) {
- return
+ if metadata, ok := android.SingletonModuleProvider(ctx, module, CodeMetadataProviderKey); ok {
+ intermediateMetadataPaths = append(intermediateMetadataPaths, metadata.IntermediatePath)
}
- intermediateMetadataPaths = append(
- intermediateMetadataPaths, ctx.ModuleProvider(
- module, CodeMetadataProviderKey,
- ).(CodeMetadataProviderData).IntermediatePath,
- )
},
)
diff --git a/testing/all_test_specs.go b/testing/all_test_specs.go
index 9d4645b..b035435 100644
--- a/testing/all_test_specs.go
+++ b/testing/all_test_specs.go
@@ -21,10 +21,9 @@
var intermediateMetadataPaths android.Paths
ctx.VisitAllModules(func(module android.Module) {
- if !ctx.ModuleHasProvider(module, TestSpecProviderKey) {
- return
+ if metadata, ok := android.SingletonModuleProvider(ctx, module, TestSpecProviderKey); ok {
+ intermediateMetadataPaths = append(intermediateMetadataPaths, metadata.IntermediatePath)
}
- intermediateMetadataPaths = append(intermediateMetadataPaths, ctx.ModuleProvider(module, TestSpecProviderKey).(TestSpecProviderData).IntermediatePath)
})
rspFile := android.PathForOutput(ctx, fileContainingFilePaths)
diff --git a/testing/code_metadata.go b/testing/code_metadata.go
index 9e20ec6..11ba430 100644
--- a/testing/code_metadata.go
+++ b/testing/code_metadata.go
@@ -20,6 +20,7 @@
"android/soong/android"
"android/soong/testing/code_metadata_internal_proto"
"github.com/google/blueprint"
+
"google.golang.org/protobuf/proto"
)
@@ -83,7 +84,7 @@
IntermediatePath android.WritablePath
}
-var CodeMetadataProviderKey = blueprint.NewProvider(CodeMetadataProviderData{})
+var CodeMetadataProviderKey = blueprint.NewProvider[CodeMetadataProviderData]()
func (module *CodeMetadataModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
metadataList := make(
@@ -95,10 +96,8 @@
for _, m := range ctx.GetDirectDepsWithTag(codeDepTag) {
targetName := m.Name()
var moduleSrcs []string
- if ctx.OtherModuleHasProvider(m, blueprint.SrcsFileProviderKey) {
- moduleSrcs = ctx.OtherModuleProvider(
- m, blueprint.SrcsFileProviderKey,
- ).(blueprint.SrcsFileProviderData).SrcPaths
+ if srcsFileInfo, ok := android.OtherModuleProvider(ctx, m, blueprint.SrcsFileProviderKey); ok {
+ moduleSrcs = srcsFileInfo.SrcPaths
}
if module.properties.MultiOwnership {
metadata := &code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership{
@@ -129,9 +128,9 @@
intermediatePath := android.PathForModuleOut(
ctx, "intermediateCodeMetadata.pb",
)
- android.WriteFileRule(ctx, intermediatePath, string(protoData))
+ android.WriteFileRuleVerbatim(ctx, intermediatePath, string(protoData))
- ctx.SetProvider(
+ android.SetProvider(ctx,
CodeMetadataProviderKey,
CodeMetadataProviderData{IntermediatePath: intermediatePath},
)
diff --git a/testing/test_spec.go b/testing/test_spec.go
index 58d9c23..4d885c6 100644
--- a/testing/test_spec.go
+++ b/testing/test_spec.go
@@ -20,8 +20,9 @@
"android/soong/android"
"android/soong/testing/test_spec_proto"
- "github.com/google/blueprint"
"google.golang.org/protobuf/proto"
+
+ "github.com/google/blueprint"
)
// ErrTestModuleDataNotFound is the error message for missing test module provider data.
@@ -81,16 +82,16 @@
IntermediatePath android.WritablePath
}
-var TestSpecProviderKey = blueprint.NewProvider(TestSpecProviderData{})
+var TestSpecProviderKey = blueprint.NewProvider[TestSpecProviderData]()
type TestModuleProviderData struct {
}
-var TestModuleProviderKey = blueprint.NewProvider(TestModuleProviderData{})
+var TestModuleProviderKey = blueprint.NewProvider[TestModuleProviderData]()
func (module *TestSpecModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
for _, m := range ctx.GetDirectDepsWithTag(testsDepTag) {
- if !ctx.OtherModuleHasProvider(m, TestModuleProviderKey) {
+ if _, ok := android.OtherModuleProvider(ctx, m, TestModuleProviderKey); !ok {
ctx.ModuleErrorf(ErrTestModuleDataNotFound, m.Name())
}
}
@@ -116,9 +117,9 @@
if err != nil {
ctx.ModuleErrorf("Error: %s", err.Error())
}
- android.WriteFileRule(ctx, intermediatePath, string(protoData))
+ android.WriteFileRuleVerbatim(ctx, intermediatePath, string(protoData))
- ctx.SetProvider(
+ android.SetProvider(ctx,
TestSpecProviderKey, TestSpecProviderData{
IntermediatePath: intermediatePath,
},
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index 21453ba..ee286f6 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -35,6 +35,7 @@
"blueprint",
"blueprint-bootstrap",
"blueprint-microfactory",
+ "soong-android",
"soong-finder",
"soong-remoteexec",
"soong-shared",
@@ -46,6 +47,7 @@
"soong-ui-tracer",
],
srcs: [
+ "androidmk_denylist.go",
"build.go",
"cleanbuild.go",
"config.go",
diff --git a/ui/build/androidmk_denylist.go b/ui/build/androidmk_denylist.go
new file mode 100644
index 0000000..b2266b2
--- /dev/null
+++ b/ui/build/androidmk_denylist.go
@@ -0,0 +1,44 @@
+// 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 build
+
+import (
+ "strings"
+
+ "android/soong/android"
+)
+
+var androidmk_denylist []string = []string{
+ "chained_build_config/",
+ "cts/",
+ "dalvik/",
+ "developers/",
+ "kernel/",
+ "libcore/",
+ "libnativehelper/",
+ "pdk/",
+ "toolchain/",
+}
+
+func blockAndroidMks(androidMks []string) []string {
+ return android.FilterListPred(androidMks, func(s string) bool {
+ for _, d := range androidmk_denylist {
+ if strings.HasPrefix(s, d) {
+ return false
+ }
+ }
+ return true
+ })
+}
diff --git a/ui/build/finder.go b/ui/build/finder.go
index d0bcf40..a114079 100644
--- a/ui/build/finder.go
+++ b/ui/build/finder.go
@@ -128,6 +128,7 @@
// Stop searching a subdirectory recursively after finding an Android.mk.
androidMks := f.FindFirstNamedAt(".", "Android.mk")
+ androidMks = blockAndroidMks(androidMks)
err := dumpListToFile(ctx, config, androidMks, filepath.Join(dumpDir, "Android.mk.list"))
if err != nil {
ctx.Fatalf("Could not export module list: %v", err)
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 0bf8862..90c3bfc 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -36,6 +36,7 @@
"github.com/google/blueprint"
"github.com/google/blueprint/bootstrap"
"github.com/google/blueprint/microfactory"
+ "github.com/google/blueprint/pathtools"
"google.golang.org/protobuf/proto"
)
@@ -181,7 +182,15 @@
return globPathName
}
-func (pb PrimaryBuilderFactory) primaryBuilderInvocation() bootstrap.PrimaryBuilderInvocation {
+func getGlobPathNameFromPrimaryBuilderFactory(config Config, pb PrimaryBuilderFactory) string {
+ if pb.name == soongBuildTag {
+ // Glob path for soong build would be separated per product target
+ return getGlobPathName(config)
+ }
+ return pb.name
+}
+
+func (pb PrimaryBuilderFactory) primaryBuilderInvocation(config Config) bootstrap.PrimaryBuilderInvocation {
commonArgs := make([]string, 0, 0)
if !pb.config.skipSoongTests {
@@ -215,11 +224,7 @@
var allArgs []string
allArgs = append(allArgs, pb.specificArgs...)
- globPathName := pb.name
- // Glob path for soong build would be separated per product target
- if pb.name == soongBuildTag {
- globPathName = getGlobPathName(pb.config)
- }
+ globPathName := getGlobPathNameFromPrimaryBuilderFactory(config, pb)
allArgs = append(allArgs,
"--globListDir", globPathName,
"--globFile", pb.config.NamedGlobFile(globPathName))
@@ -234,8 +239,11 @@
}
allArgs = append(allArgs, "Android.bp")
+ globfiles := bootstrap.GlobFileListFiles(bootstrap.GlobDirectory(config.SoongOutDir(), globPathName))
+
return bootstrap.PrimaryBuilderInvocation{
Inputs: []string{"Android.bp"},
+ Implicits: globfiles,
Outputs: []string{pb.output},
Args: allArgs,
Description: pb.description,
@@ -376,17 +384,10 @@
if debuggedInvocations[pbf.name] {
pbf.debugPort = delvePort
}
- pbi := pbf.primaryBuilderInvocation()
+ pbi := pbf.primaryBuilderInvocation(config)
invocations = append(invocations, pbi)
}
- // The glob .ninja files are subninja'd. However, they are generated during
- // the build itself so we write an empty file if the file does not exist yet
- // so that the subninja doesn't fail on clean builds
- for _, globFile := range bootstrapGlobFileList(config) {
- writeEmptyFile(ctx, globFile)
- }
-
blueprintArgs := bootstrap.Args{
ModuleListFile: filepath.Join(config.FileListDir(), "Android.bp.list"),
OutFile: shared.JoinPath(config.SoongOutDir(), "bootstrap.ninja"),
@@ -408,6 +409,28 @@
primaryBuilderInvocations: invocations,
}
+ // The glob ninja files are generated during the main build phase. However, the
+ // primary buildifer invocation depends on all of its glob files, even before
+ // it's been run. Generate a "empty" glob ninja file on the first run,
+ // so that the files can be there to satisfy the dependency.
+ for _, pb := range pbfs {
+ globPathName := getGlobPathNameFromPrimaryBuilderFactory(config, pb)
+ globNinjaFile := config.NamedGlobFile(globPathName)
+ if _, err := os.Stat(globNinjaFile); os.IsNotExist(err) {
+ err := bootstrap.WriteBuildGlobsNinjaFile(&bootstrap.GlobSingleton{
+ GlobLister: func() pathtools.MultipleGlobResults { return nil },
+ GlobFile: globNinjaFile,
+ GlobDir: bootstrap.GlobDirectory(config.SoongOutDir(), globPathName),
+ SrcDir: ".",
+ }, blueprintConfig)
+ if err != nil {
+ ctx.Fatal(err)
+ }
+ } else if err != nil {
+ ctx.Fatal(err)
+ }
+ }
+
// since `bootstrap.ninja` is regenerated unconditionally, we ignore the deps, i.e. little
// reason to write a `bootstrap.ninja.d` file
_, err := bootstrap.RunBlueprint(blueprintArgs, bootstrap.DoEverything, blueprintCtx, blueprintConfig)
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index c5dc4c5..3095139 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -63,6 +63,7 @@
outDir := config.OutDir()
modulePathsDir := filepath.Join(outDir, ".module_paths")
+ rawFilesDir := filepath.Join(outDir, "soong", "raw")
variablesFilePath := filepath.Join(outDir, "soong", "soong.variables")
// dexpreopt.config is an input to the soong_docs action, which runs the
@@ -88,6 +89,7 @@
continue
}
if strings.HasPrefix(line, modulePathsDir) ||
+ strings.HasPrefix(line, rawFilesDir) ||
line == variablesFilePath ||
line == dexpreoptConfigFilePath ||
line == buildDatetimeFilePath ||
diff --git a/ui/terminal/format.go b/ui/terminal/format.go
index 5391023..241a1dd 100644
--- a/ui/terminal/format.go
+++ b/ui/terminal/format.go
@@ -25,7 +25,6 @@
type formatter struct {
format string
quiet bool
- smart bool
start time.Time
}
@@ -33,11 +32,10 @@
// the terminal in a format similar to Ninja.
// format takes nearly all the same options as NINJA_STATUS.
// %c is currently unsupported.
-func newFormatter(format string, quiet bool, smart bool) formatter {
+func newFormatter(format string, quiet bool) formatter {
return formatter{
format: format,
quiet: quiet,
- smart: smart,
start: time.Now(),
}
}
@@ -63,9 +61,8 @@
func (s formatter) progress(counts status.Counts) string {
if s.format == "" {
output := fmt.Sprintf("[%3d%% %d/%d", 100*counts.FinishedActions/counts.TotalActions, counts.FinishedActions, counts.TotalActions)
- // Not to break parsing logic in the build bot
- // TODO(b/313981966): make buildbot more flexible for output format
- if s.smart && !counts.EstimatedTime.IsZero() {
+
+ if !counts.EstimatedTime.IsZero() {
output += fmt.Sprintf(" %s remaining", remainingTimeString(counts.EstimatedTime))
}
output += "] "
diff --git a/ui/terminal/status.go b/ui/terminal/status.go
index 810e3c9..2ad174f 100644
--- a/ui/terminal/status.go
+++ b/ui/terminal/status.go
@@ -27,10 +27,9 @@
// statusFormat takes nearly all the same options as NINJA_STATUS.
// %c is currently unsupported.
func NewStatusOutput(w io.Writer, statusFormat string, forceSimpleOutput, quietBuild, forceKeepANSI bool) status.StatusOutput {
- useSmartStatus := !forceSimpleOutput && isSmartTerminal(w)
- formatter := newFormatter(statusFormat, quietBuild, useSmartStatus)
+ formatter := newFormatter(statusFormat, quietBuild)
- if useSmartStatus {
+ if !forceSimpleOutput && isSmartTerminal(w) {
return NewSmartStatusOutput(w, formatter)
} else {
return NewSimpleStatusOutput(w, formatter, forceKeepANSI)