Android 15.0.0 Release 6 (AP4A.241205.013)
-----BEGIN PGP SIGNATURE----- iF0EABECAB0WIQRDQNE1cO+UXoOBCWTorT+BmrEOeAUCZ1IssQAKCRDorT+BmrEO eICmAJ4ucooPI46WmQPpM0P59O1mMg6tTQCeN/GI0UvgsQkpgB52QWP9VGXeRg8= =mAzQ -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQJLBAABCgA1FiEEHrBYPudH862glXQBzJUERRm+ZmkFAmdYixgXHG1rYmVzdGFz QGxpbmVhZ2Vvcy5vcmcACgkQzJUERRm+ZmntQQ/+OQD/4KTpBaQOM+hYmZv2al28 wZ2EDbuGZcdUIj9o6kgl2x5DJGv7AJ3tZZ5/WKTvAsxVkZ4oISMrR6WkE/kysIaV HGiX3JaM8t1bdAbD6HGq7I4KwS2UUTdUJMc9TUSQkT74QwAfhwAwxVM6Yw9CxQUG V5nLtYhDj3un9Xb1amiJaV3Mof+Nw/q0d1A3kpc1qH2Ul56f4COnAysa1GPiDrB3 eHssxIrAhf5+E3Vk5rN+sdoWTVLa9JdOGx4pSQNBnkBwT2HD8FpysVVN4L9DvwwN pG6U7pNN5uzPZ1HyQT8D71Y0tDRaX/mT38doPoa0u1shmiBBbMU87vl2woiEAATQ 0UHI/ZcY9Q8yX1iA08a6raK7VAedxmierfNMTtp2nyMJmoTe818u/WVAYfFYrjYZ i5bM0PtAANnQ/6elWC4C57usyLuPcUg4C7cKqPfXerfopEsi8e1v/wHjjyeQhCIK xSk11uwD26CgBxkitktn6dySmVhapnqEM53/1bQ8OWcxhlRQjE5019/SpNYysVzD Q8ef4Xu2on6NlwfNmicKymvOvIbugnKhl6i4iK9UKMaKmZ/cArpk0/OWu3yHy5OK 9AZozQHwbF2kwZLHakK9QSxtwgiRBhqLGttu3tsf1+4NDuuCTlj25BwcJgXoF5+7 Wn7EaVThxf3pkDrYNcE= =6ce+ -----END PGP SIGNATURE----- Merge tag 'android-15.0.0_r6' into staging/lineage-22.0_merge-android-15.0.0_r6 Android 15.0.0 Release 6 (AP4A.241205.013) # -----BEGIN PGP SIGNATURE----- # # iF0EABECAB0WIQRDQNE1cO+UXoOBCWTorT+BmrEOeAUCZ1IssQAKCRDorT+BmrEO # eICmAJ4ucooPI46WmQPpM0P59O1mMg6tTQCeN/GI0UvgsQkpgB52QWP9VGXeRg8= # =mAzQ # -----END PGP SIGNATURE----- # gpg: Signature made Fri Dec 6 00:44:01 2024 EET # gpg: using DSA key 4340D13570EF945E83810964E8AD3F819AB10E78 # gpg: Good signature from "The Android Open Source Project <initial-contribution@android.com>" [marginal] # gpg: initial-contribution@android.com: Verified 2457 signatures in the past # 3 years. Encrypted 4 messages in the past 2 years. # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 4340 D135 70EF 945E 8381 0964 E8AD 3F81 9AB1 0E78 # By Spandan Das (55) and others # Via Automerger Merge Worker (1031) and others * tag 'android-15.0.0_r6': (554 commits) Revert^3 "Use -target-feature for MTE" Enforce exclusive release config component directories Possible fix for stat error during globbing Remove `prebuilt_apex_module_creator` mutator Revert "pass read new storage parameter to java codegen" Temporarily bypass apex availability check for /product apexes with a specific prefix Remove the internal extractor module created by apex_set Remove the internal selector module created by prebuilt_apex pass read new storage parameter to java codegen Add an incremental parity test. Remove internal deapexer module Remove deapex support from java_*_import Revert^2 "Remove java_sdk_library "magic"" Revert^2 "Restrict java_sdk_library in libs of java_import and droidstubs modules" Revert^2 "Restrict java_sdk_library in libs" Revert "Remove java_sdk_library "magic"" Revert "Restrict java_sdk_library in libs of java_import and dro..." Revert "Restrict java_sdk_library in libs" Fixes host_required_modules for test_module_config Add some log to the build action caching test. ... Conflicts: android/Android.bp android/androidmk.go android/config.go android/defaults.go android/module.go android/module_context.go android/neverallow.go android/product_config.go android/sdk.go android/variable.go apex/apex.go cc/binary_sdk_member.go cc/cc.go cc/compiler.go cc/library.go cc/library_sdk_member.go cc/linker.go cc/object.go java/java.go scripts/gen_build_prop.py snapshot/host_fake_snapshot.go snapshot/host_snapshot.go Change-Id: I036e0ef3652f680f194dcf11e5a36844bd527221
This commit is contained in:
commit
fc5575a537
393 changed files with 17208 additions and 13622 deletions
14
Android.bp
14
Android.bp
|
|
@ -1,5 +1,8 @@
|
|||
package {
|
||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
||||
default_visibility: [
|
||||
"//build/soong:__subpackages__",
|
||||
],
|
||||
}
|
||||
|
||||
subdirs = [
|
||||
|
|
@ -23,6 +26,8 @@ bootstrap_go_package {
|
|||
srcs: [
|
||||
"doc.go",
|
||||
],
|
||||
// Used by plugins, though probably shouldn't be.
|
||||
visibility: ["//visibility:public"],
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -40,6 +45,7 @@ cc_defaults {
|
|||
enabled: true,
|
||||
},
|
||||
},
|
||||
defaults_visibility: ["//visibility:public"],
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -51,6 +57,7 @@ kernel_headers {
|
|||
vendor: true,
|
||||
recovery_available: true,
|
||||
min_sdk_version: "apex_inherit",
|
||||
visibility: ["//visibility:public"],
|
||||
}
|
||||
|
||||
cc_genrule {
|
||||
|
|
@ -75,6 +82,7 @@ cc_genrule {
|
|||
cmd: "$(location) -s $(out) $(in)",
|
||||
srcs: [":linker"],
|
||||
out: ["linker.s"],
|
||||
visibility: ["//bionic/libc"],
|
||||
}
|
||||
|
||||
cc_genrule {
|
||||
|
|
@ -99,12 +107,13 @@ cc_genrule {
|
|||
cmd: "$(location) -T $(out) $(in)",
|
||||
srcs: [":linker"],
|
||||
out: ["linker.script"],
|
||||
visibility: ["//visibility:public"],
|
||||
}
|
||||
|
||||
// Instantiate the dex_bootjars singleton module.
|
||||
dex_bootjars {
|
||||
name: "dex_bootjars",
|
||||
no_full_install: true,
|
||||
visibility: ["//visibility:public"],
|
||||
}
|
||||
|
||||
// Pseudo-test that's run on checkbuilds to ensure that get_clang_version can
|
||||
|
|
@ -124,6 +133,7 @@ dexpreopt_systemserver_check {
|
|||
// container for apex_contributions selected using build flags
|
||||
all_apex_contributions {
|
||||
name: "all_apex_contributions",
|
||||
visibility: ["//visibility:public"],
|
||||
}
|
||||
|
||||
product_config {
|
||||
|
|
@ -138,7 +148,7 @@ build_prop {
|
|||
// Currently, only microdroid and cf system image can refer to system-build.prop
|
||||
visibility: [
|
||||
"//device/google/cuttlefish/system_image",
|
||||
"//packages/modules/Virtualization/microdroid",
|
||||
"//packages/modules/Virtualization/build/microdroid",
|
||||
],
|
||||
}
|
||||
|
||||
|
|
|
|||
14
README.md
14
README.md
|
|
@ -594,19 +594,13 @@ modules (`cc_defaults`, `java_defaults`, etc.), which can then be referenced
|
|||
by all of the vendor's other modules using the normal namespace and visibility
|
||||
rules.
|
||||
|
||||
`soongConfigTraceMutator` enables modules affected by soong config variables to
|
||||
write outputs into a hashed directory path. It does this by recording accesses
|
||||
to soong config variables on each module, and then accumulating records of each
|
||||
module's all dependencies. `m soong_config_trace` builds information about
|
||||
hashes to `$OUT_DIR/soong/soong_config_trace.json`.
|
||||
|
||||
## Build logic
|
||||
|
||||
The build logic is written in Go using the
|
||||
[blueprint](http://godoc.org/github.com/google/blueprint) framework. Build
|
||||
logic receives module definitions parsed into Go structures using reflection
|
||||
and produces build rules. The build rules are collected by blueprint and
|
||||
written to a [ninja](http://ninja-build.org) build file.
|
||||
[blueprint](https://android.googlesource.com/platform/build/blueprint)
|
||||
framework. Build logic receives module definitions parsed into Go structures
|
||||
using reflection and produces build rules. The build rules are collected by
|
||||
blueprint and written to a [ninja](http://ninja-build.org) build file.
|
||||
|
||||
## Environment Variables Config File
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
package aconfig
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"android/soong/android"
|
||||
|
|
@ -22,9 +24,15 @@ import (
|
|||
"github.com/google/blueprint"
|
||||
)
|
||||
|
||||
type AconfigReleaseConfigValue struct {
|
||||
ReleaseConfig string
|
||||
Values []string `blueprint:"mutated"`
|
||||
}
|
||||
|
||||
type DeclarationsModule struct {
|
||||
android.ModuleBase
|
||||
android.DefaultableModuleBase
|
||||
blueprint.IncrementalModule
|
||||
|
||||
// Properties for "aconfig_declarations"
|
||||
properties struct {
|
||||
|
|
@ -34,8 +42,10 @@ type DeclarationsModule struct {
|
|||
// Release config flag package
|
||||
Package string
|
||||
|
||||
// Values from TARGET_RELEASE / RELEASE_ACONFIG_VALUE_SETS
|
||||
Values []string `blueprint:"mutated"`
|
||||
// Values for release configs / RELEASE_ACONFIG_VALUE_SETS
|
||||
// The current release config is `ReleaseConfig: ""`, others
|
||||
// are from RELEASE_ACONFIG_EXTRA_RELEASE_CONFIGS.
|
||||
ReleaseConfigValues []AconfigReleaseConfigValue
|
||||
|
||||
// Container(system/vendor/apex) that this module belongs to
|
||||
Container string
|
||||
|
|
@ -57,6 +67,10 @@ func DeclarationsFactory() android.Module {
|
|||
|
||||
type implicitValuesTagType struct {
|
||||
blueprint.BaseDependencyTag
|
||||
|
||||
// The release config name for these values.
|
||||
// Empty string for the actual current release config.
|
||||
ReleaseConfig string
|
||||
}
|
||||
|
||||
var implicitValuesTag = implicitValuesTagType{}
|
||||
|
|
@ -74,6 +88,13 @@ func (module *DeclarationsModule) DepsMutator(ctx android.BottomUpMutatorContext
|
|||
ctx.PropertyErrorf("container", "missing container property")
|
||||
}
|
||||
|
||||
// treating system_ext as system partition as we are combining them as one container
|
||||
// TODO remove this logic once we start enforcing that system_ext cannot be specified as
|
||||
// container in the container field.
|
||||
if module.properties.Container == "system_ext" {
|
||||
module.properties.Container = "system"
|
||||
}
|
||||
|
||||
// Add a dependency on the aconfig_value_sets defined in
|
||||
// RELEASE_ACONFIG_VALUE_SETS, and add any aconfig_values that
|
||||
// match our package.
|
||||
|
|
@ -81,6 +102,11 @@ func (module *DeclarationsModule) DepsMutator(ctx android.BottomUpMutatorContext
|
|||
if len(valuesFromConfig) > 0 {
|
||||
ctx.AddDependency(ctx.Module(), implicitValuesTag, valuesFromConfig...)
|
||||
}
|
||||
for rcName, valueSets := range ctx.Config().ReleaseAconfigExtraReleaseConfigsValueSets() {
|
||||
if len(valueSets) > 0 {
|
||||
ctx.AddDependency(ctx.Module(), implicitValuesTagType{ReleaseConfig: rcName}, valueSets...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func joinAndPrefix(prefix string, values []string) string {
|
||||
|
|
@ -101,59 +127,103 @@ func optionalVariable(prefix string, value string) string {
|
|||
return sb.String()
|
||||
}
|
||||
|
||||
// Assemble the actual filename.
|
||||
// If `rcName` is not empty, then insert "-{rcName}" into the path before the
|
||||
// file extension.
|
||||
func assembleFileName(rcName, path string) string {
|
||||
if rcName == "" {
|
||||
return path
|
||||
}
|
||||
dir, file := filepath.Split(path)
|
||||
rcName = "-" + rcName
|
||||
ext := filepath.Ext(file)
|
||||
base := file[:len(file)-len(ext)]
|
||||
return dir + base + rcName + ext
|
||||
}
|
||||
|
||||
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)
|
||||
// Determine which release configs we are processing.
|
||||
//
|
||||
// We always process the current release config (empty string).
|
||||
// We may have been told to also create artifacts for some others.
|
||||
configs := append([]string{""}, ctx.Config().ReleaseAconfigExtraReleaseConfigs()...)
|
||||
slices.Sort(configs)
|
||||
|
||||
values := make(map[string][]string)
|
||||
valuesFiles := make(map[string][]android.Path, 0)
|
||||
providerData := android.AconfigReleaseDeclarationsProviderData{}
|
||||
ctx.VisitDirectDeps(func(dep android.Module) {
|
||||
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())
|
||||
depTag := ctx.OtherModuleDependencyTag(dep)
|
||||
for _, config := range configs {
|
||||
tag := implicitValuesTagType{ReleaseConfig: config}
|
||||
if depTag == tag {
|
||||
paths, ok := depData.AvailablePackages[module.properties.Package]
|
||||
if ok {
|
||||
valuesFiles[config] = append(valuesFiles[config], paths...)
|
||||
for _, path := range paths {
|
||||
values[config] = append(values[config], path.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
for _, config := range configs {
|
||||
module.properties.ReleaseConfigValues = append(module.properties.ReleaseConfigValues, AconfigReleaseConfigValue{
|
||||
ReleaseConfig: config,
|
||||
Values: values[config],
|
||||
})
|
||||
|
||||
// Intermediate format
|
||||
declarationFiles := android.PathsForModuleSrc(ctx, module.properties.Srcs)
|
||||
intermediateCacheFilePath := android.PathForModuleOut(ctx, "intermediate.pb")
|
||||
defaultPermission := ctx.Config().ReleaseAconfigFlagDefaultPermission()
|
||||
inputFiles := make([]android.Path, len(declarationFiles))
|
||||
copy(inputFiles, declarationFiles)
|
||||
inputFiles = append(inputFiles, valuesFiles...)
|
||||
args := map[string]string{
|
||||
"release_version": ctx.Config().ReleaseVersion(),
|
||||
"package": module.properties.Package,
|
||||
"declarations": android.JoinPathsWithPrefix(declarationFiles, "--declarations "),
|
||||
"values": joinAndPrefix(" --values ", module.properties.Values),
|
||||
"default-permission": optionalVariable(" --default-permission ", defaultPermission),
|
||||
// Intermediate format
|
||||
declarationFiles := android.PathsForModuleSrc(ctx, module.properties.Srcs)
|
||||
intermediateCacheFilePath := android.PathForModuleOut(ctx, assembleFileName(config, "intermediate.pb"))
|
||||
var defaultPermission string
|
||||
defaultPermission = ctx.Config().ReleaseAconfigFlagDefaultPermission()
|
||||
if config != "" {
|
||||
if confPerm, ok := ctx.Config().GetBuildFlag("RELEASE_ACONFIG_FLAG_DEFAULT_PERMISSION_" + config); ok {
|
||||
defaultPermission = confPerm
|
||||
}
|
||||
}
|
||||
inputFiles := make([]android.Path, len(declarationFiles))
|
||||
copy(inputFiles, declarationFiles)
|
||||
inputFiles = append(inputFiles, valuesFiles[config]...)
|
||||
args := map[string]string{
|
||||
"release_version": ctx.Config().ReleaseVersion(),
|
||||
"package": module.properties.Package,
|
||||
"declarations": android.JoinPathsWithPrefix(declarationFiles, "--declarations "),
|
||||
"values": joinAndPrefix(" --values ", values[config]),
|
||||
"default-permission": optionalVariable(" --default-permission ", defaultPermission),
|
||||
}
|
||||
if len(module.properties.Container) > 0 {
|
||||
args["container"] = "--container " + module.properties.Container
|
||||
}
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: aconfigRule,
|
||||
Output: intermediateCacheFilePath,
|
||||
Inputs: inputFiles,
|
||||
Description: "aconfig_declarations",
|
||||
Args: args,
|
||||
})
|
||||
|
||||
intermediateDumpFilePath := android.PathForModuleOut(ctx, assembleFileName(config, "intermediate.txt"))
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: aconfigTextRule,
|
||||
Output: intermediateDumpFilePath,
|
||||
Inputs: android.Paths{intermediateCacheFilePath},
|
||||
Description: "aconfig_text",
|
||||
})
|
||||
|
||||
providerData[config] = android.AconfigDeclarationsProviderData{
|
||||
Package: module.properties.Package,
|
||||
Container: module.properties.Container,
|
||||
Exportable: module.properties.Exportable,
|
||||
IntermediateCacheOutputPath: intermediateCacheFilePath,
|
||||
IntermediateDumpOutputPath: intermediateDumpFilePath,
|
||||
}
|
||||
}
|
||||
if len(module.properties.Container) > 0 {
|
||||
args["container"] = "--container " + module.properties.Container
|
||||
}
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: aconfigRule,
|
||||
Output: intermediateCacheFilePath,
|
||||
Inputs: inputFiles,
|
||||
Description: "aconfig_declarations",
|
||||
Args: args,
|
||||
})
|
||||
|
||||
intermediateDumpFilePath := android.PathForModuleOut(ctx, "intermediate.txt")
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: aconfigTextRule,
|
||||
Output: intermediateDumpFilePath,
|
||||
Inputs: android.Paths{intermediateCacheFilePath},
|
||||
Description: "aconfig_text",
|
||||
})
|
||||
|
||||
android.SetProvider(ctx, android.AconfigDeclarationsProviderKey, android.AconfigDeclarationsProviderData{
|
||||
Package: module.properties.Package,
|
||||
Container: module.properties.Container,
|
||||
Exportable: module.properties.Exportable,
|
||||
IntermediateCacheOutputPath: intermediateCacheFilePath,
|
||||
IntermediateDumpOutputPath: intermediateDumpFilePath,
|
||||
})
|
||||
android.SetProvider(ctx, android.AconfigDeclarationsProviderKey, providerData[""])
|
||||
android.SetProvider(ctx, android.AconfigReleaseDeclarationsProviderKey, providerData)
|
||||
}
|
||||
|
||||
var _ blueprint.Incremental = &DeclarationsModule{}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
package aconfig
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
|
@ -39,7 +40,7 @@ func TestAconfigDeclarations(t *testing.T) {
|
|||
module := result.ModuleForTests("module_name", "").Module().(*DeclarationsModule)
|
||||
|
||||
// Check that the provider has the right contents
|
||||
depData, _ := android.SingletonModuleProvider(result, module, android.AconfigDeclarationsProviderKey)
|
||||
depData, _ := android.OtherModuleProvider(result, module, android.AconfigDeclarationsProviderKey)
|
||||
android.AssertStringEquals(t, "package", depData.Package, "com.example.package")
|
||||
android.AssertStringEquals(t, "container", depData.Container, "com.android.foo")
|
||||
android.AssertBoolEquals(t, "exportable", depData.Exportable, true)
|
||||
|
|
@ -66,7 +67,7 @@ func TestAconfigDeclarationsWithExportableUnset(t *testing.T) {
|
|||
result := runTest(t, android.FixtureExpectsNoErrors, bp)
|
||||
|
||||
module := result.ModuleForTests("module_name", "").Module().(*DeclarationsModule)
|
||||
depData, _ := android.SingletonModuleProvider(result, module, android.AconfigDeclarationsProviderKey)
|
||||
depData, _ := android.OtherModuleProvider(result, module, android.AconfigDeclarationsProviderKey)
|
||||
android.AssertBoolEquals(t, "exportable", depData.Exportable, false)
|
||||
}
|
||||
|
||||
|
|
@ -134,3 +135,95 @@ func TestMandatoryProperties(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAssembleFileName(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
releaseConfig string
|
||||
path string
|
||||
expectedValue string
|
||||
}{
|
||||
{
|
||||
name: "active release config",
|
||||
path: "file.path",
|
||||
expectedValue: "file.path",
|
||||
},
|
||||
{
|
||||
name: "release config FOO",
|
||||
releaseConfig: "FOO",
|
||||
path: "file.path",
|
||||
expectedValue: "file-FOO.path",
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
actualValue := assembleFileName(test.releaseConfig, test.path)
|
||||
if actualValue != test.expectedValue {
|
||||
t.Errorf("Expected %q found %q", test.expectedValue, actualValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateAndroidBuildActions(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
buildFlags map[string]string
|
||||
bp string
|
||||
errorHandler android.FixtureErrorHandler
|
||||
}{
|
||||
{
|
||||
name: "generate extra",
|
||||
buildFlags: map[string]string{
|
||||
"RELEASE_ACONFIG_EXTRA_RELEASE_CONFIGS": "config2",
|
||||
"RELEASE_ACONFIG_VALUE_SETS": "aconfig_value_set-config1",
|
||||
"RELEASE_ACONFIG_VALUE_SETS_config2": "aconfig_value_set-config2",
|
||||
},
|
||||
bp: `
|
||||
aconfig_declarations {
|
||||
name: "module_name",
|
||||
package: "com.example.package",
|
||||
container: "com.android.foo",
|
||||
srcs: [
|
||||
"foo.aconfig",
|
||||
"bar.aconfig",
|
||||
],
|
||||
}
|
||||
aconfig_value_set {
|
||||
name: "aconfig_value_set-config1",
|
||||
values: []
|
||||
}
|
||||
aconfig_value_set {
|
||||
name: "aconfig_value_set-config2",
|
||||
values: []
|
||||
}
|
||||
`,
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
fixture := PrepareForTest(t, addBuildFlagsForTest(test.buildFlags))
|
||||
if test.errorHandler != nil {
|
||||
fixture = fixture.ExtendWithErrorHandler(test.errorHandler)
|
||||
}
|
||||
result := fixture.RunTestWithBp(t, test.bp)
|
||||
module := result.ModuleForTests("module_name", "").Module().(*DeclarationsModule)
|
||||
depData, _ := android.OtherModuleProvider(result, module, android.AconfigReleaseDeclarationsProviderKey)
|
||||
expectedKeys := []string{""}
|
||||
for _, rc := range strings.Split(test.buildFlags["RELEASE_ACONFIG_EXTRA_RELEASE_CONFIGS"], " ") {
|
||||
expectedKeys = append(expectedKeys, rc)
|
||||
}
|
||||
slices.Sort(expectedKeys)
|
||||
actualKeys := []string{}
|
||||
for rc := range depData {
|
||||
actualKeys = append(actualKeys, rc)
|
||||
}
|
||||
slices.Sort(actualKeys)
|
||||
android.AssertStringEquals(t, "provider keys", strings.Join(expectedKeys, " "), strings.Join(actualKeys, " "))
|
||||
for _, rc := range actualKeys {
|
||||
if !strings.HasSuffix(depData[rc].IntermediateCacheOutputPath.String(), assembleFileName(rc, "/intermediate.pb")) {
|
||||
t.Errorf("Incorrect intermediates proto path in provider for release config %s: %s", rc, depData[rc].IntermediateCacheOutputPath.String())
|
||||
}
|
||||
if !strings.HasSuffix(depData[rc].IntermediateDumpOutputPath.String(), assembleFileName(rc, "/intermediate.txt")) {
|
||||
t.Errorf("Incorrect intermediates text path in provider for release config %s: %s", rc, depData[rc].IntermediateDumpOutputPath.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ package aconfig
|
|||
|
||||
import (
|
||||
"android/soong/android"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
)
|
||||
|
||||
|
|
@ -27,6 +30,9 @@ type ValueSetModule struct {
|
|||
properties struct {
|
||||
// aconfig_values modules
|
||||
Values []string
|
||||
|
||||
// Paths to the Android.bp files where the aconfig_values modules are defined.
|
||||
Srcs []string
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -56,7 +62,35 @@ type valueSetProviderData struct {
|
|||
|
||||
var valueSetProviderKey = blueprint.NewProvider[valueSetProviderData]()
|
||||
|
||||
func (module *ValueSetModule) FindAconfigValuesFromSrc(ctx android.BottomUpMutatorContext) map[string]android.Path {
|
||||
moduleDir := ctx.ModuleDir()
|
||||
srcs := android.PathsForModuleSrcExcludes(ctx, module.properties.Srcs, []string{ctx.BlueprintsFile()})
|
||||
|
||||
aconfigValuesPrefix := strings.Replace(module.Name(), "aconfig_value_set", "aconfig-values", 1)
|
||||
moduleNamesSrcMap := make(map[string]android.Path)
|
||||
for _, src := range srcs {
|
||||
subDir := strings.TrimPrefix(src.String(), moduleDir+"/")
|
||||
packageName, _, found := strings.Cut(subDir, "/")
|
||||
if found {
|
||||
moduleName := fmt.Sprintf("%s-%s-all", aconfigValuesPrefix, packageName)
|
||||
moduleNamesSrcMap[moduleName] = src
|
||||
}
|
||||
}
|
||||
return moduleNamesSrcMap
|
||||
}
|
||||
|
||||
func (module *ValueSetModule) DepsMutator(ctx android.BottomUpMutatorContext) {
|
||||
|
||||
// TODO: b/366285733 - Replace the file path based solution with more robust solution.
|
||||
aconfigValuesMap := module.FindAconfigValuesFromSrc(ctx)
|
||||
for _, moduleName := range android.SortedKeys(aconfigValuesMap) {
|
||||
if ctx.OtherModuleExists(moduleName) {
|
||||
ctx.AddDependency(ctx.Module(), valueSetTag, moduleName)
|
||||
} else {
|
||||
ctx.ModuleErrorf("module %q not found. Rename the aconfig_values module defined in %q to %q", moduleName, aconfigValuesMap[moduleName], moduleName)
|
||||
}
|
||||
}
|
||||
|
||||
deps := ctx.AddDependency(ctx.Module(), valueSetTag, module.properties.Values...)
|
||||
for _, dep := range deps {
|
||||
_, ok := dep.(*ValuesModule)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import (
|
|||
"testing"
|
||||
|
||||
"android/soong/android"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
)
|
||||
|
||||
func TestAconfigValueSet(t *testing.T) {
|
||||
|
|
@ -38,6 +40,115 @@ func TestAconfigValueSet(t *testing.T) {
|
|||
module := result.ModuleForTests("module_name", "").Module().(*ValueSetModule)
|
||||
|
||||
// Check that the provider has the right contents
|
||||
depData, _ := android.SingletonModuleProvider(result, module, valueSetProviderKey)
|
||||
depData, _ := android.OtherModuleProvider(result, module, valueSetProviderKey)
|
||||
android.AssertStringEquals(t, "AvailablePackages", "blah.aconfig_values", depData.AvailablePackages["foo.package"][0].String())
|
||||
}
|
||||
|
||||
func TestAconfigValueSetBpGlob(t *testing.T) {
|
||||
result := android.GroupFixturePreparers(
|
||||
PrepareForTestWithAconfigBuildComponents,
|
||||
android.FixtureMergeMockFs(
|
||||
map[string][]byte{
|
||||
// .../some_release/android.foo/
|
||||
"some_release/android.foo/Android.bp": []byte(`
|
||||
aconfig_values {
|
||||
name: "aconfig-values-platform_build_release-some_release-android.foo-all",
|
||||
package: "android.foo",
|
||||
srcs: [
|
||||
"*.textproto",
|
||||
],
|
||||
}
|
||||
`),
|
||||
"some_release/android.foo/flag.textproto": nil,
|
||||
|
||||
// .../some_release/android.bar/
|
||||
"some_release/android.bar/Android.bp": []byte(`
|
||||
aconfig_values {
|
||||
name: "aconfig-values-platform_build_release-some_release-android.bar-all",
|
||||
package: "android.bar",
|
||||
srcs: [
|
||||
"*.textproto",
|
||||
],
|
||||
}
|
||||
`),
|
||||
"some_release/android.bar/flag.textproto": nil,
|
||||
|
||||
// .../some_release/
|
||||
"some_release/Android.bp": []byte(`
|
||||
aconfig_value_set {
|
||||
name: "aconfig_value_set-platform_build_release-some_release",
|
||||
srcs: [
|
||||
"*/Android.bp",
|
||||
],
|
||||
}
|
||||
`),
|
||||
},
|
||||
),
|
||||
).RunTest(t)
|
||||
|
||||
checkModuleHasDependency := func(name, variant, dep string) bool {
|
||||
t.Helper()
|
||||
module := result.ModuleForTests(name, variant).Module()
|
||||
depFound := false
|
||||
result.VisitDirectDeps(module, func(m blueprint.Module) {
|
||||
if m.Name() == dep {
|
||||
depFound = true
|
||||
}
|
||||
})
|
||||
return depFound
|
||||
}
|
||||
android.AssertBoolEquals(t,
|
||||
"aconfig_value_set expected to depend on aconfig_value via srcs",
|
||||
true,
|
||||
checkModuleHasDependency(
|
||||
"aconfig_value_set-platform_build_release-some_release",
|
||||
"",
|
||||
"aconfig-values-platform_build_release-some_release-android.foo-all",
|
||||
),
|
||||
)
|
||||
android.AssertBoolEquals(t,
|
||||
"aconfig_value_set expected to depend on aconfig_value via srcs",
|
||||
true,
|
||||
checkModuleHasDependency(
|
||||
"aconfig_value_set-platform_build_release-some_release",
|
||||
"",
|
||||
"aconfig-values-platform_build_release-some_release-android.bar-all",
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func TestAconfigValueSetBpGlobError(t *testing.T) {
|
||||
android.GroupFixturePreparers(
|
||||
PrepareForTestWithAconfigBuildComponents,
|
||||
android.FixtureMergeMockFs(
|
||||
map[string][]byte{
|
||||
// .../some_release/android.bar/
|
||||
"some_release/android.bar/Android.bp": []byte(`
|
||||
aconfig_values {
|
||||
name: "aconfig-values-platform_build_release-some_release-android_bar-all",
|
||||
package: "android.bar",
|
||||
srcs: [
|
||||
"*.textproto",
|
||||
],
|
||||
}
|
||||
`),
|
||||
"some_release/android.bar/flag.textproto": nil,
|
||||
|
||||
// .../some_release/
|
||||
"some_release/Android.bp": []byte(`
|
||||
aconfig_value_set {
|
||||
name: "aconfig_value_set-platform_build_release-some_release",
|
||||
srcs: [
|
||||
"*/Android.bp",
|
||||
],
|
||||
}
|
||||
`),
|
||||
},
|
||||
),
|
||||
).ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(
|
||||
`module "aconfig_value_set-platform_build_release-some_release": module ` +
|
||||
`"aconfig-values-platform_build_release-some_release-android.bar-all" not found. ` +
|
||||
`Rename the aconfig_values module defined in "some_release/android.bar/Android.bp" ` +
|
||||
`to "aconfig-values-platform_build_release-some_release-android.bar-all"`),
|
||||
).RunTest(t)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ func TestAconfigValues(t *testing.T) {
|
|||
module := result.ModuleForTests("module_name", "").Module().(*ValuesModule)
|
||||
|
||||
// Check that the provider has the right contents
|
||||
depData, _ := android.SingletonModuleProvider(result, module, valuesProviderKey)
|
||||
depData, _ := android.OtherModuleProvider(result, module, valuesProviderKey)
|
||||
android.AssertStringEquals(t, "package", "foo.package", depData.Package)
|
||||
android.AssertPathsEndWith(t, "srcs", []string{"blah.aconfig_values"}, depData.Values)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,10 @@
|
|||
package aconfig
|
||||
|
||||
import (
|
||||
"android/soong/android"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"android/soong/android"
|
||||
)
|
||||
|
||||
// A singleton module that collects all of the aconfig flags declared in the
|
||||
|
|
@ -27,70 +29,90 @@ import (
|
|||
// ones that are relevant to the product currently being built, so that that infra
|
||||
// doesn't need to pull from multiple builds and merge them.
|
||||
func AllAconfigDeclarationsFactory() android.Singleton {
|
||||
return &allAconfigDeclarationsSingleton{}
|
||||
return &allAconfigDeclarationsSingleton{releaseMap: make(map[string]allAconfigReleaseDeclarationsSingleton)}
|
||||
}
|
||||
|
||||
type allAconfigDeclarationsSingleton struct {
|
||||
type allAconfigReleaseDeclarationsSingleton struct {
|
||||
intermediateBinaryProtoPath android.OutputPath
|
||||
intermediateTextProtoPath android.OutputPath
|
||||
}
|
||||
|
||||
type allAconfigDeclarationsSingleton struct {
|
||||
releaseMap map[string]allAconfigReleaseDeclarationsSingleton
|
||||
}
|
||||
|
||||
func (this *allAconfigDeclarationsSingleton) sortedConfigNames() []string {
|
||||
var names []string
|
||||
for k := range this.releaseMap {
|
||||
names = append(names, k)
|
||||
}
|
||||
slices.Sort(names)
|
||||
return names
|
||||
}
|
||||
|
||||
func (this *allAconfigDeclarationsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
|
||||
// Find all of the aconfig_declarations modules
|
||||
var packages = make(map[string]int)
|
||||
var cacheFiles android.Paths
|
||||
ctx.VisitAllModules(func(module android.Module) {
|
||||
decl, ok := android.SingletonModuleProvider(ctx, module, android.AconfigDeclarationsProviderKey)
|
||||
if !ok {
|
||||
return
|
||||
for _, rcName := range append([]string{""}, ctx.Config().ReleaseAconfigExtraReleaseConfigs()...) {
|
||||
// Find all of the aconfig_declarations modules
|
||||
var packages = make(map[string]int)
|
||||
var cacheFiles android.Paths
|
||||
ctx.VisitAllModules(func(module android.Module) {
|
||||
decl, ok := android.OtherModuleProvider(ctx, module, android.AconfigReleaseDeclarationsProviderKey)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
cacheFiles = append(cacheFiles, decl[rcName].IntermediateCacheOutputPath)
|
||||
packages[decl[rcName].Package]++
|
||||
})
|
||||
|
||||
var numOffendingPkg = 0
|
||||
for pkg, cnt := range packages {
|
||||
if cnt > 1 {
|
||||
fmt.Printf("%d aconfig_declarations found for package %s\n", cnt, pkg)
|
||||
numOffendingPkg++
|
||||
}
|
||||
}
|
||||
cacheFiles = append(cacheFiles, decl.IntermediateCacheOutputPath)
|
||||
packages[decl.Package]++
|
||||
})
|
||||
|
||||
var numOffendingPkg = 0
|
||||
for pkg, cnt := range packages {
|
||||
if cnt > 1 {
|
||||
fmt.Printf("%d aconfig_declarations found for package %s\n", cnt, pkg)
|
||||
numOffendingPkg++
|
||||
if numOffendingPkg > 0 {
|
||||
panic(fmt.Errorf("Only one aconfig_declarations allowed for each package."))
|
||||
}
|
||||
|
||||
// Generate build action for aconfig (binary proto output)
|
||||
paths := allAconfigReleaseDeclarationsSingleton{
|
||||
intermediateBinaryProtoPath: android.PathForIntermediates(ctx, assembleFileName(rcName, "all_aconfig_declarations.pb")),
|
||||
intermediateTextProtoPath: android.PathForIntermediates(ctx, assembleFileName(rcName, "all_aconfig_declarations.textproto")),
|
||||
}
|
||||
this.releaseMap[rcName] = paths
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: AllDeclarationsRule,
|
||||
Inputs: cacheFiles,
|
||||
Output: this.releaseMap[rcName].intermediateBinaryProtoPath,
|
||||
Description: "all_aconfig_declarations",
|
||||
Args: map[string]string{
|
||||
"cache_files": android.JoinPathsWithPrefix(cacheFiles, "--cache "),
|
||||
},
|
||||
})
|
||||
ctx.Phony("all_aconfig_declarations", this.releaseMap[rcName].intermediateBinaryProtoPath)
|
||||
|
||||
// Generate build action for aconfig (text proto output)
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: AllDeclarationsRuleTextProto,
|
||||
Inputs: cacheFiles,
|
||||
Output: this.releaseMap[rcName].intermediateTextProtoPath,
|
||||
Description: "all_aconfig_declarations_textproto",
|
||||
Args: map[string]string{
|
||||
"cache_files": android.JoinPathsWithPrefix(cacheFiles, "--cache "),
|
||||
},
|
||||
})
|
||||
ctx.Phony("all_aconfig_declarations_textproto", this.releaseMap[rcName].intermediateTextProtoPath)
|
||||
}
|
||||
|
||||
if numOffendingPkg > 0 {
|
||||
panic(fmt.Errorf("Only one aconfig_declarations allowed for each package."))
|
||||
}
|
||||
|
||||
// Generate build action for aconfig (binary proto output)
|
||||
this.intermediateBinaryProtoPath = android.PathForIntermediates(ctx, "all_aconfig_declarations.pb")
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: AllDeclarationsRule,
|
||||
Inputs: cacheFiles,
|
||||
Output: this.intermediateBinaryProtoPath,
|
||||
Description: "all_aconfig_declarations",
|
||||
Args: map[string]string{
|
||||
"cache_files": android.JoinPathsWithPrefix(cacheFiles, "--cache "),
|
||||
},
|
||||
})
|
||||
ctx.Phony("all_aconfig_declarations", this.intermediateBinaryProtoPath)
|
||||
|
||||
// Generate build action for aconfig (text proto output)
|
||||
this.intermediateTextProtoPath = android.PathForIntermediates(ctx, "all_aconfig_declarations.textproto")
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: AllDeclarationsRuleTextProto,
|
||||
Inputs: cacheFiles,
|
||||
Output: this.intermediateTextProtoPath,
|
||||
Description: "all_aconfig_declarations_textproto",
|
||||
Args: map[string]string{
|
||||
"cache_files": android.JoinPathsWithPrefix(cacheFiles, "--cache "),
|
||||
},
|
||||
})
|
||||
ctx.Phony("all_aconfig_declarations_textproto", this.intermediateTextProtoPath)
|
||||
}
|
||||
|
||||
func (this *allAconfigDeclarationsSingleton) MakeVars(ctx android.MakeVarsContext) {
|
||||
ctx.DistForGoal("droid", this.intermediateBinaryProtoPath)
|
||||
for _, goal := range []string{"docs", "droid", "sdk"} {
|
||||
ctx.DistForGoalWithFilename(goal, this.intermediateBinaryProtoPath, "flags.pb")
|
||||
ctx.DistForGoalWithFilename(goal, this.intermediateTextProtoPath, "flags.textproto")
|
||||
for _, rcName := range this.sortedConfigNames() {
|
||||
ctx.DistForGoal("droid", this.releaseMap[rcName].intermediateBinaryProtoPath)
|
||||
for _, goal := range []string{"docs", "droid", "sdk"} {
|
||||
ctx.DistForGoalWithFilename(goal, this.releaseMap[rcName].intermediateBinaryProtoPath, assembleFileName(rcName, "flags.pb"))
|
||||
ctx.DistForGoalWithFilename(goal, this.releaseMap[rcName].intermediateTextProtoPath, assembleFileName(rcName, "flags.textproto"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ func (this *allBuildFlagDeclarationsSingleton) GenerateBuildActions(ctx android.
|
|||
// Find all of the build_flag_declarations modules
|
||||
var intermediateFiles android.Paths
|
||||
ctx.VisitAllModules(func(module android.Module) {
|
||||
decl, ok := android.SingletonModuleProvider(ctx, module, BuildFlagDeclarationsProviderKey)
|
||||
decl, ok := android.OtherModuleProvider(ctx, module, BuildFlagDeclarationsProviderKey)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ bootstrap_go_package {
|
|||
"soong",
|
||||
"soong-aconfig",
|
||||
"soong-android",
|
||||
"soong-bazel",
|
||||
"soong-java",
|
||||
"soong-rust",
|
||||
],
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ var (
|
|||
` --mode ${mode}` +
|
||||
` --cache ${in}` +
|
||||
` --out ${out}.tmp` +
|
||||
` --allow-instrumentation ${debug}` +
|
||||
` && $soong_zip -write_if_changed -jar -o ${out} -C ${out}.tmp -D ${out}.tmp` +
|
||||
` && rm -rf ${out}.tmp`,
|
||||
CommandDeps: []string{
|
||||
|
|
@ -39,7 +40,7 @@ var (
|
|||
"$soong_zip",
|
||||
},
|
||||
Restat: true,
|
||||
}, "mode")
|
||||
}, "mode", "debug")
|
||||
|
||||
// For cc_aconfig_library: Generate C++ library
|
||||
cppRule = pctx.AndroidStaticRule("cc_aconfig_library",
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
|
||||
"github.com/google/blueprint"
|
||||
"github.com/google/blueprint/proptools"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type declarationsTagType struct {
|
||||
|
|
@ -71,6 +72,7 @@ func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) DepsMutator(module *ja
|
|||
module.AddSharedLibrary("aconfig-annotations-lib")
|
||||
// TODO(b/303773055): Remove the annotation after access issue is resolved.
|
||||
module.AddSharedLibrary("unsupportedappusage")
|
||||
module.AddSharedLibrary("aconfig_storage_reader_java")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +104,8 @@ func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuild
|
|||
Output: srcJarPath,
|
||||
Description: "aconfig.srcjar",
|
||||
Args: map[string]string{
|
||||
"mode": mode,
|
||||
"mode": mode,
|
||||
"debug": strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorage()),
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ func TestMkEntriesMatchedContainer(t *testing.T) {
|
|||
aconfig_declarations {
|
||||
name: "my_aconfig_declarations_bar",
|
||||
package: "com.example.package.bar",
|
||||
container: "system_ext",
|
||||
container: "vendor",
|
||||
srcs: ["bar.aconfig"],
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ func (this *exportedJavaDeclarationsLibrarySingleton) GenerateBuildActions(ctx a
|
|||
// Find all of the aconfig_declarations modules
|
||||
var cacheFiles android.Paths
|
||||
ctx.VisitAllModules(func(module android.Module) {
|
||||
decl, ok := android.SingletonModuleProvider(ctx, module, android.AconfigDeclarationsProviderKey)
|
||||
decl, ok := android.OtherModuleProvider(ctx, module, android.AconfigDeclarationsProviderKey)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ var (
|
|||
// For create-device-config-sysprops: Generate aconfig flag value map text file
|
||||
aconfigTextRule = pctx.AndroidStaticRule("aconfig_text",
|
||||
blueprint.RuleParams{
|
||||
Command: `${aconfig} dump-cache --dedup --format='{fully_qualified_name}={state:bool}'` +
|
||||
Command: `${aconfig} dump-cache --dedup --format='{fully_qualified_name}:{permission}={state:bool}'` +
|
||||
` --cache ${in}` +
|
||||
` --out ${out}.tmp` +
|
||||
` && ( if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,25 @@ import (
|
|||
var PrepareForTestWithAconfigBuildComponents = android.FixtureRegisterWithContext(RegisterBuildComponents)
|
||||
|
||||
func runTest(t *testing.T, errorHandler android.FixtureErrorHandler, bp string) *android.TestResult {
|
||||
return android.GroupFixturePreparers(PrepareForTestWithAconfigBuildComponents).
|
||||
return PrepareForTest(t).
|
||||
ExtendWithErrorHandler(errorHandler).
|
||||
RunTestWithBp(t, bp)
|
||||
}
|
||||
|
||||
func PrepareForTest(t *testing.T, preparers ...android.FixturePreparer) android.FixturePreparer {
|
||||
preparers = append([]android.FixturePreparer{PrepareForTestWithAconfigBuildComponents}, preparers...)
|
||||
return android.GroupFixturePreparers(preparers...)
|
||||
}
|
||||
|
||||
func addBuildFlagsForTest(buildFlags map[string]string) android.FixturePreparer {
|
||||
return android.GroupFixturePreparers(
|
||||
android.FixtureModifyProductVariables(func(vars android.FixtureProductVariables) {
|
||||
if vars.BuildFlags == nil {
|
||||
vars.BuildFlags = make(map[string]string)
|
||||
}
|
||||
for k, v := range buildFlags {
|
||||
vars.BuildFlags[k] = v
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,4 +29,5 @@ bootstrap_go_package {
|
|||
"aidl_library_test.go",
|
||||
],
|
||||
pluginFor: ["soong_build"],
|
||||
visibility: ["//visibility:public"],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,9 @@
|
|||
package aidl_library
|
||||
|
||||
import (
|
||||
"android/soong/android"
|
||||
"testing"
|
||||
|
||||
"android/soong/android"
|
||||
)
|
||||
|
||||
func TestAidlLibrary(t *testing.T) {
|
||||
|
|
@ -46,7 +47,7 @@ func TestAidlLibrary(t *testing.T) {
|
|||
).RunTest(t).TestContext
|
||||
|
||||
foo := ctx.ModuleForTests("foo", "").Module().(*AidlLibrary)
|
||||
actualInfo, _ := android.SingletonModuleProvider(ctx, foo, AidlLibraryProvider)
|
||||
actualInfo, _ := android.OtherModuleProvider(ctx, foo, AidlLibraryProvider)
|
||||
|
||||
android.AssertArrayString(
|
||||
t,
|
||||
|
|
@ -95,7 +96,7 @@ func TestAidlLibraryWithoutStripImportPrefix(t *testing.T) {
|
|||
).RunTest(t).TestContext
|
||||
|
||||
foo := ctx.ModuleForTests("foo", "").Module().(*AidlLibrary)
|
||||
actualInfo, _ := android.SingletonModuleProvider(ctx, foo, AidlLibraryProvider)
|
||||
actualInfo, _ := android.OtherModuleProvider(ctx, foo, AidlLibraryProvider)
|
||||
|
||||
android.AssertArrayString(
|
||||
t,
|
||||
|
|
|
|||
|
|
@ -39,7 +39,10 @@ bootstrap_go_package {
|
|||
"arch_module_context.go",
|
||||
"base_module_context.go",
|
||||
"build_prop.go",
|
||||
"compliance_metadata.go",
|
||||
"config.go",
|
||||
"container_violations.go",
|
||||
"container.go",
|
||||
"test_config.go",
|
||||
"configurable_properties.go",
|
||||
"configured_jars.go",
|
||||
|
|
@ -56,6 +59,7 @@ bootstrap_go_package {
|
|||
"gen_notice.go",
|
||||
"hooks.go",
|
||||
"image.go",
|
||||
"init.go",
|
||||
"license.go",
|
||||
"license_kind.go",
|
||||
"license_metadata.go",
|
||||
|
|
@ -84,12 +88,14 @@ bootstrap_go_package {
|
|||
"prebuilt.go",
|
||||
"prebuilt_build_tool.go",
|
||||
"product_config.go",
|
||||
"product_config_to_bp.go",
|
||||
"proto.go",
|
||||
"provider.go",
|
||||
"raw_files.go",
|
||||
"register.go",
|
||||
"rule_builder.go",
|
||||
"sandbox.go",
|
||||
"sbom.go",
|
||||
"sdk.go",
|
||||
"sdk_version.go",
|
||||
"shared_properties.go",
|
||||
|
|
@ -103,6 +109,7 @@ bootstrap_go_package {
|
|||
"updatable_modules.go",
|
||||
"util.go",
|
||||
"variable.go",
|
||||
"vintf_fragment.go",
|
||||
"visibility.go",
|
||||
],
|
||||
testSrcs: [
|
||||
|
|
@ -145,6 +152,9 @@ bootstrap_go_package {
|
|||
"test_suites_test.go",
|
||||
"util_test.go",
|
||||
"variable_test.go",
|
||||
"vintf_fragment_test.go",
|
||||
"visibility_test.go",
|
||||
],
|
||||
// Used by plugins
|
||||
visibility: ["//visibility:public"],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@ type AconfigDeclarationsProviderData struct {
|
|||
|
||||
var AconfigDeclarationsProviderKey = blueprint.NewProvider[AconfigDeclarationsProviderData]()
|
||||
|
||||
type AconfigReleaseDeclarationsProviderData map[string]AconfigDeclarationsProviderData
|
||||
|
||||
var AconfigReleaseDeclarationsProviderKey = blueprint.NewProvider[AconfigReleaseDeclarationsProviderData]()
|
||||
|
||||
type ModeInfo struct {
|
||||
Container string
|
||||
Mode string
|
||||
|
|
@ -112,6 +116,8 @@ func aconfigUpdateAndroidBuildActions(ctx ModuleContext) {
|
|||
if dep, ok := OtherModuleProvider(ctx, module, AconfigDeclarationsProviderKey); ok {
|
||||
mergedAconfigFiles[dep.Container] = append(mergedAconfigFiles[dep.Container], dep.IntermediateCacheOutputPath)
|
||||
}
|
||||
// If we were generating on-device artifacts for other release configs, we would need to add code here to propagate
|
||||
// those artifacts as well. See also b/298444886.
|
||||
if dep, ok := OtherModuleProvider(ctx, module, AconfigPropagatingProviderKey); ok {
|
||||
for container, v := range dep.AconfigFiles {
|
||||
mergedAconfigFiles[container] = append(mergedAconfigFiles[container], v...)
|
||||
|
|
@ -130,12 +136,12 @@ func aconfigUpdateAndroidBuildActions(ctx ModuleContext) {
|
|||
AconfigFiles: mergedAconfigFiles,
|
||||
ModeInfos: mergedModeInfos,
|
||||
})
|
||||
ctx.Module().base().aconfigFilePaths = getAconfigFilePaths(ctx.Module().base(), mergedAconfigFiles)
|
||||
ctx.setAconfigPaths(getAconfigFilePaths(ctx.Module().base(), mergedAconfigFiles))
|
||||
}
|
||||
}
|
||||
|
||||
func aconfigUpdateAndroidMkData(ctx fillInEntriesContext, mod Module, data *AndroidMkData) {
|
||||
info, ok := SingletonModuleProvider(ctx, mod, AconfigPropagatingProviderKey)
|
||||
info, ok := OtherModuleProvider(ctx, mod, AconfigPropagatingProviderKey)
|
||||
// If there is no aconfigPropagatingProvider, or there are no AconfigFiles, then we are done.
|
||||
if !ok || len(info.AconfigFiles) == 0 {
|
||||
return
|
||||
|
|
@ -166,7 +172,7 @@ func aconfigUpdateAndroidMkEntries(ctx fillInEntriesContext, mod Module, entries
|
|||
if len(*entries) == 0 {
|
||||
return
|
||||
}
|
||||
info, ok := SingletonModuleProvider(ctx, mod, AconfigPropagatingProviderKey)
|
||||
info, ok := OtherModuleProvider(ctx, mod, AconfigPropagatingProviderKey)
|
||||
if !ok || len(info.AconfigFiles) == 0 {
|
||||
return
|
||||
}
|
||||
|
|
@ -181,6 +187,20 @@ func aconfigUpdateAndroidMkEntries(ctx fillInEntriesContext, mod Module, entries
|
|||
}
|
||||
}
|
||||
|
||||
func aconfigUpdateAndroidMkInfos(ctx fillInEntriesContext, mod Module, infos *AndroidMkProviderInfo) {
|
||||
info, ok := OtherModuleProvider(ctx, mod, AconfigPropagatingProviderKey)
|
||||
if !ok || len(info.AconfigFiles) == 0 {
|
||||
return
|
||||
}
|
||||
// All of the files in the module potentially depend on the aconfig flag values.
|
||||
infos.PrimaryInfo.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(mod.base(), info.AconfigFiles))
|
||||
if len(infos.ExtraInfo) > 0 {
|
||||
for _, ei := range (*infos).ExtraInfo {
|
||||
ei.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(mod.base(), info.AconfigFiles))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mergeAconfigFiles(ctx ModuleContext, container string, inputs Paths, generateRule bool) Paths {
|
||||
inputs = SortedUniquePaths(inputs)
|
||||
if len(inputs) == 1 {
|
||||
|
|
@ -213,7 +233,8 @@ func getAconfigFilePaths(m *ModuleBase, aconfigFiles map[string]Paths) (paths Pa
|
|||
} else if m.ProductSpecific() {
|
||||
container = "product"
|
||||
} else if m.SystemExtSpecific() {
|
||||
container = "system_ext"
|
||||
// system_ext and system partitions should be treated as one container
|
||||
container = "system"
|
||||
}
|
||||
|
||||
paths = append(paths, aconfigFiles[container]...)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package android
|
||||
|
||||
import (
|
||||
"android/soong/android/team_proto"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"android/soong/android/team_proto"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
|
|
@ -93,7 +95,7 @@ func (t *allTeamsSingleton) GenerateBuildActions(ctx SingletonContext) {
|
|||
}
|
||||
|
||||
testModInfo := TestModuleInformation{}
|
||||
if tmi, ok := SingletonModuleProvider(ctx, module, TestOnlyProviderKey); ok {
|
||||
if tmi, ok := OtherModuleProvider(ctx, module, TestOnlyProviderKey); ok {
|
||||
testModInfo = tmi
|
||||
}
|
||||
|
||||
|
|
@ -152,6 +154,11 @@ func (t *allTeamsSingleton) lookupTeamForAllModules() *team_proto.AllTeams {
|
|||
} else {
|
||||
teamProperties, found = t.lookupDefaultTeam(m.bpFile)
|
||||
}
|
||||
// Deal with one blueprint file including another by looking up the default
|
||||
// in the main Android.bp rather than one listed with "build = [My.bp]"
|
||||
if !found {
|
||||
teamProperties, found = t.lookupDefaultTeam(path.Join(path.Dir(m.bpFile), "Android.bp"))
|
||||
}
|
||||
|
||||
trendy_team_id := ""
|
||||
if found {
|
||||
|
|
|
|||
|
|
@ -264,6 +264,84 @@ func TestPackageLookup(t *testing.T) {
|
|||
AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams)
|
||||
}
|
||||
|
||||
func TestPackageLookupForIncludedBlueprintFiles(t *testing.T) {
|
||||
t.Parallel()
|
||||
rootBp := `
|
||||
package { default_team: "team_top"}
|
||||
team {
|
||||
name: "team_top",
|
||||
trendy_team_id: "trendy://team_top",
|
||||
}
|
||||
build = ["include.bp"]
|
||||
`
|
||||
includeBp := `
|
||||
fake {
|
||||
name: "IncludedModule",
|
||||
} `
|
||||
|
||||
ctx := GroupFixturePreparers(
|
||||
prepareForTestWithTeamAndFakes,
|
||||
PrepareForTestWithPackageModule,
|
||||
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory)
|
||||
}),
|
||||
FixtureAddTextFile("Android.bp", rootBp),
|
||||
FixtureAddTextFile("include.bp", includeBp),
|
||||
).RunTest(t)
|
||||
|
||||
var teams *team_proto.AllTeams
|
||||
teams = getTeamProtoOutput(t, ctx)
|
||||
|
||||
// map of module name -> trendy team name.
|
||||
actualTeams := make(map[string]*string)
|
||||
for _, teamProto := range teams.Teams {
|
||||
actualTeams[teamProto.GetTargetName()] = teamProto.TrendyTeamId
|
||||
}
|
||||
expectedTeams := map[string]*string{
|
||||
"IncludedModule": proto.String("trendy://team_top"),
|
||||
}
|
||||
AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams)
|
||||
}
|
||||
|
||||
func TestPackageLookupForIncludedBlueprintFilesWithPackageInChildBlueprint(t *testing.T) {
|
||||
t.Parallel()
|
||||
rootBp := `
|
||||
team {
|
||||
name: "team_top",
|
||||
trendy_team_id: "trendy://team_top",
|
||||
}
|
||||
build = ["include.bp"]
|
||||
`
|
||||
includeBp := `
|
||||
package { default_team: "team_top"}
|
||||
fake {
|
||||
name: "IncludedModule",
|
||||
} `
|
||||
|
||||
ctx := GroupFixturePreparers(
|
||||
prepareForTestWithTeamAndFakes,
|
||||
PrepareForTestWithPackageModule,
|
||||
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory)
|
||||
}),
|
||||
FixtureAddTextFile("Android.bp", rootBp),
|
||||
FixtureAddTextFile("include.bp", includeBp),
|
||||
).RunTest(t)
|
||||
|
||||
var teams *team_proto.AllTeams
|
||||
teams = getTeamProtoOutput(t, ctx)
|
||||
|
||||
// map of module name -> trendy team name.
|
||||
actualTeams := make(map[string]*string)
|
||||
for _, teamProto := range teams.Teams {
|
||||
actualTeams[teamProto.GetTargetName()] = teamProto.TrendyTeamId
|
||||
}
|
||||
expectedTeams := map[string]*string{
|
||||
"IncludedModule": proto.String("trendy://team_top"),
|
||||
}
|
||||
AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams)
|
||||
}
|
||||
|
||||
type fakeForTests struct {
|
||||
ModuleBase
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
"github.com/google/blueprint/bootstrap"
|
||||
"github.com/google/blueprint/pathtools"
|
||||
"github.com/google/blueprint/proptools"
|
||||
)
|
||||
|
|
@ -157,6 +156,7 @@ type AndroidMkEntries struct {
|
|||
}
|
||||
|
||||
type AndroidMkEntriesContext interface {
|
||||
OtherModuleProviderContext
|
||||
Config() Config
|
||||
}
|
||||
|
||||
|
|
@ -170,7 +170,7 @@ type androidMkExtraEntriesContext struct {
|
|||
}
|
||||
|
||||
func (a *androidMkExtraEntriesContext) Provider(provider blueprint.AnyProviderKey) (any, bool) {
|
||||
return a.ctx.moduleProvider(a.mod, provider)
|
||||
return a.ctx.otherModuleProvider(a.mod, provider)
|
||||
}
|
||||
|
||||
type AndroidMkExtraEntriesFunc func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries)
|
||||
|
|
@ -354,14 +354,15 @@ func (a *AndroidMkEntries) getDistContributions(mod blueprint.Module) *distContr
|
|||
availableTaggedDists = availableTaggedDists.addPathsForTag(DefaultDistTag, a.OutputFile.Path())
|
||||
}
|
||||
|
||||
info := OtherModuleProviderOrDefault(a.entryContext, mod, InstallFilesProvider)
|
||||
// If the distFiles created by GenerateTaggedDistFiles contains paths for the
|
||||
// DefaultDistTag then that takes priority so delete any existing paths.
|
||||
if _, ok := amod.distFiles[DefaultDistTag]; ok {
|
||||
if _, ok := info.DistFiles[DefaultDistTag]; ok {
|
||||
delete(availableTaggedDists, DefaultDistTag)
|
||||
}
|
||||
|
||||
// Finally, merge the distFiles created by GenerateTaggedDistFiles.
|
||||
availableTaggedDists = availableTaggedDists.merge(amod.distFiles)
|
||||
availableTaggedDists = availableTaggedDists.merge(info.DistFiles)
|
||||
|
||||
if len(availableTaggedDists) == 0 {
|
||||
// Nothing dist-able for this module.
|
||||
|
|
@ -372,7 +373,7 @@ func (a *AndroidMkEntries) getDistContributions(mod blueprint.Module) *distContr
|
|||
distContributions := &distContributions{}
|
||||
|
||||
if !exemptFromRequiredApplicableLicensesProperty(mod.(Module)) {
|
||||
distContributions.licenseMetadataFile = amod.licenseMetadataFile
|
||||
distContributions.licenseMetadataFile = info.LicenseMetadataFile
|
||||
}
|
||||
|
||||
// Iterate over this module's dist structs, merged from the dist and dists properties.
|
||||
|
|
@ -497,9 +498,10 @@ type fillInEntriesContext interface {
|
|||
ModuleDir(module blueprint.Module) string
|
||||
ModuleSubDir(module blueprint.Module) string
|
||||
Config() Config
|
||||
moduleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
|
||||
otherModuleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
|
||||
ModuleType(module blueprint.Module) string
|
||||
OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{})
|
||||
HasMutatorFinished(mutatorName string) bool
|
||||
}
|
||||
|
||||
func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint.Module) {
|
||||
|
|
@ -516,6 +518,7 @@ func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint
|
|||
a.Include = "$(BUILD_PREBUILT)"
|
||||
}
|
||||
a.Required = append(a.Required, amod.RequiredModuleNames(ctx)...)
|
||||
a.Required = append(a.Required, amod.VintfFragmentModuleNames(ctx)...)
|
||||
a.Host_required = append(a.Host_required, amod.HostRequiredModuleNames()...)
|
||||
a.Target_required = append(a.Target_required, amod.TargetRequiredModuleNames()...)
|
||||
|
||||
|
|
@ -536,13 +539,14 @@ func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint
|
|||
a.AddStrings("LOCAL_SOONG_MODULE_TYPE", ctx.ModuleType(amod))
|
||||
|
||||
// If the install rule was generated by Soong tell Make about it.
|
||||
if len(base.katiInstalls) > 0 {
|
||||
info := OtherModuleProviderOrDefault(ctx, mod, InstallFilesProvider)
|
||||
if len(info.KatiInstalls) > 0 {
|
||||
// Assume the primary install file is last since it probably needs to depend on any other
|
||||
// installed files. If that is not the case we can add a method to specify the primary
|
||||
// installed file.
|
||||
a.SetPath("LOCAL_SOONG_INSTALLED_MODULE", base.katiInstalls[len(base.katiInstalls)-1].to)
|
||||
a.SetString("LOCAL_SOONG_INSTALL_PAIRS", base.katiInstalls.BuiltInstalled())
|
||||
a.SetPaths("LOCAL_SOONG_INSTALL_SYMLINKS", base.katiSymlinks.InstallPaths().Paths())
|
||||
a.SetPath("LOCAL_SOONG_INSTALLED_MODULE", info.KatiInstalls[len(info.KatiInstalls)-1].to)
|
||||
a.SetString("LOCAL_SOONG_INSTALL_PAIRS", info.KatiInstalls.BuiltInstalled())
|
||||
a.SetPaths("LOCAL_SOONG_INSTALL_SYMLINKS", info.KatiSymlinks.InstallPaths().Paths())
|
||||
} else {
|
||||
// Soong may not have generated the install rule also when `no_full_install: true`.
|
||||
// Mark this module as uninstallable in order to prevent Make from creating an
|
||||
|
|
@ -550,8 +554,16 @@ func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint
|
|||
a.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", proptools.Bool(base.commonProperties.No_full_install))
|
||||
}
|
||||
|
||||
if len(base.testData) > 0 {
|
||||
a.AddStrings("LOCAL_TEST_DATA", androidMkDataPaths(base.testData)...)
|
||||
if info.UncheckedModule {
|
||||
a.SetBool("LOCAL_DONT_CHECK_MODULE", true)
|
||||
} else if info.CheckbuildTarget != nil {
|
||||
a.SetPath("LOCAL_CHECKED_MODULE", info.CheckbuildTarget)
|
||||
} else {
|
||||
a.SetOptionalPath("LOCAL_CHECKED_MODULE", a.OutputFile)
|
||||
}
|
||||
|
||||
if len(info.TestData) > 0 {
|
||||
a.AddStrings("LOCAL_TEST_DATA", androidMkDataPaths(info.TestData)...)
|
||||
}
|
||||
|
||||
if am, ok := mod.(ApexModule); ok {
|
||||
|
|
@ -588,10 +600,10 @@ func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint
|
|||
}
|
||||
|
||||
if !base.InVendorRamdisk() {
|
||||
a.AddPaths("LOCAL_FULL_INIT_RC", base.initRcPaths)
|
||||
a.AddPaths("LOCAL_FULL_INIT_RC", info.InitRcPaths)
|
||||
}
|
||||
if len(base.vintfFragmentsPaths) > 0 {
|
||||
a.AddPaths("LOCAL_FULL_VINTF_FRAGMENTS", base.vintfFragmentsPaths)
|
||||
if len(info.VintfFragmentsPaths) > 0 {
|
||||
a.AddPaths("LOCAL_FULL_VINTF_FRAGMENTS", info.VintfFragmentsPaths)
|
||||
}
|
||||
a.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(base.commonProperties.Proprietary))
|
||||
if Bool(base.commonProperties.Vendor) || Bool(base.commonProperties.Soc_specific) {
|
||||
|
|
@ -633,11 +645,11 @@ func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint
|
|||
}
|
||||
}
|
||||
|
||||
if licenseMetadata, ok := SingletonModuleProvider(ctx, mod, LicenseMetadataProvider); ok {
|
||||
if licenseMetadata, ok := OtherModuleProvider(ctx, mod, LicenseMetadataProvider); ok {
|
||||
a.SetPath("LOCAL_SOONG_LICENSE_METADATA", licenseMetadata.LicenseMetadataPath)
|
||||
}
|
||||
|
||||
if _, ok := SingletonModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
|
||||
if _, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
|
||||
a.SetBool("LOCAL_SOONG_MODULE_INFO_JSON", true)
|
||||
}
|
||||
|
||||
|
|
@ -794,15 +806,19 @@ func translateAndroidMkModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs
|
|||
|
||||
// Additional cases here require review for correct license propagation to make.
|
||||
var err error
|
||||
switch x := mod.(type) {
|
||||
case AndroidMkDataProvider:
|
||||
err = translateAndroidModule(ctx, w, moduleInfoJSONs, mod, x)
|
||||
case bootstrap.GoBinaryTool:
|
||||
err = translateGoBinaryModule(ctx, w, mod, x)
|
||||
case AndroidMkEntriesProvider:
|
||||
err = translateAndroidMkEntriesModule(ctx, w, moduleInfoJSONs, mod, x)
|
||||
default:
|
||||
// Not exported to make so no make variables to set.
|
||||
|
||||
if info, ok := ctx.otherModuleProvider(mod, AndroidMkInfoProvider); ok {
|
||||
androidMkEntriesInfos := info.(*AndroidMkProviderInfo)
|
||||
err = translateAndroidMkEntriesInfoModule(ctx, w, moduleInfoJSONs, mod, androidMkEntriesInfos)
|
||||
} else {
|
||||
switch x := mod.(type) {
|
||||
case AndroidMkDataProvider:
|
||||
err = translateAndroidModule(ctx, w, moduleInfoJSONs, mod, x)
|
||||
case AndroidMkEntriesProvider:
|
||||
err = translateAndroidMkEntriesModule(ctx, w, moduleInfoJSONs, mod, x)
|
||||
default:
|
||||
// Not exported to make so no make variables to set.
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
@ -812,23 +828,6 @@ func translateAndroidMkModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs
|
|||
return err
|
||||
}
|
||||
|
||||
// A simple, special Android.mk entry output func to make it possible to build blueprint tools using
|
||||
// m by making them phony targets.
|
||||
func translateGoBinaryModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
|
||||
goBinary bootstrap.GoBinaryTool) error {
|
||||
|
||||
name := ctx.ModuleName(mod)
|
||||
fmt.Fprintln(w, ".PHONY:", name)
|
||||
fmt.Fprintln(w, name+":", goBinary.InstallPath())
|
||||
fmt.Fprintln(w, "")
|
||||
// Assuming no rules in make include go binaries in distributables.
|
||||
// If the assumption is wrong, make will fail to build without the necessary .meta_lic and .meta_module files.
|
||||
// In that case, add the targets and rules here to build a .meta_lic file for `name` and a .meta_module for
|
||||
// `goBinary.InstallPath()` pointing to the `name`.meta_lic file.
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (data *AndroidMkData) fillInData(ctx fillInEntriesContext, mod blueprint.Module) {
|
||||
// Get the preamble content through AndroidMkEntries logic.
|
||||
data.Entries = AndroidMkEntries{
|
||||
|
|
@ -861,6 +860,7 @@ func translateAndroidModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *
|
|||
}
|
||||
|
||||
data := provider.AndroidMk()
|
||||
|
||||
if data.Include == "" {
|
||||
data.Include = "$(BUILD_PREBUILT)"
|
||||
}
|
||||
|
|
@ -900,6 +900,7 @@ func translateAndroidModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *
|
|||
case "*android_sdk.sdkRepoHost": // doesn't go through base_rules
|
||||
case "*apex.apexBundle": // license properties written
|
||||
case "*bpf.bpf": // license properties written (both for module and objs)
|
||||
case "*libbpf_prog.libbpfProg": // license properties written (both for module and objs)
|
||||
case "*genrule.Module": // writes non-custom before adding .phony
|
||||
case "*java.SystemModules": // doesn't go through base_rules
|
||||
case "*java.systemModulesImport": // doesn't go through base_rules
|
||||
|
|
@ -907,6 +908,7 @@ func translateAndroidModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *
|
|||
case "*phony.PhonyRule": // writes phony deps and acts like `.PHONY`
|
||||
case "*selinux.selinuxContextsModule": // license properties written
|
||||
case "*sysprop.syspropLibrary": // license properties written
|
||||
case "*vintf.vintfCompatibilityMatrixRule": // use case like phony
|
||||
default:
|
||||
if !ctx.Config().IsEnvFalse("ANDROID_REQUIRE_LICENSES") {
|
||||
return fmt.Errorf("custom make rules not allowed for %q (%q) module %q", ctx.ModuleType(mod), reflect.TypeOf(mod), ctx.ModuleName(mod))
|
||||
|
|
@ -918,7 +920,7 @@ func translateAndroidModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *
|
|||
}
|
||||
|
||||
if !data.Entries.disabled() {
|
||||
if moduleInfoJSON, ok := SingletonModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
|
||||
if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
|
||||
*moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON)
|
||||
}
|
||||
}
|
||||
|
|
@ -960,7 +962,7 @@ func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, moduleIn
|
|||
}
|
||||
|
||||
if len(entriesList) > 0 && !entriesList[0].disabled() {
|
||||
if moduleInfoJSON, ok := SingletonModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
|
||||
if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
|
||||
*moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON)
|
||||
}
|
||||
}
|
||||
|
|
@ -968,11 +970,11 @@ func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, moduleIn
|
|||
return nil
|
||||
}
|
||||
|
||||
func ShouldSkipAndroidMkProcessing(ctx ConfigAndErrorContext, module Module) bool {
|
||||
func ShouldSkipAndroidMkProcessing(ctx ConfigurableEvaluatorContext, module Module) bool {
|
||||
return shouldSkipAndroidMkProcessing(ctx, module.base())
|
||||
}
|
||||
|
||||
func shouldSkipAndroidMkProcessing(ctx ConfigAndErrorContext, module *ModuleBase) bool {
|
||||
func shouldSkipAndroidMkProcessing(ctx ConfigurableEvaluatorContext, module *ModuleBase) bool {
|
||||
if !module.commonProperties.NamespaceExportedToMake {
|
||||
// TODO(jeffrygaston) do we want to validate that there are no modules being
|
||||
// exported to Kati that depend on this module?
|
||||
|
|
@ -1048,3 +1050,564 @@ func AndroidMkEmitAssignList(w io.Writer, varName string, lists ...[]string) {
|
|||
}
|
||||
fmt.Fprintln(w)
|
||||
}
|
||||
|
||||
type AndroidMkProviderInfo struct {
|
||||
PrimaryInfo AndroidMkInfo
|
||||
ExtraInfo []AndroidMkInfo
|
||||
}
|
||||
|
||||
type AndroidMkInfo struct {
|
||||
// Android.mk class string, e.g. EXECUTABLES, JAVA_LIBRARIES, ETC
|
||||
Class string
|
||||
// Optional suffix to append to the module name. Useful when a module wants to return multiple
|
||||
// AndroidMkEntries objects. For example, when a java_library returns an additional entry for
|
||||
// its hostdex sub-module, this SubName field is set to "-hostdex" so that it can have a
|
||||
// different name than the parent's.
|
||||
SubName string
|
||||
// If set, this value overrides the base module name. SubName is still appended.
|
||||
OverrideName string
|
||||
// Dist files to output
|
||||
DistFiles TaggedDistFiles
|
||||
// The output file for Kati to process and/or install. If absent, the module is skipped.
|
||||
OutputFile OptionalPath
|
||||
// If true, the module is skipped and does not appear on the final Android-<product name>.mk
|
||||
// file. Useful when a module needs to be skipped conditionally.
|
||||
Disabled bool
|
||||
// The postprocessing mk file to include, e.g. $(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk
|
||||
// If not set, $(BUILD_SYSTEM)/prebuilt.mk is used.
|
||||
Include string
|
||||
// Required modules that need to be built and included in the final build output when building
|
||||
// this module.
|
||||
Required []string
|
||||
// Required host modules that need to be built and included in the final build output when
|
||||
// building this module.
|
||||
Host_required []string
|
||||
// Required device modules that need to be built and included in the final build output when
|
||||
// building this module.
|
||||
Target_required []string
|
||||
|
||||
HeaderStrings []string
|
||||
FooterStrings []string
|
||||
|
||||
// A map that holds the up-to-date Make variable values. Can be accessed from tests.
|
||||
EntryMap map[string][]string
|
||||
// A list of EntryMap keys in insertion order. This serves a few purposes:
|
||||
// 1. Prevents churns. Golang map doesn't provide consistent iteration order, so without this,
|
||||
// the outputted Android-*.mk file may change even though there have been no content changes.
|
||||
// 2. Allows modules to refer to other variables, like LOCAL_BAR_VAR := $(LOCAL_FOO_VAR),
|
||||
// without worrying about the variables being mixed up in the actual mk file.
|
||||
// 3. Makes troubleshooting and spotting errors easier.
|
||||
EntryOrder []string
|
||||
}
|
||||
|
||||
// TODO: rename it to AndroidMkEntriesProvider after AndroidMkEntriesProvider interface is gone.
|
||||
var AndroidMkInfoProvider = blueprint.NewProvider[*AndroidMkProviderInfo]()
|
||||
|
||||
func translateAndroidMkEntriesInfoModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON,
|
||||
mod blueprint.Module, providerInfo *AndroidMkProviderInfo) error {
|
||||
if shouldSkipAndroidMkProcessing(ctx, mod.(Module).base()) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Deep copy the provider info since we need to modify the info later
|
||||
info := deepCopyAndroidMkProviderInfo(providerInfo)
|
||||
|
||||
aconfigUpdateAndroidMkInfos(ctx, mod.(Module), &info)
|
||||
|
||||
// Any new or special cases here need review to verify correct propagation of license information.
|
||||
info.PrimaryInfo.fillInEntries(ctx, mod)
|
||||
info.PrimaryInfo.write(w)
|
||||
if len(info.ExtraInfo) > 0 {
|
||||
for _, ei := range info.ExtraInfo {
|
||||
ei.fillInEntries(ctx, mod)
|
||||
ei.write(w)
|
||||
}
|
||||
}
|
||||
|
||||
if !info.PrimaryInfo.disabled() {
|
||||
if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
|
||||
*moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Utility funcs to manipulate Android.mk variable entries.
|
||||
|
||||
// SetString sets a Make variable with the given name to the given value.
|
||||
func (a *AndroidMkInfo) SetString(name, value string) {
|
||||
if _, ok := a.EntryMap[name]; !ok {
|
||||
a.EntryOrder = append(a.EntryOrder, name)
|
||||
}
|
||||
a.EntryMap[name] = []string{value}
|
||||
}
|
||||
|
||||
// SetPath sets a Make variable with the given name to the given path string.
|
||||
func (a *AndroidMkInfo) SetPath(name string, path Path) {
|
||||
if _, ok := a.EntryMap[name]; !ok {
|
||||
a.EntryOrder = append(a.EntryOrder, name)
|
||||
}
|
||||
a.EntryMap[name] = []string{path.String()}
|
||||
}
|
||||
|
||||
// SetOptionalPath sets a Make variable with the given name to the given path string if it is valid.
|
||||
// It is a no-op if the given path is invalid.
|
||||
func (a *AndroidMkInfo) SetOptionalPath(name string, path OptionalPath) {
|
||||
if path.Valid() {
|
||||
a.SetPath(name, path.Path())
|
||||
}
|
||||
}
|
||||
|
||||
// AddPath appends the given path string to a Make variable with the given name.
|
||||
func (a *AndroidMkInfo) AddPath(name string, path Path) {
|
||||
if _, ok := a.EntryMap[name]; !ok {
|
||||
a.EntryOrder = append(a.EntryOrder, name)
|
||||
}
|
||||
a.EntryMap[name] = append(a.EntryMap[name], path.String())
|
||||
}
|
||||
|
||||
// AddOptionalPath appends the given path string to a Make variable with the given name if it is
|
||||
// valid. It is a no-op if the given path is invalid.
|
||||
func (a *AndroidMkInfo) AddOptionalPath(name string, path OptionalPath) {
|
||||
if path.Valid() {
|
||||
a.AddPath(name, path.Path())
|
||||
}
|
||||
}
|
||||
|
||||
// SetPaths sets a Make variable with the given name to a slice of the given path strings.
|
||||
func (a *AndroidMkInfo) SetPaths(name string, paths Paths) {
|
||||
if _, ok := a.EntryMap[name]; !ok {
|
||||
a.EntryOrder = append(a.EntryOrder, name)
|
||||
}
|
||||
a.EntryMap[name] = paths.Strings()
|
||||
}
|
||||
|
||||
// SetOptionalPaths sets a Make variable with the given name to a slice of the given path strings
|
||||
// only if there are a non-zero amount of paths.
|
||||
func (a *AndroidMkInfo) SetOptionalPaths(name string, paths Paths) {
|
||||
if len(paths) > 0 {
|
||||
a.SetPaths(name, paths)
|
||||
}
|
||||
}
|
||||
|
||||
// AddPaths appends the given path strings to a Make variable with the given name.
|
||||
func (a *AndroidMkInfo) AddPaths(name string, paths Paths) {
|
||||
if _, ok := a.EntryMap[name]; !ok {
|
||||
a.EntryOrder = append(a.EntryOrder, name)
|
||||
}
|
||||
a.EntryMap[name] = append(a.EntryMap[name], paths.Strings()...)
|
||||
}
|
||||
|
||||
// SetBoolIfTrue sets a Make variable with the given name to true if the given flag is true.
|
||||
// It is a no-op if the given flag is false.
|
||||
func (a *AndroidMkInfo) SetBoolIfTrue(name string, flag bool) {
|
||||
if flag {
|
||||
if _, ok := a.EntryMap[name]; !ok {
|
||||
a.EntryOrder = append(a.EntryOrder, name)
|
||||
}
|
||||
a.EntryMap[name] = []string{"true"}
|
||||
}
|
||||
}
|
||||
|
||||
// SetBool sets a Make variable with the given name to if the given bool flag value.
|
||||
func (a *AndroidMkInfo) SetBool(name string, flag bool) {
|
||||
if _, ok := a.EntryMap[name]; !ok {
|
||||
a.EntryOrder = append(a.EntryOrder, name)
|
||||
}
|
||||
if flag {
|
||||
a.EntryMap[name] = []string{"true"}
|
||||
} else {
|
||||
a.EntryMap[name] = []string{"false"}
|
||||
}
|
||||
}
|
||||
|
||||
// AddStrings appends the given strings to a Make variable with the given name.
|
||||
func (a *AndroidMkInfo) AddStrings(name string, value ...string) {
|
||||
if len(value) == 0 {
|
||||
return
|
||||
}
|
||||
if _, ok := a.EntryMap[name]; !ok {
|
||||
a.EntryOrder = append(a.EntryOrder, name)
|
||||
}
|
||||
a.EntryMap[name] = append(a.EntryMap[name], value...)
|
||||
}
|
||||
|
||||
// AddCompatibilityTestSuites adds the supplied test suites to the EntryMap, with special handling
|
||||
// for partial MTS and MCTS test suites.
|
||||
func (a *AndroidMkInfo) AddCompatibilityTestSuites(suites ...string) {
|
||||
// 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...)
|
||||
}
|
||||
|
||||
func (a *AndroidMkInfo) fillInEntries(ctx fillInEntriesContext, mod blueprint.Module) {
|
||||
helperInfo := AndroidMkInfo{
|
||||
EntryMap: make(map[string][]string),
|
||||
}
|
||||
|
||||
amod := mod.(Module)
|
||||
base := amod.base()
|
||||
name := base.BaseModuleName()
|
||||
if a.OverrideName != "" {
|
||||
name = a.OverrideName
|
||||
}
|
||||
|
||||
if a.Include == "" {
|
||||
a.Include = "$(BUILD_PREBUILT)"
|
||||
}
|
||||
a.Required = append(a.Required, amod.RequiredModuleNames(ctx)...)
|
||||
a.Required = append(a.Required, amod.VintfFragmentModuleNames(ctx)...)
|
||||
a.Host_required = append(a.Host_required, amod.HostRequiredModuleNames()...)
|
||||
a.Target_required = append(a.Target_required, amod.TargetRequiredModuleNames()...)
|
||||
|
||||
for _, distString := range a.GetDistForGoals(ctx, mod) {
|
||||
a.HeaderStrings = append(a.HeaderStrings, distString)
|
||||
}
|
||||
|
||||
a.HeaderStrings = append(a.HeaderStrings, fmt.Sprintf("\ninclude $(CLEAR_VARS) # type: %s, name: %s, variant: %s\n", ctx.ModuleType(mod), base.BaseModuleName(), ctx.ModuleSubDir(mod)))
|
||||
|
||||
// Collect make variable assignment entries.
|
||||
helperInfo.SetString("LOCAL_PATH", ctx.ModuleDir(mod))
|
||||
helperInfo.SetString("LOCAL_MODULE", name+a.SubName)
|
||||
helperInfo.SetString("LOCAL_MODULE_CLASS", a.Class)
|
||||
helperInfo.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String())
|
||||
helperInfo.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...)
|
||||
helperInfo.AddStrings("LOCAL_HOST_REQUIRED_MODULES", a.Host_required...)
|
||||
helperInfo.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", a.Target_required...)
|
||||
helperInfo.AddStrings("LOCAL_SOONG_MODULE_TYPE", ctx.ModuleType(amod))
|
||||
|
||||
// If the install rule was generated by Soong tell Make about it.
|
||||
info := OtherModuleProviderOrDefault(ctx, mod, InstallFilesProvider)
|
||||
if len(info.KatiInstalls) > 0 {
|
||||
// Assume the primary install file is last since it probably needs to depend on any other
|
||||
// installed files. If that is not the case we can add a method to specify the primary
|
||||
// installed file.
|
||||
helperInfo.SetPath("LOCAL_SOONG_INSTALLED_MODULE", info.KatiInstalls[len(info.KatiInstalls)-1].to)
|
||||
helperInfo.SetString("LOCAL_SOONG_INSTALL_PAIRS", info.KatiInstalls.BuiltInstalled())
|
||||
helperInfo.SetPaths("LOCAL_SOONG_INSTALL_SYMLINKS", info.KatiSymlinks.InstallPaths().Paths())
|
||||
} else {
|
||||
// Soong may not have generated the install rule also when `no_full_install: true`.
|
||||
// Mark this module as uninstallable in order to prevent Make from creating an
|
||||
// install rule there.
|
||||
helperInfo.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", proptools.Bool(base.commonProperties.No_full_install))
|
||||
}
|
||||
|
||||
if len(info.TestData) > 0 {
|
||||
helperInfo.AddStrings("LOCAL_TEST_DATA", androidMkDataPaths(info.TestData)...)
|
||||
}
|
||||
|
||||
if am, ok := mod.(ApexModule); ok {
|
||||
helperInfo.SetBoolIfTrue("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", am.NotAvailableForPlatform())
|
||||
}
|
||||
|
||||
archStr := base.Arch().ArchType.String()
|
||||
host := false
|
||||
switch base.Os().Class {
|
||||
case Host:
|
||||
if base.Target().HostCross {
|
||||
// Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common.
|
||||
if base.Arch().ArchType != Common {
|
||||
helperInfo.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr)
|
||||
}
|
||||
} else {
|
||||
// Make cannot identify LOCAL_MODULE_HOST_ARCH:= common.
|
||||
if base.Arch().ArchType != Common {
|
||||
helperInfo.SetString("LOCAL_MODULE_HOST_ARCH", archStr)
|
||||
}
|
||||
}
|
||||
host = true
|
||||
case Device:
|
||||
// Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common.
|
||||
if base.Arch().ArchType != Common {
|
||||
if base.Target().NativeBridge {
|
||||
hostArchStr := base.Target().NativeBridgeHostArchName
|
||||
if hostArchStr != "" {
|
||||
helperInfo.SetString("LOCAL_MODULE_TARGET_ARCH", hostArchStr)
|
||||
}
|
||||
} else {
|
||||
helperInfo.SetString("LOCAL_MODULE_TARGET_ARCH", archStr)
|
||||
}
|
||||
}
|
||||
|
||||
if !base.InVendorRamdisk() {
|
||||
helperInfo.AddPaths("LOCAL_FULL_INIT_RC", info.InitRcPaths)
|
||||
}
|
||||
if len(info.VintfFragmentsPaths) > 0 {
|
||||
helperInfo.AddPaths("LOCAL_FULL_VINTF_FRAGMENTS", info.VintfFragmentsPaths)
|
||||
}
|
||||
helperInfo.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(base.commonProperties.Proprietary))
|
||||
if Bool(base.commonProperties.Vendor) || Bool(base.commonProperties.Soc_specific) {
|
||||
helperInfo.SetString("LOCAL_VENDOR_MODULE", "true")
|
||||
}
|
||||
helperInfo.SetBoolIfTrue("LOCAL_ODM_MODULE", Bool(base.commonProperties.Device_specific))
|
||||
helperInfo.SetBoolIfTrue("LOCAL_PRODUCT_MODULE", Bool(base.commonProperties.Product_specific))
|
||||
helperInfo.SetBoolIfTrue("LOCAL_SYSTEM_EXT_MODULE", Bool(base.commonProperties.System_ext_specific))
|
||||
if base.commonProperties.Owner != nil {
|
||||
helperInfo.SetString("LOCAL_MODULE_OWNER", *base.commonProperties.Owner)
|
||||
}
|
||||
}
|
||||
|
||||
if host {
|
||||
makeOs := base.Os().String()
|
||||
if base.Os() == Linux || base.Os() == LinuxBionic || base.Os() == LinuxMusl {
|
||||
makeOs = "linux"
|
||||
}
|
||||
helperInfo.SetString("LOCAL_MODULE_HOST_OS", makeOs)
|
||||
helperInfo.SetString("LOCAL_IS_HOST_MODULE", "true")
|
||||
}
|
||||
|
||||
prefix := ""
|
||||
if base.ArchSpecific() {
|
||||
switch base.Os().Class {
|
||||
case Host:
|
||||
if base.Target().HostCross {
|
||||
prefix = "HOST_CROSS_"
|
||||
} else {
|
||||
prefix = "HOST_"
|
||||
}
|
||||
case Device:
|
||||
prefix = "TARGET_"
|
||||
|
||||
}
|
||||
|
||||
if base.Arch().ArchType != ctx.Config().Targets[base.Os()][0].Arch.ArchType {
|
||||
prefix = "2ND_" + prefix
|
||||
}
|
||||
}
|
||||
|
||||
if licenseMetadata, ok := OtherModuleProvider(ctx, mod, LicenseMetadataProvider); ok {
|
||||
helperInfo.SetPath("LOCAL_SOONG_LICENSE_METADATA", licenseMetadata.LicenseMetadataPath)
|
||||
}
|
||||
|
||||
if _, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
|
||||
helperInfo.SetBool("LOCAL_SOONG_MODULE_INFO_JSON", true)
|
||||
}
|
||||
|
||||
a.mergeEntries(&helperInfo)
|
||||
|
||||
// Write to footer.
|
||||
a.FooterStrings = append([]string{"include " + a.Include}, a.FooterStrings...)
|
||||
}
|
||||
|
||||
// This method merges the entries to helperInfo, then replaces a's EntryMap and
|
||||
// EntryOrder with helperInfo's
|
||||
func (a *AndroidMkInfo) mergeEntries(helperInfo *AndroidMkInfo) {
|
||||
for _, extraEntry := range a.EntryOrder {
|
||||
if v, ok := helperInfo.EntryMap[extraEntry]; ok {
|
||||
v = append(v, a.EntryMap[extraEntry]...)
|
||||
} else {
|
||||
helperInfo.EntryMap[extraEntry] = a.EntryMap[extraEntry]
|
||||
helperInfo.EntryOrder = append(helperInfo.EntryOrder, extraEntry)
|
||||
}
|
||||
}
|
||||
a.EntryOrder = helperInfo.EntryOrder
|
||||
a.EntryMap = helperInfo.EntryMap
|
||||
}
|
||||
|
||||
func (a *AndroidMkInfo) 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 *AndroidMkInfo) write(w io.Writer) {
|
||||
if a.disabled() {
|
||||
return
|
||||
}
|
||||
|
||||
combinedHeaderString := strings.Join(a.HeaderStrings, "\n")
|
||||
combinedFooterString := strings.Join(a.FooterStrings, "\n")
|
||||
w.Write([]byte(combinedHeaderString))
|
||||
for _, name := range a.EntryOrder {
|
||||
AndroidMkEmitAssignList(w, name, a.EntryMap[name])
|
||||
}
|
||||
w.Write([]byte(combinedFooterString))
|
||||
}
|
||||
|
||||
// Compute the list of Make strings to declare phony goals and dist-for-goals
|
||||
// calls from the module's dist and dists properties.
|
||||
func (a *AndroidMkInfo) GetDistForGoals(ctx fillInEntriesContext, mod blueprint.Module) []string {
|
||||
distContributions := a.getDistContributions(ctx, mod)
|
||||
if distContributions == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return generateDistContributionsForMake(distContributions)
|
||||
}
|
||||
|
||||
// Compute the contributions that the module makes to the dist.
|
||||
func (a *AndroidMkInfo) getDistContributions(ctx fillInEntriesContext, mod blueprint.Module) *distContributions {
|
||||
amod := mod.(Module).base()
|
||||
name := amod.BaseModuleName()
|
||||
|
||||
// Collate the set of associated tag/paths available for copying to the dist.
|
||||
// Start with an empty (nil) set.
|
||||
var availableTaggedDists TaggedDistFiles
|
||||
|
||||
// Then merge in any that are provided explicitly by the module.
|
||||
if a.DistFiles != nil {
|
||||
// Merge the DistFiles into the set.
|
||||
availableTaggedDists = availableTaggedDists.merge(a.DistFiles)
|
||||
}
|
||||
|
||||
// If no paths have been provided for the DefaultDistTag and the output file is
|
||||
// valid then add that as the default dist path.
|
||||
if _, ok := availableTaggedDists[DefaultDistTag]; !ok && a.OutputFile.Valid() {
|
||||
availableTaggedDists = availableTaggedDists.addPathsForTag(DefaultDistTag, a.OutputFile.Path())
|
||||
}
|
||||
|
||||
info := OtherModuleProviderOrDefault(ctx, mod, InstallFilesProvider)
|
||||
// If the distFiles created by GenerateTaggedDistFiles contains paths for the
|
||||
// DefaultDistTag then that takes priority so delete any existing paths.
|
||||
if _, ok := info.DistFiles[DefaultDistTag]; ok {
|
||||
delete(availableTaggedDists, DefaultDistTag)
|
||||
}
|
||||
|
||||
// Finally, merge the distFiles created by GenerateTaggedDistFiles.
|
||||
availableTaggedDists = availableTaggedDists.merge(info.DistFiles)
|
||||
|
||||
if len(availableTaggedDists) == 0 {
|
||||
// Nothing dist-able for this module.
|
||||
return nil
|
||||
}
|
||||
|
||||
// Collate the contributions this module makes to the dist.
|
||||
distContributions := &distContributions{}
|
||||
|
||||
if !exemptFromRequiredApplicableLicensesProperty(mod.(Module)) {
|
||||
distContributions.licenseMetadataFile = info.LicenseMetadataFile
|
||||
}
|
||||
|
||||
// Iterate over this module's dist structs, merged from the dist and dists properties.
|
||||
for _, dist := range amod.Dists() {
|
||||
// Get the list of goals this dist should be enabled for. e.g. sdk, droidcore
|
||||
goals := strings.Join(dist.Targets, " ")
|
||||
|
||||
// Get the tag representing the output files to be dist'd. e.g. ".jar", ".proguard_map"
|
||||
var tag string
|
||||
if dist.Tag == nil {
|
||||
// If the dist struct does not specify a tag, use the default output files tag.
|
||||
tag = DefaultDistTag
|
||||
} else {
|
||||
tag = *dist.Tag
|
||||
}
|
||||
|
||||
// Get the paths of the output files to be dist'd, represented by the tag.
|
||||
// Can be an empty list.
|
||||
tagPaths := availableTaggedDists[tag]
|
||||
if len(tagPaths) == 0 {
|
||||
// Nothing to dist for this tag, continue to the next dist.
|
||||
continue
|
||||
}
|
||||
|
||||
if len(tagPaths) > 1 && (dist.Dest != nil || dist.Suffix != nil) {
|
||||
errorMessage := "%s: Cannot apply dest/suffix for more than one dist " +
|
||||
"file for %q goals tag %q in module %s. The list of dist files, " +
|
||||
"which should have a single element, is:\n%s"
|
||||
panic(fmt.Errorf(errorMessage, mod, goals, tag, name, tagPaths))
|
||||
}
|
||||
|
||||
copiesForGoals := distContributions.getCopiesForGoals(goals)
|
||||
|
||||
// Iterate over each path adding a copy instruction to copiesForGoals
|
||||
for _, path := range tagPaths {
|
||||
// It's possible that the Path is nil from errant modules. Be defensive here.
|
||||
if path == nil {
|
||||
tagName := "default" // for error message readability
|
||||
if dist.Tag != nil {
|
||||
tagName = *dist.Tag
|
||||
}
|
||||
panic(fmt.Errorf("Dist file should not be nil for the %s tag in %s", tagName, name))
|
||||
}
|
||||
|
||||
dest := filepath.Base(path.String())
|
||||
|
||||
if dist.Dest != nil {
|
||||
var err error
|
||||
if dest, err = validateSafePath(*dist.Dest); err != nil {
|
||||
// This was checked in ModuleBase.GenerateBuildActions
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
ext := filepath.Ext(dest)
|
||||
suffix := ""
|
||||
if dist.Suffix != nil {
|
||||
suffix = *dist.Suffix
|
||||
}
|
||||
|
||||
productString := ""
|
||||
if dist.Append_artifact_with_product != nil && *dist.Append_artifact_with_product {
|
||||
productString = fmt.Sprintf("_%s", ctx.Config().DeviceProduct())
|
||||
}
|
||||
|
||||
if suffix != "" || productString != "" {
|
||||
dest = strings.TrimSuffix(dest, ext) + suffix + productString + ext
|
||||
}
|
||||
|
||||
if dist.Dir != nil {
|
||||
var err error
|
||||
if dest, err = validateSafePath(*dist.Dir, dest); err != nil {
|
||||
// This was checked in ModuleBase.GenerateBuildActions
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
copiesForGoals.addCopyInstruction(path, dest)
|
||||
}
|
||||
}
|
||||
|
||||
return distContributions
|
||||
}
|
||||
|
||||
func deepCopyAndroidMkProviderInfo(providerInfo *AndroidMkProviderInfo) AndroidMkProviderInfo {
|
||||
info := AndroidMkProviderInfo{
|
||||
PrimaryInfo: deepCopyAndroidMkInfo(&providerInfo.PrimaryInfo),
|
||||
}
|
||||
if len(providerInfo.ExtraInfo) > 0 {
|
||||
for _, i := range providerInfo.ExtraInfo {
|
||||
info.ExtraInfo = append(info.ExtraInfo, deepCopyAndroidMkInfo(&i))
|
||||
}
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
func deepCopyAndroidMkInfo(mkinfo *AndroidMkInfo) AndroidMkInfo {
|
||||
info := AndroidMkInfo{
|
||||
Class: mkinfo.Class,
|
||||
SubName: mkinfo.SubName,
|
||||
OverrideName: mkinfo.OverrideName,
|
||||
// There is no modification on DistFiles or OutputFile, so no need to
|
||||
// make their deep copy.
|
||||
DistFiles: mkinfo.DistFiles,
|
||||
OutputFile: mkinfo.OutputFile,
|
||||
Disabled: mkinfo.Disabled,
|
||||
Include: mkinfo.Include,
|
||||
Required: deepCopyStringSlice(mkinfo.Required),
|
||||
Host_required: deepCopyStringSlice(mkinfo.Host_required),
|
||||
Target_required: deepCopyStringSlice(mkinfo.Target_required),
|
||||
HeaderStrings: deepCopyStringSlice(mkinfo.HeaderStrings),
|
||||
FooterStrings: deepCopyStringSlice(mkinfo.FooterStrings),
|
||||
EntryOrder: deepCopyStringSlice(mkinfo.EntryOrder),
|
||||
}
|
||||
info.EntryMap = make(map[string][]string)
|
||||
for k, v := range mkinfo.EntryMap {
|
||||
info.EntryMap[k] = deepCopyStringSlice(v)
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
func deepCopyStringSlice(original []string) []string {
|
||||
result := make([]string, len(original))
|
||||
copy(result, original)
|
||||
return result
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,10 +36,6 @@ type customModule struct {
|
|||
data AndroidMkData
|
||||
distFiles TaggedDistFiles
|
||||
outputFile OptionalPath
|
||||
|
||||
// The paths that will be used as the default dist paths if no tag is
|
||||
// specified.
|
||||
defaultDistPaths Paths
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
@ -50,7 +46,7 @@ const (
|
|||
|
||||
func (m *customModule) GenerateAndroidBuildActions(ctx ModuleContext) {
|
||||
|
||||
m.base().licenseMetadataFile = PathForOutput(ctx, "meta_lic")
|
||||
var defaultDistPaths Paths
|
||||
|
||||
// If the dist_output_file: true then create an output file that is stored in
|
||||
// the OutputFile property of the AndroidMkEntry.
|
||||
|
|
@ -62,7 +58,7 @@ func (m *customModule) GenerateAndroidBuildActions(ctx ModuleContext) {
|
|||
// property in AndroidMkEntry when determining the default dist paths.
|
||||
// Setting this first allows it to be overridden based on the
|
||||
// default_dist_files setting replicating that previous behavior.
|
||||
m.defaultDistPaths = Paths{path}
|
||||
defaultDistPaths = Paths{path}
|
||||
}
|
||||
|
||||
// Based on the setting of the default_dist_files property possibly create a
|
||||
|
|
@ -71,29 +67,40 @@ func (m *customModule) GenerateAndroidBuildActions(ctx ModuleContext) {
|
|||
defaultDistFiles := proptools.StringDefault(m.properties.Default_dist_files, defaultDistFiles_Tagged)
|
||||
switch defaultDistFiles {
|
||||
case defaultDistFiles_None:
|
||||
// Do nothing
|
||||
m.setOutputFiles(ctx, defaultDistPaths)
|
||||
|
||||
case defaultDistFiles_Default:
|
||||
path := PathForTesting("default-dist.out")
|
||||
m.defaultDistPaths = Paths{path}
|
||||
defaultDistPaths = Paths{path}
|
||||
m.setOutputFiles(ctx, defaultDistPaths)
|
||||
m.distFiles = MakeDefaultDistFiles(path)
|
||||
|
||||
case defaultDistFiles_Tagged:
|
||||
// Module types that set AndroidMkEntry.DistFiles to the result of calling
|
||||
// GenerateTaggedDistFiles(ctx) relied on no tag being treated as "" which
|
||||
// meant that the default dist paths would be whatever was returned by
|
||||
// OutputFiles(""). In order to preserve that behavior when treating no tag
|
||||
// as being equal to DefaultDistTag this ensures that
|
||||
// OutputFiles(DefaultDistTag) will return the same as OutputFiles("").
|
||||
m.defaultDistPaths = PathsForTesting("one.out")
|
||||
// meant that the default dist paths would be the same as empty-string-tag
|
||||
// output files. In order to preserve that behavior when treating no tag
|
||||
// as being equal to DefaultDistTag this ensures that DefaultDistTag output
|
||||
// will be the same as empty-string-tag output.
|
||||
defaultDistPaths = PathsForTesting("one.out")
|
||||
m.setOutputFiles(ctx, defaultDistPaths)
|
||||
|
||||
// This must be called after setting defaultDistPaths/outputFile as
|
||||
// GenerateTaggedDistFiles calls into OutputFiles(tag) which may use those
|
||||
// fields.
|
||||
// GenerateTaggedDistFiles calls into outputFiles property which may use
|
||||
// those fields.
|
||||
m.distFiles = m.GenerateTaggedDistFiles(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *customModule) setOutputFiles(ctx ModuleContext, defaultDistPaths Paths) {
|
||||
ctx.SetOutputFiles(PathsForTesting("one.out"), "")
|
||||
ctx.SetOutputFiles(PathsForTesting("two.out", "three/four.out"), ".multiple")
|
||||
ctx.SetOutputFiles(PathsForTesting("another.out"), ".another-tag")
|
||||
if defaultDistPaths != nil {
|
||||
ctx.SetOutputFiles(defaultDistPaths, DefaultDistTag)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *customModule) AndroidMk() AndroidMkData {
|
||||
return AndroidMkData{
|
||||
Custom: func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) {
|
||||
|
|
@ -102,25 +109,6 @@ func (m *customModule) AndroidMk() AndroidMkData {
|
|||
}
|
||||
}
|
||||
|
||||
func (m *customModule) OutputFiles(tag string) (Paths, error) {
|
||||
switch tag {
|
||||
case DefaultDistTag:
|
||||
if m.defaultDistPaths != nil {
|
||||
return m.defaultDistPaths, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("default dist tag is not available")
|
||||
}
|
||||
case "":
|
||||
return PathsForTesting("one.out"), nil
|
||||
case ".multiple":
|
||||
return PathsForTesting("two.out", "three/four.out"), nil
|
||||
case ".another-tag":
|
||||
return PathsForTesting("another.out"), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported module reference tag %q", tag)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *customModule) AndroidMkEntries() []AndroidMkEntries {
|
||||
return []AndroidMkEntries{
|
||||
{
|
||||
|
|
@ -287,7 +275,8 @@ func TestGetDistForGoals(t *testing.T) {
|
|||
)
|
||||
}
|
||||
for idx, line := range androidMkLines {
|
||||
expectedLine := strings.ReplaceAll(expectedAndroidMkLines[idx], "meta_lic", module.base().licenseMetadataFile.String())
|
||||
expectedLine := strings.ReplaceAll(expectedAndroidMkLines[idx], "meta_lic",
|
||||
OtherModuleProviderOrDefault(ctx, module, InstallFilesProvider).LicenseMetadataFile.String())
|
||||
if line != expectedLine {
|
||||
t.Errorf(
|
||||
"Expected AndroidMk line to be '%s', got '%s'",
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ package android
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
|
@ -84,6 +85,12 @@ type ApexInfo struct {
|
|||
|
||||
// Returns the name of the test apexes that this module is included in.
|
||||
TestApexes []string
|
||||
|
||||
// Returns the name of the overridden apex (com.android.foo)
|
||||
BaseApexName string
|
||||
|
||||
// Returns the value of `apex_available_name`
|
||||
ApexAvailableName string
|
||||
}
|
||||
|
||||
// AllApexInfo holds the ApexInfo of all apexes that include this module.
|
||||
|
|
@ -142,6 +149,17 @@ func (i ApexInfo) InApexModule(apexModuleName string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// To satisfy the comparable interface
|
||||
func (i ApexInfo) Equal(other any) bool {
|
||||
otherApexInfo, ok := other.(ApexInfo)
|
||||
return ok && i.ApexVariationName == otherApexInfo.ApexVariationName &&
|
||||
i.MinSdkVersion == otherApexInfo.MinSdkVersion &&
|
||||
i.Updatable == otherApexInfo.Updatable &&
|
||||
i.UsePlatformApis == otherApexInfo.UsePlatformApis &&
|
||||
reflect.DeepEqual(i.InApexVariants, otherApexInfo.InApexVariants) &&
|
||||
reflect.DeepEqual(i.InApexModules, otherApexInfo.InApexModules)
|
||||
}
|
||||
|
||||
// ApexTestForInfo stores the contents of APEXes for which this module is a test - although this
|
||||
// module is not part of the APEX - and thus has access to APEX internals.
|
||||
type ApexTestForInfo struct {
|
||||
|
|
@ -277,7 +295,7 @@ type ApexProperties struct {
|
|||
//
|
||||
// "//apex_available:anyapex" is a pseudo APEX name that matches to any APEX.
|
||||
// "//apex_available:platform" refers to non-APEX partitions like "system.img".
|
||||
// "com.android.gki.*" matches any APEX module name with the prefix "com.android.gki.".
|
||||
// Prefix pattern (com.foo.*) can be used to match with any APEX name with the prefix(com.foo.).
|
||||
// Default is ["//apex_available:platform"].
|
||||
Apex_available []string
|
||||
|
||||
|
|
@ -470,15 +488,6 @@ func (m *ApexModuleBase) DepIsInSameApex(ctx BaseModuleContext, dep Module) bool
|
|||
const (
|
||||
AvailableToPlatform = "//apex_available:platform"
|
||||
AvailableToAnyApex = "//apex_available:anyapex"
|
||||
AvailableToGkiApex = "com.android.gki.*"
|
||||
)
|
||||
|
||||
var (
|
||||
AvailableToRecognziedWildcards = []string{
|
||||
AvailableToPlatform,
|
||||
AvailableToAnyApex,
|
||||
AvailableToGkiApex,
|
||||
}
|
||||
)
|
||||
|
||||
// CheckAvailableForApex provides the default algorithm for checking the apex availability. When the
|
||||
|
|
@ -491,11 +500,27 @@ func CheckAvailableForApex(what string, apex_available []string) bool {
|
|||
if len(apex_available) == 0 {
|
||||
return what == AvailableToPlatform
|
||||
}
|
||||
return InList(what, apex_available) ||
|
||||
(what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available)) ||
|
||||
(strings.HasPrefix(what, "com.android.gki.") && InList(AvailableToGkiApex, apex_available)) ||
|
||||
(what == "com.google.mainline.primary.libs") || // TODO b/248601389
|
||||
(what == "com.google.mainline.go.primary.libs") // TODO b/248601389
|
||||
|
||||
// TODO b/248601389
|
||||
if what == "com.google.mainline.primary.libs" || what == "com.google.mainline.go.primary.libs" {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, apex_name := range apex_available {
|
||||
// exact match.
|
||||
if apex_name == what {
|
||||
return true
|
||||
}
|
||||
// //apex_available:anyapex matches with any apex name, but not //apex_available:platform
|
||||
if apex_name == AvailableToAnyApex && what != AvailableToPlatform {
|
||||
return true
|
||||
}
|
||||
// prefix match.
|
||||
if strings.HasSuffix(apex_name, ".*") && strings.HasPrefix(what, strings.TrimSuffix(apex_name, "*")) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Implements ApexModule
|
||||
|
|
@ -521,7 +546,20 @@ func (m *ApexModuleBase) SetNotAvailableForPlatform() {
|
|||
// This function makes sure that the apex_available property is valid
|
||||
func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
|
||||
for _, n := range m.ApexProperties.Apex_available {
|
||||
if n == AvailableToPlatform || n == AvailableToAnyApex || n == AvailableToGkiApex {
|
||||
if n == AvailableToPlatform || n == AvailableToAnyApex {
|
||||
continue
|
||||
}
|
||||
// Prefix pattern should end with .* and has at least two components.
|
||||
if strings.Contains(n, "*") {
|
||||
if !strings.HasSuffix(n, ".*") {
|
||||
mctx.PropertyErrorf("apex_available", "Wildcard should end with .* like com.foo.*")
|
||||
}
|
||||
if strings.Count(n, ".") < 2 {
|
||||
mctx.PropertyErrorf("apex_available", "Wildcard requires two or more components like com.foo.*")
|
||||
}
|
||||
if strings.Count(n, "*") != 1 {
|
||||
mctx.PropertyErrorf("apex_available", "Wildcard is not allowed in the middle.")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !mctx.OtherModuleExists(n) && !mctx.Config().AllowMissingDependencies() {
|
||||
|
|
@ -607,9 +645,15 @@ func IncomingApexTransition(ctx IncomingTransitionContext, incomingVariation str
|
|||
return ""
|
||||
}
|
||||
|
||||
// If this module has no apex variations the use the platform variation.
|
||||
if len(apexInfos) == 0 {
|
||||
return ""
|
||||
if ctx.IsAddingDependency() {
|
||||
// If this module has no apex variations we can't do any mapping on the incoming variation, just return it
|
||||
// and let the caller get a "missing variant" error.
|
||||
return incomingVariation
|
||||
} else {
|
||||
// If this module has no apex variations the use the platform variation.
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the list of apex infos into from the AllApexInfoProvider into the merged list
|
||||
|
|
@ -671,7 +715,7 @@ func MutateApexTransition(ctx BaseModuleContext, variation string) {
|
|||
base.ApexProperties.InAnyApex = true
|
||||
base.ApexProperties.DirectlyInAnyApex = inApex == directlyInApex
|
||||
|
||||
if platformVariation && !ctx.Host() && !module.AvailableFor(AvailableToPlatform) {
|
||||
if platformVariation && !ctx.Host() && !module.AvailableFor(AvailableToPlatform) && module.NotAvailableForPlatform() {
|
||||
// Do not install the module for platform, but still allow it to output
|
||||
// uninstallable AndroidMk entries in certain cases when they have side
|
||||
// effects. TODO(jiyong): move this routine to somewhere else
|
||||
|
|
|
|||
316
android/arch.go
316
android/arch.go
|
|
@ -19,10 +19,10 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
"github.com/google/blueprint/bootstrap"
|
||||
"github.com/google/blueprint/proptools"
|
||||
)
|
||||
|
||||
|
|
@ -396,45 +396,21 @@ func (target Target) Variations() []blueprint.Variation {
|
|||
// device_supported and host_supported properties to determine which OsTypes are enabled for this
|
||||
// module, then searches through the Targets to determine which have enabled Targets for this
|
||||
// module.
|
||||
func osMutator(bpctx blueprint.BottomUpMutatorContext) {
|
||||
var module Module
|
||||
var ok bool
|
||||
if module, ok = bpctx.Module().(Module); !ok {
|
||||
// The module is not a Soong module, it is a Blueprint module.
|
||||
if bootstrap.IsBootstrapModule(bpctx.Module()) {
|
||||
// Bootstrap Go modules are always the build OS or linux bionic.
|
||||
config := bpctx.Config().(Config)
|
||||
osNames := []string{config.BuildOSTarget.OsVariation()}
|
||||
for _, hostCrossTarget := range config.Targets[LinuxBionic] {
|
||||
if hostCrossTarget.Arch.ArchType == config.BuildOSTarget.Arch.ArchType {
|
||||
osNames = append(osNames, hostCrossTarget.OsVariation())
|
||||
}
|
||||
}
|
||||
osNames = FirstUniqueStrings(osNames)
|
||||
bpctx.CreateVariations(osNames...)
|
||||
}
|
||||
return
|
||||
}
|
||||
type osTransitionMutator struct{}
|
||||
|
||||
// Bootstrap Go module support above requires this mutator to be a
|
||||
// blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext
|
||||
// filters out non-Soong modules. Now that we've handled them, create a
|
||||
// normal android.BottomUpMutatorContext.
|
||||
mctx := bottomUpMutatorContextFactory(bpctx, module, false)
|
||||
defer bottomUpMutatorContextPool.Put(mctx)
|
||||
type allOsInfo struct {
|
||||
Os map[string]OsType
|
||||
Variations []string
|
||||
}
|
||||
|
||||
base := module.base()
|
||||
var allOsProvider = blueprint.NewMutatorProvider[*allOsInfo]("os_propagate")
|
||||
|
||||
// Nothing to do for modules that are not architecture specific (e.g. a genrule).
|
||||
if !base.ArchSpecific() {
|
||||
return
|
||||
}
|
||||
|
||||
// Collect a list of OSTypes supported by this module based on the HostOrDevice value
|
||||
// passed to InitAndroidArchModule and the device_supported and host_supported properties.
|
||||
// moduleOSList collects a list of OSTypes supported by this module based on the HostOrDevice
|
||||
// value passed to InitAndroidArchModule and the device_supported and host_supported properties.
|
||||
func moduleOSList(ctx ConfigContext, base *ModuleBase) []OsType {
|
||||
var moduleOSList []OsType
|
||||
for _, os := range osTypeList {
|
||||
for _, t := range mctx.Config().Targets[os] {
|
||||
for _, t := range ctx.Config().Targets[os] {
|
||||
if base.supportsTarget(t) {
|
||||
moduleOSList = append(moduleOSList, os)
|
||||
break
|
||||
|
|
@ -442,53 +418,91 @@ func osMutator(bpctx blueprint.BottomUpMutatorContext) {
|
|||
}
|
||||
}
|
||||
|
||||
createCommonOSVariant := base.commonProperties.CreateCommonOSVariant
|
||||
if base.commonProperties.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
|
||||
// the other variants and inter variant dependencies can only be created from a
|
||||
// later variant in that list to an earlier one. That is because variants are
|
||||
// always processed in the order in which they are created.
|
||||
moduleOSList = append(moduleOSList, CommonOS)
|
||||
}
|
||||
|
||||
return moduleOSList
|
||||
}
|
||||
|
||||
func (o *osTransitionMutator) Split(ctx BaseModuleContext) []string {
|
||||
module := ctx.Module()
|
||||
base := module.base()
|
||||
|
||||
// Nothing to do for modules that are not architecture specific (e.g. a genrule).
|
||||
if !base.ArchSpecific() {
|
||||
return []string{""}
|
||||
}
|
||||
|
||||
moduleOSList := moduleOSList(ctx, base)
|
||||
|
||||
// If there are no supported OSes then disable the module.
|
||||
if len(moduleOSList) == 0 && !createCommonOSVariant {
|
||||
if len(moduleOSList) == 0 {
|
||||
base.Disable()
|
||||
return
|
||||
return []string{""}
|
||||
}
|
||||
|
||||
// Convert the list of supported OsTypes to the variation names.
|
||||
osNames := make([]string, len(moduleOSList))
|
||||
osMapping := make(map[string]OsType, len(moduleOSList))
|
||||
for i, os := range moduleOSList {
|
||||
osNames[i] = os.String()
|
||||
osMapping[osNames[i]] = os
|
||||
}
|
||||
|
||||
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
|
||||
// the other variants in the list returned by CreateVariations(...) and inter
|
||||
// variant dependencies can only be created from a later variant in that list to
|
||||
// an earlier one. That is because variants are always processed in the order in
|
||||
// which they are returned from CreateVariations(...).
|
||||
osNames = append(osNames, CommonOS.Name)
|
||||
moduleOSList = append(moduleOSList, CommonOS)
|
||||
SetProvider(ctx, allOsProvider, &allOsInfo{
|
||||
Os: osMapping,
|
||||
Variations: osNames,
|
||||
})
|
||||
|
||||
return osNames
|
||||
}
|
||||
|
||||
func (o *osTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
|
||||
return sourceVariation
|
||||
}
|
||||
|
||||
func (o *osTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
|
||||
module := ctx.Module()
|
||||
base := module.base()
|
||||
|
||||
if !base.ArchSpecific() {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Create the variations, annotate each one with which OS it was created for, and
|
||||
return incomingVariation
|
||||
}
|
||||
|
||||
func (o *osTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
|
||||
module := ctx.Module()
|
||||
base := module.base()
|
||||
|
||||
if variation == "" {
|
||||
return
|
||||
}
|
||||
|
||||
allOsInfo, ok := ModuleProvider(ctx, allOsProvider)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("missing allOsProvider"))
|
||||
}
|
||||
|
||||
// Annotate this variant with which OS it was created for, and
|
||||
// squash the appropriate OS-specific properties into the top level properties.
|
||||
modules := mctx.CreateVariations(osNames...)
|
||||
for i, m := range modules {
|
||||
m.base().commonProperties.CompileOS = moduleOSList[i]
|
||||
m.base().setOSProperties(mctx)
|
||||
}
|
||||
base.commonProperties.CompileOS = allOsInfo.Os[variation]
|
||||
base.setOSProperties(ctx)
|
||||
|
||||
if createCommonOSVariant {
|
||||
if variation == CommonOS.String() {
|
||||
// A CommonOS variant was requested so add dependencies from it (the last one in
|
||||
// the list) to the OS type specific variants.
|
||||
last := len(modules) - 1
|
||||
commonOSVariant := modules[last]
|
||||
commonOSVariant.base().commonProperties.CommonOSVariant = true
|
||||
for _, module := range modules[0:last] {
|
||||
// Ignore modules that are enabled. Note, this will only avoid adding
|
||||
// dependencies on OsType variants that are explicitly disabled in their
|
||||
// properties. The CommonOS variant will still depend on disabled variants
|
||||
// if they are disabled afterwards, e.g. in archMutator if
|
||||
if module.Enabled(mctx) {
|
||||
mctx.AddInterVariantDependency(commonOsToOsSpecificVariantTag, commonOSVariant, module)
|
||||
}
|
||||
osList := allOsInfo.Variations[:len(allOsInfo.Variations)-1]
|
||||
for _, os := range osList {
|
||||
variation := []blueprint.Variation{{"os", os}}
|
||||
ctx.AddVariationDependencies(variation, commonOsToOsSpecificVariantTag, ctx.ModuleName())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -521,7 +535,7 @@ func GetOsSpecificVariantsOfCommonOSVariant(mctx BaseModuleContext) []Module {
|
|||
|
||||
var DarwinUniversalVariantTag = archDepTag{name: "darwin universal binary"}
|
||||
|
||||
// archMutator splits a module into a variant for each Target requested by the module. Target selection
|
||||
// archTransitionMutator splits a module into a variant for each Target requested by the module. Target selection
|
||||
// for a module is in three levels, OsClass, multilib, and then Target.
|
||||
// OsClass selection is determined by:
|
||||
// - The HostOrDeviceSupported value passed in to InitAndroidArchModule by the module type factory, which selects
|
||||
|
|
@ -552,54 +566,47 @@ var DarwinUniversalVariantTag = archDepTag{name: "darwin universal binary"}
|
|||
//
|
||||
// Modules can be initialized with InitAndroidMultiTargetsArchModule, in which case they will be split by OsClass,
|
||||
// but will have a common Target that is expected to handle all other selected Targets via ctx.MultiTargets().
|
||||
func archMutator(bpctx blueprint.BottomUpMutatorContext) {
|
||||
var module Module
|
||||
var ok bool
|
||||
if module, ok = bpctx.Module().(Module); !ok {
|
||||
if bootstrap.IsBootstrapModule(bpctx.Module()) {
|
||||
// Bootstrap Go modules are always the build architecture.
|
||||
bpctx.CreateVariations(bpctx.Config().(Config).BuildOSTarget.ArchVariation())
|
||||
}
|
||||
return
|
||||
}
|
||||
type archTransitionMutator struct{}
|
||||
|
||||
// Bootstrap Go module support above requires this mutator to be a
|
||||
// blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext
|
||||
// filters out non-Soong modules. Now that we've handled them, create a
|
||||
// normal android.BottomUpMutatorContext.
|
||||
mctx := bottomUpMutatorContextFactory(bpctx, module, false)
|
||||
defer bottomUpMutatorContextPool.Put(mctx)
|
||||
type allArchInfo struct {
|
||||
Targets map[string]Target
|
||||
MultiTargets []Target
|
||||
Primary string
|
||||
Multilib string
|
||||
}
|
||||
|
||||
var allArchProvider = blueprint.NewMutatorProvider[*allArchInfo]("arch_propagate")
|
||||
|
||||
func (a *archTransitionMutator) Split(ctx BaseModuleContext) []string {
|
||||
module := ctx.Module()
|
||||
base := module.base()
|
||||
|
||||
if !base.ArchSpecific() {
|
||||
return
|
||||
return []string{""}
|
||||
}
|
||||
|
||||
os := base.commonProperties.CompileOS
|
||||
if os == CommonOS {
|
||||
// Make sure that the target related properties are initialized for the
|
||||
// CommonOS variant.
|
||||
addTargetProperties(module, commonTargetMap[os.Name], nil, true)
|
||||
|
||||
// Do not create arch specific variants for the CommonOS variant.
|
||||
return
|
||||
return []string{""}
|
||||
}
|
||||
|
||||
osTargets := mctx.Config().Targets[os]
|
||||
osTargets := ctx.Config().Targets[os]
|
||||
|
||||
image := base.commonProperties.ImageVariation
|
||||
// Filter NativeBridge targets unless they are explicitly supported.
|
||||
// Skip creating native bridge variants for non-core modules.
|
||||
if os == Android && !(base.IsNativeBridgeSupported() && image == CoreVariation) {
|
||||
osTargets = slices.DeleteFunc(slices.Clone(osTargets), func(t Target) bool {
|
||||
return bool(t.NativeBridge)
|
||||
})
|
||||
}
|
||||
|
||||
var targets []Target
|
||||
for _, t := range osTargets {
|
||||
if !t.NativeBridge {
|
||||
targets = append(targets, t)
|
||||
}
|
||||
}
|
||||
|
||||
osTargets = targets
|
||||
// Filter HostCross targets if disabled.
|
||||
if base.HostSupported() && !base.HostCrossSupported() {
|
||||
osTargets = slices.DeleteFunc(slices.Clone(osTargets), func(t Target) bool {
|
||||
return t.HostCross
|
||||
})
|
||||
}
|
||||
|
||||
// only the primary arch in the ramdisk / vendor_ramdisk / recovery partition
|
||||
|
|
@ -611,19 +618,18 @@ func archMutator(bpctx blueprint.BottomUpMutatorContext) {
|
|||
prefer32 := os == Windows
|
||||
|
||||
// Determine the multilib selection for this module.
|
||||
ignorePrefer32OnDevice := mctx.Config().IgnorePrefer32OnDevice()
|
||||
multilib, extraMultilib := decodeMultilib(base, os, ignorePrefer32OnDevice)
|
||||
multilib, extraMultilib := decodeMultilib(ctx, base)
|
||||
|
||||
// Convert the multilib selection into a list of Targets.
|
||||
targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
|
||||
if err != nil {
|
||||
mctx.ModuleErrorf("%s", err.Error())
|
||||
ctx.ModuleErrorf("%s", err.Error())
|
||||
}
|
||||
|
||||
// If there are no supported targets disable the module.
|
||||
if len(targets) == 0 {
|
||||
base.Disable()
|
||||
return
|
||||
return []string{""}
|
||||
}
|
||||
|
||||
// If the module is using extraMultilib, decode the extraMultilib selection into
|
||||
|
|
@ -632,7 +638,7 @@ func archMutator(bpctx blueprint.BottomUpMutatorContext) {
|
|||
if extraMultilib != "" {
|
||||
multiTargets, err = decodeMultilibTargets(extraMultilib, osTargets, prefer32)
|
||||
if err != nil {
|
||||
mctx.ModuleErrorf("%s", err.Error())
|
||||
ctx.ModuleErrorf("%s", err.Error())
|
||||
}
|
||||
multiTargets = filterHostCross(multiTargets, targets[0].HostCross)
|
||||
}
|
||||
|
|
@ -640,7 +646,7 @@ func archMutator(bpctx blueprint.BottomUpMutatorContext) {
|
|||
// Recovery is always the primary architecture, filter out any other architectures.
|
||||
// Common arch is also allowed
|
||||
if image == RecoveryVariation {
|
||||
primaryArch := mctx.Config().DevicePrimaryArchType()
|
||||
primaryArch := ctx.Config().DevicePrimaryArchType()
|
||||
targets = filterToArch(targets, primaryArch, Common)
|
||||
multiTargets = filterToArch(multiTargets, primaryArch, Common)
|
||||
}
|
||||
|
|
@ -648,37 +654,109 @@ func archMutator(bpctx blueprint.BottomUpMutatorContext) {
|
|||
// If there are no supported targets disable the module.
|
||||
if len(targets) == 0 {
|
||||
base.Disable()
|
||||
return
|
||||
return []string{""}
|
||||
}
|
||||
|
||||
// Convert the targets into a list of arch variation names.
|
||||
targetNames := make([]string, len(targets))
|
||||
targetMapping := make(map[string]Target, len(targets))
|
||||
for i, target := range targets {
|
||||
targetNames[i] = target.ArchVariation()
|
||||
targetMapping[targetNames[i]] = targets[i]
|
||||
}
|
||||
|
||||
// Create the variations, annotate each one with which Target it was created for, and
|
||||
// squash the appropriate arch-specific properties into the top level properties.
|
||||
modules := mctx.CreateVariations(targetNames...)
|
||||
for i, m := range modules {
|
||||
addTargetProperties(m, targets[i], multiTargets, i == 0)
|
||||
m.base().setArchProperties(mctx)
|
||||
SetProvider(ctx, allArchProvider, &allArchInfo{
|
||||
Targets: targetMapping,
|
||||
MultiTargets: multiTargets,
|
||||
Primary: targetNames[0],
|
||||
Multilib: multilib,
|
||||
})
|
||||
return targetNames
|
||||
}
|
||||
|
||||
// Install support doesn't understand Darwin+Arm64
|
||||
if os == Darwin && targets[i].HostCross {
|
||||
m.base().commonProperties.SkipInstall = true
|
||||
func (a *archTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
|
||||
return sourceVariation
|
||||
}
|
||||
|
||||
func (a *archTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
|
||||
module := ctx.Module()
|
||||
base := module.base()
|
||||
|
||||
if !base.ArchSpecific() {
|
||||
return ""
|
||||
}
|
||||
|
||||
os := base.commonProperties.CompileOS
|
||||
if os == CommonOS {
|
||||
// Do not create arch specific variants for the CommonOS variant.
|
||||
return ""
|
||||
}
|
||||
|
||||
if incomingVariation == "" {
|
||||
multilib, _ := decodeMultilib(ctx, base)
|
||||
if multilib == "common" {
|
||||
return "common"
|
||||
}
|
||||
}
|
||||
return incomingVariation
|
||||
}
|
||||
|
||||
func (a *archTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
|
||||
module := ctx.Module()
|
||||
base := module.base()
|
||||
os := base.commonProperties.CompileOS
|
||||
|
||||
if os == CommonOS {
|
||||
// Make sure that the target related properties are initialized for the
|
||||
// CommonOS variant.
|
||||
addTargetProperties(module, commonTargetMap[os.Name], nil, true)
|
||||
return
|
||||
}
|
||||
|
||||
if variation == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if !base.ArchSpecific() {
|
||||
panic(fmt.Errorf("found variation %q for non arch specifc module", variation))
|
||||
}
|
||||
|
||||
allArchInfo, ok := ModuleProvider(ctx, allArchProvider)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
target, ok := allArchInfo.Targets[variation]
|
||||
if !ok {
|
||||
panic(fmt.Errorf("missing Target for %q", variation))
|
||||
}
|
||||
primary := variation == allArchInfo.Primary
|
||||
multiTargets := allArchInfo.MultiTargets
|
||||
|
||||
// Annotate the new variant with which Target it was created for, and
|
||||
// squash the appropriate arch-specific properties into the top level properties.
|
||||
addTargetProperties(ctx.Module(), target, multiTargets, primary)
|
||||
base.setArchProperties(ctx)
|
||||
|
||||
// Install support doesn't understand Darwin+Arm64
|
||||
if os == Darwin && target.HostCross {
|
||||
base.commonProperties.SkipInstall = true
|
||||
}
|
||||
|
||||
// Create a dependency for Darwin Universal binaries from the primary to secondary
|
||||
// architecture. The module itself will be responsible for calling lipo to merge the outputs.
|
||||
if os == Darwin {
|
||||
if multilib == "darwin_universal" && len(modules) == 2 {
|
||||
mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[1], modules[0])
|
||||
} else if multilib == "darwin_universal_common_first" && len(modules) == 3 {
|
||||
mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[2], modules[1])
|
||||
isUniversalBinary := (allArchInfo.Multilib == "darwin_universal" && len(allArchInfo.Targets) == 2) ||
|
||||
allArchInfo.Multilib == "darwin_universal_common_first" && len(allArchInfo.Targets) == 3
|
||||
isPrimary := variation == ctx.Config().BuildArch.String()
|
||||
hasSecondaryConfigured := len(ctx.Config().Targets[Darwin]) > 1
|
||||
if isUniversalBinary && isPrimary && hasSecondaryConfigured {
|
||||
secondaryArch := ctx.Config().Targets[Darwin][1].Arch.String()
|
||||
variation := []blueprint.Variation{{"arch", secondaryArch}}
|
||||
ctx.AddVariationDependencies(variation, DarwinUniversalVariantTag, ctx.ModuleName())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// addTargetProperties annotates a variant with the Target is is being compiled for, the list
|
||||
|
|
@ -695,7 +773,9 @@ func addTargetProperties(m Module, target Target, multiTargets []Target, primary
|
|||
// multilib from the factory's call to InitAndroidArchModule if none was set. For modules that
|
||||
// called InitAndroidMultiTargetsArchModule it always returns "common" for multilib, and returns
|
||||
// the actual multilib in extraMultilib.
|
||||
func decodeMultilib(base *ModuleBase, os OsType, ignorePrefer32OnDevice bool) (multilib, extraMultilib string) {
|
||||
func decodeMultilib(ctx ConfigContext, base *ModuleBase) (multilib, extraMultilib string) {
|
||||
os := base.commonProperties.CompileOS
|
||||
ignorePrefer32OnDevice := ctx.Config().IgnorePrefer32OnDevice()
|
||||
// First check the "android.compile_multilib" or "host.compile_multilib" properties.
|
||||
switch os.Class {
|
||||
case Device:
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ package android
|
|||
|
||||
var archVariants = map[ArchType][]string{
|
||||
Arm: {
|
||||
"armv7-a",
|
||||
"armv7-a-neon",
|
||||
"armv8-a",
|
||||
"armv8-2a",
|
||||
|
|
@ -27,6 +26,7 @@ var archVariants = map[ArchType][]string{
|
|||
"armv8-2a",
|
||||
"armv8-2a-dotprod",
|
||||
"armv9-a",
|
||||
"armv9-2a",
|
||||
},
|
||||
X86: {
|
||||
"amberlake",
|
||||
|
|
@ -160,6 +160,9 @@ var androidArchFeatureMap = map[ArchType]map[string][]string{
|
|||
"armv9-a": {
|
||||
"dotprod",
|
||||
},
|
||||
"armv9-2a": {
|
||||
"dotprod",
|
||||
},
|
||||
},
|
||||
X86: {
|
||||
"amberlake": {
|
||||
|
|
|
|||
|
|
@ -331,6 +331,12 @@ func TestArchMutator(t *testing.T) {
|
|||
host_supported: true,
|
||||
}
|
||||
|
||||
module {
|
||||
name: "nohostcross",
|
||||
host_supported: true,
|
||||
host_cross_supported: false,
|
||||
}
|
||||
|
||||
module {
|
||||
name: "baz",
|
||||
device_supported: false,
|
||||
|
|
@ -355,13 +361,14 @@ func TestArchMutator(t *testing.T) {
|
|||
`
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
preparer FixturePreparer
|
||||
fooVariants []string
|
||||
barVariants []string
|
||||
bazVariants []string
|
||||
quxVariants []string
|
||||
firstVariants []string
|
||||
name string
|
||||
preparer FixturePreparer
|
||||
fooVariants []string
|
||||
barVariants []string
|
||||
noHostCrossVariants []string
|
||||
bazVariants []string
|
||||
quxVariants []string
|
||||
firstVariants []string
|
||||
|
||||
multiTargetVariants []string
|
||||
multiTargetVariantsMap map[string][]string
|
||||
|
|
@ -373,6 +380,7 @@ func TestArchMutator(t *testing.T) {
|
|||
preparer: nil,
|
||||
fooVariants: []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"},
|
||||
barVariants: append(buildOSVariants, "android_arm64_armv8-a", "android_arm_armv7-a-neon"),
|
||||
noHostCrossVariants: append(buildOSVariants, "android_arm64_armv8-a", "android_arm_armv7-a-neon"),
|
||||
bazVariants: nil,
|
||||
quxVariants: append(buildOS32Variants, "android_arm_armv7-a-neon"),
|
||||
firstVariants: append(buildOS64Variants, "android_arm64_armv8-a"),
|
||||
|
|
@ -390,6 +398,7 @@ func TestArchMutator(t *testing.T) {
|
|||
}),
|
||||
fooVariants: nil,
|
||||
barVariants: buildOSVariants,
|
||||
noHostCrossVariants: buildOSVariants,
|
||||
bazVariants: nil,
|
||||
quxVariants: buildOS32Variants,
|
||||
firstVariants: buildOS64Variants,
|
||||
|
|
@ -406,6 +415,7 @@ func TestArchMutator(t *testing.T) {
|
|||
}),
|
||||
fooVariants: []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"},
|
||||
barVariants: []string{"linux_musl_x86_64", "linux_musl_arm64", "linux_musl_x86", "android_arm64_armv8-a", "android_arm_armv7-a-neon"},
|
||||
noHostCrossVariants: []string{"linux_musl_x86_64", "linux_musl_x86", "android_arm64_armv8-a", "android_arm_armv7-a-neon"},
|
||||
bazVariants: nil,
|
||||
quxVariants: []string{"linux_musl_x86", "android_arm_armv7-a-neon"},
|
||||
firstVariants: []string{"linux_musl_x86_64", "linux_musl_arm64", "android_arm64_armv8-a"},
|
||||
|
|
@ -441,7 +451,7 @@ func TestArchMutator(t *testing.T) {
|
|||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.goOS != runtime.GOOS {
|
||||
if tt.goOS != "" && tt.goOS != runtime.GOOS {
|
||||
t.Skipf("requries runtime.GOOS %s", tt.goOS)
|
||||
}
|
||||
|
||||
|
|
@ -461,6 +471,10 @@ func TestArchMutator(t *testing.T) {
|
|||
t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g)
|
||||
}
|
||||
|
||||
if g, w := enabledVariants(ctx, "nohostcross"), tt.noHostCrossVariants; !reflect.DeepEqual(w, g) {
|
||||
t.Errorf("want nohostcross variants:\n%q\ngot:\n%q\n", w, g)
|
||||
}
|
||||
|
||||
if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) {
|
||||
t.Errorf("want baz variants:\n%q\ngot:\n%q\n", w, g)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -220,6 +220,10 @@ type BaseModuleContext interface {
|
|||
// EvaluateConfiguration makes ModuleContext a valid proptools.ConfigurableEvaluator, so this context
|
||||
// can be used to evaluate the final value of Configurable properties.
|
||||
EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue
|
||||
|
||||
// HasMutatorFinished returns true if the given mutator has finished running.
|
||||
// It will panic if given an invalid mutator name.
|
||||
HasMutatorFinished(mutatorName string) bool
|
||||
}
|
||||
|
||||
type baseModuleContext struct {
|
||||
|
|
@ -270,6 +274,10 @@ func (b *baseModuleContext) setProvider(provider blueprint.AnyProviderKey, value
|
|||
b.bp.SetProvider(provider, value)
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) HasMutatorFinished(mutatorName string) bool {
|
||||
return b.bp.HasMutatorFinished(mutatorName)
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
|
||||
return b.bp.GetDirectDepWithTag(name, tag)
|
||||
}
|
||||
|
|
|
|||
337
android/compliance_metadata.go
Normal file
337
android/compliance_metadata.go
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
// Copyright 2024 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package android
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
)
|
||||
|
||||
var (
|
||||
// Constants of property names used in compliance metadata of modules
|
||||
ComplianceMetadataProp = struct {
|
||||
NAME string
|
||||
PACKAGE string
|
||||
MODULE_TYPE string
|
||||
OS string
|
||||
ARCH string
|
||||
IS_PRIMARY_ARCH string
|
||||
VARIANT string
|
||||
IS_STATIC_LIB string
|
||||
INSTALLED_FILES string
|
||||
BUILT_FILES string
|
||||
STATIC_DEPS string
|
||||
STATIC_DEP_FILES string
|
||||
WHOLE_STATIC_DEPS string
|
||||
WHOLE_STATIC_DEP_FILES string
|
||||
LICENSES string
|
||||
|
||||
// module_type=package
|
||||
PKG_DEFAULT_APPLICABLE_LICENSES string
|
||||
|
||||
// module_type=license
|
||||
LIC_LICENSE_KINDS string
|
||||
LIC_LICENSE_TEXT string
|
||||
LIC_PACKAGE_NAME string
|
||||
|
||||
// module_type=license_kind
|
||||
LK_CONDITIONS string
|
||||
LK_URL string
|
||||
}{
|
||||
"name",
|
||||
"package",
|
||||
"module_type",
|
||||
"os",
|
||||
"arch",
|
||||
"is_primary_arch",
|
||||
"variant",
|
||||
"is_static_lib",
|
||||
"installed_files",
|
||||
"built_files",
|
||||
"static_deps",
|
||||
"static_dep_files",
|
||||
"whole_static_deps",
|
||||
"whole_static_dep_files",
|
||||
"licenses",
|
||||
|
||||
"pkg_default_applicable_licenses",
|
||||
|
||||
"lic_license_kinds",
|
||||
"lic_license_text",
|
||||
"lic_package_name",
|
||||
|
||||
"lk_conditions",
|
||||
"lk_url",
|
||||
}
|
||||
|
||||
// A constant list of all property names in compliance metadata
|
||||
// Order of properties here is the order of columns in the exported CSV file.
|
||||
COMPLIANCE_METADATA_PROPS = []string{
|
||||
ComplianceMetadataProp.NAME,
|
||||
ComplianceMetadataProp.PACKAGE,
|
||||
ComplianceMetadataProp.MODULE_TYPE,
|
||||
ComplianceMetadataProp.OS,
|
||||
ComplianceMetadataProp.ARCH,
|
||||
ComplianceMetadataProp.VARIANT,
|
||||
ComplianceMetadataProp.IS_STATIC_LIB,
|
||||
ComplianceMetadataProp.IS_PRIMARY_ARCH,
|
||||
// Space separated installed files
|
||||
ComplianceMetadataProp.INSTALLED_FILES,
|
||||
// Space separated built files
|
||||
ComplianceMetadataProp.BUILT_FILES,
|
||||
// Space separated module names of static dependencies
|
||||
ComplianceMetadataProp.STATIC_DEPS,
|
||||
// Space separated file paths of static dependencies
|
||||
ComplianceMetadataProp.STATIC_DEP_FILES,
|
||||
// Space separated module names of whole static dependencies
|
||||
ComplianceMetadataProp.WHOLE_STATIC_DEPS,
|
||||
// Space separated file paths of whole static dependencies
|
||||
ComplianceMetadataProp.WHOLE_STATIC_DEP_FILES,
|
||||
ComplianceMetadataProp.LICENSES,
|
||||
// module_type=package
|
||||
ComplianceMetadataProp.PKG_DEFAULT_APPLICABLE_LICENSES,
|
||||
// module_type=license
|
||||
ComplianceMetadataProp.LIC_LICENSE_KINDS,
|
||||
ComplianceMetadataProp.LIC_LICENSE_TEXT, // resolve to file paths
|
||||
ComplianceMetadataProp.LIC_PACKAGE_NAME,
|
||||
// module_type=license_kind
|
||||
ComplianceMetadataProp.LK_CONDITIONS,
|
||||
ComplianceMetadataProp.LK_URL,
|
||||
}
|
||||
)
|
||||
|
||||
// ComplianceMetadataInfo provides all metadata of a module, e.g. name, module type, package, license,
|
||||
// dependencies, built/installed files, etc. It is a wrapper on a map[string]string with some utility
|
||||
// methods to get/set properties' values.
|
||||
type ComplianceMetadataInfo struct {
|
||||
properties map[string]string
|
||||
}
|
||||
|
||||
func NewComplianceMetadataInfo() *ComplianceMetadataInfo {
|
||||
return &ComplianceMetadataInfo{
|
||||
properties: map[string]string{},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ComplianceMetadataInfo) GobEncode() ([]byte, error) {
|
||||
w := new(bytes.Buffer)
|
||||
encoder := gob.NewEncoder(w)
|
||||
err := encoder.Encode(c.properties)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return w.Bytes(), nil
|
||||
}
|
||||
|
||||
func (c *ComplianceMetadataInfo) GobDecode(data []byte) error {
|
||||
r := bytes.NewBuffer(data)
|
||||
decoder := gob.NewDecoder(r)
|
||||
err := decoder.Decode(&c.properties)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ComplianceMetadataInfo) SetStringValue(propertyName string, value string) {
|
||||
if !slices.Contains(COMPLIANCE_METADATA_PROPS, propertyName) {
|
||||
panic(fmt.Errorf("Unknown metadata property: %s.", propertyName))
|
||||
}
|
||||
c.properties[propertyName] = value
|
||||
}
|
||||
|
||||
func (c *ComplianceMetadataInfo) SetListValue(propertyName string, value []string) {
|
||||
c.SetStringValue(propertyName, strings.TrimSpace(strings.Join(value, " ")))
|
||||
}
|
||||
|
||||
func (c *ComplianceMetadataInfo) getStringValue(propertyName string) string {
|
||||
if !slices.Contains(COMPLIANCE_METADATA_PROPS, propertyName) {
|
||||
panic(fmt.Errorf("Unknown metadata property: %s.", propertyName))
|
||||
}
|
||||
return c.properties[propertyName]
|
||||
}
|
||||
|
||||
func (c *ComplianceMetadataInfo) getAllValues() map[string]string {
|
||||
return c.properties
|
||||
}
|
||||
|
||||
var (
|
||||
ComplianceMetadataProvider = blueprint.NewProvider[*ComplianceMetadataInfo]()
|
||||
)
|
||||
|
||||
// buildComplianceMetadataProvider starts with the ModuleContext.ComplianceMetadataInfo() and fills in more common metadata
|
||||
// for different module types without accessing their private fields but through android.Module interface
|
||||
// and public/private fields of package android. The final metadata is stored to a module's ComplianceMetadataProvider.
|
||||
func buildComplianceMetadataProvider(ctx *moduleContext, m *ModuleBase) {
|
||||
complianceMetadataInfo := ctx.ComplianceMetadataInfo()
|
||||
complianceMetadataInfo.SetStringValue(ComplianceMetadataProp.NAME, m.Name())
|
||||
complianceMetadataInfo.SetStringValue(ComplianceMetadataProp.PACKAGE, ctx.ModuleDir())
|
||||
complianceMetadataInfo.SetStringValue(ComplianceMetadataProp.MODULE_TYPE, ctx.ModuleType())
|
||||
|
||||
switch ctx.ModuleType() {
|
||||
case "license":
|
||||
licenseModule := m.module.(*licenseModule)
|
||||
complianceMetadataInfo.SetListValue(ComplianceMetadataProp.LIC_LICENSE_KINDS, licenseModule.properties.License_kinds)
|
||||
complianceMetadataInfo.SetListValue(ComplianceMetadataProp.LIC_LICENSE_TEXT, PathsForModuleSrc(ctx, licenseModule.properties.License_text).Strings())
|
||||
complianceMetadataInfo.SetStringValue(ComplianceMetadataProp.LIC_PACKAGE_NAME, String(licenseModule.properties.Package_name))
|
||||
case "license_kind":
|
||||
licenseKindModule := m.module.(*licenseKindModule)
|
||||
complianceMetadataInfo.SetListValue(ComplianceMetadataProp.LK_CONDITIONS, licenseKindModule.properties.Conditions)
|
||||
complianceMetadataInfo.SetStringValue(ComplianceMetadataProp.LK_URL, licenseKindModule.properties.Url)
|
||||
default:
|
||||
complianceMetadataInfo.SetStringValue(ComplianceMetadataProp.OS, ctx.Os().String())
|
||||
complianceMetadataInfo.SetStringValue(ComplianceMetadataProp.ARCH, ctx.Arch().String())
|
||||
complianceMetadataInfo.SetStringValue(ComplianceMetadataProp.IS_PRIMARY_ARCH, strconv.FormatBool(ctx.PrimaryArch()))
|
||||
complianceMetadataInfo.SetStringValue(ComplianceMetadataProp.VARIANT, ctx.ModuleSubDir())
|
||||
if m.primaryLicensesProperty != nil && m.primaryLicensesProperty.getName() == "licenses" {
|
||||
complianceMetadataInfo.SetListValue(ComplianceMetadataProp.LICENSES, m.primaryLicensesProperty.getStrings())
|
||||
}
|
||||
|
||||
var installed InstallPaths
|
||||
installed = append(installed, ctx.installFiles...)
|
||||
installed = append(installed, ctx.katiInstalls.InstallPaths()...)
|
||||
installed = append(installed, ctx.katiSymlinks.InstallPaths()...)
|
||||
installed = append(installed, ctx.katiInitRcInstalls.InstallPaths()...)
|
||||
installed = append(installed, ctx.katiVintfInstalls.InstallPaths()...)
|
||||
complianceMetadataInfo.SetListValue(ComplianceMetadataProp.INSTALLED_FILES, FirstUniqueStrings(installed.Strings()))
|
||||
}
|
||||
ctx.setProvider(ComplianceMetadataProvider, complianceMetadataInfo)
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterComplianceMetadataSingleton(InitRegistrationContext)
|
||||
}
|
||||
|
||||
func RegisterComplianceMetadataSingleton(ctx RegistrationContext) {
|
||||
ctx.RegisterParallelSingletonType("compliance_metadata_singleton", complianceMetadataSingletonFactory)
|
||||
}
|
||||
|
||||
var (
|
||||
// sqlite3 command line tool
|
||||
sqlite3 = pctx.HostBinToolVariable("sqlite3", "sqlite3")
|
||||
|
||||
// Command to import .csv files to sqlite3 database
|
||||
importCsv = pctx.AndroidStaticRule("importCsv",
|
||||
blueprint.RuleParams{
|
||||
Command: `rm -rf $out && ` +
|
||||
`${sqlite3} $out ".import --csv $in modules" && ` +
|
||||
`${sqlite3} $out ".import --csv ${make_metadata} make_metadata" && ` +
|
||||
`${sqlite3} $out ".import --csv ${make_modules} make_modules"`,
|
||||
CommandDeps: []string{"${sqlite3}"},
|
||||
}, "make_metadata", "make_modules")
|
||||
)
|
||||
|
||||
func complianceMetadataSingletonFactory() Singleton {
|
||||
return &complianceMetadataSingleton{}
|
||||
}
|
||||
|
||||
type complianceMetadataSingleton struct {
|
||||
}
|
||||
|
||||
func writerToCsv(csvWriter *csv.Writer, row []string) {
|
||||
err := csvWriter.Write(row)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Collect compliance metadata from all Soong modules, write to a CSV file and
|
||||
// import compliance metadata from Make and Soong to a sqlite3 database.
|
||||
func (c *complianceMetadataSingleton) GenerateBuildActions(ctx SingletonContext) {
|
||||
if !ctx.Config().HasDeviceProduct() {
|
||||
return
|
||||
}
|
||||
var buffer bytes.Buffer
|
||||
csvWriter := csv.NewWriter(&buffer)
|
||||
|
||||
// Collect compliance metadata of modules in Soong and write to out/soong/compliance-metadata/<product>/soong-modules.csv file.
|
||||
columnNames := []string{"id"}
|
||||
columnNames = append(columnNames, COMPLIANCE_METADATA_PROPS...)
|
||||
writerToCsv(csvWriter, columnNames)
|
||||
|
||||
rowId := -1
|
||||
ctx.VisitAllModules(func(module Module) {
|
||||
if !module.Enabled(ctx) {
|
||||
return
|
||||
}
|
||||
moduleType := ctx.ModuleType(module)
|
||||
if moduleType == "package" {
|
||||
metadataMap := map[string]string{
|
||||
ComplianceMetadataProp.NAME: ctx.ModuleName(module),
|
||||
ComplianceMetadataProp.MODULE_TYPE: ctx.ModuleType(module),
|
||||
ComplianceMetadataProp.PKG_DEFAULT_APPLICABLE_LICENSES: strings.Join(module.base().primaryLicensesProperty.getStrings(), " "),
|
||||
}
|
||||
rowId = rowId + 1
|
||||
metadata := []string{strconv.Itoa(rowId)}
|
||||
for _, propertyName := range COMPLIANCE_METADATA_PROPS {
|
||||
metadata = append(metadata, metadataMap[propertyName])
|
||||
}
|
||||
writerToCsv(csvWriter, metadata)
|
||||
return
|
||||
}
|
||||
if provider, ok := ctx.otherModuleProvider(module, ComplianceMetadataProvider); ok {
|
||||
metadataInfo := provider.(*ComplianceMetadataInfo)
|
||||
rowId = rowId + 1
|
||||
metadata := []string{strconv.Itoa(rowId)}
|
||||
for _, propertyName := range COMPLIANCE_METADATA_PROPS {
|
||||
metadata = append(metadata, metadataInfo.getStringValue(propertyName))
|
||||
}
|
||||
writerToCsv(csvWriter, metadata)
|
||||
return
|
||||
}
|
||||
})
|
||||
csvWriter.Flush()
|
||||
|
||||
deviceProduct := ctx.Config().DeviceProduct()
|
||||
modulesCsv := PathForOutput(ctx, "compliance-metadata", deviceProduct, "soong-modules.csv")
|
||||
WriteFileRuleVerbatim(ctx, modulesCsv, buffer.String())
|
||||
|
||||
// Metadata generated in Make
|
||||
makeMetadataCsv := PathForOutput(ctx, "compliance-metadata", deviceProduct, "make-metadata.csv")
|
||||
makeModulesCsv := PathForOutput(ctx, "compliance-metadata", deviceProduct, "make-modules.csv")
|
||||
|
||||
// Import metadata from Make and Soong to sqlite3 database
|
||||
complianceMetadataDb := PathForOutput(ctx, "compliance-metadata", deviceProduct, "compliance-metadata.db")
|
||||
ctx.Build(pctx, BuildParams{
|
||||
Rule: importCsv,
|
||||
Input: modulesCsv,
|
||||
Implicits: []Path{
|
||||
makeMetadataCsv,
|
||||
makeModulesCsv,
|
||||
},
|
||||
Output: complianceMetadataDb,
|
||||
Args: map[string]string{
|
||||
"make_metadata": makeMetadataCsv.String(),
|
||||
"make_modules": makeModulesCsv.String(),
|
||||
},
|
||||
})
|
||||
|
||||
// Phony rule "compliance-metadata.db". "m compliance-metadata.db" to create the compliance metadata database.
|
||||
ctx.Build(pctx, BuildParams{
|
||||
Rule: blueprint.Phony,
|
||||
Inputs: []Path{complianceMetadataDb},
|
||||
Output: PathForPhony(ctx, "compliance-metadata.db"),
|
||||
})
|
||||
|
||||
}
|
||||
|
|
@ -173,6 +173,13 @@ func (c Config) DisableVerifyOverlaps() bool {
|
|||
return c.IsEnvTrue("DISABLE_VERIFY_OVERLAPS") || c.ReleaseDisableVerifyOverlaps() || !c.ReleaseDefaultModuleBuildFromSource()
|
||||
}
|
||||
|
||||
func (c Config) CoverageSuffix() string {
|
||||
if v := c.IsEnvTrue("EMMA_INSTRUMENT"); v {
|
||||
return "coverage."
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// MaxPageSizeSupported returns the max page size supported by the device. This
|
||||
// value will define the ELF segment alignment for binaries (executables and
|
||||
// shared libraries).
|
||||
|
|
@ -198,12 +205,44 @@ func (c Config) ReleaseAconfigValueSets() []string {
|
|||
return c.config.productVariables.ReleaseAconfigValueSets
|
||||
}
|
||||
|
||||
func (c Config) ReleaseAconfigExtraReleaseConfigs() []string {
|
||||
result := []string{}
|
||||
if val, ok := c.config.productVariables.BuildFlags["RELEASE_ACONFIG_EXTRA_RELEASE_CONFIGS"]; ok {
|
||||
if len(val) > 0 {
|
||||
// Remove any duplicates from the list.
|
||||
found := make(map[string]bool)
|
||||
for _, k := range strings.Split(val, " ") {
|
||||
if !found[k] {
|
||||
found[k] = true
|
||||
result = append(result, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (c Config) ReleaseAconfigExtraReleaseConfigsValueSets() map[string][]string {
|
||||
result := make(map[string][]string)
|
||||
for _, rcName := range c.ReleaseAconfigExtraReleaseConfigs() {
|
||||
if value, ok := c.config.productVariables.BuildFlags["RELEASE_ACONFIG_VALUE_SETS_"+rcName]; ok {
|
||||
result[rcName] = strings.Split(value, " ")
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// The flag default permission value passed to aconfig
|
||||
// derived from RELEASE_ACONFIG_FLAG_DEFAULT_PERMISSION
|
||||
func (c Config) ReleaseAconfigFlagDefaultPermission() string {
|
||||
return c.config.productVariables.ReleaseAconfigFlagDefaultPermission
|
||||
}
|
||||
|
||||
// Enable object size sanitizer
|
||||
func (c Config) ReleaseBuildObjectSizeSanitizer() bool {
|
||||
return c.config.productVariables.GetBuildFlagBool("RELEASE_BUILD_OBJECT_SIZE_SANITIZER")
|
||||
}
|
||||
|
||||
// The flag indicating behavior for the tree wrt building modules or using prebuilts
|
||||
// derived from RELEASE_DEFAULT_MODULE_BUILD_FROM_SOURCE
|
||||
func (c Config) ReleaseDefaultModuleBuildFromSource() bool {
|
||||
|
|
@ -321,9 +360,6 @@ type config struct {
|
|||
// modules that aren't mixed-built for at least one variant will cause a build
|
||||
// failure
|
||||
ensureAllowlistIntegrity bool
|
||||
|
||||
// List of Api libraries that contribute to Api surfaces.
|
||||
apiLibraries map[string]struct{}
|
||||
}
|
||||
|
||||
type deviceConfig struct {
|
||||
|
|
@ -573,40 +609,6 @@ func NewConfig(cmdArgs CmdArgs, availableEnv map[string]string) (Config, error)
|
|||
setBuildMode(cmdArgs.ModuleGraphFile, GenerateModuleGraph)
|
||||
setBuildMode(cmdArgs.DocFile, GenerateDocFile)
|
||||
|
||||
// TODO(b/276958307): Replace the hardcoded list to a sdk_library local prop.
|
||||
config.apiLibraries = map[string]struct{}{
|
||||
"android.net.ipsec.ike": {},
|
||||
"art.module.public.api": {},
|
||||
"conscrypt.module.public.api": {},
|
||||
"framework-adservices": {},
|
||||
"framework-appsearch": {},
|
||||
"framework-bluetooth": {},
|
||||
"framework-configinfrastructure": {},
|
||||
"framework-connectivity": {},
|
||||
"framework-connectivity-t": {},
|
||||
"framework-devicelock": {},
|
||||
"framework-graphics": {},
|
||||
"framework-healthfitness": {},
|
||||
"framework-location": {},
|
||||
"framework-media": {},
|
||||
"framework-mediaprovider": {},
|
||||
"framework-nfc": {},
|
||||
"framework-ondevicepersonalization": {},
|
||||
"framework-pdf": {},
|
||||
"framework-pdf-v": {},
|
||||
"framework-permission": {},
|
||||
"framework-permission-s": {},
|
||||
"framework-scheduling": {},
|
||||
"framework-sdkextensions": {},
|
||||
"framework-statsd": {},
|
||||
"framework-sdksandbox": {},
|
||||
"framework-tethering": {},
|
||||
"framework-uwb": {},
|
||||
"framework-virtualization": {},
|
||||
"framework-wifi": {},
|
||||
"i18n.module.public.api": {},
|
||||
}
|
||||
|
||||
config.productVariables.Build_from_text_stub = boolPtr(config.BuildFromTextStub())
|
||||
|
||||
return Config{config}, err
|
||||
|
|
@ -1033,6 +1035,22 @@ func (c *config) DefaultAppCertificate(ctx PathContext) (pem, key SourcePath) {
|
|||
return defaultDir.Join(ctx, "testkey.x509.pem"), defaultDir.Join(ctx, "testkey.pk8")
|
||||
}
|
||||
|
||||
func (c *config) ExtraOtaKeys(ctx PathContext, recovery bool) []SourcePath {
|
||||
var otaKeys []string
|
||||
if recovery {
|
||||
otaKeys = c.productVariables.ExtraOtaRecoveryKeys
|
||||
} else {
|
||||
otaKeys = c.productVariables.ExtraOtaKeys
|
||||
}
|
||||
|
||||
otaPaths := make([]SourcePath, len(otaKeys))
|
||||
for i, key := range otaKeys {
|
||||
otaPaths[i] = PathForSource(ctx, key+".x509.pem")
|
||||
}
|
||||
|
||||
return otaPaths
|
||||
}
|
||||
|
||||
func (c *config) BuildKeys() string {
|
||||
defaultCert := String(c.productVariables.DefaultAppCertificate)
|
||||
if defaultCert == "" || defaultCert == filepath.Join(testKeyDir, "testkey") {
|
||||
|
|
@ -1157,6 +1175,10 @@ func (c *config) UseGoma() bool {
|
|||
return Bool(c.productVariables.UseGoma)
|
||||
}
|
||||
|
||||
func (c *config) UseABFS() bool {
|
||||
return Bool(c.productVariables.UseABFS)
|
||||
}
|
||||
|
||||
func (c *config) UseRBE() bool {
|
||||
return Bool(c.productVariables.UseRBE)
|
||||
}
|
||||
|
|
@ -1318,10 +1340,6 @@ func (c *config) FrameworksBaseDirExists(ctx PathGlobContext) bool {
|
|||
return ExistentPathForSource(ctx, "frameworks", "base", "Android.bp").Valid()
|
||||
}
|
||||
|
||||
func (c *config) VndkSnapshotBuildArtifacts() bool {
|
||||
return Bool(c.productVariables.VndkSnapshotBuildArtifacts)
|
||||
}
|
||||
|
||||
func (c *config) HasMultilibConflict(arch ArchType) bool {
|
||||
return c.multilibConflicts[arch]
|
||||
}
|
||||
|
|
@ -1385,10 +1403,6 @@ func (c *deviceConfig) VendorPath() string {
|
|||
return "vendor"
|
||||
}
|
||||
|
||||
func (c *deviceConfig) RecoverySnapshotVersion() string {
|
||||
return String(c.config.productVariables.RecoverySnapshotVersion)
|
||||
}
|
||||
|
||||
func (c *deviceConfig) CurrentApiLevelForVendorModules() string {
|
||||
return StringDefault(c.config.productVariables.DeviceCurrentApiLevelForVendorModules, "current")
|
||||
}
|
||||
|
|
@ -1490,11 +1504,6 @@ func (c *deviceConfig) NativeCoverageEnabledForPath(path string) bool {
|
|||
}
|
||||
}
|
||||
if coverage && len(c.config.productVariables.NativeCoverageExcludePaths) > 0 {
|
||||
// Workaround coverage boot failure.
|
||||
// http://b/269981180
|
||||
if strings.HasPrefix(path, "external/protobuf") {
|
||||
coverage = false
|
||||
}
|
||||
if HasAnyPrefix(path, c.config.productVariables.NativeCoverageExcludePaths) {
|
||||
coverage = false
|
||||
}
|
||||
|
|
@ -1663,6 +1672,17 @@ func (c *config) ApexTrimEnabled() bool {
|
|||
return Bool(c.productVariables.TrimmedApex)
|
||||
}
|
||||
|
||||
func (c *config) UseSoongSystemImage() bool {
|
||||
return Bool(c.productVariables.UseSoongSystemImage)
|
||||
}
|
||||
|
||||
func (c *config) SoongDefinedSystemImage() string {
|
||||
if c.UseSoongSystemImage() {
|
||||
return String(c.productVariables.ProductSoongDefinedSystemImage)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c *config) EnforceSystemCertificate() bool {
|
||||
return Bool(c.productVariables.EnforceSystemCertificate)
|
||||
}
|
||||
|
|
@ -1770,22 +1790,6 @@ func (c *deviceConfig) IsPartnerTrebleSepolicyTestEnabled() bool {
|
|||
return c.SystemExtSepolicyPrebuiltApiDir() != "" || c.ProductSepolicyPrebuiltApiDir() != ""
|
||||
}
|
||||
|
||||
func (c *deviceConfig) DirectedVendorSnapshot() bool {
|
||||
return c.config.productVariables.DirectedVendorSnapshot
|
||||
}
|
||||
|
||||
func (c *deviceConfig) VendorSnapshotModules() map[string]bool {
|
||||
return c.config.productVariables.VendorSnapshotModules
|
||||
}
|
||||
|
||||
func (c *deviceConfig) DirectedRecoverySnapshot() bool {
|
||||
return c.config.productVariables.DirectedRecoverySnapshot
|
||||
}
|
||||
|
||||
func (c *deviceConfig) RecoverySnapshotModules() map[string]bool {
|
||||
return c.config.productVariables.RecoverySnapshotModules
|
||||
}
|
||||
|
||||
func createDirsMap(previous map[string]bool, dirs []string) (map[string]bool, error) {
|
||||
var ret = make(map[string]bool)
|
||||
for _, dir := range dirs {
|
||||
|
|
@ -1812,40 +1816,6 @@ func (c *deviceConfig) createDirsMapOnce(onceKey OnceKey, previous map[string]bo
|
|||
return dirMap.(map[string]bool)
|
||||
}
|
||||
|
||||
var vendorSnapshotDirsExcludedKey = NewOnceKey("VendorSnapshotDirsExcludedMap")
|
||||
|
||||
func (c *deviceConfig) VendorSnapshotDirsExcludedMap() map[string]bool {
|
||||
return c.createDirsMapOnce(vendorSnapshotDirsExcludedKey, nil,
|
||||
c.config.productVariables.VendorSnapshotDirsExcluded)
|
||||
}
|
||||
|
||||
var vendorSnapshotDirsIncludedKey = NewOnceKey("VendorSnapshotDirsIncludedMap")
|
||||
|
||||
func (c *deviceConfig) VendorSnapshotDirsIncludedMap() map[string]bool {
|
||||
excludedMap := c.VendorSnapshotDirsExcludedMap()
|
||||
return c.createDirsMapOnce(vendorSnapshotDirsIncludedKey, excludedMap,
|
||||
c.config.productVariables.VendorSnapshotDirsIncluded)
|
||||
}
|
||||
|
||||
var recoverySnapshotDirsExcludedKey = NewOnceKey("RecoverySnapshotDirsExcludedMap")
|
||||
|
||||
func (c *deviceConfig) RecoverySnapshotDirsExcludedMap() map[string]bool {
|
||||
return c.createDirsMapOnce(recoverySnapshotDirsExcludedKey, nil,
|
||||
c.config.productVariables.RecoverySnapshotDirsExcluded)
|
||||
}
|
||||
|
||||
var recoverySnapshotDirsIncludedKey = NewOnceKey("RecoverySnapshotDirsIncludedMap")
|
||||
|
||||
func (c *deviceConfig) RecoverySnapshotDirsIncludedMap() map[string]bool {
|
||||
excludedMap := c.RecoverySnapshotDirsExcludedMap()
|
||||
return c.createDirsMapOnce(recoverySnapshotDirsIncludedKey, excludedMap,
|
||||
c.config.productVariables.RecoverySnapshotDirsIncluded)
|
||||
}
|
||||
|
||||
func (c *deviceConfig) HostFakeSnapshotEnabled() bool {
|
||||
return c.config.productVariables.HostFakeSnapshotEnabled
|
||||
}
|
||||
|
||||
func (c *deviceConfig) ShippingApiLevel() ApiLevel {
|
||||
if c.config.productVariables.Shipping_api_level == nil {
|
||||
return NoneApiLevel
|
||||
|
|
@ -1878,10 +1848,6 @@ func (c *deviceConfig) BuildBrokenTrebleSyspropNeverallow() bool {
|
|||
return c.config.productVariables.BuildBrokenTrebleSyspropNeverallow
|
||||
}
|
||||
|
||||
func (c *deviceConfig) BuildBrokenUsesSoongPython2Modules() bool {
|
||||
return c.config.productVariables.BuildBrokenUsesSoongPython2Modules
|
||||
}
|
||||
|
||||
func (c *deviceConfig) BuildDebugfsRestrictionsEnabled() bool {
|
||||
return c.config.productVariables.BuildDebugfsRestrictionsEnabled
|
||||
}
|
||||
|
|
@ -1999,17 +1965,6 @@ func (c *config) SetBuildFromTextStub(b bool) {
|
|||
c.productVariables.Build_from_text_stub = boolPtr(b)
|
||||
}
|
||||
|
||||
func (c *config) SetApiLibraries(libs []string) {
|
||||
c.apiLibraries = make(map[string]struct{})
|
||||
for _, lib := range libs {
|
||||
c.apiLibraries[lib] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *config) GetApiLibraries() map[string]struct{} {
|
||||
return c.apiLibraries
|
||||
}
|
||||
|
||||
func (c *deviceConfig) CheckVendorSeappViolations() bool {
|
||||
return Bool(c.config.productVariables.CheckVendorSeappViolations)
|
||||
}
|
||||
|
|
@ -2019,10 +1974,18 @@ func (c *config) GetBuildFlag(name string) (string, bool) {
|
|||
return val, ok
|
||||
}
|
||||
|
||||
func (c *config) UseOptimizedResourceShrinkingByDefault() bool {
|
||||
return c.productVariables.GetBuildFlagBool("RELEASE_USE_OPTIMIZED_RESOURCE_SHRINKING_BY_DEFAULT")
|
||||
}
|
||||
|
||||
func (c *config) UseResourceProcessorByDefault() bool {
|
||||
return c.productVariables.GetBuildFlagBool("RELEASE_USE_RESOURCE_PROCESSOR_BY_DEFAULT")
|
||||
}
|
||||
|
||||
func (c *config) UseTransitiveJarsInClasspath() bool {
|
||||
return c.productVariables.GetBuildFlagBool("RELEASE_USE_TRANSITIVE_JARS_IN_CLASSPATH")
|
||||
}
|
||||
|
||||
var (
|
||||
mainlineApexContributionBuildFlagsToApexNames = map[string]string{
|
||||
"RELEASE_APEX_CONTRIBUTIONS_ADBD": "com.android.adbd",
|
||||
|
|
@ -2125,3 +2088,19 @@ func (c *config) OdmPropFiles(ctx PathContext) Paths {
|
|||
func (c *config) EnableUffdGc() string {
|
||||
return String(c.productVariables.EnableUffdGc)
|
||||
}
|
||||
|
||||
func (c *config) DeviceFrameworkCompatibilityMatrixFile() []string {
|
||||
return c.productVariables.DeviceFrameworkCompatibilityMatrixFile
|
||||
}
|
||||
|
||||
func (c *config) DeviceProductCompatibilityMatrixFile() []string {
|
||||
return c.productVariables.DeviceProductCompatibilityMatrixFile
|
||||
}
|
||||
|
||||
func (c *config) BoardAvbEnable() bool {
|
||||
return Bool(c.productVariables.BoardAvbEnable)
|
||||
}
|
||||
|
||||
func (c *config) BoardAvbSystemAddHashtreeFooterArgs() []string {
|
||||
return c.productVariables.BoardAvbSystemAddHashtreeFooterArgs
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,6 +125,38 @@ func assertStringEquals(t *testing.T, expected, actual string) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestReleaseAconfigExtraReleaseConfigs(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
flag string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
flag: "",
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "specified",
|
||||
flag: "bar foo",
|
||||
expected: []string{"bar", "foo"},
|
||||
},
|
||||
{
|
||||
name: "duplicates",
|
||||
flag: "foo bar foo",
|
||||
expected: []string{"foo", "bar"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
fixture := GroupFixturePreparers(
|
||||
PrepareForTestWithBuildFlag("RELEASE_ACONFIG_EXTRA_RELEASE_CONFIGS", tc.flag),
|
||||
)
|
||||
actual := fixture.RunTest(t).Config.ReleaseAconfigExtraReleaseConfigs()
|
||||
AssertArrayString(t, tc.name, tc.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfiguredJarList(t *testing.T) {
|
||||
list1 := CreateTestConfiguredJarList([]string{"apex1:jarA"})
|
||||
|
||||
|
|
|
|||
|
|
@ -26,3 +26,9 @@ func CreateSelectOsToBool(cases map[string]*bool) proptools.Configurable[bool] {
|
|||
resultCases,
|
||||
)
|
||||
}
|
||||
|
||||
func NewSimpleConfigurable[T proptools.ConfigurableElements](value T) proptools.Configurable[T] {
|
||||
return proptools.NewConfigurable(nil, []proptools.ConfigurableCase[T]{
|
||||
proptools.NewConfigurableCase(nil, &value),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
506
android/container.go
Normal file
506
android/container.go
Normal file
|
|
@ -0,0 +1,506 @@
|
|||
// Copyright 2024 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package android
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Start of the definitions of exception functions and the lookup table.
|
||||
//
|
||||
// Functions cannot be used as a value passed in providers, because functions are not
|
||||
// hashable. As a workaround, the [exceptionHandleFuncLabel] enum values are passed using providers,
|
||||
// and the corresponding functions are called from [exceptionHandleFunctionsTable] map.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
type exceptionHandleFunc func(ModuleContext, Module, Module) bool
|
||||
|
||||
type StubsAvailableModule interface {
|
||||
IsStubsModule() bool
|
||||
}
|
||||
|
||||
// Returns true if the dependency module is a stubs module
|
||||
var depIsStubsModule exceptionHandleFunc = func(_ ModuleContext, _, dep Module) bool {
|
||||
if stubsModule, ok := dep.(StubsAvailableModule); ok {
|
||||
return stubsModule.IsStubsModule()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Returns true if the dependency module belongs to any of the apexes.
|
||||
var depIsApexModule exceptionHandleFunc = func(mctx ModuleContext, _, dep Module) bool {
|
||||
depContainersInfo, _ := getContainerModuleInfo(mctx, dep)
|
||||
return InList(ApexContainer, depContainersInfo.belongingContainers)
|
||||
}
|
||||
|
||||
// Returns true if the module and the dependent module belongs to common apexes.
|
||||
var belongsToCommonApexes exceptionHandleFunc = func(mctx ModuleContext, m, dep Module) bool {
|
||||
mContainersInfo, _ := getContainerModuleInfo(mctx, m)
|
||||
depContainersInfo, _ := getContainerModuleInfo(mctx, dep)
|
||||
|
||||
return HasIntersection(mContainersInfo.ApexNames(), depContainersInfo.ApexNames())
|
||||
}
|
||||
|
||||
// Returns true when all apexes that the module belongs to are non updatable.
|
||||
// For an apex module to be allowed to depend on a non-apex partition module,
|
||||
// all apexes that the module belong to must be non updatable.
|
||||
var belongsToNonUpdatableApex exceptionHandleFunc = func(mctx ModuleContext, m, _ Module) bool {
|
||||
mContainersInfo, _ := getContainerModuleInfo(mctx, m)
|
||||
|
||||
return !mContainersInfo.UpdatableApex()
|
||||
}
|
||||
|
||||
// Returns true if the dependency is added via dependency tags that are not used to tag dynamic
|
||||
// dependency tags.
|
||||
var depIsNotDynamicDepTag exceptionHandleFunc = func(ctx ModuleContext, m, dep Module) bool {
|
||||
mInstallable, _ := m.(InstallableModule)
|
||||
depTag := ctx.OtherModuleDependencyTag(dep)
|
||||
return !InList(depTag, mInstallable.DynamicDependencyTags())
|
||||
}
|
||||
|
||||
// Returns true if the dependency is added via dependency tags that are not used to tag static
|
||||
// or dynamic dependency tags. These dependencies do not affect the module in compile time or in
|
||||
// runtime, thus are not significant enough to raise an error.
|
||||
var depIsNotStaticOrDynamicDepTag exceptionHandleFunc = func(ctx ModuleContext, m, dep Module) bool {
|
||||
mInstallable, _ := m.(InstallableModule)
|
||||
depTag := ctx.OtherModuleDependencyTag(dep)
|
||||
return !InList(depTag, append(mInstallable.StaticDependencyTags(), mInstallable.DynamicDependencyTags()...))
|
||||
}
|
||||
|
||||
var globallyAllowlistedDependencies = []string{
|
||||
// Modules that provide annotations used within the platform and apexes.
|
||||
"aconfig-annotations-lib",
|
||||
"framework-annotations-lib",
|
||||
"unsupportedappusage",
|
||||
|
||||
// TODO(b/363016634): Remove from the allowlist when the module is converted
|
||||
// to java_sdk_library and the java_aconfig_library modules depend on the stub.
|
||||
"aconfig_storage_reader_java",
|
||||
|
||||
// framework-res provides core resources essential for building apps and system UI.
|
||||
// This module is implicitly added as a dependency for java modules even when the
|
||||
// dependency specifies sdk_version.
|
||||
"framework-res",
|
||||
|
||||
// jacocoagent is implicitly added as a dependency in coverage builds, and is not installed
|
||||
// on the device.
|
||||
"jacocoagent",
|
||||
}
|
||||
|
||||
// Returns true when the dependency is globally allowlisted for inter-container dependency
|
||||
var depIsGloballyAllowlisted exceptionHandleFunc = func(_ ModuleContext, _, dep Module) bool {
|
||||
return InList(dep.Name(), globallyAllowlistedDependencies)
|
||||
}
|
||||
|
||||
// Labels of exception functions, which are used to determine special dependencies that allow
|
||||
// otherwise restricted inter-container dependencies
|
||||
type exceptionHandleFuncLabel int
|
||||
|
||||
const (
|
||||
checkStubs exceptionHandleFuncLabel = iota
|
||||
checkApexModule
|
||||
checkInCommonApexes
|
||||
checkApexIsNonUpdatable
|
||||
checkNotDynamicDepTag
|
||||
checkNotStaticOrDynamicDepTag
|
||||
checkGlobalAllowlistedDep
|
||||
)
|
||||
|
||||
// Map of [exceptionHandleFuncLabel] to the [exceptionHandleFunc]
|
||||
var exceptionHandleFunctionsTable = map[exceptionHandleFuncLabel]exceptionHandleFunc{
|
||||
checkStubs: depIsStubsModule,
|
||||
checkApexModule: depIsApexModule,
|
||||
checkInCommonApexes: belongsToCommonApexes,
|
||||
checkApexIsNonUpdatable: belongsToNonUpdatableApex,
|
||||
checkNotDynamicDepTag: depIsNotDynamicDepTag,
|
||||
checkNotStaticOrDynamicDepTag: depIsNotStaticOrDynamicDepTag,
|
||||
checkGlobalAllowlistedDep: depIsGloballyAllowlisted,
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Start of the definitions of container determination functions.
|
||||
//
|
||||
// Similar to the above section, below defines the functions used to determine
|
||||
// the container of each modules.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
type containerBoundaryFunc func(mctx ModuleContext) bool
|
||||
|
||||
var vendorContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
|
||||
m, ok := mctx.Module().(ImageInterface)
|
||||
return mctx.Module().InstallInVendor() || (ok && m.VendorVariantNeeded(mctx))
|
||||
}
|
||||
|
||||
var systemContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
|
||||
module := mctx.Module()
|
||||
|
||||
return !module.InstallInTestcases() &&
|
||||
!module.InstallInData() &&
|
||||
!module.InstallInRamdisk() &&
|
||||
!module.InstallInVendorRamdisk() &&
|
||||
!module.InstallInDebugRamdisk() &&
|
||||
!module.InstallInRecovery() &&
|
||||
!module.InstallInVendor() &&
|
||||
!module.InstallInOdm() &&
|
||||
!module.InstallInProduct() &&
|
||||
determineModuleKind(module.base(), mctx.blueprintBaseModuleContext()) == platformModule
|
||||
}
|
||||
|
||||
var productContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
|
||||
m, ok := mctx.Module().(ImageInterface)
|
||||
return mctx.Module().InstallInProduct() || (ok && m.ProductVariantNeeded(mctx))
|
||||
}
|
||||
|
||||
var apexContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
|
||||
_, ok := ModuleProvider(mctx, AllApexInfoProvider)
|
||||
return ok
|
||||
}
|
||||
|
||||
var ctsContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
|
||||
props := mctx.Module().GetProperties()
|
||||
for _, prop := range props {
|
||||
val := reflect.ValueOf(prop).Elem()
|
||||
if val.Kind() == reflect.Struct {
|
||||
testSuites := val.FieldByName("Test_suites")
|
||||
if testSuites.IsValid() && testSuites.Kind() == reflect.Slice && slices.Contains(testSuites.Interface().([]string), "cts") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type unstableInfo struct {
|
||||
// Determines if the module contains the private APIs of the platform.
|
||||
ContainsPlatformPrivateApis bool
|
||||
}
|
||||
|
||||
var unstableInfoProvider = blueprint.NewProvider[unstableInfo]()
|
||||
|
||||
func determineUnstableModule(mctx ModuleContext) bool {
|
||||
module := mctx.Module()
|
||||
unstableModule := module.Name() == "framework-minus-apex"
|
||||
if installable, ok := module.(InstallableModule); ok {
|
||||
for _, staticDepTag := range installable.StaticDependencyTags() {
|
||||
mctx.VisitDirectDepsWithTag(staticDepTag, func(dep Module) {
|
||||
if unstableInfo, ok := OtherModuleProvider(mctx, dep, unstableInfoProvider); ok {
|
||||
unstableModule = unstableModule || unstableInfo.ContainsPlatformPrivateApis
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return unstableModule
|
||||
}
|
||||
|
||||
var unstableContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
|
||||
return determineUnstableModule(mctx)
|
||||
}
|
||||
|
||||
// Map of [*container] to the [containerBoundaryFunc]
|
||||
var containerBoundaryFunctionsTable = map[*container]containerBoundaryFunc{
|
||||
VendorContainer: vendorContainerBoundaryFunc,
|
||||
SystemContainer: systemContainerBoundaryFunc,
|
||||
ProductContainer: productContainerBoundaryFunc,
|
||||
ApexContainer: apexContainerBoundaryFunc,
|
||||
CtsContainer: ctsContainerBoundaryFunc,
|
||||
UnstableContainer: unstableContainerBoundaryFunc,
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// End of the definitions of container determination functions.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
type InstallableModule interface {
|
||||
StaticDependencyTags() []blueprint.DependencyTag
|
||||
DynamicDependencyTags() []blueprint.DependencyTag
|
||||
}
|
||||
|
||||
type restriction struct {
|
||||
// container of the dependency
|
||||
dependency *container
|
||||
|
||||
// Error message to be emitted to the user when the dependency meets this restriction
|
||||
errorMessage string
|
||||
|
||||
// List of labels of allowed exception functions that allows bypassing this restriction.
|
||||
// If any of the functions mapped to each labels returns true, this dependency would be
|
||||
// considered allowed and an error will not be thrown.
|
||||
allowedExceptions []exceptionHandleFuncLabel
|
||||
}
|
||||
type container struct {
|
||||
// The name of the container i.e. partition, api domain
|
||||
name string
|
||||
|
||||
// Map of dependency restricted containers.
|
||||
restricted []restriction
|
||||
}
|
||||
|
||||
var (
|
||||
VendorContainer = &container{
|
||||
name: VendorVariation,
|
||||
restricted: nil,
|
||||
}
|
||||
|
||||
SystemContainer = &container{
|
||||
name: "system",
|
||||
restricted: []restriction{
|
||||
{
|
||||
dependency: VendorContainer,
|
||||
errorMessage: "Module belonging to the system partition other than HALs is " +
|
||||
"not allowed to depend on the vendor partition module, in order to support " +
|
||||
"independent development/update cycles and to support the Generic System " +
|
||||
"Image. Try depending on HALs, VNDK or AIDL instead.",
|
||||
allowedExceptions: []exceptionHandleFuncLabel{
|
||||
checkStubs,
|
||||
checkNotDynamicDepTag,
|
||||
checkGlobalAllowlistedDep,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ProductContainer = &container{
|
||||
name: ProductVariation,
|
||||
restricted: []restriction{
|
||||
{
|
||||
dependency: VendorContainer,
|
||||
errorMessage: "Module belonging to the product partition is not allowed to " +
|
||||
"depend on the vendor partition module, as this may lead to security " +
|
||||
"vulnerabilities. Try depending on the HALs or utilize AIDL instead.",
|
||||
allowedExceptions: []exceptionHandleFuncLabel{
|
||||
checkStubs,
|
||||
checkNotDynamicDepTag,
|
||||
checkGlobalAllowlistedDep,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ApexContainer = initializeApexContainer()
|
||||
|
||||
CtsContainer = &container{
|
||||
name: "cts",
|
||||
restricted: []restriction{
|
||||
{
|
||||
dependency: UnstableContainer,
|
||||
errorMessage: "CTS module should not depend on the modules that contain the " +
|
||||
"platform implementation details, including \"framework\". Depending on these " +
|
||||
"modules may lead to disclosure of implementation details and regression " +
|
||||
"due to API changes across platform versions. Try depending on the stubs instead " +
|
||||
"and ensure that the module sets an appropriate 'sdk_version'.",
|
||||
allowedExceptions: []exceptionHandleFuncLabel{
|
||||
checkStubs,
|
||||
checkNotStaticOrDynamicDepTag,
|
||||
checkGlobalAllowlistedDep,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Container signifying that the module contains unstable platform private APIs
|
||||
UnstableContainer = &container{
|
||||
name: "unstable",
|
||||
restricted: nil,
|
||||
}
|
||||
|
||||
allContainers = []*container{
|
||||
VendorContainer,
|
||||
SystemContainer,
|
||||
ProductContainer,
|
||||
ApexContainer,
|
||||
CtsContainer,
|
||||
UnstableContainer,
|
||||
}
|
||||
)
|
||||
|
||||
func initializeApexContainer() *container {
|
||||
apexContainer := &container{
|
||||
name: "apex",
|
||||
restricted: []restriction{
|
||||
{
|
||||
dependency: SystemContainer,
|
||||
errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
|
||||
"modules belonging to the system partition. Either statically depend on the " +
|
||||
"module or convert the depending module to java_sdk_library and depend on " +
|
||||
"the stubs.",
|
||||
allowedExceptions: []exceptionHandleFuncLabel{
|
||||
checkStubs,
|
||||
checkApexModule,
|
||||
checkInCommonApexes,
|
||||
checkApexIsNonUpdatable,
|
||||
checkNotStaticOrDynamicDepTag,
|
||||
checkGlobalAllowlistedDep,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
apexContainer.restricted = append(apexContainer.restricted, restriction{
|
||||
dependency: apexContainer,
|
||||
errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
|
||||
"modules belonging to other Apex(es). Either include the depending " +
|
||||
"module in the Apex or convert the depending module to java_sdk_library " +
|
||||
"and depend on its stubs.",
|
||||
allowedExceptions: []exceptionHandleFuncLabel{
|
||||
checkStubs,
|
||||
checkInCommonApexes,
|
||||
checkNotStaticOrDynamicDepTag,
|
||||
checkGlobalAllowlistedDep,
|
||||
},
|
||||
})
|
||||
|
||||
return apexContainer
|
||||
}
|
||||
|
||||
type ContainersInfo struct {
|
||||
belongingContainers []*container
|
||||
|
||||
belongingApexes []ApexInfo
|
||||
}
|
||||
|
||||
func (c *ContainersInfo) BelongingContainers() []*container {
|
||||
return c.belongingContainers
|
||||
}
|
||||
|
||||
func (c *ContainersInfo) ApexNames() (ret []string) {
|
||||
for _, apex := range c.belongingApexes {
|
||||
ret = append(ret, apex.InApexModules...)
|
||||
}
|
||||
slices.Sort(ret)
|
||||
return ret
|
||||
}
|
||||
|
||||
// Returns true if any of the apex the module belongs to is updatable.
|
||||
func (c *ContainersInfo) UpdatableApex() bool {
|
||||
for _, apex := range c.belongingApexes {
|
||||
if apex.Updatable {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var ContainersInfoProvider = blueprint.NewProvider[ContainersInfo]()
|
||||
|
||||
func satisfyAllowedExceptions(ctx ModuleContext, allowedExceptionLabels []exceptionHandleFuncLabel, m, dep Module) bool {
|
||||
for _, label := range allowedExceptionLabels {
|
||||
if exceptionHandleFunctionsTable[label](ctx, m, dep) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *ContainersInfo) GetViolations(mctx ModuleContext, m, dep Module, depInfo ContainersInfo) []string {
|
||||
var violations []string
|
||||
|
||||
// Any containers that the module belongs to but the dependency does not belong to must be examined.
|
||||
_, containersUniqueToModule, _ := ListSetDifference(c.belongingContainers, depInfo.belongingContainers)
|
||||
|
||||
// Apex container should be examined even if both the module and the dependency belong to
|
||||
// the apex container to check that the two modules belong to the same apex.
|
||||
if InList(ApexContainer, c.belongingContainers) && !InList(ApexContainer, containersUniqueToModule) {
|
||||
containersUniqueToModule = append(containersUniqueToModule, ApexContainer)
|
||||
}
|
||||
|
||||
for _, containerUniqueToModule := range containersUniqueToModule {
|
||||
for _, restriction := range containerUniqueToModule.restricted {
|
||||
if InList(restriction.dependency, depInfo.belongingContainers) {
|
||||
if !satisfyAllowedExceptions(mctx, restriction.allowedExceptions, m, dep) {
|
||||
violations = append(violations, restriction.errorMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return violations
|
||||
}
|
||||
|
||||
func generateContainerInfo(ctx ModuleContext) ContainersInfo {
|
||||
var containers []*container
|
||||
|
||||
for _, cnt := range allContainers {
|
||||
if containerBoundaryFunctionsTable[cnt](ctx) {
|
||||
containers = append(containers, cnt)
|
||||
}
|
||||
}
|
||||
|
||||
var belongingApexes []ApexInfo
|
||||
if apexInfo, ok := ModuleProvider(ctx, AllApexInfoProvider); ok {
|
||||
belongingApexes = apexInfo.ApexInfos
|
||||
}
|
||||
|
||||
return ContainersInfo{
|
||||
belongingContainers: containers,
|
||||
belongingApexes: belongingApexes,
|
||||
}
|
||||
}
|
||||
|
||||
func getContainerModuleInfo(ctx ModuleContext, module Module) (ContainersInfo, bool) {
|
||||
if ctx.Module() == module {
|
||||
return ctx.getContainersInfo(), true
|
||||
}
|
||||
|
||||
return OtherModuleProvider(ctx, module, ContainersInfoProvider)
|
||||
}
|
||||
|
||||
func setContainerInfo(ctx ModuleContext) {
|
||||
// Required to determine the unstable container. This provider is set here instead of the
|
||||
// unstableContainerBoundaryFunc in order to prevent setting the provider multiple times.
|
||||
SetProvider(ctx, unstableInfoProvider, unstableInfo{
|
||||
ContainsPlatformPrivateApis: determineUnstableModule(ctx),
|
||||
})
|
||||
|
||||
if _, ok := ctx.Module().(InstallableModule); ok {
|
||||
containersInfo := generateContainerInfo(ctx)
|
||||
ctx.setContainersInfo(containersInfo)
|
||||
SetProvider(ctx, ContainersInfoProvider, containersInfo)
|
||||
}
|
||||
}
|
||||
|
||||
func checkContainerViolations(ctx ModuleContext) {
|
||||
if _, ok := ctx.Module().(InstallableModule); ok {
|
||||
containersInfo, _ := getContainerModuleInfo(ctx, ctx.Module())
|
||||
ctx.VisitDirectDepsIgnoreBlueprint(func(dep Module) {
|
||||
if !dep.Enabled(ctx) {
|
||||
return
|
||||
}
|
||||
|
||||
// Pre-existing violating dependencies are tracked in containerDependencyViolationAllowlist.
|
||||
// If this dependency is allowlisted, do not check for violation.
|
||||
// If not, check if this dependency matches any restricted dependency and
|
||||
// satisfies any exception functions, which allows bypassing the
|
||||
// restriction. If all of the exceptions are not satisfied, throw an error.
|
||||
if depContainersInfo, ok := getContainerModuleInfo(ctx, dep); ok {
|
||||
if allowedViolations, ok := ContainerDependencyViolationAllowlist[ctx.ModuleName()]; ok && InList(dep.Name(), allowedViolations) {
|
||||
return
|
||||
} else {
|
||||
violations := containersInfo.GetViolations(ctx, ctx.Module(), dep, depContainersInfo)
|
||||
if len(violations) > 0 {
|
||||
errorMessage := fmt.Sprintf("%s cannot depend on %s. ", ctx.ModuleName(), dep.Name())
|
||||
errorMessage += strings.Join(violations, " ")
|
||||
ctx.ModuleErrorf(errorMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
1145
android/container_violations.go
Normal file
1145
android/container_violations.go
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -15,7 +15,6 @@
|
|||
package android
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
|
|
@ -109,10 +108,6 @@ 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]()
|
||||
|
||||
// NewDeapexerInfo creates and initializes a DeapexerInfo that is suitable
|
||||
// for use with a prebuilt_apex module.
|
||||
//
|
||||
|
|
@ -169,41 +164,6 @@ type RequiresFilesFromPrebuiltApexTag interface {
|
|||
RequiresFilesFromPrebuiltApex()
|
||||
}
|
||||
|
||||
// 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 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) {
|
||||
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
|
||||
// equivalent. If they are then use the selected one, otherwise fail.
|
||||
if selected := equivalentDeapexerInfoProviders(di, p); selected != nil {
|
||||
di = selected
|
||||
return
|
||||
}
|
||||
err = fmt.Errorf("Multiple installable prebuilt APEXes provide ambiguous deapexers: %s and %s", di.ApexModuleName(), p.ApexModuleName())
|
||||
}
|
||||
di = p
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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.
|
||||
func removeCompressedApexSuffix(name string) string {
|
||||
return strings.TrimSuffix(name, "_compressed")
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ type defaultsDependencyTag struct {
|
|||
var DefaultsDepTag defaultsDependencyTag
|
||||
|
||||
type defaultsProperties struct {
|
||||
Defaults proptools.Configurable[[]string]
|
||||
Defaults []string
|
||||
}
|
||||
|
||||
type DefaultableModuleBase struct {
|
||||
|
|
@ -69,7 +69,7 @@ type Defaultable interface {
|
|||
|
||||
// Apply defaults from the supplied Defaults to the property structures supplied to
|
||||
// setProperties(...).
|
||||
applyDefaults(TopDownMutatorContext, []Defaults)
|
||||
applyDefaults(BottomUpMutatorContext, []Defaults)
|
||||
|
||||
// Set the hook to be called after any defaults have been applied.
|
||||
//
|
||||
|
|
@ -101,6 +101,7 @@ func InitDefaultableModule(module DefaultableModule) {
|
|||
// A restricted subset of context methods, similar to LoadHookContext.
|
||||
type DefaultableHookContext interface {
|
||||
EarlyModuleContext
|
||||
OtherModuleProviderContext
|
||||
|
||||
CreateModule(ModuleFactory, ...interface{}) Module
|
||||
AddMissingDependencies(missingDeps []string)
|
||||
|
|
@ -209,7 +210,7 @@ func InitDefaultsModule(module DefaultsModule) {
|
|||
|
||||
var _ Defaults = (*DefaultsModuleBase)(nil)
|
||||
|
||||
func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContext,
|
||||
func (defaultable *DefaultableModuleBase) applyDefaults(ctx BottomUpMutatorContext,
|
||||
defaultsList []Defaults) {
|
||||
|
||||
for _, defaults := range defaultsList {
|
||||
|
|
@ -226,7 +227,7 @@ func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContex
|
|||
// Product variable properties need special handling, the type of the filtered product variable
|
||||
// property struct may not be identical between the defaults module and the defaultable module.
|
||||
// Use PrependMatchingProperties to apply whichever properties match.
|
||||
func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx TopDownMutatorContext,
|
||||
func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx BottomUpMutatorContext,
|
||||
defaults Defaults, defaultableProp interface{}) {
|
||||
if defaultableProp == nil {
|
||||
return
|
||||
|
|
@ -254,7 +255,7 @@ func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx Top
|
|||
}
|
||||
}
|
||||
|
||||
func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMutatorContext,
|
||||
func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx BottomUpMutatorContext,
|
||||
defaults Defaults, defaultableProp interface{}) {
|
||||
|
||||
for _, def := range defaults.properties() {
|
||||
|
|
@ -273,18 +274,22 @@ func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMuta
|
|||
|
||||
func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) {
|
||||
ctx.BottomUp("defaults_deps", defaultsDepsMutator).Parallel()
|
||||
ctx.TopDown("defaults", defaultsMutator).Parallel()
|
||||
ctx.BottomUp("defaults", defaultsMutator).Parallel()
|
||||
}
|
||||
|
||||
func defaultsDepsMutator(ctx BottomUpMutatorContext) {
|
||||
if defaultable, ok := ctx.Module().(Defaultable); ok {
|
||||
ctx.AddDependency(ctx.Module(), DefaultsDepTag, defaultable.defaults().Defaults.GetOrDefault(ctx, nil)...)
|
||||
ctx.AddDependency(ctx.Module(), DefaultsDepTag, defaultable.defaults().Defaults...)
|
||||
}
|
||||
}
|
||||
|
||||
func defaultsMutator(ctx TopDownMutatorContext) {
|
||||
func defaultsMutator(ctx BottomUpMutatorContext) {
|
||||
if defaultable, ok := ctx.Module().(Defaultable); ok {
|
||||
defaults := defaultable.defaults().Defaults.GetOrDefault(ctx, nil)
|
||||
if _, isDefaultsModule := ctx.Module().(Defaults); isDefaultsModule {
|
||||
// Don't squash transitive defaults into defaults modules
|
||||
return
|
||||
}
|
||||
defaults := defaultable.defaults().Defaults
|
||||
if len(defaults) > 0 {
|
||||
var defaultsList []Defaults
|
||||
seen := make(map[Defaults]bool)
|
||||
|
|
@ -295,7 +300,7 @@ func defaultsMutator(ctx TopDownMutatorContext) {
|
|||
if !seen[defaults] {
|
||||
seen[defaults] = true
|
||||
defaultsList = append(defaultsList, defaults)
|
||||
return len(defaults.defaults().Defaults.GetOrDefault(ctx, nil)) > 0
|
||||
return len(defaults.defaults().Defaults) > 0
|
||||
}
|
||||
} else {
|
||||
ctx.PropertyErrorf("defaults", "module %s is not an defaults module",
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ package android
|
|||
|
||||
import (
|
||||
"github.com/google/blueprint"
|
||||
"github.com/google/blueprint/bootstrap"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -120,8 +119,3 @@ func init() {
|
|||
return ctx.Config().RBEWrapper()
|
||||
})
|
||||
}
|
||||
|
||||
// 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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
package android
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
|
|
@ -65,6 +68,30 @@ type DepSet[T depSettableType] struct {
|
|||
transitive []*DepSet[T]
|
||||
}
|
||||
|
||||
func (d *DepSet[T]) GobEncode() ([]byte, error) {
|
||||
w := new(bytes.Buffer)
|
||||
encoder := gob.NewEncoder(w)
|
||||
err := errors.Join(encoder.Encode(d.preorder), encoder.Encode(d.reverse),
|
||||
encoder.Encode(d.order), encoder.Encode(d.direct), encoder.Encode(d.transitive))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return w.Bytes(), nil
|
||||
}
|
||||
|
||||
func (d *DepSet[T]) GobDecode(data []byte) error {
|
||||
r := bytes.NewBuffer(data)
|
||||
decoder := gob.NewDecoder(r)
|
||||
err := errors.Join(decoder.Decode(&d.preorder), decoder.Decode(&d.reverse),
|
||||
decoder.Decode(&d.order), decoder.Decode(&d.direct), decoder.Decode(&d.transitive))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewDepSet returns an immutable DepSet with the given order, direct and transitive contents.
|
||||
func NewDepSet[T depSettableType](order DepSetOrder, direct []T, transitive []*DepSet[T]) *DepSet[T] {
|
||||
var directCopy []T
|
||||
|
|
|
|||
|
|
@ -14,11 +14,17 @@
|
|||
|
||||
package android
|
||||
|
||||
// ImageInterface is implemented by modules that need to be split by the imageMutator.
|
||||
// ImageInterface is implemented by modules that need to be split by the imageTransitionMutator.
|
||||
type ImageInterface interface {
|
||||
// ImageMutatorBegin is called before any other method in the ImageInterface.
|
||||
ImageMutatorBegin(ctx BaseModuleContext)
|
||||
|
||||
// VendorVariantNeeded should return true if the module needs a vendor variant (installed on the vendor image).
|
||||
VendorVariantNeeded(ctx BaseModuleContext) bool
|
||||
|
||||
// ProductVariantNeeded should return true if the module needs a product variant (installed on the product image).
|
||||
ProductVariantNeeded(ctx BaseModuleContext) bool
|
||||
|
||||
// CoreVariantNeeded should return true if the module needs a core variant (installed on the system image).
|
||||
CoreVariantNeeded(ctx BaseModuleContext) bool
|
||||
|
||||
|
|
@ -49,6 +55,14 @@ type ImageInterface interface {
|
|||
}
|
||||
|
||||
const (
|
||||
// VendorVariation is the variant name used for /vendor code that does not
|
||||
// compile against the VNDK.
|
||||
VendorVariation string = "vendor"
|
||||
|
||||
// ProductVariation is the variant name used for /product code that does not
|
||||
// compile against the VNDK.
|
||||
ProductVariation string = "product"
|
||||
|
||||
// CoreVariation is the variant used for framework-private libraries, or
|
||||
// SDK libraries. (which framework-private libraries can use), which
|
||||
// will be installed to the system image.
|
||||
|
|
@ -67,18 +81,16 @@ const (
|
|||
DebugRamdiskVariation string = "debug_ramdisk"
|
||||
)
|
||||
|
||||
// imageMutator creates variants for modules that implement the ImageInterface that
|
||||
// imageTransitionMutator creates variants for modules that implement the ImageInterface that
|
||||
// allow them to build differently for each partition (recovery, core, vendor, etc.).
|
||||
func imageMutator(ctx BottomUpMutatorContext) {
|
||||
if ctx.Os() != Android {
|
||||
return
|
||||
}
|
||||
type imageTransitionMutator struct{}
|
||||
|
||||
if m, ok := ctx.Module().(ImageInterface); ok {
|
||||
func (imageTransitionMutator) Split(ctx BaseModuleContext) []string {
|
||||
var variations []string
|
||||
|
||||
if m, ok := ctx.Module().(ImageInterface); ctx.Os() == Android && ok {
|
||||
m.ImageMutatorBegin(ctx)
|
||||
|
||||
var variations []string
|
||||
|
||||
if m.CoreVariantNeeded(ctx) {
|
||||
variations = append(variations, CoreVariation)
|
||||
}
|
||||
|
|
@ -94,18 +106,38 @@ func imageMutator(ctx BottomUpMutatorContext) {
|
|||
if m.RecoveryVariantNeeded(ctx) {
|
||||
variations = append(variations, RecoveryVariation)
|
||||
}
|
||||
if m.VendorVariantNeeded(ctx) {
|
||||
variations = append(variations, VendorVariation)
|
||||
}
|
||||
if m.ProductVariantNeeded(ctx) {
|
||||
variations = append(variations, ProductVariation)
|
||||
}
|
||||
|
||||
extraVariations := m.ExtraImageVariations(ctx)
|
||||
variations = append(variations, extraVariations...)
|
||||
}
|
||||
|
||||
if len(variations) == 0 {
|
||||
return
|
||||
}
|
||||
if len(variations) == 0 {
|
||||
variations = append(variations, "")
|
||||
}
|
||||
|
||||
mod := ctx.CreateVariations(variations...)
|
||||
for i, v := range variations {
|
||||
mod[i].base().setImageVariation(v)
|
||||
mod[i].(ImageInterface).SetImageVariation(ctx, v)
|
||||
}
|
||||
return variations
|
||||
}
|
||||
|
||||
func (imageTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
|
||||
return sourceVariation
|
||||
}
|
||||
|
||||
func (imageTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
|
||||
if _, ok := ctx.Module().(ImageInterface); ctx.Os() != Android || !ok {
|
||||
return CoreVariation
|
||||
}
|
||||
return incomingVariation
|
||||
}
|
||||
|
||||
func (imageTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
|
||||
ctx.Module().base().setImageVariation(variation)
|
||||
if m, ok := ctx.Module().(ImageInterface); ok {
|
||||
m.SetImageVariation(ctx, variation)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
23
android/init.go
Normal file
23
android/init.go
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2024 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package android
|
||||
|
||||
import "encoding/gob"
|
||||
|
||||
func init() {
|
||||
gob.Register(ModuleOutPath{})
|
||||
gob.Register(PhonyPath{})
|
||||
gob.Register(unstableInfo{})
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ var (
|
|||
}, "args")
|
||||
)
|
||||
|
||||
func buildLicenseMetadata(ctx ModuleContext, licenseMetadataFile WritablePath) {
|
||||
func buildLicenseMetadata(ctx *moduleContext, licenseMetadataFile WritablePath) {
|
||||
base := ctx.Module().base()
|
||||
|
||||
if !base.Enabled(ctx) {
|
||||
|
|
@ -45,16 +45,15 @@ func buildLicenseMetadata(ctx ModuleContext, licenseMetadataFile WritablePath) {
|
|||
}
|
||||
|
||||
var outputFiles Paths
|
||||
if outputFileProducer, ok := ctx.Module().(OutputFileProducer); ok {
|
||||
outputFiles, _ = outputFileProducer.OutputFiles("")
|
||||
if outputFiles, err := outputFilesForModule(ctx, ctx.Module(), ""); err == nil {
|
||||
outputFiles = PathsIfNonNil(outputFiles...)
|
||||
}
|
||||
|
||||
// Only pass the last installed file to isContainerFromFileExtensions so a *.zip file in test data
|
||||
// doesn't mark the whole module as a container.
|
||||
var installFiles InstallPaths
|
||||
if len(base.installFiles) > 0 {
|
||||
installFiles = InstallPaths{base.installFiles[len(base.installFiles)-1]}
|
||||
if len(ctx.installFiles) > 0 {
|
||||
installFiles = InstallPaths{ctx.installFiles[len(ctx.installFiles)-1]}
|
||||
}
|
||||
|
||||
isContainer := isContainerFromFileExtensions(installFiles, outputFiles)
|
||||
|
|
@ -93,7 +92,7 @@ func buildLicenseMetadata(ctx ModuleContext, licenseMetadataFile WritablePath) {
|
|||
|
||||
allDepMetadataArgs = append(allDepMetadataArgs, info.LicenseMetadataPath.String()+depAnnotations)
|
||||
|
||||
if depInstallFiles := dep.base().installFiles; len(depInstallFiles) > 0 {
|
||||
if depInstallFiles := OtherModuleProviderOrDefault(ctx, dep, InstallFilesProvider).InstallFiles; len(depInstallFiles) > 0 {
|
||||
allDepOutputFiles = append(allDepOutputFiles, depInstallFiles.Paths()...)
|
||||
} else if depOutputFiles, err := outputFilesForModule(ctx, dep, ""); err == nil {
|
||||
depOutputFiles = PathsIfNonNil(depOutputFiles...)
|
||||
|
|
@ -153,7 +152,7 @@ func buildLicenseMetadata(ctx ModuleContext, licenseMetadataFile WritablePath) {
|
|||
|
||||
// Install map
|
||||
args = append(args,
|
||||
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.licenseInstallMap), "-m "))
|
||||
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(ctx.licenseInstallMap), "-m "))
|
||||
|
||||
// Built files
|
||||
if len(outputFiles) > 0 {
|
||||
|
|
@ -163,7 +162,7 @@ func buildLicenseMetadata(ctx ModuleContext, licenseMetadataFile WritablePath) {
|
|||
|
||||
// Installed files
|
||||
args = append(args,
|
||||
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.installFiles.Strings()), "-i "))
|
||||
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(ctx.installFiles.Strings()), "-i "))
|
||||
|
||||
if isContainer {
|
||||
args = append(args, "--is_container")
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ func (l *logtagsSingleton) GenerateBuildActions(ctx SingletonContext) {
|
|||
if !module.ExportedToMake() {
|
||||
return
|
||||
}
|
||||
if logtagsInfo, ok := SingletonModuleProvider(ctx, module, LogtagsProviderKey); ok {
|
||||
if logtagsInfo, ok := OtherModuleProvider(ctx, module, LogtagsProviderKey); ok {
|
||||
allLogtags = append(allLogtags, logtagsInfo.Logtags...)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ type MakeVarsContext interface {
|
|||
ModuleDir(module blueprint.Module) string
|
||||
ModuleSubDir(module blueprint.Module) string
|
||||
ModuleType(module blueprint.Module) string
|
||||
moduleProvider(module blueprint.Module, key blueprint.AnyProviderKey) (any, bool)
|
||||
otherModuleProvider(module blueprint.Module, key blueprint.AnyProviderKey) (any, bool)
|
||||
BlueprintFile(module blueprint.Module) string
|
||||
|
||||
ModuleErrorf(module blueprint.Module, format string, args ...interface{})
|
||||
|
|
@ -279,10 +279,11 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
|
|||
}
|
||||
|
||||
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...)
|
||||
info := OtherModuleProviderOrDefault(ctx, m, InstallFilesProvider)
|
||||
katiInstalls = append(katiInstalls, info.KatiInstalls...)
|
||||
katiInitRcInstalls = append(katiInitRcInstalls, info.KatiInitRcInstalls...)
|
||||
katiVintfManifestInstalls = append(katiVintfManifestInstalls, info.KatiVintfInstalls...)
|
||||
katiSymlinks = append(katiSymlinks, info.KatiSymlinks...)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -85,7 +85,9 @@ type ModuleBuildParams BuildParams
|
|||
type ModuleContext interface {
|
||||
BaseModuleContext
|
||||
|
||||
blueprintModuleContext() blueprint.ModuleContext
|
||||
// BlueprintModuleContext returns the blueprint.ModuleContext that the ModuleContext wraps. It may only be
|
||||
// used by the golang module types that need to call into the bootstrap module types.
|
||||
BlueprintModuleContext() blueprint.ModuleContext
|
||||
|
||||
// Deprecated: use ModuleContext.Build instead.
|
||||
ModuleBuild(pctx PackageContext, params ModuleBuildParams)
|
||||
|
|
@ -107,68 +109,79 @@ type ModuleContext interface {
|
|||
// InstallExecutable creates a rule to copy srcPath to name in the installPath directory,
|
||||
// with the given additional dependencies. The file is marked executable after copying.
|
||||
//
|
||||
// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
|
||||
// installed file will be returned by PackagingSpecs() on this module or by
|
||||
// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
|
||||
// for which IsInstallDepNeeded returns true.
|
||||
// The installed file can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
|
||||
// for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module
|
||||
// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
|
||||
// dependency tags for which IsInstallDepNeeded returns true.
|
||||
InstallExecutable(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath
|
||||
|
||||
// InstallFile creates a rule to copy srcPath to name in the installPath directory,
|
||||
// with the given additional dependencies.
|
||||
//
|
||||
// The installed file can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
|
||||
// for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module
|
||||
// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
|
||||
// dependency tags for which IsInstallDepNeeded returns true.
|
||||
InstallFile(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath
|
||||
|
||||
// InstallFileWithoutCheckbuild creates a rule to copy srcPath to name in the installPath directory,
|
||||
// with the given additional dependencies, but does not add the file to the list of files to build
|
||||
// during `m checkbuild`.
|
||||
//
|
||||
// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
|
||||
// installed file will be returned by PackagingSpecs() on this module or by
|
||||
// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
|
||||
// for which IsInstallDepNeeded returns true.
|
||||
InstallFile(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath
|
||||
InstallFileWithoutCheckbuild(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath
|
||||
|
||||
// InstallFileWithExtraFilesZip creates a rule to copy srcPath to name in the installPath
|
||||
// directory, and also unzip a zip file containing extra files to install into the same
|
||||
// directory.
|
||||
//
|
||||
// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
|
||||
// installed file will be returned by PackagingSpecs() on this module or by
|
||||
// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
|
||||
// for which IsInstallDepNeeded returns true.
|
||||
// The installed file can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
|
||||
// for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module
|
||||
// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
|
||||
// dependency tags for which IsInstallDepNeeded returns true.
|
||||
InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, extraZip Path, deps ...InstallPath) InstallPath
|
||||
|
||||
// InstallSymlink creates a rule to create a symlink from src srcPath to name in the installPath
|
||||
// directory.
|
||||
//
|
||||
// The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
|
||||
// installed file will be returned by PackagingSpecs() on this module or by
|
||||
// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
|
||||
// for which IsInstallDepNeeded returns true.
|
||||
// The installed symlink can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
|
||||
// for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module
|
||||
// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
|
||||
// dependency tags for which IsInstallDepNeeded returns true.
|
||||
InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath
|
||||
|
||||
// InstallAbsoluteSymlink creates a rule to create an absolute symlink from src srcPath to name
|
||||
// in the installPath directory.
|
||||
//
|
||||
// The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
|
||||
// installed file will be returned by PackagingSpecs() on this module or by
|
||||
// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
|
||||
// for which IsInstallDepNeeded returns true.
|
||||
// The installed symlink can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
|
||||
// for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module
|
||||
// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
|
||||
// dependency tags for which IsInstallDepNeeded returns true.
|
||||
InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath
|
||||
|
||||
// InstallTestData creates rules to install test data (e.g. data files used during a test) into
|
||||
// the installPath directory.
|
||||
//
|
||||
// The installed files will be returned by FilesToInstall(), and the PackagingSpec for the
|
||||
// installed files will be returned by PackagingSpecs() on this module or by
|
||||
// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
|
||||
// for which IsInstallDepNeeded returns true.
|
||||
// The installed files can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
|
||||
// for the installed files can be accessed by InstallFilesInfo.PackagingSpecs on this module
|
||||
// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
|
||||
// dependency tags for which IsInstallDepNeeded returns true.
|
||||
InstallTestData(installPath InstallPath, data []DataPath) InstallPaths
|
||||
|
||||
// PackageFile creates a PackagingSpec as if InstallFile was called, but without creating
|
||||
// the rule to copy the file. This is useful to define how a module would be packaged
|
||||
// without installing it into the global installation directories.
|
||||
//
|
||||
// The created PackagingSpec for the will be returned by PackagingSpecs() on this module or by
|
||||
// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
|
||||
// for which IsInstallDepNeeded returns true.
|
||||
// The created PackagingSpec can be accessed by InstallFilesInfo.PackagingSpecs on this module
|
||||
// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
|
||||
// dependency tags for which IsInstallDepNeeded returns true.
|
||||
PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec
|
||||
|
||||
CheckbuildFile(srcPath Path)
|
||||
CheckbuildFile(srcPaths ...Path)
|
||||
UncheckedModule()
|
||||
|
||||
InstallInData() bool
|
||||
InstallInTestcases() bool
|
||||
|
|
@ -183,12 +196,11 @@ type ModuleContext interface {
|
|||
InstallInVendor() bool
|
||||
InstallForceOS() (*OsType, *ArchType)
|
||||
|
||||
RequiredModuleNames(ctx ConfigAndErrorContext) []string
|
||||
RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string
|
||||
HostRequiredModuleNames() []string
|
||||
TargetRequiredModuleNames() []string
|
||||
|
||||
ModuleSubDir() string
|
||||
SoongConfigTraceHash() string
|
||||
|
||||
Variable(pctx PackageContext, name, value string)
|
||||
Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
|
||||
|
|
@ -216,19 +228,58 @@ type ModuleContext interface {
|
|||
// SetOutputFiles stores the outputFiles to outputFiles property, which is used
|
||||
// to set the OutputFilesProvider later.
|
||||
SetOutputFiles(outputFiles Paths, tag string)
|
||||
|
||||
GetOutputFiles() OutputFilesInfo
|
||||
|
||||
// SetLicenseInstallMap stores the set of dependency module:location mappings for files in an
|
||||
// apex container for use when generation the license metadata file.
|
||||
SetLicenseInstallMap(installMap []string)
|
||||
|
||||
// ComplianceMetadataInfo returns a ComplianceMetadataInfo instance for different module types to dump metadata,
|
||||
// which usually happens in GenerateAndroidBuildActions() of a module type.
|
||||
// See android.ModuleBase.complianceMetadataInfo
|
||||
ComplianceMetadataInfo() *ComplianceMetadataInfo
|
||||
|
||||
// Get the information about the containers this module belongs to.
|
||||
getContainersInfo() ContainersInfo
|
||||
setContainersInfo(info ContainersInfo)
|
||||
|
||||
setAconfigPaths(paths Paths)
|
||||
}
|
||||
|
||||
type moduleContext struct {
|
||||
bp blueprint.ModuleContext
|
||||
baseModuleContext
|
||||
packagingSpecs []PackagingSpec
|
||||
installFiles InstallPaths
|
||||
checkbuildFiles Paths
|
||||
module Module
|
||||
phonies map[string]Paths
|
||||
packagingSpecs []PackagingSpec
|
||||
installFiles InstallPaths
|
||||
checkbuildFiles Paths
|
||||
checkbuildTarget Path
|
||||
uncheckedModule bool
|
||||
module Module
|
||||
phonies map[string]Paths
|
||||
// outputFiles stores the output of a module by tag and is used to set
|
||||
// the OutputFilesProvider in GenerateBuildActions
|
||||
outputFiles OutputFilesInfo
|
||||
|
||||
katiInstalls []katiInstall
|
||||
katiSymlinks []katiInstall
|
||||
TransitiveInstallFiles *DepSet[InstallPath]
|
||||
|
||||
// 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
|
||||
|
||||
katiInstalls katiInstalls
|
||||
katiSymlinks katiInstalls
|
||||
// katiInitRcInstalls and katiVintfInstalls track the install rules created by Soong that are
|
||||
// allowed to have duplicates across modules and variants.
|
||||
katiInitRcInstalls katiInstalls
|
||||
katiVintfInstalls katiInstalls
|
||||
initRcPaths Paths
|
||||
vintfFragmentsPaths Paths
|
||||
installedInitRcPaths InstallPaths
|
||||
installedVintfFragmentsPaths InstallPaths
|
||||
|
||||
testData []DataPath
|
||||
|
||||
|
|
@ -236,6 +287,21 @@ type moduleContext struct {
|
|||
buildParams []BuildParams
|
||||
ruleParams map[blueprint.Rule]blueprint.RuleParams
|
||||
variables map[string]string
|
||||
|
||||
// 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
|
||||
|
||||
// containersInfo stores the information about the containers and the information of the
|
||||
// apexes the module belongs to.
|
||||
containersInfo ContainersInfo
|
||||
|
||||
// Merged Aconfig files for all transitive deps.
|
||||
aconfigFilePaths Paths
|
||||
|
||||
// complianceMetadataInfo is for different module types to dump metadata.
|
||||
// See android.ModuleContext interface.
|
||||
complianceMetadataInfo *ComplianceMetadataInfo
|
||||
}
|
||||
|
||||
var _ ModuleContext = &moduleContext{}
|
||||
|
|
@ -357,7 +423,7 @@ func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {
|
|||
}
|
||||
|
||||
func (m *moduleContext) Phony(name string, deps ...Path) {
|
||||
addPhony(m.config, name, deps...)
|
||||
m.phonies[name] = append(m.phonies[name], deps...)
|
||||
}
|
||||
|
||||
func (m *moduleContext) GetMissingDependencies() []string {
|
||||
|
|
@ -377,10 +443,6 @@ func (m *moduleContext) ModuleSubDir() string {
|
|||
return m.bp.ModuleSubDir()
|
||||
}
|
||||
|
||||
func (m *moduleContext) SoongConfigTraceHash() string {
|
||||
return m.module.base().commonProperties.SoongConfigTraceHash
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallInData() bool {
|
||||
return m.module.InstallInData()
|
||||
}
|
||||
|
|
@ -465,17 +527,22 @@ func (m *moduleContext) requiresFullInstall() bool {
|
|||
|
||||
func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path,
|
||||
deps ...InstallPath) InstallPath {
|
||||
return m.installFile(installPath, name, srcPath, deps, false, true, nil)
|
||||
return m.installFile(installPath, name, srcPath, deps, false, true, true, nil)
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallFileWithoutCheckbuild(installPath InstallPath, name string, srcPath Path,
|
||||
deps ...InstallPath) InstallPath {
|
||||
return m.installFile(installPath, name, srcPath, deps, false, true, false, nil)
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path,
|
||||
deps ...InstallPath) InstallPath {
|
||||
return m.installFile(installPath, name, srcPath, deps, true, true, nil)
|
||||
return m.installFile(installPath, name, srcPath, deps, true, true, true, nil)
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path,
|
||||
extraZip Path, deps ...InstallPath) InstallPath {
|
||||
return m.installFile(installPath, name, srcPath, deps, false, true, &extraFilesZip{
|
||||
return m.installFile(installPath, name, srcPath, deps, false, true, true, &extraFilesZip{
|
||||
zip: extraZip,
|
||||
dir: installPath,
|
||||
})
|
||||
|
|
@ -487,11 +554,16 @@ func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPat
|
|||
}
|
||||
|
||||
func (m *moduleContext) getAconfigPaths() *Paths {
|
||||
return &m.module.base().aconfigFilePaths
|
||||
return &m.aconfigFilePaths
|
||||
}
|
||||
|
||||
func (m *moduleContext) setAconfigPaths(paths Paths) {
|
||||
m.aconfigFilePaths = paths
|
||||
}
|
||||
|
||||
func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool) PackagingSpec {
|
||||
licenseFiles := m.Module().EffectiveLicenseFiles()
|
||||
overrides := CopyOf(m.Module().base().commonProperties.Overrides)
|
||||
spec := PackagingSpec{
|
||||
relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
|
||||
srcPath: srcPath,
|
||||
|
|
@ -502,13 +574,15 @@ func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, e
|
|||
skipInstall: m.skipInstall(),
|
||||
aconfigPaths: m.getAconfigPaths(),
|
||||
archType: m.target.Arch.ArchType,
|
||||
overrides: &overrides,
|
||||
owner: m.ModuleName(),
|
||||
}
|
||||
m.packagingSpecs = append(m.packagingSpecs, spec)
|
||||
return spec
|
||||
}
|
||||
|
||||
func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []InstallPath,
|
||||
executable bool, hooks bool, extraZip *extraFilesZip) InstallPath {
|
||||
executable bool, hooks bool, checkbuild bool, extraZip *extraFilesZip) InstallPath {
|
||||
|
||||
fullInstallPath := installPath.Join(m, name)
|
||||
if hooks {
|
||||
|
|
@ -516,9 +590,9 @@ func (m *moduleContext) installFile(installPath InstallPath, name string, srcPat
|
|||
}
|
||||
|
||||
if m.requiresFullInstall() {
|
||||
deps = append(deps, InstallPaths(m.module.base().installFilesDepSet.ToList())...)
|
||||
deps = append(deps, m.module.base().installedInitRcPaths...)
|
||||
deps = append(deps, m.module.base().installedVintfFragmentsPaths...)
|
||||
deps = append(deps, InstallPaths(m.TransitiveInstallFiles.ToList())...)
|
||||
deps = append(deps, m.installedInitRcPaths...)
|
||||
deps = append(deps, m.installedVintfFragmentsPaths...)
|
||||
|
||||
var implicitDeps, orderOnlyDeps Paths
|
||||
|
||||
|
|
@ -575,7 +649,9 @@ func (m *moduleContext) installFile(installPath InstallPath, name string, srcPat
|
|||
|
||||
m.packageFile(fullInstallPath, srcPath, executable)
|
||||
|
||||
m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
|
||||
if checkbuild {
|
||||
m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
|
||||
}
|
||||
|
||||
return fullInstallPath
|
||||
}
|
||||
|
|
@ -616,9 +692,9 @@ func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, src
|
|||
}
|
||||
|
||||
m.installFiles = append(m.installFiles, fullInstallPath)
|
||||
m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
|
||||
}
|
||||
|
||||
overrides := CopyOf(m.Module().base().commonProperties.Overrides)
|
||||
m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
|
||||
relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
|
||||
srcPath: nil,
|
||||
|
|
@ -628,6 +704,8 @@ func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, src
|
|||
skipInstall: m.skipInstall(),
|
||||
aconfigPaths: m.getAconfigPaths(),
|
||||
archType: m.target.Arch.ArchType,
|
||||
overrides: &overrides,
|
||||
owner: m.ModuleName(),
|
||||
})
|
||||
|
||||
return fullInstallPath
|
||||
|
|
@ -663,6 +741,7 @@ func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name str
|
|||
m.installFiles = append(m.installFiles, fullInstallPath)
|
||||
}
|
||||
|
||||
overrides := CopyOf(m.Module().base().commonProperties.Overrides)
|
||||
m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
|
||||
relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
|
||||
srcPath: nil,
|
||||
|
|
@ -672,6 +751,8 @@ func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name str
|
|||
skipInstall: m.skipInstall(),
|
||||
aconfigPaths: m.getAconfigPaths(),
|
||||
archType: m.target.Arch.ArchType,
|
||||
overrides: &overrides,
|
||||
owner: m.ModuleName(),
|
||||
})
|
||||
|
||||
return fullInstallPath
|
||||
|
|
@ -683,52 +764,73 @@ func (m *moduleContext) InstallTestData(installPath InstallPath, data []DataPath
|
|||
ret := make(InstallPaths, 0, len(data))
|
||||
for _, d := range data {
|
||||
relPath := d.ToRelativeInstallPath()
|
||||
installed := m.installFile(installPath, relPath, d.SrcPath, nil, false, false, nil)
|
||||
installed := m.installFile(installPath, relPath, d.SrcPath, nil, false, false, true, nil)
|
||||
ret = append(ret, installed)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (m *moduleContext) CheckbuildFile(srcPath Path) {
|
||||
m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
|
||||
// CheckbuildFile specifies the output files that should be built by checkbuild.
|
||||
func (m *moduleContext) CheckbuildFile(srcPaths ...Path) {
|
||||
m.checkbuildFiles = append(m.checkbuildFiles, srcPaths...)
|
||||
}
|
||||
|
||||
func (m *moduleContext) blueprintModuleContext() blueprint.ModuleContext {
|
||||
// UncheckedModule marks the current module has having no files that should be built by checkbuild.
|
||||
func (m *moduleContext) UncheckedModule() {
|
||||
m.uncheckedModule = true
|
||||
}
|
||||
|
||||
func (m *moduleContext) BlueprintModuleContext() blueprint.ModuleContext {
|
||||
return m.bp
|
||||
}
|
||||
|
||||
func (m *moduleContext) LicenseMetadataFile() Path {
|
||||
return m.module.base().licenseMetadataFile
|
||||
return m.licenseMetadataFile
|
||||
}
|
||||
|
||||
func (m *moduleContext) ModuleInfoJSON() *ModuleInfoJSON {
|
||||
if moduleInfoJSON := m.module.base().moduleInfoJSON; moduleInfoJSON != nil {
|
||||
if moduleInfoJSON := m.moduleInfoJSON; moduleInfoJSON != nil {
|
||||
return moduleInfoJSON
|
||||
}
|
||||
moduleInfoJSON := &ModuleInfoJSON{}
|
||||
m.module.base().moduleInfoJSON = moduleInfoJSON
|
||||
m.moduleInfoJSON = moduleInfoJSON
|
||||
return moduleInfoJSON
|
||||
}
|
||||
|
||||
func (m *moduleContext) SetOutputFiles(outputFiles Paths, tag string) {
|
||||
if tag == "" {
|
||||
if len(m.module.base().outputFiles.DefaultOutputFiles) > 0 {
|
||||
if len(m.outputFiles.DefaultOutputFiles) > 0 {
|
||||
m.ModuleErrorf("Module %s default OutputFiles cannot be overwritten", m.ModuleName())
|
||||
}
|
||||
m.module.base().outputFiles.DefaultOutputFiles = outputFiles
|
||||
m.outputFiles.DefaultOutputFiles = outputFiles
|
||||
} else {
|
||||
if m.module.base().outputFiles.TaggedOutputFiles == nil {
|
||||
m.module.base().outputFiles.TaggedOutputFiles = make(map[string]Paths)
|
||||
if m.outputFiles.TaggedOutputFiles == nil {
|
||||
m.outputFiles.TaggedOutputFiles = make(map[string]Paths)
|
||||
}
|
||||
if _, exists := m.module.base().outputFiles.TaggedOutputFiles[tag]; exists {
|
||||
if _, exists := m.outputFiles.TaggedOutputFiles[tag]; exists {
|
||||
m.ModuleErrorf("Module %s OutputFiles at tag %s cannot be overwritten", m.ModuleName(), tag)
|
||||
} else {
|
||||
m.module.base().outputFiles.TaggedOutputFiles[tag] = outputFiles
|
||||
m.outputFiles.TaggedOutputFiles[tag] = outputFiles
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *moduleContext) GetOutputFiles() OutputFilesInfo {
|
||||
return m.outputFiles
|
||||
}
|
||||
|
||||
func (m *moduleContext) SetLicenseInstallMap(installMap []string) {
|
||||
m.licenseInstallMap = append(m.licenseInstallMap, installMap...)
|
||||
}
|
||||
|
||||
func (m *moduleContext) ComplianceMetadataInfo() *ComplianceMetadataInfo {
|
||||
if m.complianceMetadataInfo == nil {
|
||||
m.complianceMetadataInfo = NewComplianceMetadataInfo()
|
||||
}
|
||||
return m.complianceMetadataInfo
|
||||
}
|
||||
|
||||
// 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.
|
||||
//
|
||||
|
|
@ -755,7 +857,7 @@ func (m *moduleContext) ExpandOptionalSource(srcFile *string, _ string) Optional
|
|||
return OptionalPath{}
|
||||
}
|
||||
|
||||
func (m *moduleContext) RequiredModuleNames(ctx ConfigAndErrorContext) []string {
|
||||
func (m *moduleContext) RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string {
|
||||
return m.module.RequiredModuleNames(ctx)
|
||||
}
|
||||
|
||||
|
|
@ -766,3 +868,11 @@ func (m *moduleContext) HostRequiredModuleNames() []string {
|
|||
func (m *moduleContext) TargetRequiredModuleNames() []string {
|
||||
return m.module.TargetRequiredModuleNames()
|
||||
}
|
||||
|
||||
func (m *moduleContext) getContainersInfo() ContainersInfo {
|
||||
return m.containersInfo
|
||||
}
|
||||
|
||||
func (m *moduleContext) setContainersInfo(info ContainersInfo) {
|
||||
m.containersInfo = info
|
||||
}
|
||||
|
|
|
|||
|
|
@ -722,6 +722,7 @@ test {
|
|||
propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "x86_64 a"},
|
||||
propInfo{Name: "B", Type: "bool", Value: "true"},
|
||||
propInfo{Name: "C", Type: "string slice", Values: []string{"default_c", "c"}},
|
||||
propInfo{Name: "Defaults", Type: "string slice", Values: []string{"foo_defaults"}},
|
||||
propInfo{Name: "Embedded_prop", Type: "string", Value: "a"},
|
||||
propInfo{Name: "Name", Type: "string", Value: "foo"},
|
||||
propInfo{Name: "Nested.E", Type: "string", Value: "nested e"},
|
||||
|
|
@ -933,31 +934,54 @@ func TestSetAndroidMkEntriesWithTestOptions(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
type fakeBlueprintModule struct{}
|
||||
|
||||
func (fakeBlueprintModule) Name() string { return "foo" }
|
||||
|
||||
func (fakeBlueprintModule) GenerateBuildActions(blueprint.ModuleContext) {}
|
||||
|
||||
type sourceProducerTestModule struct {
|
||||
fakeBlueprintModule
|
||||
source Path
|
||||
ModuleBase
|
||||
props struct {
|
||||
// A represents the source file
|
||||
A string
|
||||
}
|
||||
}
|
||||
|
||||
func (s sourceProducerTestModule) Srcs() Paths { return Paths{s.source} }
|
||||
|
||||
type outputFileProducerTestModule struct {
|
||||
fakeBlueprintModule
|
||||
output map[string]Path
|
||||
error map[string]error
|
||||
func sourceProducerTestModuleFactory() Module {
|
||||
module := &sourceProducerTestModule{}
|
||||
module.AddProperties(&module.props)
|
||||
InitAndroidModule(module)
|
||||
return module
|
||||
}
|
||||
|
||||
func (o outputFileProducerTestModule) OutputFiles(tag string) (Paths, error) {
|
||||
return PathsIfNonNil(o.output[tag]), o.error[tag]
|
||||
func (s sourceProducerTestModule) GenerateAndroidBuildActions(ModuleContext) {}
|
||||
|
||||
func (s sourceProducerTestModule) Srcs() Paths { return PathsForTesting(s.props.A) }
|
||||
|
||||
type outputFilesTestModule struct {
|
||||
ModuleBase
|
||||
props struct {
|
||||
// A represents the tag
|
||||
A string
|
||||
// B represents the output file for tag A
|
||||
B string
|
||||
}
|
||||
}
|
||||
|
||||
func outputFilesTestModuleFactory() Module {
|
||||
module := &outputFilesTestModule{}
|
||||
module.AddProperties(&module.props)
|
||||
InitAndroidModule(module)
|
||||
return module
|
||||
}
|
||||
|
||||
func (o outputFilesTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
|
||||
if o.props.A != "" || o.props.B != "" {
|
||||
ctx.SetOutputFiles(PathsForTesting(o.props.B), o.props.A)
|
||||
}
|
||||
// This is to simulate the case that some module uses an object to set its
|
||||
// OutputFilesProvider, but the object itself is empty.
|
||||
ctx.SetOutputFiles(Paths{}, "missing")
|
||||
}
|
||||
|
||||
type pathContextAddMissingDependenciesWrapper struct {
|
||||
PathContext
|
||||
OtherModuleProviderContext
|
||||
missingDeps []string
|
||||
}
|
||||
|
||||
|
|
@ -968,52 +992,91 @@ func (p *pathContextAddMissingDependenciesWrapper) OtherModuleName(module bluepr
|
|||
return module.Name()
|
||||
}
|
||||
|
||||
func (p *pathContextAddMissingDependenciesWrapper) Module() Module { return nil }
|
||||
|
||||
func (p *pathContextAddMissingDependenciesWrapper) GetOutputFiles() OutputFilesInfo {
|
||||
return OutputFilesInfo{}
|
||||
}
|
||||
|
||||
func TestOutputFileForModule(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
module blueprint.Module
|
||||
bp string
|
||||
tag string
|
||||
env map[string]string
|
||||
config func(*config)
|
||||
expected string
|
||||
missingDeps []string
|
||||
env map[string]string
|
||||
config func(*config)
|
||||
}{
|
||||
{
|
||||
name: "SourceFileProducer",
|
||||
module: &sourceProducerTestModule{source: PathForTesting("foo.txt")},
|
||||
expected: "foo.txt",
|
||||
name: "SourceFileProducer",
|
||||
bp: `spt_module {
|
||||
name: "test_module",
|
||||
a: "spt.txt",
|
||||
}
|
||||
`,
|
||||
tag: "",
|
||||
expected: "spt.txt",
|
||||
},
|
||||
{
|
||||
name: "OutputFileProducer",
|
||||
module: &outputFileProducerTestModule{output: map[string]Path{"": PathForTesting("foo.txt")}},
|
||||
expected: "foo.txt",
|
||||
name: "OutputFileProviderEmptyStringTag",
|
||||
bp: `oft_module {
|
||||
name: "test_module",
|
||||
a: "",
|
||||
b: "empty.txt",
|
||||
}
|
||||
`,
|
||||
tag: "",
|
||||
expected: "empty.txt",
|
||||
},
|
||||
{
|
||||
name: "OutputFileProducer_tag",
|
||||
module: &outputFileProducerTestModule{output: map[string]Path{"foo": PathForTesting("foo.txt")}},
|
||||
name: "OutputFileProviderTag",
|
||||
bp: `oft_module {
|
||||
name: "test_module",
|
||||
a: "foo",
|
||||
b: "foo.txt",
|
||||
}
|
||||
`,
|
||||
tag: "foo",
|
||||
expected: "foo.txt",
|
||||
},
|
||||
{
|
||||
name: "OutputFileProducer_AllowMissingDependencies",
|
||||
name: "OutputFileAllowMissingDependencies",
|
||||
bp: `oft_module {
|
||||
name: "test_module",
|
||||
}
|
||||
`,
|
||||
tag: "missing",
|
||||
expected: "missing_output_file/test_module",
|
||||
missingDeps: []string{"test_module"},
|
||||
config: func(config *config) {
|
||||
config.TestProductVariables.Allow_missing_dependencies = boolPtr(true)
|
||||
},
|
||||
module: &outputFileProducerTestModule{},
|
||||
missingDeps: []string{"foo"},
|
||||
expected: "missing_output_file/foo",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testcases {
|
||||
config := TestConfig(buildDir, tt.env, "", nil)
|
||||
if tt.config != nil {
|
||||
tt.config(config.config)
|
||||
}
|
||||
ctx := &pathContextAddMissingDependenciesWrapper{
|
||||
PathContext: PathContextForTesting(config),
|
||||
}
|
||||
got := OutputFileForModule(ctx, tt.module, tt.tag)
|
||||
AssertPathRelativeToTopEquals(t, "expected source path", tt.expected, got)
|
||||
AssertArrayString(t, "expected missing deps", tt.missingDeps, ctx.missingDeps)
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := GroupFixturePreparers(
|
||||
PrepareForTestWithDefaults,
|
||||
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
ctx.RegisterModuleType("spt_module", sourceProducerTestModuleFactory)
|
||||
ctx.RegisterModuleType("oft_module", outputFilesTestModuleFactory)
|
||||
}),
|
||||
FixtureWithRootAndroidBp(tt.bp),
|
||||
).RunTest(t)
|
||||
|
||||
config := TestConfig(buildDir, tt.env, tt.bp, nil)
|
||||
if tt.config != nil {
|
||||
tt.config(config.config)
|
||||
}
|
||||
ctx := &pathContextAddMissingDependenciesWrapper{
|
||||
PathContext: PathContextForTesting(config),
|
||||
OtherModuleProviderContext: result.TestContext.OtherModuleProviderAdaptor(),
|
||||
}
|
||||
got := OutputFileForModule(ctx, result.ModuleForTests("test_module", "").Module(), tt.tag)
|
||||
AssertPathRelativeToTopEquals(t, "expected output path", tt.expected, got)
|
||||
AssertArrayString(t, "expected missing deps", tt.missingDeps, ctx.missingDeps)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,9 +148,9 @@ var preArch = []RegisterMutatorFunc{
|
|||
}
|
||||
|
||||
func registerArchMutator(ctx RegisterMutatorsContext) {
|
||||
ctx.BottomUpBlueprint("os", osMutator).Parallel()
|
||||
ctx.BottomUp("image", imageMutator).Parallel()
|
||||
ctx.BottomUpBlueprint("arch", archMutator).Parallel()
|
||||
ctx.Transition("os", &osTransitionMutator{})
|
||||
ctx.Transition("image", &imageTransitionMutator{})
|
||||
ctx.Transition("arch", &archTransitionMutator{})
|
||||
}
|
||||
|
||||
var preDeps = []RegisterMutatorFunc{
|
||||
|
|
@ -193,16 +193,16 @@ type BaseMutatorContext interface {
|
|||
// Rename all variants of a module. The new name is not visible to calls to ModuleName,
|
||||
// AddDependency or OtherModuleName until after this mutator pass is complete.
|
||||
Rename(name string)
|
||||
|
||||
// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
|
||||
// the specified property structs to it as if the properties were set in a blueprint file.
|
||||
CreateModule(ModuleFactory, ...interface{}) Module
|
||||
}
|
||||
|
||||
type TopDownMutator func(TopDownMutatorContext)
|
||||
|
||||
type TopDownMutatorContext interface {
|
||||
BaseMutatorContext
|
||||
|
||||
// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
|
||||
// the specified property structs to it as if the properties were set in a blueprint file.
|
||||
CreateModule(ModuleFactory, ...interface{}) Module
|
||||
}
|
||||
|
||||
type topDownMutatorContext struct {
|
||||
|
|
@ -400,6 +400,12 @@ type IncomingTransitionContext interface {
|
|||
Config() Config
|
||||
|
||||
DeviceConfig() DeviceConfig
|
||||
|
||||
// IsAddingDependency returns true if the transition is being called while adding a dependency
|
||||
// after the transition mutator has already run, or false if it is being called when the transition
|
||||
// mutator is running. This should be used sparingly, all uses will have to be removed in order
|
||||
// to support creating variants on demand.
|
||||
IsAddingDependency() bool
|
||||
}
|
||||
|
||||
type OutgoingTransitionContext interface {
|
||||
|
|
@ -510,6 +516,9 @@ type androidTransitionMutator struct {
|
|||
}
|
||||
|
||||
func (a *androidTransitionMutator) Split(ctx blueprint.BaseModuleContext) []string {
|
||||
if a.finalPhase {
|
||||
panic("TransitionMutator not allowed in FinalDepsMutators")
|
||||
}
|
||||
if m, ok := ctx.Module().(Module); ok {
|
||||
moduleContext := m.base().baseModuleContextFactory(ctx)
|
||||
return a.mutator.Split(&moduleContext)
|
||||
|
|
@ -574,6 +583,10 @@ func (c *incomingTransitionContextImpl) DeviceConfig() DeviceConfig {
|
|||
return DeviceConfig{c.bp.Config().(Config).deviceConfig}
|
||||
}
|
||||
|
||||
func (c *incomingTransitionContextImpl) IsAddingDependency() bool {
|
||||
return c.bp.IsAddingDependency()
|
||||
}
|
||||
|
||||
func (c *incomingTransitionContextImpl) provider(provider blueprint.AnyProviderKey) (any, bool) {
|
||||
return c.bp.Provider(provider)
|
||||
}
|
||||
|
|
@ -729,6 +742,14 @@ func (b *bottomUpMutatorContext) Rename(name string) {
|
|||
b.Module().base().commonProperties.DebugName = name
|
||||
}
|
||||
|
||||
func (b *bottomUpMutatorContext) createModule(factory blueprint.ModuleFactory, name string, props ...interface{}) blueprint.Module {
|
||||
return b.bp.CreateModule(factory, name, props...)
|
||||
}
|
||||
|
||||
func (b *bottomUpMutatorContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
|
||||
return createModule(b, factory, "_bottomUpMutatorModule", props...)
|
||||
}
|
||||
|
||||
func (b *bottomUpMutatorContext) AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []blueprint.Module {
|
||||
if b.baseModuleContext.checkedMissingDeps() {
|
||||
panic("Adding deps not allowed after checking for missing deps")
|
||||
|
|
|
|||
|
|
@ -81,6 +81,40 @@ func TestMutatorAddMissingDependencies(t *testing.T) {
|
|||
AssertDeepEquals(t, "foo missing deps", []string{"added_missing_dep", "regular_missing_dep"}, foo.missingDeps)
|
||||
}
|
||||
|
||||
type testTransitionMutator struct {
|
||||
split func(ctx BaseModuleContext) []string
|
||||
outgoingTransition func(ctx OutgoingTransitionContext, sourceVariation string) string
|
||||
incomingTransition func(ctx IncomingTransitionContext, incomingVariation string) string
|
||||
mutate func(ctx BottomUpMutatorContext, variation string)
|
||||
}
|
||||
|
||||
func (t *testTransitionMutator) Split(ctx BaseModuleContext) []string {
|
||||
if t.split != nil {
|
||||
return t.split(ctx)
|
||||
}
|
||||
return []string{""}
|
||||
}
|
||||
|
||||
func (t *testTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
|
||||
if t.outgoingTransition != nil {
|
||||
return t.outgoingTransition(ctx, sourceVariation)
|
||||
}
|
||||
return sourceVariation
|
||||
}
|
||||
|
||||
func (t *testTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
|
||||
if t.incomingTransition != nil {
|
||||
return t.incomingTransition(ctx, incomingVariation)
|
||||
}
|
||||
return incomingVariation
|
||||
}
|
||||
|
||||
func (t *testTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
|
||||
if t.mutate != nil {
|
||||
t.mutate(ctx, variation)
|
||||
}
|
||||
}
|
||||
|
||||
func TestModuleString(t *testing.T) {
|
||||
bp := `
|
||||
test {
|
||||
|
|
@ -94,9 +128,11 @@ func TestModuleString(t *testing.T) {
|
|||
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
|
||||
ctx.PreArchMutators(func(ctx RegisterMutatorsContext) {
|
||||
ctx.BottomUp("pre_arch", func(ctx BottomUpMutatorContext) {
|
||||
moduleStrings = append(moduleStrings, ctx.Module().String())
|
||||
ctx.CreateVariations("a", "b")
|
||||
ctx.Transition("pre_arch", &testTransitionMutator{
|
||||
split: func(ctx BaseModuleContext) []string {
|
||||
moduleStrings = append(moduleStrings, ctx.Module().String())
|
||||
return []string{"a", "b"}
|
||||
},
|
||||
})
|
||||
ctx.TopDown("rename_top_down", func(ctx TopDownMutatorContext) {
|
||||
moduleStrings = append(moduleStrings, ctx.Module().String())
|
||||
|
|
@ -105,16 +141,23 @@ func TestModuleString(t *testing.T) {
|
|||
})
|
||||
|
||||
ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
|
||||
ctx.BottomUp("pre_deps", func(ctx BottomUpMutatorContext) {
|
||||
moduleStrings = append(moduleStrings, ctx.Module().String())
|
||||
ctx.CreateVariations("c", "d")
|
||||
ctx.Transition("pre_deps", &testTransitionMutator{
|
||||
split: func(ctx BaseModuleContext) []string {
|
||||
moduleStrings = append(moduleStrings, ctx.Module().String())
|
||||
return []string{"c", "d"}
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
ctx.PostDepsMutators(func(ctx RegisterMutatorsContext) {
|
||||
ctx.BottomUp("post_deps", func(ctx BottomUpMutatorContext) {
|
||||
moduleStrings = append(moduleStrings, ctx.Module().String())
|
||||
ctx.CreateLocalVariations("e", "f")
|
||||
ctx.Transition("post_deps", &testTransitionMutator{
|
||||
split: func(ctx BaseModuleContext) []string {
|
||||
moduleStrings = append(moduleStrings, ctx.Module().String())
|
||||
return []string{"e", "f"}
|
||||
},
|
||||
outgoingTransition: func(ctx OutgoingTransitionContext, sourceVariation string) string {
|
||||
return ""
|
||||
},
|
||||
})
|
||||
ctx.BottomUp("rename_bottom_up", func(ctx BottomUpMutatorContext) {
|
||||
moduleStrings = append(moduleStrings, ctx.Module().String())
|
||||
|
|
@ -138,15 +181,15 @@ func TestModuleString(t *testing.T) {
|
|||
"foo{pre_arch:b}",
|
||||
"foo{pre_arch:a}",
|
||||
|
||||
// After rename_top_down.
|
||||
"foo_renamed1{pre_arch:a}",
|
||||
// After rename_top_down (reversed because pre_deps TransitionMutator.Split is TopDown).
|
||||
"foo_renamed1{pre_arch:b}",
|
||||
"foo_renamed1{pre_arch:a}",
|
||||
|
||||
// After pre_deps.
|
||||
"foo_renamed1{pre_arch:a,pre_deps:c}",
|
||||
"foo_renamed1{pre_arch:a,pre_deps:d}",
|
||||
"foo_renamed1{pre_arch:b,pre_deps:c}",
|
||||
// After pre_deps (reversed because post_deps TransitionMutator.Split is TopDown).
|
||||
"foo_renamed1{pre_arch:b,pre_deps:d}",
|
||||
"foo_renamed1{pre_arch:b,pre_deps:c}",
|
||||
"foo_renamed1{pre_arch:a,pre_deps:d}",
|
||||
"foo_renamed1{pre_arch:a,pre_deps:c}",
|
||||
|
||||
// After post_deps.
|
||||
"foo_renamed1{pre_arch:a,pre_deps:c,post_deps:e}",
|
||||
|
|
@ -202,8 +245,10 @@ func TestFinalDepsPhase(t *testing.T) {
|
|||
ctx.AddFarVariationDependencies([]blueprint.Variation{}, dep1Tag, "common_dep_1")
|
||||
}
|
||||
})
|
||||
ctx.BottomUp("variant", func(ctx BottomUpMutatorContext) {
|
||||
ctx.CreateLocalVariations("a", "b")
|
||||
ctx.Transition("variant", &testTransitionMutator{
|
||||
split: func(ctx BaseModuleContext) []string {
|
||||
return []string{"a", "b"}
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -243,27 +288,20 @@ func TestFinalDepsPhase(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNoCreateVariationsInFinalDeps(t *testing.T) {
|
||||
checkErr := func() {
|
||||
if err := recover(); err == nil || !strings.Contains(fmt.Sprintf("%s", err), "not allowed in FinalDepsMutators") {
|
||||
panic("Expected FinalDepsMutators consistency check to fail")
|
||||
}
|
||||
}
|
||||
|
||||
GroupFixturePreparers(
|
||||
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) {
|
||||
ctx.BottomUp("vars", func(ctx BottomUpMutatorContext) {
|
||||
defer checkErr()
|
||||
ctx.CreateVariations("a", "b")
|
||||
})
|
||||
ctx.BottomUp("local_vars", func(ctx BottomUpMutatorContext) {
|
||||
defer checkErr()
|
||||
ctx.CreateLocalVariations("a", "b")
|
||||
ctx.Transition("vars", &testTransitionMutator{
|
||||
split: func(ctx BaseModuleContext) []string {
|
||||
return []string{"a", "b"}
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
ctx.RegisterModuleType("test", mutatorTestModuleFactory)
|
||||
}),
|
||||
FixtureWithRootAndroidBp(`test {name: "foo"}`),
|
||||
).RunTest(t)
|
||||
).
|
||||
ExtendWithErrorHandler(FixtureExpectsOneErrorPattern("not allowed in FinalDepsMutators")).
|
||||
RunTest(t)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ func init() {
|
|||
AddNeverAllowRules(createCcStubsRule())
|
||||
AddNeverAllowRules(createJavaExcludeStaticLibsRule())
|
||||
AddNeverAllowRules(createProhibitHeaderOnlyRule())
|
||||
AddNeverAllowRules(createLimitNdkExportRule()...)
|
||||
AddNeverAllowRules(createKotlinPluginRule()...)
|
||||
}
|
||||
|
||||
|
|
@ -183,6 +184,7 @@ func createCcSdkVariantRules() []Rule {
|
|||
"packages/modules/SdkExtensions/derive_sdk",
|
||||
// These are for apps and shouldn't be used by non-SDK variant modules.
|
||||
"prebuilts/ndk",
|
||||
"frameworks/native/libs/binder/ndk",
|
||||
"tools/test/graphicsbenchmark/apps/sample_app",
|
||||
"tools/test/graphicsbenchmark/functional_tests/java",
|
||||
"vendor/xts/gts-tests/hostsidetests/gamedevicecert/apps/javatests",
|
||||
|
|
@ -213,7 +215,7 @@ func createCcSdkVariantRules() []Rule {
|
|||
|
||||
func createCcStubsRule() Rule {
|
||||
ccStubsImplementationInstallableProjectsAllowedList := []string{
|
||||
"packages/modules/Virtualization/vm_payload",
|
||||
"packages/modules/Virtualization/libs/libvm_payload",
|
||||
}
|
||||
|
||||
return NeverAllow().
|
||||
|
|
@ -238,6 +240,7 @@ func createInitFirstStageRules() []Rule {
|
|||
Without("name", "init_first_stage").
|
||||
Without("name", "init_first_stage.microdroid").
|
||||
With("install_in_root", "true").
|
||||
NotModuleType("prebuilt_root").
|
||||
Because("install_in_root is only for init_first_stage."),
|
||||
}
|
||||
}
|
||||
|
|
@ -266,6 +269,22 @@ func createProhibitHeaderOnlyRule() Rule {
|
|||
Because("headers_only can only be used for generating framework-minus-apex headers for non-updatable modules")
|
||||
}
|
||||
|
||||
func createLimitNdkExportRule() []Rule {
|
||||
reason := "If the headers you're trying to export are meant to be a part of the NDK, they should be exposed by an ndk_headers module. If the headers shouldn't be a part of the NDK, the headers should instead be exposed from a separate `cc_library_headers` which consumers depend on."
|
||||
// DO NOT ADD HERE - please consult danalbert@
|
||||
// b/357711733
|
||||
return []Rule{
|
||||
NeverAllow().
|
||||
NotIn("frameworks/native/libs/binder/ndk").
|
||||
ModuleType("ndk_library").
|
||||
WithMatcher("export_header_libs", isSetMatcherInstance).Because(reason),
|
||||
NeverAllow().ModuleType("ndk_library").WithMatcher("export_generated_headers", isSetMatcherInstance).Because(reason),
|
||||
NeverAllow().ModuleType("ndk_library").WithMatcher("export_include_dirs", isSetMatcherInstance).Because(reason),
|
||||
NeverAllow().ModuleType("ndk_library").WithMatcher("export_shared_lib_headers", isSetMatcherInstance).Because(reason),
|
||||
NeverAllow().ModuleType("ndk_library").WithMatcher("export_static_lib_headers", isSetMatcherInstance).Because(reason),
|
||||
}
|
||||
}
|
||||
|
||||
func createKotlinPluginRule() []Rule {
|
||||
kotlinPluginProjectsAllowedList := []string{
|
||||
// TODO: Migrate compose plugin to the bundled compiler plugin
|
||||
|
|
|
|||
|
|
@ -36,10 +36,22 @@ func modulesOutputDirs(ctx BuilderContext, modules ...Module) []string {
|
|||
return SortedUniqueStrings(dirs)
|
||||
}
|
||||
|
||||
func modulesLicenseMetadata(ctx BuilderContext, modules ...Module) Paths {
|
||||
type BuilderAndOtherModuleProviderContext interface {
|
||||
BuilderContext
|
||||
OtherModuleProviderContext
|
||||
}
|
||||
|
||||
func modulesLicenseMetadata(ctx OtherModuleProviderContext, modules ...Module) Paths {
|
||||
result := make(Paths, 0, len(modules))
|
||||
mctx, isMctx := ctx.(ModuleContext)
|
||||
for _, module := range modules {
|
||||
if mf := module.base().licenseMetadataFile; mf != nil {
|
||||
var mf Path
|
||||
if isMctx && mctx.Module() == module {
|
||||
mf = mctx.LicenseMetadataFile()
|
||||
} else {
|
||||
mf = OtherModuleProviderOrDefault(ctx, module, InstallFilesProvider).LicenseMetadataFile
|
||||
}
|
||||
if mf != nil {
|
||||
result = append(result, mf)
|
||||
}
|
||||
}
|
||||
|
|
@ -48,7 +60,7 @@ func modulesLicenseMetadata(ctx BuilderContext, modules ...Module) Paths {
|
|||
|
||||
// buildNoticeOutputFromLicenseMetadata writes out a notice file.
|
||||
func buildNoticeOutputFromLicenseMetadata(
|
||||
ctx BuilderContext, tool, ruleName string, outputFile WritablePath,
|
||||
ctx BuilderAndOtherModuleProviderContext, tool, ruleName string, outputFile WritablePath,
|
||||
libraryName string, stripPrefix []string, modules ...Module) {
|
||||
depsFile := outputFile.ReplaceExtension(ctx, strings.TrimPrefix(outputFile.Ext()+".d", "."))
|
||||
rule := NewRuleBuilder(pctx, ctx)
|
||||
|
|
@ -84,7 +96,7 @@ func buildNoticeOutputFromLicenseMetadata(
|
|||
// on the license metadata files for the input `modules` defaulting to the
|
||||
// current context module if none given.
|
||||
func BuildNoticeTextOutputFromLicenseMetadata(
|
||||
ctx BuilderContext, outputFile WritablePath, ruleName, libraryName string,
|
||||
ctx BuilderAndOtherModuleProviderContext, outputFile WritablePath, ruleName, libraryName string,
|
||||
stripPrefix []string, modules ...Module) {
|
||||
buildNoticeOutputFromLicenseMetadata(ctx, "textnotice", "text_notice_"+ruleName,
|
||||
outputFile, libraryName, stripPrefix, modules...)
|
||||
|
|
@ -94,7 +106,7 @@ func BuildNoticeTextOutputFromLicenseMetadata(
|
|||
// on the license metadata files for the input `modules` defaulting to the
|
||||
// current context module if none given.
|
||||
func BuildNoticeHtmlOutputFromLicenseMetadata(
|
||||
ctx BuilderContext, outputFile WritablePath, ruleName, libraryName string,
|
||||
ctx BuilderAndOtherModuleProviderContext, outputFile WritablePath, ruleName, libraryName string,
|
||||
stripPrefix []string, modules ...Module) {
|
||||
buildNoticeOutputFromLicenseMetadata(ctx, "htmlnotice", "html_notice_"+ruleName,
|
||||
outputFile, libraryName, stripPrefix, modules...)
|
||||
|
|
@ -104,7 +116,7 @@ func BuildNoticeHtmlOutputFromLicenseMetadata(
|
|||
// on the license metadata files for the input `modules` defaulting to the
|
||||
// current context module if none given.
|
||||
func BuildNoticeXmlOutputFromLicenseMetadata(
|
||||
ctx BuilderContext, outputFile WritablePath, ruleName, libraryName string,
|
||||
ctx BuilderAndOtherModuleProviderContext, outputFile WritablePath, ruleName, libraryName string,
|
||||
stripPrefix []string, modules ...Module) {
|
||||
buildNoticeOutputFromLicenseMetadata(ctx, "xmlnotice", "xml_notice_"+ruleName,
|
||||
outputFile, libraryName, stripPrefix, modules...)
|
||||
|
|
|
|||
|
|
@ -15,8 +15,12 @@
|
|||
package android
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
|
|
@ -55,6 +59,42 @@ type PackagingSpec struct {
|
|||
|
||||
// ArchType of the module which produced this packaging spec
|
||||
archType ArchType
|
||||
|
||||
// List of module names that this packaging spec overrides
|
||||
overrides *[]string
|
||||
|
||||
// Name of the module where this packaging spec is output of
|
||||
owner string
|
||||
}
|
||||
|
||||
func (p *PackagingSpec) GobEncode() ([]byte, error) {
|
||||
w := new(bytes.Buffer)
|
||||
encoder := gob.NewEncoder(w)
|
||||
err := errors.Join(encoder.Encode(p.relPathInPackage), encoder.Encode(p.srcPath),
|
||||
encoder.Encode(p.symlinkTarget), encoder.Encode(p.executable),
|
||||
encoder.Encode(p.effectiveLicenseFiles), encoder.Encode(p.partition),
|
||||
encoder.Encode(p.skipInstall), encoder.Encode(p.aconfigPaths),
|
||||
encoder.Encode(p.archType))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return w.Bytes(), nil
|
||||
}
|
||||
|
||||
func (p *PackagingSpec) GobDecode(data []byte) error {
|
||||
r := bytes.NewBuffer(data)
|
||||
decoder := gob.NewDecoder(r)
|
||||
err := errors.Join(decoder.Decode(&p.relPathInPackage), decoder.Decode(&p.srcPath),
|
||||
decoder.Decode(&p.symlinkTarget), decoder.Decode(&p.executable),
|
||||
decoder.Decode(&p.effectiveLicenseFiles), decoder.Decode(&p.partition),
|
||||
decoder.Decode(&p.skipInstall), decoder.Decode(&p.aconfigPaths),
|
||||
decoder.Decode(&p.archType))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PackagingSpec) Equals(other *PackagingSpec) bool {
|
||||
|
|
@ -324,7 +364,10 @@ func (p *PackagingBase) AddDeps(ctx BottomUpMutatorContext, depTag blueprint.Dep
|
|||
}
|
||||
|
||||
func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec {
|
||||
m := make(map[string]PackagingSpec)
|
||||
// all packaging specs gathered from the dep.
|
||||
var all []PackagingSpec
|
||||
// list of module names overridden
|
||||
var overridden []string
|
||||
|
||||
var arches []ArchType
|
||||
for _, target := range getSupportedTargets(ctx) {
|
||||
|
|
@ -345,7 +388,8 @@ func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter
|
|||
if pi, ok := ctx.OtherModuleDependencyTag(child).(PackagingItem); !ok || !pi.IsPackagingItem() {
|
||||
return
|
||||
}
|
||||
for _, ps := range child.TransitivePackagingSpecs() {
|
||||
for _, ps := range OtherModuleProviderOrDefault(
|
||||
ctx, child, InstallFilesProvider).TransitivePackagingSpecs.ToList() {
|
||||
if !filterArch(ps) {
|
||||
continue
|
||||
}
|
||||
|
|
@ -355,17 +399,33 @@ func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter
|
|||
continue
|
||||
}
|
||||
}
|
||||
dstPath := ps.relPathInPackage
|
||||
if existingPs, ok := m[dstPath]; ok {
|
||||
if !existingPs.Equals(&ps) {
|
||||
ctx.ModuleErrorf("packaging conflict at %v:\n%v\n%v", dstPath, existingPs, ps)
|
||||
}
|
||||
continue
|
||||
all = append(all, ps)
|
||||
if ps.overrides != nil {
|
||||
overridden = append(overridden, *ps.overrides...)
|
||||
}
|
||||
|
||||
m[dstPath] = ps
|
||||
}
|
||||
})
|
||||
|
||||
// all minus packaging specs that are overridden
|
||||
var filtered []PackagingSpec
|
||||
for _, ps := range all {
|
||||
if ps.owner != "" && InList(ps.owner, overridden) {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, ps)
|
||||
}
|
||||
|
||||
m := make(map[string]PackagingSpec)
|
||||
for _, ps := range filtered {
|
||||
dstPath := ps.relPathInPackage
|
||||
if existingPs, ok := m[dstPath]; ok {
|
||||
if !existingPs.Equals(&ps) {
|
||||
ctx.ModuleErrorf("packaging conflict at %v:\n%v\n%v", dstPath, existingPs, ps)
|
||||
}
|
||||
continue
|
||||
}
|
||||
m[dstPath] = ps
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
|
|
@ -377,31 +437,59 @@ func (p *PackagingBase) GatherPackagingSpecs(ctx ModuleContext) map[string]Packa
|
|||
// 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 {
|
||||
dirsToSpecs := make(map[WritablePath]map[string]PackagingSpec)
|
||||
dirsToSpecs[dir] = specs
|
||||
return p.CopySpecsToDirs(ctx, builder, dirsToSpecs)
|
||||
}
|
||||
|
||||
// CopySpecsToDirs is a helper that will add commands to the rule builder to copy the PackagingSpec
|
||||
// entries into corresponding directories.
|
||||
func (p *PackagingBase) CopySpecsToDirs(ctx ModuleContext, builder *RuleBuilder, dirsToSpecs map[WritablePath]map[string]PackagingSpec) (entries []string) {
|
||||
empty := true
|
||||
for _, specs := range dirsToSpecs {
|
||||
if len(specs) > 0 {
|
||||
empty = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if empty {
|
||||
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)
|
||||
destDir := filepath.Dir(destPath)
|
||||
entries = append(entries, ps.relPathInPackage)
|
||||
if _, ok := seenDir[destDir]; !ok {
|
||||
seenDir[destDir] = true
|
||||
sb.WriteString(fmt.Sprintf("mkdir -p %s\n", destDir))
|
||||
}
|
||||
if ps.symlinkTarget == "" {
|
||||
cmd.Implicit(ps.srcPath)
|
||||
sb.WriteString(fmt.Sprintf("cp %s %s\n", ps.srcPath, destPath))
|
||||
} else {
|
||||
sb.WriteString(fmt.Sprintf("ln -sf %s %s\n", ps.symlinkTarget, destPath))
|
||||
}
|
||||
if ps.executable {
|
||||
sb.WriteString(fmt.Sprintf("chmod a+x %s\n", destPath))
|
||||
|
||||
dirs := make([]WritablePath, 0, len(dirsToSpecs))
|
||||
for dir, _ := range dirsToSpecs {
|
||||
dirs = append(dirs, dir)
|
||||
}
|
||||
sort.Slice(dirs, func(i, j int) bool {
|
||||
return dirs[i].String() < dirs[j].String()
|
||||
})
|
||||
|
||||
for _, dir := range dirs {
|
||||
specs := dirsToSpecs[dir]
|
||||
for _, k := range SortedKeys(specs) {
|
||||
ps := specs[k]
|
||||
destPath := filepath.Join(dir.String(), ps.relPathInPackage)
|
||||
destDir := filepath.Dir(destPath)
|
||||
entries = append(entries, ps.relPathInPackage)
|
||||
if _, ok := seenDir[destDir]; !ok {
|
||||
seenDir[destDir] = true
|
||||
sb.WriteString(fmt.Sprintf("mkdir -p %s\n", destDir))
|
||||
}
|
||||
if ps.symlinkTarget == "" {
|
||||
cmd.Implicit(ps.srcPath)
|
||||
sb.WriteString(fmt.Sprintf("cp %s %s\n", ps.srcPath, destPath))
|
||||
} else {
|
||||
sb.WriteString(fmt.Sprintf("ln -sf %s %s\n", ps.symlinkTarget, destPath))
|
||||
}
|
||||
if ps.executable {
|
||||
sb.WriteString(fmt.Sprintf("chmod a+x %s\n", destPath))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ type componentTestModule struct {
|
|||
props struct {
|
||||
Deps []string
|
||||
Skip_install *bool
|
||||
Overrides []string
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,6 +118,7 @@ func runPackagingTest(t *testing.T, config testConfig, bp string, expected []str
|
|||
}
|
||||
|
||||
result := GroupFixturePreparers(
|
||||
PrepareForTestWithDefaults,
|
||||
PrepareForTestWithArchMutator,
|
||||
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
ctx.RegisterModuleType("component", componentTestModuleFactory)
|
||||
|
|
@ -650,3 +652,64 @@ func TestPrefer32Deps(t *testing.T) {
|
|||
runPackagingTest(t, config, bp, tc.expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverrides(t *testing.T) {
|
||||
bpTemplate := `
|
||||
component {
|
||||
name: "foo",
|
||||
deps: ["bar"],
|
||||
}
|
||||
|
||||
component {
|
||||
name: "bar",
|
||||
}
|
||||
|
||||
component {
|
||||
name: "bar_override",
|
||||
overrides: ["bar"],
|
||||
}
|
||||
|
||||
component {
|
||||
name: "baz",
|
||||
deps: ["bar_override"],
|
||||
}
|
||||
|
||||
package_module {
|
||||
name: "package",
|
||||
deps: %DEPS%,
|
||||
}
|
||||
`
|
||||
testcases := []struct {
|
||||
deps []string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
deps: []string{"foo"},
|
||||
expected: []string{"lib64/foo", "lib64/bar"},
|
||||
},
|
||||
{
|
||||
deps: []string{"foo", "bar_override"},
|
||||
expected: []string{"lib64/foo", "lib64/bar_override"},
|
||||
},
|
||||
{
|
||||
deps: []string{"foo", "bar", "bar_override"},
|
||||
expected: []string{"lib64/foo", "lib64/bar_override"},
|
||||
},
|
||||
{
|
||||
deps: []string{"bar", "bar_override"},
|
||||
expected: []string{"lib64/bar_override"},
|
||||
},
|
||||
{
|
||||
deps: []string{"foo", "baz"},
|
||||
expected: []string{"lib64/foo", "lib64/baz", "lib64/bar_override"},
|
||||
},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
config := testConfig{
|
||||
multiTarget: true,
|
||||
depsCollectFirstTargetOnly: false,
|
||||
}
|
||||
bp := strings.Replace(bpTemplate, "%DEPS%", `["`+strings.Join(tc.deps, `", "`)+`"]`, -1)
|
||||
runPackagingTest(t, config, bp, tc.expected)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
181
android/paths.go
181
android/paths.go
|
|
@ -15,6 +15,9 @@
|
|||
package android
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
|
@ -24,7 +27,6 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
"github.com/google/blueprint/bootstrap"
|
||||
"github.com/google/blueprint/pathtools"
|
||||
)
|
||||
|
||||
|
|
@ -89,8 +91,10 @@ func GlobFiles(ctx EarlyModulePathContext, globPattern string, excludes []string
|
|||
// the Path methods that rely on module dependencies having been resolved.
|
||||
type ModuleWithDepsPathContext interface {
|
||||
EarlyModulePathContext
|
||||
OtherModuleProviderContext
|
||||
VisitDirectDepsBlueprint(visit func(blueprint.Module))
|
||||
OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
|
||||
HasMutatorFinished(mutatorName string) bool
|
||||
}
|
||||
|
||||
// ModuleMissingDepsPathContext is a subset of *ModuleContext methods required by
|
||||
|
|
@ -234,6 +238,9 @@ type Path interface {
|
|||
// directory, and OutputPath.Join("foo").Rel() would return "foo".
|
||||
Rel() string
|
||||
|
||||
// WithoutRel returns a new Path with no relative path, i.e. Rel() will return the same value as Base().
|
||||
WithoutRel() Path
|
||||
|
||||
// RelativeToTop returns a new path relative to the top, it is provided solely for use in tests.
|
||||
//
|
||||
// It is guaranteed to always return the same type as it is called on, e.g. if called on an
|
||||
|
|
@ -242,13 +249,13 @@ type Path interface {
|
|||
// A standard build has the following structure:
|
||||
// ../top/
|
||||
// out/ - make install files go here.
|
||||
// out/soong - this is the soongOutDir passed to NewTestConfig()
|
||||
// out/soong - this is the outDir passed to NewTestConfig()
|
||||
// ... - the source files
|
||||
//
|
||||
// This function converts a path so that it appears relative to the ../top/ directory, i.e.
|
||||
// * Make install paths, which have the pattern "soongOutDir/../<path>" are converted into the top
|
||||
// * Make install paths, which have the pattern "outDir/../<path>" are converted into the top
|
||||
// relative path "out/<path>"
|
||||
// * Soong install paths and other writable paths, which have the pattern "soongOutDir/<path>" are
|
||||
// * Soong install paths and other writable paths, which have the pattern "outDir/soong/<path>" are
|
||||
// converted into the top relative path "out/soong/<path>".
|
||||
// * Source paths are already relative to the top.
|
||||
// * Phony paths are not relative to anything.
|
||||
|
|
@ -258,8 +265,9 @@ type Path interface {
|
|||
}
|
||||
|
||||
const (
|
||||
OutDir = "out"
|
||||
OutSoongDir = OutDir + "/soong"
|
||||
testOutDir = "out"
|
||||
testOutSoongSubDir = "/soong"
|
||||
TestOutSoongDir = testOutDir + testOutSoongSubDir
|
||||
)
|
||||
|
||||
// WritablePath is a type of path that can be used as an output for build rules.
|
||||
|
|
@ -460,8 +468,8 @@ func ExistentPathsForSources(ctx PathGlobContext, paths []string) Paths {
|
|||
// - glob, relative to the local module directory, resolves as filepath(s), relative to the local
|
||||
// source directory.
|
||||
// - other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
|
||||
// or OutputFileProducer. These resolve as a filepath to an output filepath or generated source
|
||||
// filepath.
|
||||
// or set the OutputFilesProvider. These resolve as a filepath to an output filepath or generated
|
||||
// source filepath.
|
||||
//
|
||||
// Properties passed as the paths argument must have been annotated with struct tag
|
||||
// `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
|
||||
|
|
@ -488,8 +496,8 @@ type SourceInput struct {
|
|||
// - glob, relative to the local module directory, resolves as filepath(s), relative to the local
|
||||
// source directory. Not valid in excludes.
|
||||
// - other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
|
||||
// or OutputFileProducer. These resolve as a filepath to an output filepath or generated source
|
||||
// filepath.
|
||||
// or set the OutputFilesProvider. These resolve as a filepath to an output filepath or generated
|
||||
// source filepath.
|
||||
//
|
||||
// excluding the items (similarly resolved
|
||||
// Properties passed as the paths argument must have been annotated with struct tag
|
||||
|
|
@ -547,13 +555,6 @@ func (p OutputPaths) Strings() []string {
|
|||
return ret
|
||||
}
|
||||
|
||||
// PathForGoBinary returns the path to the installed location of a bootstrap_go_binary module.
|
||||
func PathForGoBinary(ctx PathContext, goBinary bootstrap.GoBinaryTool) Path {
|
||||
goBinaryInstallDir := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "bin")
|
||||
rel := Rel(ctx, goBinaryInstallDir.String(), goBinary.InstallPath())
|
||||
return goBinaryInstallDir.Join(ctx, rel)
|
||||
}
|
||||
|
||||
// Expands Paths to a SourceFileProducer or OutputFileProducer module dependency referenced via ":name" or ":name{.tag}" syntax.
|
||||
// If the dependency is not found, a missingErrorDependency is returned.
|
||||
// If the module dependency is not a SourceFileProducer or OutputFileProducer, appropriate errors will be returned.
|
||||
|
|
@ -565,10 +566,6 @@ func getPathsFromModuleDep(ctx ModuleWithDepsPathContext, path, moduleName, tag
|
|||
if aModule, ok := module.(Module); ok && !aModule.Enabled(ctx) {
|
||||
return nil, missingDependencyError{[]string{moduleName}}
|
||||
}
|
||||
if goBinary, ok := module.(bootstrap.GoBinaryTool); ok && tag == "" {
|
||||
goBinaryPath := PathForGoBinary(ctx, goBinary)
|
||||
return Paths{goBinaryPath}, nil
|
||||
}
|
||||
outputFiles, err := outputFilesForModule(ctx, module, tag)
|
||||
if outputFiles != nil && err == nil {
|
||||
return outputFiles, nil
|
||||
|
|
@ -617,8 +614,8 @@ func GetModuleFromPathDep(ctx ModuleWithDepsPathContext, moduleName, tag string)
|
|||
// - glob, relative to the local module directory, resolves as filepath(s), relative to the local
|
||||
// source directory. Not valid in excludes.
|
||||
// - other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
|
||||
// or OutputFileProducer. These resolve as a filepath to an output filepath or generated source
|
||||
// filepath.
|
||||
// or set the OutputFilesProvider. These resolve as a filepath to an output filepath or generated
|
||||
// source filepath.
|
||||
//
|
||||
// and a list of the module names of missing module dependencies are returned as the second return.
|
||||
// Properties passed as the paths argument must have been annotated with struct tag
|
||||
|
|
@ -1068,6 +1065,28 @@ type basePath struct {
|
|||
rel string
|
||||
}
|
||||
|
||||
func (p basePath) GobEncode() ([]byte, error) {
|
||||
w := new(bytes.Buffer)
|
||||
encoder := gob.NewEncoder(w)
|
||||
err := errors.Join(encoder.Encode(p.path), encoder.Encode(p.rel))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return w.Bytes(), nil
|
||||
}
|
||||
|
||||
func (p *basePath) GobDecode(data []byte) error {
|
||||
r := bytes.NewBuffer(data)
|
||||
decoder := gob.NewDecoder(r)
|
||||
err := errors.Join(decoder.Decode(&p.path), decoder.Decode(&p.rel))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p basePath) Ext() string {
|
||||
return filepath.Ext(p.path)
|
||||
}
|
||||
|
|
@ -1093,8 +1112,8 @@ func (p basePath) withRel(rel string) basePath {
|
|||
return p
|
||||
}
|
||||
|
||||
func (p basePath) RelativeToTop() Path {
|
||||
ensureTestOnly()
|
||||
func (p basePath) withoutRel() basePath {
|
||||
p.rel = filepath.Base(p.path)
|
||||
return p
|
||||
}
|
||||
|
||||
|
|
@ -1110,6 +1129,11 @@ func (p SourcePath) withRel(rel string) SourcePath {
|
|||
return p
|
||||
}
|
||||
|
||||
func (p SourcePath) RelativeToTop() Path {
|
||||
ensureTestOnly()
|
||||
return p
|
||||
}
|
||||
|
||||
// safePathForSource is for paths that we expect are safe -- only for use by go
|
||||
// code that is embedding ninja variables in paths
|
||||
func safePathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) {
|
||||
|
|
@ -1243,11 +1267,13 @@ func PathForSourceRelaxed(ctx PathContext, pathComponents ...string) SourcePath
|
|||
// PathForArbitraryOutput creates a path for the given components. Unlike PathForOutput,
|
||||
// the path is relative to the root of the output folder, not the out/soong folder.
|
||||
func PathForArbitraryOutput(ctx PathContext, pathComponents ...string) Path {
|
||||
p, err := validatePath(pathComponents...)
|
||||
path, err := validatePath(pathComponents...)
|
||||
if err != nil {
|
||||
reportPathError(ctx, err)
|
||||
}
|
||||
return basePath{path: filepath.Join(ctx.Config().OutDir(), p)}
|
||||
fullPath := filepath.Join(ctx.Config().OutDir(), path)
|
||||
path = fullPath[len(fullPath)-len(path):]
|
||||
return OutputPath{basePath{path, ""}, ctx.Config().OutDir(), fullPath}
|
||||
}
|
||||
|
||||
// MaybeExistentPathForSource joins the provided path components and validates that the result
|
||||
|
|
@ -1300,6 +1326,11 @@ func (p SourcePath) String() string {
|
|||
return p.path
|
||||
}
|
||||
|
||||
func (p SourcePath) WithoutRel() Path {
|
||||
p.basePath = p.basePath.withoutRel()
|
||||
return p
|
||||
}
|
||||
|
||||
// Join creates a new SourcePath with paths... joined with the current path. The
|
||||
// provided paths... may not use '..' to escape from the current path.
|
||||
func (p SourcePath) Join(ctx PathContext, paths ...string) SourcePath {
|
||||
|
|
@ -1350,25 +1381,47 @@ func (p SourcePath) OverlayPath(ctx ModuleMissingDepsPathContext, path Path) Opt
|
|||
type OutputPath struct {
|
||||
basePath
|
||||
|
||||
// The soong build directory, i.e. Config.SoongOutDir()
|
||||
soongOutDir string
|
||||
// The base out directory for this path, either Config.SoongOutDir() or Config.OutDir()
|
||||
outDir string
|
||||
|
||||
fullPath string
|
||||
}
|
||||
|
||||
func (p OutputPath) GobEncode() ([]byte, error) {
|
||||
w := new(bytes.Buffer)
|
||||
encoder := gob.NewEncoder(w)
|
||||
err := errors.Join(encoder.Encode(p.basePath), encoder.Encode(p.outDir), encoder.Encode(p.fullPath))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return w.Bytes(), nil
|
||||
}
|
||||
|
||||
func (p *OutputPath) GobDecode(data []byte) error {
|
||||
r := bytes.NewBuffer(data)
|
||||
decoder := gob.NewDecoder(r)
|
||||
err := errors.Join(decoder.Decode(&p.basePath), decoder.Decode(&p.outDir), decoder.Decode(&p.fullPath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p OutputPath) withRel(rel string) OutputPath {
|
||||
p.basePath = p.basePath.withRel(rel)
|
||||
p.fullPath = filepath.Join(p.fullPath, rel)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p OutputPath) WithoutRel() OutputPath {
|
||||
p.basePath.rel = filepath.Base(p.basePath.path)
|
||||
func (p OutputPath) WithoutRel() Path {
|
||||
p.basePath = p.basePath.withoutRel()
|
||||
return p
|
||||
}
|
||||
|
||||
func (p OutputPath) getSoongOutDir() string {
|
||||
return p.soongOutDir
|
||||
return p.outDir
|
||||
}
|
||||
|
||||
func (p OutputPath) RelativeToTop() Path {
|
||||
|
|
@ -1376,8 +1429,13 @@ func (p OutputPath) RelativeToTop() Path {
|
|||
}
|
||||
|
||||
func (p OutputPath) outputPathRelativeToTop() OutputPath {
|
||||
p.fullPath = StringPathRelativeToTop(p.soongOutDir, p.fullPath)
|
||||
p.soongOutDir = OutSoongDir
|
||||
p.fullPath = StringPathRelativeToTop(p.outDir, p.fullPath)
|
||||
if strings.HasSuffix(p.outDir, testOutSoongSubDir) {
|
||||
p.outDir = TestOutSoongDir
|
||||
} else {
|
||||
// Handle the PathForArbitraryOutput case
|
||||
p.outDir = testOutDir
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
|
|
@ -1394,6 +1452,11 @@ type toolDepPath struct {
|
|||
basePath
|
||||
}
|
||||
|
||||
func (t toolDepPath) WithoutRel() Path {
|
||||
t.basePath = t.basePath.withoutRel()
|
||||
return t
|
||||
}
|
||||
|
||||
func (t toolDepPath) RelativeToTop() Path {
|
||||
ensureTestOnly()
|
||||
return t
|
||||
|
|
@ -1423,7 +1486,7 @@ func PathForOutput(ctx PathContext, pathComponents ...string) OutputPath {
|
|||
return OutputPath{basePath{path, ""}, ctx.Config().soongOutDir, fullPath}
|
||||
}
|
||||
|
||||
// PathsForOutput returns Paths rooted from soongOutDir
|
||||
// PathsForOutput returns Paths rooted from outDir
|
||||
func PathsForOutput(ctx PathContext, paths []string) WritablePaths {
|
||||
ret := make(WritablePaths, len(paths))
|
||||
for i, path := range paths {
|
||||
|
|
@ -1607,11 +1670,10 @@ type ModuleOutPathContext interface {
|
|||
ModuleName() string
|
||||
ModuleDir() string
|
||||
ModuleSubDir() string
|
||||
SoongConfigTraceHash() string
|
||||
}
|
||||
|
||||
func pathForModuleOut(ctx ModuleOutPathContext) OutputPath {
|
||||
return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir(), ctx.SoongConfigTraceHash())
|
||||
return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir())
|
||||
}
|
||||
|
||||
// PathForModuleOut returns a Path representing the paths... under the module's
|
||||
|
|
@ -1744,6 +1806,32 @@ type InstallPath struct {
|
|||
fullPath string
|
||||
}
|
||||
|
||||
func (p *InstallPath) GobEncode() ([]byte, error) {
|
||||
w := new(bytes.Buffer)
|
||||
encoder := gob.NewEncoder(w)
|
||||
err := errors.Join(encoder.Encode(p.basePath), encoder.Encode(p.soongOutDir),
|
||||
encoder.Encode(p.partitionDir), encoder.Encode(p.partition),
|
||||
encoder.Encode(p.makePath), encoder.Encode(p.fullPath))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return w.Bytes(), nil
|
||||
}
|
||||
|
||||
func (p *InstallPath) GobDecode(data []byte) error {
|
||||
r := bytes.NewBuffer(data)
|
||||
decoder := gob.NewDecoder(r)
|
||||
err := errors.Join(decoder.Decode(&p.basePath), decoder.Decode(&p.soongOutDir),
|
||||
decoder.Decode(&p.partitionDir), decoder.Decode(&p.partition),
|
||||
decoder.Decode(&p.makePath), decoder.Decode(&p.fullPath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Will panic if called from outside a test environment.
|
||||
func ensureTestOnly() {
|
||||
if PrefixInList(os.Args, "-test.") {
|
||||
|
|
@ -1755,14 +1843,19 @@ func ensureTestOnly() {
|
|||
func (p InstallPath) RelativeToTop() Path {
|
||||
ensureTestOnly()
|
||||
if p.makePath {
|
||||
p.soongOutDir = OutDir
|
||||
p.soongOutDir = testOutDir
|
||||
} else {
|
||||
p.soongOutDir = OutSoongDir
|
||||
p.soongOutDir = TestOutSoongDir
|
||||
}
|
||||
p.fullPath = filepath.Join(p.soongOutDir, p.path)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p InstallPath) WithoutRel() Path {
|
||||
p.basePath = p.basePath.withoutRel()
|
||||
return p
|
||||
}
|
||||
|
||||
func (p InstallPath) getSoongOutDir() string {
|
||||
return p.soongOutDir
|
||||
}
|
||||
|
|
@ -2083,6 +2176,11 @@ func (p PhonyPath) RelativeToTop() Path {
|
|||
return p
|
||||
}
|
||||
|
||||
func (p PhonyPath) WithoutRel() Path {
|
||||
p.basePath = p.basePath.withoutRel()
|
||||
return p
|
||||
}
|
||||
|
||||
func (p PhonyPath) ReplaceExtension(ctx PathContext, ext string) OutputPath {
|
||||
panic("Not implemented")
|
||||
}
|
||||
|
|
@ -2099,6 +2197,11 @@ func (p testPath) RelativeToTop() Path {
|
|||
return p
|
||||
}
|
||||
|
||||
func (p testPath) WithoutRel() Path {
|
||||
p.basePath = p.basePath.withoutRel()
|
||||
return p
|
||||
}
|
||||
|
||||
func (p testPath) String() string {
|
||||
return p.path
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1183,9 +1183,6 @@ type pathForModuleSrcOutputFileProviderModule struct {
|
|||
Outs []string
|
||||
Tagged []string
|
||||
}
|
||||
|
||||
outs Paths
|
||||
tagged Paths
|
||||
}
|
||||
|
||||
func pathForModuleSrcOutputFileProviderModuleFactory() Module {
|
||||
|
|
@ -1196,24 +1193,17 @@ func pathForModuleSrcOutputFileProviderModuleFactory() Module {
|
|||
}
|
||||
|
||||
func (p *pathForModuleSrcOutputFileProviderModule) GenerateAndroidBuildActions(ctx ModuleContext) {
|
||||
var outs, taggedOuts Paths
|
||||
for _, out := range p.props.Outs {
|
||||
p.outs = append(p.outs, PathForModuleOut(ctx, out))
|
||||
outs = append(outs, PathForModuleOut(ctx, out))
|
||||
}
|
||||
|
||||
for _, tagged := range p.props.Tagged {
|
||||
p.tagged = append(p.tagged, PathForModuleOut(ctx, tagged))
|
||||
taggedOuts = append(taggedOuts, PathForModuleOut(ctx, tagged))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pathForModuleSrcOutputFileProviderModule) OutputFiles(tag string) (Paths, error) {
|
||||
switch tag {
|
||||
case "":
|
||||
return p.outs, nil
|
||||
case ".tagged":
|
||||
return p.tagged, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported tag %q", tag)
|
||||
}
|
||||
ctx.SetOutputFiles(outs, "")
|
||||
ctx.SetOutputFiles(taggedOuts, ".tagged")
|
||||
}
|
||||
|
||||
type pathForModuleSrcTestCase struct {
|
||||
|
|
|
|||
|
|
@ -26,14 +26,20 @@ type phonyMap map[string]Paths
|
|||
|
||||
var phonyMapLock sync.Mutex
|
||||
|
||||
func getPhonyMap(config Config) phonyMap {
|
||||
type ModulePhonyInfo struct {
|
||||
Phonies map[string]Paths
|
||||
}
|
||||
|
||||
var ModulePhonyProvider = blueprint.NewProvider[ModulePhonyInfo]()
|
||||
|
||||
func getSingletonPhonyMap(config Config) phonyMap {
|
||||
return config.Once(phonyMapOnceKey, func() interface{} {
|
||||
return make(phonyMap)
|
||||
}).(phonyMap)
|
||||
}
|
||||
|
||||
func addPhony(config Config, name string, deps ...Path) {
|
||||
phonyMap := getPhonyMap(config)
|
||||
func addSingletonPhony(config Config, name string, deps ...Path) {
|
||||
phonyMap := getSingletonPhonyMap(config)
|
||||
phonyMapLock.Lock()
|
||||
defer phonyMapLock.Unlock()
|
||||
phonyMap[name] = append(phonyMap[name], deps...)
|
||||
|
|
@ -47,7 +53,15 @@ type phonySingleton struct {
|
|||
var _ SingletonMakeVarsProvider = (*phonySingleton)(nil)
|
||||
|
||||
func (p *phonySingleton) GenerateBuildActions(ctx SingletonContext) {
|
||||
p.phonyMap = getPhonyMap(ctx.Config())
|
||||
p.phonyMap = getSingletonPhonyMap(ctx.Config())
|
||||
ctx.VisitAllModules(func(m Module) {
|
||||
if info, ok := OtherModuleProvider(ctx, m, ModulePhonyProvider); ok {
|
||||
for k, v := range info.Phonies {
|
||||
p.phonyMap[k] = append(p.phonyMap[k], v...)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
p.phonyList = SortedKeys(p.phonyMap)
|
||||
for _, phony := range p.phonyList {
|
||||
p.phonyMap[phony] = SortedUniquePaths(p.phonyMap[phony])
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ var _ ExcludeFromApexContentsTag = PrebuiltDepTag
|
|||
type UserSuppliedPrebuiltProperties struct {
|
||||
// When prefer is set to true the prebuilt will be used instead of any source module with
|
||||
// a matching name.
|
||||
Prefer *bool `android:"arch_variant"`
|
||||
Prefer proptools.Configurable[bool] `android:"arch_variant,replace_instead_of_append"`
|
||||
|
||||
// When specified this names a Soong config variable that controls the prefer property.
|
||||
//
|
||||
|
|
@ -148,11 +148,7 @@ func PrebuiltNameFromSource(name string) string {
|
|||
}
|
||||
|
||||
func (p *Prebuilt) ForcePrefer() {
|
||||
p.properties.Prefer = proptools.BoolPtr(true)
|
||||
}
|
||||
|
||||
func (p *Prebuilt) Prefer() bool {
|
||||
return proptools.Bool(p.properties.Prefer)
|
||||
p.properties.Prefer = NewSimpleConfigurable(true)
|
||||
}
|
||||
|
||||
// SingleSourcePathFromSupplier invokes the supplied supplier for the current module in the
|
||||
|
|
@ -248,6 +244,8 @@ func InitPrebuiltModuleWithSrcSupplier(module PrebuiltInterface, srcsSupplier Pr
|
|||
p.srcsPropertyName = srcsPropertyName
|
||||
}
|
||||
|
||||
// InitPrebuiltModule is the same as InitPrebuiltModuleWithSrcSupplier, but uses the
|
||||
// provided list of strings property as the source provider.
|
||||
func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
|
||||
if srcs == nil {
|
||||
panic(fmt.Errorf("srcs must not be nil"))
|
||||
|
|
@ -260,6 +258,20 @@ func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
|
|||
InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
|
||||
}
|
||||
|
||||
// InitConfigurablePrebuiltModule is the same as InitPrebuiltModule, but uses a
|
||||
// Configurable list of strings property instead of a regular list of strings.
|
||||
func InitConfigurablePrebuiltModule(module PrebuiltInterface, srcs *proptools.Configurable[[]string]) {
|
||||
if srcs == nil {
|
||||
panic(fmt.Errorf("srcs must not be nil"))
|
||||
}
|
||||
|
||||
srcsSupplier := func(ctx BaseModuleContext, _ Module) []string {
|
||||
return srcs.GetOrDefault(ctx, nil)
|
||||
}
|
||||
|
||||
InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
|
||||
}
|
||||
|
||||
func InitSingleSourcePrebuiltModule(module PrebuiltInterface, srcProps interface{}, srcField string) {
|
||||
srcPropsValue := reflect.ValueOf(srcProps).Elem()
|
||||
srcStructField, _ := srcPropsValue.Type().FieldByName(srcField)
|
||||
|
|
@ -738,7 +750,7 @@ func (p *Prebuilt) usePrebuilt(ctx BaseMutatorContext, source Module, prebuilt M
|
|||
}
|
||||
|
||||
// TODO: use p.Properties.Name and ctx.ModuleDir to override preference
|
||||
return Bool(p.properties.Prefer)
|
||||
return p.properties.Prefer.GetOrDefault(ctx, false)
|
||||
}
|
||||
|
||||
func (p *Prebuilt) SourceExists() bool {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
package android
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
|
|
@ -494,7 +493,6 @@ type prebuiltModule struct {
|
|||
properties struct {
|
||||
Srcs []string `android:"path,arch_variant"`
|
||||
}
|
||||
src Path
|
||||
}
|
||||
|
||||
func newPrebuiltModule() Module {
|
||||
|
|
@ -510,24 +508,17 @@ func (p *prebuiltModule) Name() string {
|
|||
}
|
||||
|
||||
func (p *prebuiltModule) GenerateAndroidBuildActions(ctx ModuleContext) {
|
||||
var src Path
|
||||
if len(p.properties.Srcs) >= 1 {
|
||||
p.src = p.prebuilt.SingleSourcePath(ctx)
|
||||
src = p.prebuilt.SingleSourcePath(ctx)
|
||||
}
|
||||
ctx.SetOutputFiles(Paths{src}, "")
|
||||
}
|
||||
|
||||
func (p *prebuiltModule) Prebuilt() *Prebuilt {
|
||||
return &p.prebuilt
|
||||
}
|
||||
|
||||
func (p *prebuiltModule) OutputFiles(tag string) (Paths, error) {
|
||||
switch tag {
|
||||
case "":
|
||||
return Paths{p.src}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported module reference tag %q", tag)
|
||||
}
|
||||
}
|
||||
|
||||
type sourceModuleProperties struct {
|
||||
Deps []string `android:"path,arch_variant"`
|
||||
}
|
||||
|
|
@ -583,11 +574,7 @@ func newOverrideSourceModule() Module {
|
|||
|
||||
func TestPrebuiltErrorCannotListBothSourceAndPrebuiltInContributions(t *testing.T) {
|
||||
selectMainlineModuleContritbutions := GroupFixturePreparers(
|
||||
FixtureModifyProductVariables(func(variables FixtureProductVariables) {
|
||||
variables.BuildFlags = map[string]string{
|
||||
"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_apex_contributions",
|
||||
}
|
||||
}),
|
||||
PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ADSERVICES", "my_apex_contributions"),
|
||||
)
|
||||
testPrebuiltErrorWithFixture(t, `Found duplicate variations of the same module in apex_contributions: foo and prebuilt_foo. Please remove one of these`, `
|
||||
source {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@
|
|||
|
||||
package android
|
||||
|
||||
import "github.com/google/blueprint/proptools"
|
||||
import (
|
||||
"github.com/google/blueprint/proptools"
|
||||
)
|
||||
|
||||
func init() {
|
||||
ctx := InitRegistrationContext
|
||||
|
|
@ -37,8 +39,10 @@ func (p *productConfigModule) GenerateAndroidBuildActions(ctx ModuleContext) {
|
|||
if targetProduct != "" {
|
||||
targetProduct += "."
|
||||
}
|
||||
soongVariablesPath := PathForOutput(ctx, "soong."+targetProduct+"variables")
|
||||
extraVariablesPath := PathForOutput(ctx, "soong."+targetProduct+"extra.variables")
|
||||
|
||||
coverageSuffix := ctx.Config().CoverageSuffix()
|
||||
soongVariablesPath := PathForOutput(ctx, "soong."+targetProduct+coverageSuffix+"variables")
|
||||
extraVariablesPath := PathForOutput(ctx, "soong."+targetProduct+coverageSuffix+"extra.variables")
|
||||
|
||||
rule := NewRuleBuilder(pctx, ctx)
|
||||
rule.Command().BuiltTool("merge_json").
|
||||
|
|
|
|||
35
android/product_config_to_bp.go
Normal file
35
android/product_config_to_bp.go
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2024 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package android
|
||||
|
||||
func init() {
|
||||
ctx := InitRegistrationContext
|
||||
ctx.RegisterParallelSingletonType("product_config_to_bp_singleton", productConfigToBpSingletonFactory)
|
||||
}
|
||||
|
||||
type productConfigToBpSingleton struct{}
|
||||
|
||||
func (s *productConfigToBpSingleton) GenerateBuildActions(ctx SingletonContext) {
|
||||
// TODO: update content from make-based product config
|
||||
var content string
|
||||
generatedBp := PathForOutput(ctx, "soong_generated_product_config.bp")
|
||||
WriteFileRule(ctx, generatedBp, content)
|
||||
ctx.Phony("product_config_to_bp", generatedBp)
|
||||
}
|
||||
|
||||
// productConfigToBpSingleton generates a bp file from make-based product config
|
||||
func productConfigToBpSingletonFactory() Singleton {
|
||||
return &productConfigToBpSingleton{}
|
||||
}
|
||||
|
|
@ -14,6 +14,8 @@ var _ OtherModuleProviderContext = BaseModuleContext(nil)
|
|||
var _ OtherModuleProviderContext = ModuleContext(nil)
|
||||
var _ OtherModuleProviderContext = BottomUpMutatorContext(nil)
|
||||
var _ OtherModuleProviderContext = TopDownMutatorContext(nil)
|
||||
var _ OtherModuleProviderContext = SingletonContext(nil)
|
||||
var _ OtherModuleProviderContext = (*TestContext)(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
|
||||
|
|
@ -30,6 +32,11 @@ func OtherModuleProvider[K any](ctx OtherModuleProviderContext, module blueprint
|
|||
return value.(K), ok
|
||||
}
|
||||
|
||||
func OtherModuleProviderOrDefault[K any](ctx OtherModuleProviderContext, module blueprint.Module, provider blueprint.ProviderKey[K]) K {
|
||||
value, _ := OtherModuleProvider(ctx, module, provider)
|
||||
return value
|
||||
}
|
||||
|
||||
// ModuleProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or
|
||||
// TopDownMutatorContext for use in ModuleProvider.
|
||||
type ModuleProviderContext interface {
|
||||
|
|
@ -56,26 +63,6 @@ func ModuleProvider[K any](ctx ModuleProviderContext, provider blueprint.Provide
|
|||
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 {
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ type RuleBuilder struct {
|
|||
sboxInputs bool
|
||||
sboxManifestPath WritablePath
|
||||
missingDeps []string
|
||||
args map[string]string
|
||||
}
|
||||
|
||||
// NewRuleBuilder returns a newly created RuleBuilder.
|
||||
|
|
@ -78,6 +79,17 @@ func (rb *RuleBuilder) SetSboxOutDirDirAsEmpty() *RuleBuilder {
|
|||
return rb
|
||||
}
|
||||
|
||||
// Set the phony_output argument.
|
||||
// This causes the output files to be ignored.
|
||||
// If the output isn't created, it's not treated as an error.
|
||||
// The build rule is run every time whether or not the output is created.
|
||||
func (rb *RuleBuilder) SetPhonyOutput() {
|
||||
if rb.args == nil {
|
||||
rb.args = make(map[string]string)
|
||||
}
|
||||
rb.args["phony_output"] = "true"
|
||||
}
|
||||
|
||||
// RuleBuilderInstall is a tuple of install from and to locations.
|
||||
type RuleBuilderInstall struct {
|
||||
From Path
|
||||
|
|
@ -451,6 +463,8 @@ func (r *RuleBuilder) Build(name string, desc string) {
|
|||
r.build(name, desc, true)
|
||||
}
|
||||
|
||||
var sandboxEnvOnceKey = NewOnceKey("sandbox_environment_variables")
|
||||
|
||||
func (r *RuleBuilder) build(name string, desc string, ninjaEscapeCommandString bool) {
|
||||
name = ninjaNameEscape(name)
|
||||
|
||||
|
|
@ -542,6 +556,12 @@ func (r *RuleBuilder) build(name string, desc string, ninjaEscapeCommandString b
|
|||
To: proto.String(r.sboxPathForInputRel(input)),
|
||||
})
|
||||
}
|
||||
for _, input := range r.OrderOnlys() {
|
||||
command.CopyBefore = append(command.CopyBefore, &sbox_proto.Copy{
|
||||
From: proto.String(input.String()),
|
||||
To: proto.String(r.sboxPathForInputRel(input)),
|
||||
})
|
||||
}
|
||||
|
||||
// If using rsp files copy them and their contents into the sbox directory with
|
||||
// the appropriate path mappings.
|
||||
|
|
@ -562,6 +582,44 @@ func (r *RuleBuilder) build(name string, desc string, ninjaEscapeCommandString b
|
|||
})
|
||||
}
|
||||
|
||||
// Only allow the build to access certain environment variables
|
||||
command.DontInheritEnv = proto.Bool(true)
|
||||
command.Env = r.ctx.Config().Once(sandboxEnvOnceKey, func() interface{} {
|
||||
// The list of allowed variables was found by running builds of all
|
||||
// genrules and seeing what failed
|
||||
var result []*sbox_proto.EnvironmentVariable
|
||||
inheritedVars := []string{
|
||||
"PATH",
|
||||
"JAVA_HOME",
|
||||
"TMPDIR",
|
||||
// Allow RBE variables because the art tests invoke RBE manually
|
||||
"RBE_log_dir",
|
||||
"RBE_platform",
|
||||
"RBE_server_address",
|
||||
// TODO: RBE_exec_root is set to the absolute path to the root of the source
|
||||
// tree, which we don't want sandboxed actions to find. Remap it to ".".
|
||||
"RBE_exec_root",
|
||||
}
|
||||
for _, v := range inheritedVars {
|
||||
result = append(result, &sbox_proto.EnvironmentVariable{
|
||||
Name: proto.String(v),
|
||||
State: &sbox_proto.EnvironmentVariable_Inherit{
|
||||
Inherit: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
// Set OUT_DIR to the relative path of the sandboxed out directory.
|
||||
// Otherwise, OUT_DIR will be inherited from the rest of the build,
|
||||
// which will allow scripts to escape the sandbox if OUT_DIR is an
|
||||
// absolute path.
|
||||
result = append(result, &sbox_proto.EnvironmentVariable{
|
||||
Name: proto.String("OUT_DIR"),
|
||||
State: &sbox_proto.EnvironmentVariable_Value{
|
||||
Value: sboxOutSubDir,
|
||||
},
|
||||
})
|
||||
return result
|
||||
}).([]*sbox_proto.EnvironmentVariable)
|
||||
command.Chdir = proto.Bool(true)
|
||||
}
|
||||
|
||||
|
|
@ -726,6 +784,12 @@ func (r *RuleBuilder) build(name string, desc string, ninjaEscapeCommandString b
|
|||
commandString = proptools.NinjaEscape(commandString)
|
||||
}
|
||||
|
||||
args_vars := make([]string, len(r.args))
|
||||
i := 0
|
||||
for k, _ := range r.args {
|
||||
args_vars[i] = k
|
||||
i++
|
||||
}
|
||||
r.ctx.Build(r.pctx, BuildParams{
|
||||
Rule: r.ctx.Rule(r.pctx, name, blueprint.RuleParams{
|
||||
Command: commandString,
|
||||
|
|
@ -734,7 +798,7 @@ func (r *RuleBuilder) build(name string, desc string, ninjaEscapeCommandString b
|
|||
Rspfile: proptools.NinjaEscape(rspFile),
|
||||
RspfileContent: rspFileContent,
|
||||
Pool: pool,
|
||||
}),
|
||||
}, args_vars...),
|
||||
Inputs: rspFileInputs,
|
||||
Implicits: inputs,
|
||||
OrderOnly: r.OrderOnlys(),
|
||||
|
|
@ -744,6 +808,7 @@ func (r *RuleBuilder) build(name string, desc string, ninjaEscapeCommandString b
|
|||
Depfile: depFile,
|
||||
Deps: depFormat,
|
||||
Description: desc,
|
||||
Args: r.args,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
111
android/sbom.go
Normal file
111
android/sbom.go
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
// Copyright 2024 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package android
|
||||
|
||||
import (
|
||||
"io"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
)
|
||||
|
||||
var (
|
||||
// Command line tool to generate SBOM in Soong
|
||||
genSbom = pctx.HostBinToolVariable("genSbom", "gen_sbom")
|
||||
|
||||
// Command to generate SBOM in Soong.
|
||||
genSbomRule = pctx.AndroidStaticRule("genSbomRule", blueprint.RuleParams{
|
||||
Command: "rm -rf $out && ${genSbom} --output_file ${out} --metadata ${in} --product_out ${productOut} --soong_out ${soongOut} --build_version \"$$(cat ${buildFingerprintFile})\" --product_mfr \"${productManufacturer}\" --json",
|
||||
CommandDeps: []string{"${genSbom}"},
|
||||
}, "productOut", "soongOut", "buildFingerprintFile", "productManufacturer")
|
||||
)
|
||||
|
||||
func init() {
|
||||
RegisterSbomSingleton(InitRegistrationContext)
|
||||
}
|
||||
|
||||
func RegisterSbomSingleton(ctx RegistrationContext) {
|
||||
ctx.RegisterParallelSingletonType("sbom_singleton", sbomSingletonFactory)
|
||||
}
|
||||
|
||||
// sbomSingleton is used to generate build actions of generating SBOM of products.
|
||||
type sbomSingleton struct {
|
||||
sbomFile OutputPath
|
||||
}
|
||||
|
||||
func sbomSingletonFactory() Singleton {
|
||||
return &sbomSingleton{}
|
||||
}
|
||||
|
||||
// Generates SBOM of products
|
||||
func (this *sbomSingleton) GenerateBuildActions(ctx SingletonContext) {
|
||||
if !ctx.Config().HasDeviceProduct() {
|
||||
return
|
||||
}
|
||||
// Get all METADATA files and add them as implicit input
|
||||
metadataFileListFile := PathForArbitraryOutput(ctx, ".module_paths", "METADATA.list")
|
||||
f, err := ctx.Config().fs.Open(metadataFileListFile.String())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
b, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
allMetadataFiles := strings.Split(string(b), "\n")
|
||||
implicits := []Path{metadataFileListFile}
|
||||
for _, path := range allMetadataFiles {
|
||||
implicits = append(implicits, PathForSource(ctx, path))
|
||||
}
|
||||
prodVars := ctx.Config().productVariables
|
||||
buildFingerprintFile := PathForArbitraryOutput(ctx, "target", "product", String(prodVars.DeviceName), "build_fingerprint.txt")
|
||||
implicits = append(implicits, buildFingerprintFile)
|
||||
|
||||
// Add installed_files.stamp as implicit input, which depends on all installed files of the product.
|
||||
installedFilesStamp := PathForOutput(ctx, "compliance-metadata", ctx.Config().DeviceProduct(), "installed_files.stamp")
|
||||
implicits = append(implicits, installedFilesStamp)
|
||||
|
||||
metadataDb := PathForOutput(ctx, "compliance-metadata", ctx.Config().DeviceProduct(), "compliance-metadata.db")
|
||||
this.sbomFile = PathForOutput(ctx, "sbom", ctx.Config().DeviceProduct(), "sbom.spdx.json")
|
||||
ctx.Build(pctx, BuildParams{
|
||||
Rule: genSbomRule,
|
||||
Input: metadataDb,
|
||||
Implicits: implicits,
|
||||
Output: this.sbomFile,
|
||||
Args: map[string]string{
|
||||
"productOut": filepath.Join(ctx.Config().OutDir(), "target", "product", String(prodVars.DeviceName)),
|
||||
"soongOut": ctx.Config().soongOutDir,
|
||||
"buildFingerprintFile": buildFingerprintFile.String(),
|
||||
"productManufacturer": ctx.Config().ProductVariables().ProductManufacturer,
|
||||
},
|
||||
})
|
||||
|
||||
if !ctx.Config().UnbundledBuildApps() {
|
||||
// When building SBOM of products, phony rule "sbom" is for generating product SBOM in Soong.
|
||||
ctx.Build(pctx, BuildParams{
|
||||
Rule: blueprint.Phony,
|
||||
Inputs: []Path{this.sbomFile},
|
||||
Output: PathForPhony(ctx, "sbom"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (this *sbomSingleton) MakeVars(ctx MakeVarsContext) {
|
||||
// When building SBOM of products
|
||||
if !ctx.Config().UnbundledBuildApps() {
|
||||
ctx.DistForGoalWithFilename("droid", this.sbomFile, "sbom/sbom.spdx.json")
|
||||
}
|
||||
}
|
||||
|
|
@ -513,6 +513,9 @@ type SdkMemberType interface {
|
|||
// SupportedLinkages returns the names of the linkage variants supported by this module.
|
||||
SupportedLinkages() []string
|
||||
|
||||
// DisablesStrip returns true if the stripping needs to be disabled for this module.
|
||||
DisablesStrip() bool
|
||||
|
||||
// ArePrebuiltsRequired returns true if prebuilts are required in the sdk snapshot, false
|
||||
// otherwise.
|
||||
ArePrebuiltsRequired() bool
|
||||
|
|
@ -618,6 +621,9 @@ type SdkMemberTypeBase struct {
|
|||
// The names of linkage variants supported by this module.
|
||||
SupportedLinkageNames []string
|
||||
|
||||
// StripDisabled returns true if the stripping needs to be disabled for this module.
|
||||
StripDisabled bool
|
||||
|
||||
// When set to true BpPropertyNotRequired indicates that the member type does not require the
|
||||
// property to be specifiable in an Android.bp file.
|
||||
BpPropertyNotRequired bool
|
||||
|
|
@ -689,6 +695,10 @@ func (b *SdkMemberTypeBase) SupportedLinkages() []string {
|
|||
return b.SupportedLinkageNames
|
||||
}
|
||||
|
||||
func (b *SdkMemberTypeBase) DisablesStrip() bool {
|
||||
return b.StripDisabled
|
||||
}
|
||||
|
||||
// registeredModuleExportsMemberTypes is the set of registered SdkMemberTypes for module_exports
|
||||
// modules.
|
||||
var registeredModuleExportsMemberTypes = &sdkRegistry{}
|
||||
|
|
@ -803,8 +813,6 @@ type SdkMemberProperties interface {
|
|||
|
||||
// SdkMemberContext provides access to information common to a specific member.
|
||||
type SdkMemberContext interface {
|
||||
ConfigAndErrorContext
|
||||
|
||||
// SdkModuleContext returns the module context of the sdk common os variant which is creating the
|
||||
// snapshot.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -93,6 +93,15 @@ func (k SdkKind) String() string {
|
|||
}
|
||||
}
|
||||
|
||||
func ToSdkKind(s string) SdkKind {
|
||||
for kind := SdkNone; kind <= SdkPrivate; kind++ {
|
||||
if s == kind.String() {
|
||||
return kind
|
||||
}
|
||||
}
|
||||
return SdkInvalid
|
||||
}
|
||||
|
||||
func (k SdkKind) DefaultJavaLibraryName() string {
|
||||
switch k {
|
||||
case SdkPublic:
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ type SingletonContext interface {
|
|||
// Allows generating build actions for `referer` based on the metadata for `name` deferred until the singleton context.
|
||||
ModuleVariantsFromName(referer Module, name string) []Module
|
||||
|
||||
moduleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
|
||||
otherModuleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
|
||||
|
||||
ModuleErrorf(module blueprint.Module, format string, args ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
|
|
@ -90,6 +90,10 @@ type SingletonContext interface {
|
|||
|
||||
// OtherModulePropertyErrorf reports an error on the line number of the given property of the given module
|
||||
OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{})
|
||||
|
||||
// HasMutatorFinished returns true if the given mutator has finished running.
|
||||
// It will panic if given an invalid mutator name.
|
||||
HasMutatorFinished(mutatorName string) bool
|
||||
}
|
||||
|
||||
type singletonAdaptor struct {
|
||||
|
|
@ -177,7 +181,7 @@ func (s *singletonContextAdaptor) Build(pctx PackageContext, params BuildParams)
|
|||
}
|
||||
|
||||
func (s *singletonContextAdaptor) Phony(name string, deps ...Path) {
|
||||
addPhony(s.Config(), name, deps...)
|
||||
addSingletonPhony(s.Config(), name, deps...)
|
||||
}
|
||||
|
||||
func (s *singletonContextAdaptor) SetOutDir(pctx PackageContext, value string) {
|
||||
|
|
@ -279,10 +283,14 @@ func (s *singletonContextAdaptor) ModuleVariantsFromName(referer Module, name st
|
|||
return result
|
||||
}
|
||||
|
||||
func (s *singletonContextAdaptor) moduleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
|
||||
func (s *singletonContextAdaptor) otherModuleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
|
||||
return s.SingletonContext.ModuleProvider(module, provider)
|
||||
}
|
||||
|
||||
func (s *singletonContextAdaptor) OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{}) {
|
||||
s.blueprintSingletonContext().OtherModulePropertyErrorf(module, property, format, args...)
|
||||
}
|
||||
|
||||
func (s *singletonContextAdaptor) HasMutatorFinished(mutatorName string) bool {
|
||||
return s.blueprintSingletonContext().HasMutatorFinished(mutatorName)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ type SingletonModuleBase struct {
|
|||
func (smb *SingletonModuleBase) GenerateBuildActions(ctx blueprint.ModuleContext) {
|
||||
smb.lock.Lock()
|
||||
if smb.variant != "" {
|
||||
ctx.ModuleErrorf("GenerateAndroidBuildActions already called for variant %q, SingletonModules can only have one variant", smb.variant)
|
||||
ctx.ModuleErrorf("GenerateAndroidBuildActions already called for variant %q, SingletonModules can only have one variant", smb.variant)
|
||||
}
|
||||
smb.variant = ctx.ModuleSubDir()
|
||||
smb.lock.Unlock()
|
||||
|
|
|
|||
|
|
@ -96,12 +96,6 @@ func TestUnusedSingletonModule(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func testVariantSingletonModuleMutator(ctx BottomUpMutatorContext) {
|
||||
if _, ok := ctx.Module().(*testSingletonModule); ok {
|
||||
ctx.CreateVariations("a", "b")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVariantSingletonModule(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("test fails with data race enabled")
|
||||
|
|
@ -116,7 +110,11 @@ func TestVariantSingletonModule(t *testing.T) {
|
|||
prepareForSingletonModuleTest,
|
||||
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
|
||||
ctx.BottomUp("test_singleton_module_mutator", testVariantSingletonModuleMutator)
|
||||
ctx.Transition("test_singleton_module_mutator", &testTransitionMutator{
|
||||
split: func(ctx BaseModuleContext) []string {
|
||||
return []string{"a", "b"}
|
||||
},
|
||||
})
|
||||
})
|
||||
}),
|
||||
).
|
||||
|
|
|
|||
|
|
@ -463,57 +463,6 @@ func loadSoongConfigModuleTypeDefinition(ctx LoadHookContext, from string) map[s
|
|||
}).(map[string]blueprint.ModuleFactory)
|
||||
}
|
||||
|
||||
// tracingConfig is a wrapper to soongconfig.SoongConfig which records all accesses to SoongConfig.
|
||||
type tracingConfig struct {
|
||||
config soongconfig.SoongConfig
|
||||
boolSet map[string]bool
|
||||
stringSet map[string]string
|
||||
isSetSet map[string]bool
|
||||
}
|
||||
|
||||
func (c *tracingConfig) Bool(name string) bool {
|
||||
c.boolSet[name] = c.config.Bool(name)
|
||||
return c.boolSet[name]
|
||||
}
|
||||
|
||||
func (c *tracingConfig) String(name string) string {
|
||||
c.stringSet[name] = c.config.String(name)
|
||||
return c.stringSet[name]
|
||||
}
|
||||
|
||||
func (c *tracingConfig) IsSet(name string) bool {
|
||||
c.isSetSet[name] = c.config.IsSet(name)
|
||||
return c.isSetSet[name]
|
||||
}
|
||||
|
||||
func (c *tracingConfig) getTrace() soongConfigTrace {
|
||||
ret := soongConfigTrace{}
|
||||
|
||||
for k, v := range c.boolSet {
|
||||
ret.Bools = append(ret.Bools, fmt.Sprintf("%q:%t", k, v))
|
||||
}
|
||||
for k, v := range c.stringSet {
|
||||
ret.Strings = append(ret.Strings, fmt.Sprintf("%q:%q", k, v))
|
||||
}
|
||||
for k, v := range c.isSetSet {
|
||||
ret.IsSets = append(ret.IsSets, fmt.Sprintf("%q:%t", k, v))
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func newTracingConfig(config soongconfig.SoongConfig) *tracingConfig {
|
||||
c := tracingConfig{
|
||||
config: config,
|
||||
boolSet: make(map[string]bool),
|
||||
stringSet: make(map[string]string),
|
||||
isSetSet: make(map[string]bool),
|
||||
}
|
||||
return &c
|
||||
}
|
||||
|
||||
var _ soongconfig.SoongConfig = (*tracingConfig)(nil)
|
||||
|
||||
// configModuleFactory takes an existing soongConfigModuleFactory and a
|
||||
// ModuleType to create a new ModuleFactory that uses a custom loadhook.
|
||||
func configModuleFactory(factory blueprint.ModuleFactory, moduleType *soongconfig.ModuleType) blueprint.ModuleFactory {
|
||||
|
|
@ -561,8 +510,8 @@ func configModuleFactory(factory blueprint.ModuleFactory, moduleType *soongconfi
|
|||
// conditional on Soong config variables by reading the product
|
||||
// config variables from Make.
|
||||
AddLoadHook(module, func(ctx LoadHookContext) {
|
||||
tracingConfig := newTracingConfig(ctx.Config().VendorConfig(moduleType.ConfigNamespace))
|
||||
newProps, err := soongconfig.PropertiesToApply(moduleType, conditionalProps, tracingConfig)
|
||||
config := ctx.Config().VendorConfig(moduleType.ConfigNamespace)
|
||||
newProps, err := soongconfig.PropertiesToApply(moduleType, conditionalProps, config)
|
||||
if err != nil {
|
||||
ctx.ModuleErrorf("%s", err)
|
||||
return
|
||||
|
|
@ -570,8 +519,6 @@ func configModuleFactory(factory blueprint.ModuleFactory, moduleType *soongconfi
|
|||
for _, ps := range newProps {
|
||||
ctx.AppendProperties(ps)
|
||||
}
|
||||
|
||||
module.(Module).base().commonProperties.SoongConfigTrace = tracingConfig.getTrace()
|
||||
})
|
||||
return module, props
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ package android
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -506,197 +505,3 @@ func TestSoongConfigModuleSingletonModule(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSoongConfigModuleTrace(t *testing.T) {
|
||||
bp := `
|
||||
soong_config_module_type {
|
||||
name: "acme_test",
|
||||
module_type: "test",
|
||||
config_namespace: "acme",
|
||||
variables: ["board", "feature1", "FEATURE3", "unused_string_var"],
|
||||
bool_variables: ["feature2", "unused_feature", "always_true"],
|
||||
value_variables: ["size", "unused_size"],
|
||||
properties: ["cflags", "srcs", "defaults"],
|
||||
}
|
||||
|
||||
soong_config_module_type {
|
||||
name: "acme_test_defaults",
|
||||
module_type: "test_defaults",
|
||||
config_namespace: "acme",
|
||||
variables: ["board", "feature1", "FEATURE3", "unused_string_var"],
|
||||
bool_variables: ["feature2", "unused_feature", "always_true"],
|
||||
value_variables: ["size", "unused_size"],
|
||||
properties: ["cflags", "srcs", "defaults"],
|
||||
}
|
||||
|
||||
soong_config_string_variable {
|
||||
name: "board",
|
||||
values: ["soc_a", "soc_b", "soc_c"],
|
||||
}
|
||||
|
||||
soong_config_string_variable {
|
||||
name: "unused_string_var",
|
||||
values: ["a", "b"],
|
||||
}
|
||||
|
||||
soong_config_bool_variable {
|
||||
name: "feature1",
|
||||
}
|
||||
|
||||
soong_config_bool_variable {
|
||||
name: "FEATURE3",
|
||||
}
|
||||
|
||||
test_defaults {
|
||||
name: "test_defaults",
|
||||
cflags: ["DEFAULT"],
|
||||
}
|
||||
|
||||
test {
|
||||
name: "normal",
|
||||
defaults: ["test_defaults"],
|
||||
}
|
||||
|
||||
acme_test {
|
||||
name: "board_1",
|
||||
defaults: ["test_defaults"],
|
||||
soong_config_variables: {
|
||||
board: {
|
||||
soc_a: {
|
||||
cflags: ["-DSOC_A"],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
acme_test {
|
||||
name: "board_2",
|
||||
defaults: ["test_defaults"],
|
||||
soong_config_variables: {
|
||||
board: {
|
||||
soc_a: {
|
||||
cflags: ["-DSOC_A"],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
acme_test {
|
||||
name: "size",
|
||||
defaults: ["test_defaults"],
|
||||
soong_config_variables: {
|
||||
size: {
|
||||
cflags: ["-DSIZE=%s"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
acme_test {
|
||||
name: "board_and_size",
|
||||
defaults: ["test_defaults"],
|
||||
soong_config_variables: {
|
||||
board: {
|
||||
soc_a: {
|
||||
cflags: ["-DSOC_A"],
|
||||
},
|
||||
},
|
||||
size: {
|
||||
cflags: ["-DSIZE=%s"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
acme_test_defaults {
|
||||
name: "board_defaults",
|
||||
soong_config_variables: {
|
||||
board: {
|
||||
soc_a: {
|
||||
cflags: ["-DSOC_A"],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
acme_test_defaults {
|
||||
name: "size_defaults",
|
||||
soong_config_variables: {
|
||||
size: {
|
||||
cflags: ["-DSIZE=%s"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
test {
|
||||
name: "board_and_size_with_defaults",
|
||||
defaults: ["board_defaults", "size_defaults"],
|
||||
}
|
||||
`
|
||||
|
||||
fixtureForVendorVars := func(vars map[string]map[string]string) FixturePreparer {
|
||||
return FixtureModifyProductVariables(func(variables FixtureProductVariables) {
|
||||
variables.VendorVars = vars
|
||||
})
|
||||
}
|
||||
|
||||
preparer := fixtureForVendorVars(map[string]map[string]string{
|
||||
"acme": {
|
||||
"board": "soc_a",
|
||||
"size": "42",
|
||||
"feature1": "true",
|
||||
"feature2": "false",
|
||||
// FEATURE3 unset
|
||||
"unused_feature": "true", // unused
|
||||
"unused_size": "1", // unused
|
||||
"unused_string_var": "a", // unused
|
||||
"always_true": "true",
|
||||
},
|
||||
})
|
||||
|
||||
t.Run("soong config trace hash", func(t *testing.T) {
|
||||
result := GroupFixturePreparers(
|
||||
preparer,
|
||||
PrepareForTestWithDefaults,
|
||||
PrepareForTestWithSoongConfigModuleBuildComponents,
|
||||
prepareForSoongConfigTestModule,
|
||||
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
ctx.FinalDepsMutators(registerSoongConfigTraceMutator)
|
||||
}),
|
||||
FixtureWithRootAndroidBp(bp),
|
||||
).RunTest(t)
|
||||
|
||||
// Hashes of modules not using soong config should be empty
|
||||
normal := result.ModuleForTests("normal", "").Module().(*soongConfigTestModule)
|
||||
AssertDeepEquals(t, "normal hash", normal.base().commonProperties.SoongConfigTraceHash, "")
|
||||
AssertDeepEquals(t, "normal hash out", normal.outputPath.RelativeToTop().String(), "out/soong/.intermediates/normal/test")
|
||||
|
||||
board1 := result.ModuleForTests("board_1", "").Module().(*soongConfigTestModule)
|
||||
board2 := result.ModuleForTests("board_2", "").Module().(*soongConfigTestModule)
|
||||
size := result.ModuleForTests("size", "").Module().(*soongConfigTestModule)
|
||||
|
||||
// Trace mutator sets soong config trace hash correctly
|
||||
board1Hash := board1.base().commonProperties.SoongConfigTrace.hash()
|
||||
board1Output := board1.outputPath.RelativeToTop().String()
|
||||
AssertDeepEquals(t, "board hash calc", board1Hash, board1.base().commonProperties.SoongConfigTraceHash)
|
||||
AssertDeepEquals(t, "board hash path", board1Output, filepath.Join("out/soong/.intermediates/board_1", board1Hash, "test"))
|
||||
|
||||
sizeHash := size.base().commonProperties.SoongConfigTrace.hash()
|
||||
sizeOutput := size.outputPath.RelativeToTop().String()
|
||||
AssertDeepEquals(t, "size hash calc", sizeHash, size.base().commonProperties.SoongConfigTraceHash)
|
||||
AssertDeepEquals(t, "size hash path", sizeOutput, filepath.Join("out/soong/.intermediates/size", sizeHash, "test"))
|
||||
|
||||
// Trace should be identical for modules using the same set of variables
|
||||
AssertDeepEquals(t, "board trace", board1.base().commonProperties.SoongConfigTrace, board2.base().commonProperties.SoongConfigTrace)
|
||||
AssertDeepEquals(t, "board hash", board1.base().commonProperties.SoongConfigTraceHash, board2.base().commonProperties.SoongConfigTraceHash)
|
||||
|
||||
// Trace hash should be different for different sets of soong variables
|
||||
AssertBoolEquals(t, "board hash not equal to size hash", board1.base().commonProperties.SoongConfigTraceHash == size.commonProperties.SoongConfigTraceHash, false)
|
||||
|
||||
boardSize := result.ModuleForTests("board_and_size", "").Module().(*soongConfigTestModule)
|
||||
boardSizeDefaults := result.ModuleForTests("board_and_size_with_defaults", "").Module()
|
||||
|
||||
// Trace should propagate
|
||||
AssertDeepEquals(t, "board_size hash calc", boardSize.base().commonProperties.SoongConfigTrace.hash(), boardSize.base().commonProperties.SoongConfigTraceHash)
|
||||
AssertDeepEquals(t, "board_size trace", boardSize.base().commonProperties.SoongConfigTrace, boardSizeDefaults.base().commonProperties.SoongConfigTrace)
|
||||
AssertDeepEquals(t, "board_size hash", boardSize.base().commonProperties.SoongConfigTraceHash, boardSizeDefaults.base().commonProperties.SoongConfigTraceHash)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ bootstrap_go_package {
|
|||
"blueprint",
|
||||
"blueprint-parser",
|
||||
"blueprint-proptools",
|
||||
"soong-bazel",
|
||||
"soong-starlark-format",
|
||||
],
|
||||
srcs: [
|
||||
|
|
|
|||
|
|
@ -40,4 +40,8 @@ python_library_host {
|
|||
proto: {
|
||||
canonical_path_from_root: false,
|
||||
},
|
||||
visibility: [
|
||||
"//build/soong:__subpackages__",
|
||||
"//tools/asuite/team_build_scripts",
|
||||
],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ func (t *testSuiteFiles) GenerateBuildActions(ctx SingletonContext) {
|
|||
files[testSuite] = make(map[string]InstallPaths)
|
||||
}
|
||||
name := ctx.ModuleName(m)
|
||||
files[testSuite][name] = append(files[testSuite][name], tsm.FilesToInstall()...)
|
||||
files[testSuite][name] = append(files[testSuite][name],
|
||||
OtherModuleProviderOrDefault(ctx, tsm, InstallFilesProvider).InstallFiles...)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -126,6 +126,10 @@ var PrepareForTestWithMakevars = FixtureRegisterWithContext(func(ctx Registratio
|
|||
ctx.RegisterSingletonType("makevars", makeVarsSingletonFunc)
|
||||
})
|
||||
|
||||
var PrepareForTestVintfFragmentModules = FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
registerVintfFragmentComponents(ctx)
|
||||
})
|
||||
|
||||
// Test fixture preparer that will register most java build components.
|
||||
//
|
||||
// Singletons and mutators should only be added here if they are needed for a majority of java
|
||||
|
|
@ -149,6 +153,7 @@ var PrepareForTestWithAndroidBuildComponents = GroupFixturePreparers(
|
|||
PrepareForTestWithPackageModule,
|
||||
PrepareForTestWithPrebuilts,
|
||||
PrepareForTestWithVisibility,
|
||||
PrepareForTestVintfFragmentModules,
|
||||
)
|
||||
|
||||
// Prepares an integration test with all build components from the android package.
|
||||
|
|
@ -174,6 +179,16 @@ var PrepareForTestDisallowNonExistentPaths = FixtureModifyConfig(func(config Con
|
|||
config.TestAllowNonExistentPaths = false
|
||||
})
|
||||
|
||||
// PrepareForTestWithBuildFlag returns a FixturePreparer that sets the given flag to the given value.
|
||||
func PrepareForTestWithBuildFlag(flag, value string) FixturePreparer {
|
||||
return FixtureModifyProductVariables(func(variables FixtureProductVariables) {
|
||||
if variables.BuildFlags == nil {
|
||||
variables.BuildFlags = make(map[string]string)
|
||||
}
|
||||
variables.BuildFlags[flag] = value
|
||||
})
|
||||
}
|
||||
|
||||
func NewTestArchContext(config Config) *TestContext {
|
||||
ctx := NewTestContext(config)
|
||||
ctx.preDeps = append(ctx.preDeps, registerArchMutator)
|
||||
|
|
@ -202,7 +217,7 @@ func (ctx *TestContext) HardCodedPreArchMutators(f RegisterMutatorFunc) {
|
|||
ctx.PreArchMutators(f)
|
||||
}
|
||||
|
||||
func (ctx *TestContext) moduleProvider(m blueprint.Module, p blueprint.AnyProviderKey) (any, bool) {
|
||||
func (ctx *TestContext) otherModuleProvider(m blueprint.Module, p blueprint.AnyProviderKey) (any, bool) {
|
||||
return ctx.Context.ModuleProvider(m, p)
|
||||
}
|
||||
|
||||
|
|
@ -220,7 +235,7 @@ func (ctx *TestContext) FinalDepsMutators(f RegisterMutatorFunc) {
|
|||
|
||||
func (ctx *TestContext) OtherModuleProviderAdaptor() OtherModuleProviderContext {
|
||||
return NewOtherModuleProviderAdaptor(func(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
|
||||
return ctx.moduleProvider(module, provider)
|
||||
return ctx.otherModuleProvider(module, provider)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -822,15 +837,15 @@ func newBaseTestingComponent(config Config, provider testBuildProvider) baseTest
|
|||
// containing at most one instance of the temporary build directory at the start of the path while
|
||||
// this assumes that there can be any number at any position.
|
||||
func normalizeStringRelativeToTop(config Config, s string) string {
|
||||
// The soongOutDir usually looks something like: /tmp/testFoo2345/001
|
||||
// The outDir usually looks something like: /tmp/testFoo2345/001
|
||||
//
|
||||
// Replace any usage of the soongOutDir with out/soong, e.g. replace "/tmp/testFoo2345/001" with
|
||||
// Replace any usage of the outDir with out/soong, e.g. replace "/tmp/testFoo2345/001" with
|
||||
// "out/soong".
|
||||
outSoongDir := filepath.Clean(config.soongOutDir)
|
||||
re := regexp.MustCompile(`\Q` + outSoongDir + `\E\b`)
|
||||
s = re.ReplaceAllString(s, "out/soong")
|
||||
|
||||
// Replace any usage of the soongOutDir/.. with out, e.g. replace "/tmp/testFoo2345" with
|
||||
// Replace any usage of the outDir/.. with out, e.g. replace "/tmp/testFoo2345" with
|
||||
// "out". This must come after the previous replacement otherwise this would replace
|
||||
// "/tmp/testFoo2345/001" with "out/001" instead of "out/soong".
|
||||
outDir := filepath.Dir(outSoongDir)
|
||||
|
|
@ -1018,28 +1033,21 @@ func (m TestingModule) VariablesForTestsRelativeToTop() map[string]string {
|
|||
return normalizeStringMapRelativeToTop(m.config, m.module.VariablesForTests())
|
||||
}
|
||||
|
||||
// OutputFiles first checks if module base outputFiles property has any output
|
||||
// OutputFiles checks if module base outputFiles property has any output
|
||||
// files can be used to return.
|
||||
// If not, it calls OutputFileProducer.OutputFiles on the
|
||||
// encapsulated module, exits the test immediately if there is an error and
|
||||
// Exits the test immediately if there is an error and
|
||||
// otherwise returns the result of calling Paths.RelativeToTop
|
||||
// on the returned Paths.
|
||||
func (m TestingModule) OutputFiles(t *testing.T, tag string) Paths {
|
||||
// TODO: add non-empty-string tag case and remove OutputFileProducer part
|
||||
if tag == "" && m.module.base().outputFiles.DefaultOutputFiles != nil {
|
||||
return m.module.base().outputFiles.DefaultOutputFiles.RelativeToTop()
|
||||
func (m TestingModule) OutputFiles(ctx *TestContext, t *testing.T, tag string) Paths {
|
||||
outputFiles := OtherModuleProviderOrDefault(ctx.OtherModuleProviderAdaptor(), m.Module(), OutputFilesProvider)
|
||||
if tag == "" && outputFiles.DefaultOutputFiles != nil {
|
||||
return outputFiles.DefaultOutputFiles.RelativeToTop()
|
||||
} else if taggedOutputFiles, hasTag := outputFiles.TaggedOutputFiles[tag]; hasTag {
|
||||
return taggedOutputFiles.RelativeToTop()
|
||||
}
|
||||
|
||||
producer, ok := m.module.(OutputFileProducer)
|
||||
if !ok {
|
||||
t.Fatalf("%q must implement OutputFileProducer\n", m.module.Name())
|
||||
}
|
||||
paths, err := producer.OutputFiles(tag)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return paths.RelativeToTop()
|
||||
t.Fatal(fmt.Errorf("No test output file has been set for tag %q", tag))
|
||||
return nil
|
||||
}
|
||||
|
||||
// TestingSingleton is wrapper around an android.Singleton that provides methods to find information about individual
|
||||
|
|
@ -1241,8 +1249,14 @@ func StringPathRelativeToTop(soongOutDir string, path string) string {
|
|||
}
|
||||
|
||||
if isRel {
|
||||
// The path is in the soong out dir so indicate that in the relative path.
|
||||
return filepath.Join("out/soong", rel)
|
||||
if strings.HasSuffix(soongOutDir, testOutSoongSubDir) {
|
||||
// The path is in the soong out dir so indicate that in the relative path.
|
||||
return filepath.Join(TestOutSoongDir, rel)
|
||||
} else {
|
||||
// Handle the PathForArbitraryOutput case
|
||||
return filepath.Join(testOutDir, rel)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if the path is relative to the top level out dir.
|
||||
|
|
@ -1312,7 +1326,15 @@ func (ctx *panickingConfigAndErrorContext) Config() Config {
|
|||
return ctx.ctx.Config()
|
||||
}
|
||||
|
||||
func PanickingConfigAndErrorContext(ctx *TestContext) ConfigAndErrorContext {
|
||||
func (ctx *panickingConfigAndErrorContext) HasMutatorFinished(mutatorName string) bool {
|
||||
return ctx.ctx.HasMutatorFinished(mutatorName)
|
||||
}
|
||||
|
||||
func (ctx *panickingConfigAndErrorContext) otherModuleProvider(m blueprint.Module, p blueprint.AnyProviderKey) (any, bool) {
|
||||
return ctx.ctx.otherModuleProvider(m, p)
|
||||
}
|
||||
|
||||
func PanickingConfigAndErrorContext(ctx *TestContext) ConfigurableEvaluatorContext {
|
||||
return &panickingConfigAndErrorContext{
|
||||
ctx: ctx,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,6 +177,41 @@ func setFromList[T comparable](l []T) map[T]bool {
|
|||
return m
|
||||
}
|
||||
|
||||
// PrettyConcat returns the formatted concatenated string suitable for displaying user-facing
|
||||
// messages.
|
||||
func PrettyConcat(list []string, quote bool, lastSep string) string {
|
||||
if len(list) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
quoteStr := func(v string) string {
|
||||
if !quote {
|
||||
return v
|
||||
}
|
||||
return fmt.Sprintf("%q", v)
|
||||
}
|
||||
|
||||
if len(list) == 1 {
|
||||
return quoteStr(list[0])
|
||||
}
|
||||
|
||||
var sb strings.Builder
|
||||
for i, val := range list {
|
||||
if i > 0 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
if i == len(list)-1 {
|
||||
sb.WriteString(lastSep)
|
||||
if lastSep != "" {
|
||||
sb.WriteString(" ")
|
||||
}
|
||||
}
|
||||
sb.WriteString(quoteStr(val))
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// ListSetDifference checks if the two lists contain the same elements. It returns
|
||||
// a boolean which is true if there is a difference, and then returns lists of elements
|
||||
// that are in l1 but not l2, and l2 but not l1.
|
||||
|
|
@ -201,6 +236,12 @@ func ListSetDifference[T comparable](l1, l2 []T) (bool, []T, []T) {
|
|||
return listsDiffer, diff1, diff2
|
||||
}
|
||||
|
||||
// Returns true if the two lists have common elements.
|
||||
func HasIntersection[T comparable](l1, l2 []T) bool {
|
||||
_, a, b := ListSetDifference(l1, l2)
|
||||
return len(a)+len(b) < len(setFromList(l1))+len(setFromList(l2))
|
||||
}
|
||||
|
||||
// Returns true if the given string s is prefixed with any string in the given prefix list.
|
||||
func HasAnyPrefix(s string, prefixList []string) bool {
|
||||
for _, prefix := range prefixList {
|
||||
|
|
|
|||
|
|
@ -818,3 +818,100 @@ func TestReverseSlice(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
var hasIntersectionTestCases = []struct {
|
||||
name string
|
||||
l1 []string
|
||||
l2 []string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
l1: []string{"a", "b", "c"},
|
||||
l2: []string{},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "both empty",
|
||||
l1: []string{},
|
||||
l2: []string{},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "identical",
|
||||
l1: []string{"a", "b", "c"},
|
||||
l2: []string{"a", "b", "c"},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "duplicates",
|
||||
l1: []string{"a", "a", "a"},
|
||||
l2: []string{"a", "b", "c"},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "duplicates with no intersection",
|
||||
l1: []string{"d", "d", "d", "d"},
|
||||
l2: []string{"a", "b", "c"},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
func TestHasIntersection(t *testing.T) {
|
||||
for _, testCase := range hasIntersectionTestCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
hasIntersection := HasIntersection(testCase.l1, testCase.l2)
|
||||
if !reflect.DeepEqual(hasIntersection, testCase.expected) {
|
||||
t.Errorf("expected %#v, got %#v", testCase.expected, hasIntersection)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var prettyConcatTestCases = []struct {
|
||||
name string
|
||||
list []string
|
||||
quote bool
|
||||
lastSeparator string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
list: []string{},
|
||||
quote: false,
|
||||
lastSeparator: "and",
|
||||
expected: ``,
|
||||
},
|
||||
{
|
||||
name: "single",
|
||||
list: []string{"a"},
|
||||
quote: true,
|
||||
lastSeparator: "and",
|
||||
expected: `"a"`,
|
||||
},
|
||||
{
|
||||
name: "with separator",
|
||||
list: []string{"a", "b", "c"},
|
||||
quote: true,
|
||||
lastSeparator: "or",
|
||||
expected: `"a", "b", or "c"`,
|
||||
},
|
||||
{
|
||||
name: "without separator",
|
||||
list: []string{"a", "b", "c"},
|
||||
quote: false,
|
||||
lastSeparator: "",
|
||||
expected: `a, b, c`,
|
||||
},
|
||||
}
|
||||
|
||||
func TestPrettyConcat(t *testing.T) {
|
||||
for _, testCase := range prettyConcatTestCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
concatString := PrettyConcat(testCase.list, testCase.quote, testCase.lastSeparator)
|
||||
if !reflect.DeepEqual(concatString, testCase.expected) {
|
||||
t.Errorf("expected %#v, got %#v", testCase.expected, concatString)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@ type variableProperties struct {
|
|||
// are used for dogfooding and performance testing, and should be as similar to user builds
|
||||
// as possible.
|
||||
Debuggable struct {
|
||||
Apk *string
|
||||
Cflags []string
|
||||
Cppflags []string
|
||||
Init_rc []string
|
||||
|
|
@ -142,9 +143,11 @@ type variableProperties struct {
|
|||
Keep_symbols *bool
|
||||
Keep_symbols_and_debug_frame *bool
|
||||
}
|
||||
Static_libs []string
|
||||
Whole_static_libs []string
|
||||
Shared_libs []string
|
||||
Static_libs []string
|
||||
Exclude_static_libs []string
|
||||
Whole_static_libs []string
|
||||
Shared_libs []string
|
||||
Jni_libs []string
|
||||
|
||||
Cmdline []string
|
||||
|
||||
|
|
@ -196,10 +199,10 @@ type variableProperties struct {
|
|||
// release_aidl_use_unfrozen is "true" when a device can
|
||||
// use the unfrozen versions of AIDL interfaces.
|
||||
Release_aidl_use_unfrozen struct {
|
||||
Cflags []string
|
||||
Cmd *string
|
||||
Required []string
|
||||
Vintf_fragments []string
|
||||
Cflags []string
|
||||
Cmd *string
|
||||
Required []string
|
||||
Vintf_fragment_modules []string
|
||||
}
|
||||
} `android:"arch_variant"`
|
||||
}
|
||||
|
|
@ -248,8 +251,6 @@ type ProductVariables struct {
|
|||
|
||||
VendorApiLevel *string `json:",omitempty"`
|
||||
|
||||
RecoverySnapshotVersion *string `json:",omitempty"`
|
||||
|
||||
DeviceSecondaryArch *string `json:",omitempty"`
|
||||
DeviceSecondaryArchVariant *string `json:",omitempty"`
|
||||
DeviceSecondaryCpuVariant *string `json:",omitempty"`
|
||||
|
|
@ -285,8 +286,10 @@ type ProductVariables struct {
|
|||
AAPTPreferredConfig *string `json:",omitempty"`
|
||||
AAPTPrebuiltDPI []string `json:",omitempty"`
|
||||
|
||||
DefaultAppCertificate *string `json:",omitempty"`
|
||||
MainlineSepolicyDevCertificates *string `json:",omitempty"`
|
||||
DefaultAppCertificate *string `json:",omitempty"`
|
||||
ExtraOtaKeys []string `json:",omitempty"`
|
||||
ExtraOtaRecoveryKeys []string `json:",omitempty"`
|
||||
MainlineSepolicyDevCertificates *string `json:",omitempty"`
|
||||
|
||||
AppsDefaultVersionName *string `json:",omitempty"`
|
||||
|
||||
|
|
@ -304,6 +307,7 @@ type ProductVariables struct {
|
|||
HostStaticBinaries *bool `json:",omitempty"`
|
||||
Binder32bit *bool `json:",omitempty"`
|
||||
UseGoma *bool `json:",omitempty"`
|
||||
UseABFS *bool `json:",omitempty"`
|
||||
UseRBE *bool `json:",omitempty"`
|
||||
UseRBEJAVAC *bool `json:",omitempty"`
|
||||
UseRBER8 *bool `json:",omitempty"`
|
||||
|
|
@ -383,20 +387,6 @@ type ProductVariables struct {
|
|||
|
||||
PgoAdditionalProfileDirs []string `json:",omitempty"`
|
||||
|
||||
VndkSnapshotBuildArtifacts *bool `json:",omitempty"`
|
||||
|
||||
DirectedVendorSnapshot bool `json:",omitempty"`
|
||||
VendorSnapshotModules map[string]bool `json:",omitempty"`
|
||||
|
||||
DirectedRecoverySnapshot bool `json:",omitempty"`
|
||||
RecoverySnapshotModules map[string]bool `json:",omitempty"`
|
||||
|
||||
VendorSnapshotDirsIncluded []string `json:",omitempty"`
|
||||
VendorSnapshotDirsExcluded []string `json:",omitempty"`
|
||||
RecoverySnapshotDirsExcluded []string `json:",omitempty"`
|
||||
RecoverySnapshotDirsIncluded []string `json:",omitempty"`
|
||||
HostFakeSnapshotEnabled bool `json:",omitempty"`
|
||||
|
||||
MultitreeUpdateMeta bool `json:",omitempty"`
|
||||
|
||||
BoardVendorSepolicyDirs []string `json:",omitempty"`
|
||||
|
|
@ -405,6 +395,7 @@ type ProductVariables struct {
|
|||
SystemExtPrivateSepolicyDirs []string `json:",omitempty"`
|
||||
BoardSepolicyM4Defs []string `json:",omitempty"`
|
||||
|
||||
BoardPlatform *string `json:",omitempty"`
|
||||
BoardSepolicyVers *string `json:",omitempty"`
|
||||
PlatformSepolicyVersion *string `json:",omitempty"`
|
||||
|
||||
|
|
@ -446,6 +437,9 @@ type ProductVariables struct {
|
|||
|
||||
TargetFSConfigGen []string `json:",omitempty"`
|
||||
|
||||
UseSoongSystemImage *bool `json:",omitempty"`
|
||||
ProductSoongDefinedSystemImage *string `json:",omitempty"`
|
||||
|
||||
EnforceProductPartitionInterface *bool `json:",omitempty"`
|
||||
|
||||
EnforceInterPartitionJavaSdkLibrary *bool `json:",omitempty"`
|
||||
|
|
@ -469,7 +463,6 @@ type ProductVariables struct {
|
|||
GenruleSandboxing *bool `json:",omitempty"`
|
||||
BuildBrokenEnforceSyspropOwner bool `json:",omitempty"`
|
||||
BuildBrokenTrebleSyspropNeverallow bool `json:",omitempty"`
|
||||
BuildBrokenUsesSoongPython2Modules bool `json:",omitempty"`
|
||||
BuildBrokenVendorPropertyNamespace bool `json:",omitempty"`
|
||||
BuildBrokenIncorrectPartitionImages bool `json:",omitempty"`
|
||||
BuildBrokenInputDirModules []string `json:",omitempty"`
|
||||
|
|
@ -539,6 +532,11 @@ type ProductVariables struct {
|
|||
OdmPropFiles []string `json:",omitempty"`
|
||||
|
||||
EnableUffdGc *string `json:",omitempty"`
|
||||
|
||||
BoardAvbEnable *bool `json:",omitempty"`
|
||||
BoardAvbSystemAddHashtreeFooterArgs []string `json:",omitempty"`
|
||||
DeviceFrameworkCompatibilityMatrixFile []string `json:",omitempty"`
|
||||
DeviceProductCompatibilityMatrixFile []string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type PartitionQualifiedVariablesType struct {
|
||||
|
|
|
|||
|
|
@ -199,9 +199,7 @@ func TestProductVariables(t *testing.T) {
|
|||
ctx.RegisterModuleType("module3", testProductVariableModuleFactoryFactory(&struct {
|
||||
Foo []string
|
||||
}{}))
|
||||
ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
|
||||
ctx.BottomUp("variable", VariableMutator).Parallel()
|
||||
})
|
||||
registerVariableBuildComponents(ctx)
|
||||
}),
|
||||
FixtureWithRootAndroidBp(bp),
|
||||
).RunTest(t)
|
||||
|
|
@ -210,14 +208,14 @@ func TestProductVariables(t *testing.T) {
|
|||
var testProductVariableDefaultsProperties = struct {
|
||||
Product_variables struct {
|
||||
Eng struct {
|
||||
Foo []string
|
||||
Foo []string `android:"arch_variant"`
|
||||
Bar []string
|
||||
}
|
||||
}
|
||||
} `android:"arch_variant"`
|
||||
} `android:"arch_variant"`
|
||||
}{}
|
||||
|
||||
type productVariablesDefaultsTestProperties struct {
|
||||
Foo []string
|
||||
Foo []string `android:"arch_variant"`
|
||||
}
|
||||
|
||||
type productVariablesDefaultsTestProperties2 struct {
|
||||
|
|
@ -242,7 +240,7 @@ func productVariablesDefaultsTestModuleFactory() Module {
|
|||
module := &productVariablesDefaultsTestModule{}
|
||||
module.AddProperties(&module.properties)
|
||||
module.variableProperties = testProductVariableDefaultsProperties
|
||||
InitAndroidModule(module)
|
||||
InitAndroidArchModule(module, DeviceSupported, MultilibBoth)
|
||||
InitDefaultableModule(module)
|
||||
return module
|
||||
}
|
||||
|
|
@ -324,3 +322,46 @@ func BenchmarkSliceToTypeArray(b *testing.B) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Test a defaults module that supports more product variable properties than the target module.
|
||||
func TestProductVariablesArch(t *testing.T) {
|
||||
bp := `
|
||||
test {
|
||||
name: "foo",
|
||||
arch: {
|
||||
arm: {
|
||||
product_variables: {
|
||||
eng: {
|
||||
foo: ["arm"],
|
||||
},
|
||||
},
|
||||
},
|
||||
arm64: {
|
||||
product_variables: {
|
||||
eng: {
|
||||
foo: ["arm64"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
foo: ["module"],
|
||||
}
|
||||
`
|
||||
|
||||
result := GroupFixturePreparers(
|
||||
FixtureModifyProductVariables(func(variables FixtureProductVariables) {
|
||||
variables.Eng = boolPtr(true)
|
||||
}),
|
||||
PrepareForTestWithArchMutator,
|
||||
PrepareForTestWithVariables,
|
||||
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
ctx.RegisterModuleType("test", productVariablesDefaultsTestModuleFactory)
|
||||
}),
|
||||
FixtureWithRootAndroidBp(bp),
|
||||
).RunTest(t)
|
||||
|
||||
foo := result.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*productVariablesDefaultsTestModule)
|
||||
|
||||
want := []string{"module", "arm64"}
|
||||
AssertDeepEquals(t, "foo", want, foo.properties.Foo)
|
||||
}
|
||||
|
|
|
|||
84
android/vintf_fragment.go
Normal file
84
android/vintf_fragment.go
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright 2024 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package android
|
||||
|
||||
type vintfFragmentProperties struct {
|
||||
// Vintf fragment XML file.
|
||||
Src string `android:"path"`
|
||||
}
|
||||
|
||||
type vintfFragmentModule struct {
|
||||
ModuleBase
|
||||
|
||||
properties vintfFragmentProperties
|
||||
|
||||
installDirPath InstallPath
|
||||
outputFilePath OutputPath
|
||||
}
|
||||
|
||||
func init() {
|
||||
registerVintfFragmentComponents(InitRegistrationContext)
|
||||
}
|
||||
|
||||
func registerVintfFragmentComponents(ctx RegistrationContext) {
|
||||
ctx.RegisterModuleType("vintf_fragment", vintfLibraryFactory)
|
||||
}
|
||||
|
||||
// vintf_fragment module processes vintf fragment file and installs under etc/vintf/manifest.
|
||||
// Vintf fragment files formerly listed in vintf_fragment property would be transformed into
|
||||
// this module type.
|
||||
func vintfLibraryFactory() Module {
|
||||
m := &vintfFragmentModule{}
|
||||
m.AddProperties(
|
||||
&m.properties,
|
||||
)
|
||||
InitAndroidArchModule(m, DeviceSupported, MultilibFirst)
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *vintfFragmentModule) GenerateAndroidBuildActions(ctx ModuleContext) {
|
||||
builder := NewRuleBuilder(pctx, ctx)
|
||||
srcVintfFragment := PathForModuleSrc(ctx, m.properties.Src)
|
||||
processedVintfFragment := PathForModuleOut(ctx, srcVintfFragment.Base())
|
||||
|
||||
// Process vintf fragment source file with assemble_vintf tool
|
||||
builder.Command().
|
||||
Flag("VINTF_IGNORE_TARGET_FCM_VERSION=true").
|
||||
BuiltTool("assemble_vintf").
|
||||
FlagWithInput("-i ", srcVintfFragment).
|
||||
FlagWithOutput("-o ", processedVintfFragment)
|
||||
|
||||
builder.Build("assemble_vintf", "Process vintf fragment "+processedVintfFragment.String())
|
||||
|
||||
m.installDirPath = PathForModuleInstall(ctx, "etc", "vintf", "manifest")
|
||||
m.outputFilePath = processedVintfFragment.OutputPath
|
||||
|
||||
ctx.InstallFile(m.installDirPath, processedVintfFragment.Base(), processedVintfFragment)
|
||||
}
|
||||
|
||||
// Make this module visible to AndroidMK so it can be referenced from modules defined from Android.mk files
|
||||
func (m *vintfFragmentModule) AndroidMkEntries() []AndroidMkEntries {
|
||||
return []AndroidMkEntries{{
|
||||
Class: "ETC",
|
||||
OutputFile: OptionalPathForPath(m.outputFilePath),
|
||||
ExtraEntries: []AndroidMkExtraEntriesFunc{
|
||||
func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries) {
|
||||
entries.SetString("LOCAL_MODULE_PATH", m.installDirPath.String())
|
||||
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", m.outputFilePath.Base())
|
||||
},
|
||||
},
|
||||
}}
|
||||
}
|
||||
36
android/vintf_fragment_test.go
Normal file
36
android/vintf_fragment_test.go
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2024 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package android
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestVintfManifestBuildAction(t *testing.T) {
|
||||
bp := `
|
||||
vintf_fragment {
|
||||
name: "test_vintf_fragment",
|
||||
src: "test_vintf_file",
|
||||
}
|
||||
`
|
||||
|
||||
testResult := PrepareForTestWithAndroidBuildComponents.RunTestWithBp(t, bp)
|
||||
|
||||
vintfFragmentBuild := testResult.TestContext.ModuleForTests("test_vintf_fragment", "android_arm64_armv8-a").Rule("assemble_vintf")
|
||||
if !strings.Contains(vintfFragmentBuild.RuleParams.Command, "assemble_vintf") {
|
||||
t.Errorf("Vintf_manifest build command does not process with assemble_vintf : " + vintfFragmentBuild.RuleParams.Command)
|
||||
}
|
||||
}
|
||||
|
|
@ -283,7 +283,7 @@ func RegisterVisibilityRuleGatherer(ctx RegisterMutatorsContext) {
|
|||
|
||||
// This must be registered after the deps have been resolved.
|
||||
func RegisterVisibilityRuleEnforcer(ctx RegisterMutatorsContext) {
|
||||
ctx.TopDown("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel()
|
||||
ctx.BottomUp("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel()
|
||||
}
|
||||
|
||||
// Checks the per-module visibility rule lists before defaults expansion.
|
||||
|
|
@ -507,7 +507,7 @@ func splitRule(ctx BaseModuleContext, ruleExpression string, currentPkg, propert
|
|||
return true, pkg, name
|
||||
}
|
||||
|
||||
func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
|
||||
func visibilityRuleEnforcer(ctx BottomUpMutatorContext) {
|
||||
qualified := createVisibilityModuleReference(ctx.ModuleName(), ctx.ModuleDir(), ctx.Module())
|
||||
|
||||
// Visit all the dependencies making sure that this module has access to them all.
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ type sdkRepoHost struct {
|
|||
|
||||
outputBaseName string
|
||||
outputFile android.OptionalPath
|
||||
|
||||
// TODO(b/357908583): Temp field, remove this once we support Android Mk providers
|
||||
installFile android.InstallPath
|
||||
}
|
||||
|
||||
type remapProperties struct {
|
||||
|
|
@ -234,14 +237,18 @@ func (s *sdkRepoHost) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
|
||||
s.outputBaseName = name
|
||||
s.outputFile = android.OptionalPathForPath(outputZipFile)
|
||||
ctx.InstallFile(android.PathForModuleInstall(ctx, "sdk-repo"), name+".zip", outputZipFile)
|
||||
installPath := android.PathForModuleInstall(ctx, "sdk-repo")
|
||||
name = name + ".zip"
|
||||
ctx.InstallFile(installPath, name, outputZipFile)
|
||||
// TODO(b/357908583): Temp field, remove this once we support Android Mk providers
|
||||
s.installFile = installPath.Join(ctx, name)
|
||||
}
|
||||
|
||||
func (s *sdkRepoHost) AndroidMk() android.AndroidMkData {
|
||||
return android.AndroidMkData{
|
||||
Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
|
||||
fmt.Fprintln(w, ".PHONY:", name, "sdk_repo", "sdk-repo-"+name)
|
||||
fmt.Fprintln(w, "sdk_repo", "sdk-repo-"+name+":", strings.Join(s.FilesToInstall().Strings(), " "))
|
||||
fmt.Fprintln(w, "sdk_repo", "sdk-repo-"+name+":", s.installFile.String())
|
||||
|
||||
fmt.Fprintf(w, "$(call dist-for-goals,sdk_repo sdk-repo-%s,%s:%s-FILE_NAME_TAG_PLACEHOLDER.zip)\n\n", s.BaseModuleName(), s.outputFile.String(), s.outputBaseName)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ type Rule struct {
|
|||
Prerequisites *MakeString
|
||||
RecipePos Pos
|
||||
Recipe string
|
||||
RecipeEndPos Pos
|
||||
}
|
||||
|
||||
func (x *Rule) Dump() string {
|
||||
|
|
@ -95,7 +96,7 @@ func (x *Rule) Dump() string {
|
|||
}
|
||||
|
||||
func (x *Rule) Pos() Pos { return x.Target.Pos() }
|
||||
func (x *Rule) End() Pos { return Pos(int(x.RecipePos) + len(x.Recipe)) }
|
||||
func (x *Rule) End() Pos { return x.RecipeEndPos }
|
||||
|
||||
type Variable struct {
|
||||
Name *MakeString
|
||||
|
|
|
|||
|
|
@ -448,6 +448,7 @@ loop:
|
|||
Prerequisites: prerequisites,
|
||||
Recipe: recipe,
|
||||
RecipePos: recipePos,
|
||||
RecipeEndPos: p.pos(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,20 +86,19 @@ endif`,
|
|||
},
|
||||
{
|
||||
name: "Blank line in rule's command",
|
||||
in: `all:
|
||||
in: `all:
|
||||
echo first line
|
||||
|
||||
echo second line`,
|
||||
out: []Node{
|
||||
&Rule{
|
||||
Target: SimpleMakeString("all", NoPos),
|
||||
RecipePos: NoPos,
|
||||
Recipe: "echo first line\necho second line",
|
||||
Target: SimpleMakeString("all", NoPos),
|
||||
RecipePos: NoPos,
|
||||
Recipe: "echo first line\necho second line",
|
||||
Prerequisites: SimpleMakeString("", NoPos),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
|
|
@ -125,3 +124,25 @@ func TestParse(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRuleEnd(t *testing.T) {
|
||||
name := "ruleEndTest"
|
||||
in := `all:
|
||||
ifeq (A, A)
|
||||
echo foo
|
||||
echo foo
|
||||
echo foo
|
||||
echo foo
|
||||
endif
|
||||
echo bar
|
||||
`
|
||||
p := NewParser(name, bytes.NewBufferString(in))
|
||||
got, errs := p.Parse()
|
||||
if len(errs) != 0 {
|
||||
t.Fatalf("Unexpected errors while parsing: %v", errs)
|
||||
}
|
||||
|
||||
if got[0].End() < got[len(got) -1].Pos() {
|
||||
t.Errorf("Rule's end (%d) is smaller than directive that inside of rule's start (%v)\n", got[0].End(), got[len(got) -1].Pos())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ bootstrap_go_package {
|
|||
"soong-cc",
|
||||
"soong-filesystem",
|
||||
"soong-java",
|
||||
"soong-multitree",
|
||||
"soong-provenance",
|
||||
"soong-python",
|
||||
"soong-rust",
|
||||
|
|
@ -37,9 +36,12 @@ bootstrap_go_package {
|
|||
"apex_test.go",
|
||||
"bootclasspath_fragment_test.go",
|
||||
"classpath_element_test.go",
|
||||
"container_test.go",
|
||||
"dexpreopt_bootjars_test.go",
|
||||
"platform_bootclasspath_test.go",
|
||||
"systemserver_classpath_fragment_test.go",
|
||||
],
|
||||
pluginFor: ["soong_build"],
|
||||
// Used by plugins
|
||||
visibility: ["//visibility:public"],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ func TestValidationAcrossContainersExportedPass(t *testing.T) {
|
|||
apex_available: [
|
||||
"myapex",
|
||||
],
|
||||
sdk_version: "none",
|
||||
system_modules: "none",
|
||||
}`,
|
||||
},
|
||||
{
|
||||
|
|
@ -122,6 +124,8 @@ func TestValidationAcrossContainersExportedPass(t *testing.T) {
|
|||
apex_available: [
|
||||
"myapex",
|
||||
],
|
||||
sdk_version: "none",
|
||||
system_modules: "none",
|
||||
}`,
|
||||
},
|
||||
{
|
||||
|
|
@ -345,6 +349,8 @@ func TestValidationAcrossContainersNotExportedFail(t *testing.T) {
|
|||
apex_available: [
|
||||
"myapex",
|
||||
],
|
||||
sdk_version: "none",
|
||||
system_modules: "none",
|
||||
}`,
|
||||
expectedError: `.*my_java_library_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
|
||||
},
|
||||
|
|
@ -392,6 +398,8 @@ func TestValidationAcrossContainersNotExportedFail(t *testing.T) {
|
|||
apex_available: [
|
||||
"myapex",
|
||||
],
|
||||
sdk_version: "none",
|
||||
system_modules: "none",
|
||||
}`,
|
||||
expectedError: `.*my_android_app_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
|
||||
},
|
||||
|
|
@ -693,6 +701,8 @@ func TestValidationAcrossContainersNotExportedFail(t *testing.T) {
|
|||
apex_available: [
|
||||
"myapex",
|
||||
],
|
||||
sdk_version: "none",
|
||||
system_modules: "none",
|
||||
}`,
|
||||
expectedError: `.*my_android_app_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
|
||||
},
|
||||
|
|
@ -769,6 +779,8 @@ func TestValidationNotPropagateAcrossShared(t *testing.T) {
|
|||
apex_available: [
|
||||
"myapex",
|
||||
],
|
||||
sdk_version: "none",
|
||||
system_modules: "none",
|
||||
}`,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,6 +136,11 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, moduleDir st
|
|||
fmt.Fprintln(w, "LOCAL_SOONG_INSTALLED_MODULE :=", filepath.Join(modulePath, fi.stem()))
|
||||
fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_PAIRS :=", fi.builtFile.String()+":"+filepath.Join(modulePath, fi.stem()))
|
||||
fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String())
|
||||
if fi.checkbuildTarget != nil {
|
||||
fmt.Fprintln(w, "LOCAL_CHECKED_MODULE :=", fi.checkbuildTarget.String())
|
||||
} else {
|
||||
fmt.Fprintln(w, "LOCAL_CHECKED_MODULE :=", fi.builtFile.String())
|
||||
}
|
||||
fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.nameInMake())
|
||||
if fi.module != nil {
|
||||
// This apexFile's module comes from Soong
|
||||
|
|
|
|||
364
apex/apex.go
364
apex/apex.go
|
|
@ -32,7 +32,6 @@ import (
|
|||
prebuilt_etc "android/soong/etc"
|
||||
"android/soong/filesystem"
|
||||
"android/soong/java"
|
||||
"android/soong/multitree"
|
||||
"android/soong/rust"
|
||||
"android/soong/sh"
|
||||
)
|
||||
|
|
@ -50,17 +49,11 @@ func registerApexBuildComponents(ctx android.RegistrationContext) {
|
|||
ctx.RegisterModuleType("override_apex", OverrideApexFactory)
|
||||
ctx.RegisterModuleType("apex_set", apexSetFactory)
|
||||
|
||||
ctx.PreArchMutators(registerPreArchMutators)
|
||||
ctx.PreDepsMutators(RegisterPreDepsMutators)
|
||||
ctx.PostDepsMutators(RegisterPostDepsMutators)
|
||||
}
|
||||
|
||||
func registerPreArchMutators(ctx android.RegisterMutatorsContext) {
|
||||
ctx.TopDown("prebuilt_apex_module_creator", prebuiltApexModuleCreatorMutator).Parallel()
|
||||
}
|
||||
|
||||
func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) {
|
||||
ctx.TopDown("apex_vndk", apexVndkMutator).Parallel()
|
||||
ctx.BottomUp("apex_vndk_deps", apexVndkDepsMutator).Parallel()
|
||||
}
|
||||
|
||||
|
|
@ -158,10 +151,6 @@ type apexBundleProperties struct {
|
|||
// Default: true.
|
||||
Installable *bool
|
||||
|
||||
// If set true, VNDK libs are considered as stable libs and are not included in this APEX.
|
||||
// Should be only used in non-system apexes (e.g. vendor: true). Default is false.
|
||||
Use_vndk_as_stable *bool
|
||||
|
||||
// The type of filesystem to use. Either 'ext4', 'f2fs' or 'erofs'. Default 'ext4'.
|
||||
Payload_fs_type *string
|
||||
|
||||
|
|
@ -169,10 +158,6 @@ type apexBundleProperties struct {
|
|||
// Default is false.
|
||||
Ignore_system_library_special_case *bool
|
||||
|
||||
// Whenever apex_payload.img of the APEX should include dm-verity hashtree.
|
||||
// Default value is true.
|
||||
Generate_hashtree *bool
|
||||
|
||||
// Whenever apex_payload.img of the APEX should not be dm-verity signed. Should be only
|
||||
// used in tests.
|
||||
Test_only_unsigned_payload *bool
|
||||
|
|
@ -213,6 +198,50 @@ type apexBundleProperties struct {
|
|||
}
|
||||
|
||||
type ApexNativeDependencies struct {
|
||||
// List of native libraries that are embedded inside this APEX.
|
||||
Native_shared_libs proptools.Configurable[[]string]
|
||||
|
||||
// List of JNI libraries that are embedded inside this APEX.
|
||||
Jni_libs []string
|
||||
|
||||
// List of rust dyn libraries that are embedded inside this APEX.
|
||||
Rust_dyn_libs []string
|
||||
|
||||
// List of native executables that are embedded inside this APEX.
|
||||
Binaries proptools.Configurable[[]string]
|
||||
|
||||
// List of native tests that are embedded inside this APEX.
|
||||
Tests []string
|
||||
|
||||
// List of filesystem images that are embedded inside this APEX bundle.
|
||||
Filesystems []string
|
||||
|
||||
// List of prebuilt_etcs that are embedded inside this APEX bundle.
|
||||
Prebuilts proptools.Configurable[[]string]
|
||||
|
||||
// List of native libraries to exclude from this APEX.
|
||||
Exclude_native_shared_libs []string
|
||||
|
||||
// List of JNI libraries to exclude from this APEX.
|
||||
Exclude_jni_libs []string
|
||||
|
||||
// List of rust dyn libraries to exclude from this APEX.
|
||||
Exclude_rust_dyn_libs []string
|
||||
|
||||
// List of native executables to exclude from this APEX.
|
||||
Exclude_binaries []string
|
||||
|
||||
// List of native tests to exclude from this APEX.
|
||||
Exclude_tests []string
|
||||
|
||||
// List of filesystem images to exclude from this APEX bundle.
|
||||
Exclude_filesystems []string
|
||||
|
||||
// List of prebuilt_etcs to exclude from this APEX bundle.
|
||||
Exclude_prebuilts []string
|
||||
}
|
||||
|
||||
type ResolvedApexNativeDependencies struct {
|
||||
// List of native libraries that are embedded inside this APEX.
|
||||
Native_shared_libs []string
|
||||
|
||||
|
|
@ -223,8 +252,7 @@ type ApexNativeDependencies struct {
|
|||
Rust_dyn_libs []string
|
||||
|
||||
// List of native executables that are embedded inside this APEX.
|
||||
Binaries proptools.Configurable[[]string]
|
||||
ResolvedBinaries []string `blueprint:"mutated"`
|
||||
Binaries []string
|
||||
|
||||
// List of native tests that are embedded inside this APEX.
|
||||
Tests []string
|
||||
|
|
@ -233,8 +261,7 @@ type ApexNativeDependencies struct {
|
|||
Filesystems []string
|
||||
|
||||
// List of prebuilt_etcs that are embedded inside this APEX bundle.
|
||||
Prebuilts proptools.Configurable[[]string]
|
||||
ResolvedPrebuilts []string `blueprint:"mutated"`
|
||||
Prebuilts []string
|
||||
|
||||
// List of native libraries to exclude from this APEX.
|
||||
Exclude_native_shared_libs []string
|
||||
|
|
@ -259,14 +286,14 @@ type ApexNativeDependencies struct {
|
|||
}
|
||||
|
||||
// Merge combines another ApexNativeDependencies into this one
|
||||
func (a *ApexNativeDependencies) Merge(ctx android.BaseMutatorContext, b ApexNativeDependencies) {
|
||||
a.Native_shared_libs = append(a.Native_shared_libs, b.Native_shared_libs...)
|
||||
func (a *ResolvedApexNativeDependencies) Merge(ctx android.BaseMutatorContext, b ApexNativeDependencies) {
|
||||
a.Native_shared_libs = append(a.Native_shared_libs, b.Native_shared_libs.GetOrDefault(ctx, nil)...)
|
||||
a.Jni_libs = append(a.Jni_libs, b.Jni_libs...)
|
||||
a.Rust_dyn_libs = append(a.Rust_dyn_libs, b.Rust_dyn_libs...)
|
||||
a.ResolvedBinaries = append(a.ResolvedBinaries, b.Binaries.GetOrDefault(ctx, nil)...)
|
||||
a.Binaries = append(a.Binaries, b.Binaries.GetOrDefault(ctx, nil)...)
|
||||
a.Tests = append(a.Tests, b.Tests...)
|
||||
a.Filesystems = append(a.Filesystems, b.Filesystems...)
|
||||
a.ResolvedPrebuilts = append(a.ResolvedPrebuilts, b.Prebuilts.GetOrDefault(ctx, nil)...)
|
||||
a.Prebuilts = append(a.Prebuilts, b.Prebuilts.GetOrDefault(ctx, nil)...)
|
||||
|
||||
a.Exclude_native_shared_libs = append(a.Exclude_native_shared_libs, b.Exclude_native_shared_libs...)
|
||||
a.Exclude_jni_libs = append(a.Exclude_jni_libs, b.Exclude_jni_libs...)
|
||||
|
|
@ -397,7 +424,6 @@ type apexBundle struct {
|
|||
android.ModuleBase
|
||||
android.DefaultableModuleBase
|
||||
android.OverridableModuleBase
|
||||
multitree.ExportableModuleBase
|
||||
|
||||
// Properties
|
||||
properties apexBundleProperties
|
||||
|
|
@ -536,6 +562,8 @@ type apexFile struct {
|
|||
customStem string
|
||||
symlinks []string // additional symlinks
|
||||
|
||||
checkbuildTarget android.Path
|
||||
|
||||
// Info for Android.mk Module name of `module` in AndroidMk. Note the generated AndroidMk
|
||||
// module for apexFile is named something like <AndroidMk module name>.<apex name>[<apex
|
||||
// suffix>]
|
||||
|
|
@ -571,6 +599,9 @@ func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, androidM
|
|||
module: module,
|
||||
}
|
||||
if module != nil {
|
||||
if installFilesInfo, ok := android.OtherModuleProvider(ctx, module, android.InstallFilesProvider); ok {
|
||||
ret.checkbuildTarget = installFilesInfo.CheckbuildTarget
|
||||
}
|
||||
ret.moduleDir = ctx.OtherModuleDir(module)
|
||||
ret.partition = module.PartitionTag(ctx.DeviceConfig())
|
||||
ret.requiredModuleNames = module.RequiredModuleNames(ctx)
|
||||
|
|
@ -658,6 +689,8 @@ type dependencyTag struct {
|
|||
// If not-nil and an APEX is a member of an SDK then dependencies of that APEX with this tag will
|
||||
// also be added as exported members of that SDK.
|
||||
memberType android.SdkMemberType
|
||||
|
||||
installable bool
|
||||
}
|
||||
|
||||
func (d *dependencyTag) SdkMemberType(_ android.Module) android.SdkMemberType {
|
||||
|
|
@ -676,18 +709,23 @@ func (d *dependencyTag) ReplaceSourceWithPrebuilt() bool {
|
|||
return !d.sourceOnly
|
||||
}
|
||||
|
||||
func (d *dependencyTag) InstallDepNeeded() bool {
|
||||
return d.installable
|
||||
}
|
||||
|
||||
var _ android.ReplaceSourceWithPrebuilt = &dependencyTag{}
|
||||
var _ android.SdkMemberDependencyTag = &dependencyTag{}
|
||||
|
||||
var (
|
||||
androidAppTag = &dependencyTag{name: "androidApp", payload: true}
|
||||
bpfTag = &dependencyTag{name: "bpf", payload: true}
|
||||
certificateTag = &dependencyTag{name: "certificate"}
|
||||
dclaTag = &dependencyTag{name: "dcla"}
|
||||
executableTag = &dependencyTag{name: "executable", payload: true}
|
||||
fsTag = &dependencyTag{name: "filesystem", payload: true}
|
||||
bcpfTag = &dependencyTag{name: "bootclasspathFragment", payload: true, sourceOnly: true, memberType: java.BootclasspathFragmentSdkMemberType}
|
||||
sscpfTag = &dependencyTag{name: "systemserverclasspathFragment", payload: true, sourceOnly: true, memberType: java.SystemServerClasspathFragmentSdkMemberType}
|
||||
androidAppTag = &dependencyTag{name: "androidApp", payload: true}
|
||||
bpfTag = &dependencyTag{name: "bpf", payload: true}
|
||||
certificateTag = &dependencyTag{name: "certificate"}
|
||||
dclaTag = &dependencyTag{name: "dcla"}
|
||||
executableTag = &dependencyTag{name: "executable", payload: true}
|
||||
fsTag = &dependencyTag{name: "filesystem", payload: true}
|
||||
bcpfTag = &dependencyTag{name: "bootclasspathFragment", payload: true, sourceOnly: true, memberType: java.BootclasspathFragmentSdkMemberType}
|
||||
// The dexpreopt artifacts of apex system server jars are installed onto system image.
|
||||
sscpfTag = &dependencyTag{name: "systemserverclasspathFragment", payload: true, sourceOnly: true, memberType: java.SystemServerClasspathFragmentSdkMemberType, installable: true}
|
||||
compatConfigTag = &dependencyTag{name: "compatConfig", payload: true, sourceOnly: true, memberType: java.CompatConfigSdkMemberType}
|
||||
javaLibTag = &dependencyTag{name: "javaLib", payload: true}
|
||||
jniLibTag = &dependencyTag{name: "jniLib", payload: true}
|
||||
|
|
@ -701,13 +739,12 @@ var (
|
|||
)
|
||||
|
||||
// TODO(jiyong): shorten this function signature
|
||||
func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, nativeModules ApexNativeDependencies, target android.Target, imageVariation string) {
|
||||
func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, nativeModules ResolvedApexNativeDependencies, target android.Target, imageVariation string) {
|
||||
binVariations := target.Variations()
|
||||
libVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"})
|
||||
rustLibVariations := append(
|
||||
target.Variations(), []blueprint.Variation{
|
||||
{Mutator: "rust_libraries", Variation: "dylib"},
|
||||
{Mutator: "link", Variation: ""},
|
||||
}...,
|
||||
)
|
||||
|
||||
|
|
@ -720,7 +757,7 @@ func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, nativeM
|
|||
// this module. This is required since arch variant of an APEX bundle is 'common' but it is
|
||||
// 'arm' or 'arm64' for native shared libs.
|
||||
ctx.AddFarVariationDependencies(binVariations, executableTag,
|
||||
android.RemoveListFromList(nativeModules.ResolvedBinaries, nativeModules.Exclude_binaries)...)
|
||||
android.RemoveListFromList(nativeModules.Binaries, nativeModules.Exclude_binaries)...)
|
||||
ctx.AddFarVariationDependencies(binVariations, testTag,
|
||||
android.RemoveListFromList(nativeModules.Tests, nativeModules.Exclude_tests)...)
|
||||
ctx.AddFarVariationDependencies(libVariations, jniLibTag,
|
||||
|
|
@ -732,7 +769,7 @@ func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, nativeM
|
|||
ctx.AddFarVariationDependencies(target.Variations(), fsTag,
|
||||
android.RemoveListFromList(nativeModules.Filesystems, nativeModules.Exclude_filesystems)...)
|
||||
ctx.AddFarVariationDependencies(target.Variations(), prebuiltTag,
|
||||
android.RemoveListFromList(nativeModules.ResolvedPrebuilts, nativeModules.Exclude_prebuilts)...)
|
||||
android.RemoveListFromList(nativeModules.Prebuilts, nativeModules.Exclude_prebuilts)...)
|
||||
}
|
||||
|
||||
func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
|
||||
|
|
@ -751,9 +788,9 @@ func (a *apexBundle) getImageVariationPair() (string, string) {
|
|||
|
||||
prefix := android.CoreVariation
|
||||
if a.SocSpecific() || a.DeviceSpecific() {
|
||||
prefix = cc.VendorVariation
|
||||
prefix = android.VendorVariation
|
||||
} else if a.ProductSpecific() {
|
||||
prefix = cc.ProductVariation
|
||||
prefix = android.ProductVariation
|
||||
}
|
||||
|
||||
return prefix, ""
|
||||
|
|
@ -783,7 +820,7 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) {
|
|||
}
|
||||
}
|
||||
for i, target := range targets {
|
||||
var deps ApexNativeDependencies
|
||||
var deps ResolvedApexNativeDependencies
|
||||
|
||||
// Add native modules targeting both ABIs. When multilib.* is omitted for
|
||||
// native_shared_libs/jni_libs/tests, it implies multilib.both
|
||||
|
|
@ -800,7 +837,7 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) {
|
|||
if isPrimaryAbi {
|
||||
deps.Merge(ctx, a.properties.Multilib.First)
|
||||
deps.Merge(ctx, ApexNativeDependencies{
|
||||
Native_shared_libs: nil,
|
||||
Native_shared_libs: proptools.NewConfigurable[[]string](nil, nil),
|
||||
Tests: nil,
|
||||
Jni_libs: nil,
|
||||
Binaries: a.properties.Binaries,
|
||||
|
|
@ -954,24 +991,6 @@ func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) {
|
|||
return
|
||||
}
|
||||
|
||||
// Special casing for APEXes on non-system (e.g., vendor, odm, etc.) partitions. They are
|
||||
// provided with a property named use_vndk_as_stable, which when set to true doesn't collect
|
||||
// VNDK libraries as transitive dependencies. This option is useful for reducing the size of
|
||||
// the non-system APEXes because the VNDK libraries won't be included (and duped) in the
|
||||
// APEX, but shared across APEXes via the VNDK APEX.
|
||||
useVndk := a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && mctx.Config().EnforceProductPartitionInterface())
|
||||
if proptools.Bool(a.properties.Use_vndk_as_stable) {
|
||||
if !useVndk {
|
||||
mctx.PropertyErrorf("use_vndk_as_stable", "not supported for system/system_ext APEXes")
|
||||
}
|
||||
if a.minSdkVersionValue(mctx) != "" {
|
||||
mctx.PropertyErrorf("use_vndk_as_stable", "not supported when min_sdk_version is set")
|
||||
}
|
||||
if mctx.Failed() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
continueApexDepsWalk := func(child, parent android.Module) bool {
|
||||
am, ok := child.(android.ApexModule)
|
||||
if !ok || !am.CanHaveApexVariants() {
|
||||
|
|
@ -989,10 +1008,6 @@ func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) {
|
|||
return false
|
||||
}
|
||||
|
||||
if useVndk && child.Name() == "libbinder" {
|
||||
mctx.ModuleErrorf("Module %s in the vendor APEX %s should not use libbinder. Use libbinder_ndk instead.", parent.Name(), a.Name())
|
||||
}
|
||||
|
||||
// By default, all the transitive dependencies are collected, unless filtered out
|
||||
// above.
|
||||
return true
|
||||
|
|
@ -1047,6 +1062,8 @@ func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) {
|
|||
InApexModules: []string{a.Name()}, // could be com.mycompany.android.foo
|
||||
ApexContents: []*android.ApexContents{apexContents},
|
||||
TestApexes: testApexes,
|
||||
BaseApexName: mctx.ModuleName(),
|
||||
ApexAvailableName: proptools.String(a.properties.Apex_available_name),
|
||||
}
|
||||
mctx.WalkDeps(func(child, parent android.Module) bool {
|
||||
if !continueApexDepsWalk(child, parent) {
|
||||
|
|
@ -1058,7 +1075,7 @@ func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) {
|
|||
|
||||
if a.dynamic_common_lib_apex() {
|
||||
android.SetProvider(mctx, DCLAInfoProvider, DCLAInfo{
|
||||
ProvidedLibs: a.properties.Native_shared_libs,
|
||||
ProvidedLibs: a.properties.Native_shared_libs.GetOrDefault(mctx, nil),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1175,6 +1192,7 @@ var (
|
|||
"test_com.android.os.statsd",
|
||||
"test_com.android.permission",
|
||||
"test_com.android.wifi",
|
||||
"test_imgdiag_com.android.art",
|
||||
"test_jitzygote_com.android.art",
|
||||
// go/keep-sorted end
|
||||
}
|
||||
|
|
@ -1373,27 +1391,6 @@ func (a *apexBundle) DepIsInSameApex(_ android.BaseModuleContext, _ android.Modu
|
|||
return true
|
||||
}
|
||||
|
||||
var _ android.OutputFileProducer = (*apexBundle)(nil)
|
||||
|
||||
// Implements android.OutputFileProducer
|
||||
func (a *apexBundle) OutputFiles(tag string) (android.Paths, error) {
|
||||
switch tag {
|
||||
case "", android.DefaultDistTag:
|
||||
// This is the default dist path.
|
||||
return android.Paths{a.outputFile}, nil
|
||||
case imageApexSuffix:
|
||||
// uncompressed one
|
||||
if a.outputApexFile != nil {
|
||||
return android.Paths{a.outputApexFile}, nil
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported module reference tag %q", tag)
|
||||
}
|
||||
}
|
||||
|
||||
var _ multitree.Exportable = (*apexBundle)(nil)
|
||||
|
||||
func (a *apexBundle) Exportable() bool {
|
||||
return true
|
||||
}
|
||||
|
|
@ -1407,7 +1404,7 @@ func (a *apexBundle) TaggedOutputs() map[string]android.Paths {
|
|||
var _ cc.Coverage = (*apexBundle)(nil)
|
||||
|
||||
// Implements cc.Coverage
|
||||
func (a *apexBundle) IsNativeCoverageNeeded(ctx android.IncomingTransitionContext) bool {
|
||||
func (a *apexBundle) IsNativeCoverageNeeded(ctx cc.IsNativeCoverageNeededContext) bool {
|
||||
return ctx.DeviceConfig().NativeCoverageEnabled()
|
||||
}
|
||||
|
||||
|
|
@ -1469,11 +1466,6 @@ func (a *apexBundle) installable() bool {
|
|||
return !a.properties.PreventInstall && (a.properties.Installable == nil || proptools.Bool(a.properties.Installable))
|
||||
}
|
||||
|
||||
// See the generate_hashtree property
|
||||
func (a *apexBundle) shouldGenerateHashtree() bool {
|
||||
return proptools.BoolDefault(a.properties.Generate_hashtree, true)
|
||||
}
|
||||
|
||||
// See the test_only_unsigned_payload property
|
||||
func (a *apexBundle) testOnlyShouldSkipPayloadSign() bool {
|
||||
return proptools.Bool(a.properties.Test_only_unsigned_payload)
|
||||
|
|
@ -1533,7 +1525,7 @@ func (a *apexBundle) AddSanitizerDependencies(ctx android.BottomUpMutatorContext
|
|||
imageVariation := a.getImageVariation()
|
||||
for _, target := range ctx.MultiTargets() {
|
||||
if target.Arch.ArchType.Multilib == "lib64" {
|
||||
addDependenciesForNativeModules(ctx, ApexNativeDependencies{
|
||||
addDependenciesForNativeModules(ctx, ResolvedApexNativeDependencies{
|
||||
Native_shared_libs: []string{"libclang_rt.hwasan"},
|
||||
Tests: nil,
|
||||
Jni_libs: nil,
|
||||
|
|
@ -1685,12 +1677,10 @@ func apexFileForJavaModuleWithFile(ctx android.ModuleContext, module javaModule,
|
|||
if sdkLib, ok := module.(*java.SdkLibrary); ok {
|
||||
for _, install := range sdkLib.BuiltInstalledForApex() {
|
||||
af.requiredModuleNames = append(af.requiredModuleNames, install.FullModuleName())
|
||||
install.PackageFile(ctx)
|
||||
}
|
||||
} else if dexpreopter, ok := module.(java.DexpreopterInterface); ok {
|
||||
for _, install := range dexpreopter.DexpreoptBuiltInstalledForApex() {
|
||||
af.requiredModuleNames = append(af.requiredModuleNames, install.FullModuleName())
|
||||
install.PackageFile(ctx)
|
||||
}
|
||||
}
|
||||
return af
|
||||
|
|
@ -1931,8 +1921,6 @@ type visitorContext struct {
|
|||
|
||||
// visitor skips these from this list of module names
|
||||
unwantedTransitiveDeps []string
|
||||
|
||||
aconfigFiles []android.Path
|
||||
}
|
||||
|
||||
func (vctx *visitorContext) normalizeFileInfo(mctx android.ModuleContext) {
|
||||
|
|
@ -1999,7 +1987,6 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
|
|||
fi := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs)
|
||||
fi.isJniLib = isJniLib
|
||||
vctx.filesInfo = append(vctx.filesInfo, fi)
|
||||
addAconfigFiles(vctx, ctx, child)
|
||||
// Collect the list of stub-providing libs except:
|
||||
// - VNDK libs are only for vendors
|
||||
// - bootstrap bionic libs are treated as provided by system
|
||||
|
|
@ -2011,7 +1998,6 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
|
|||
fi := apexFileForRustLibrary(ctx, ch)
|
||||
fi.isJniLib = isJniLib
|
||||
vctx.filesInfo = append(vctx.filesInfo, fi)
|
||||
addAconfigFiles(vctx, ctx, child)
|
||||
return true // track transitive dependencies
|
||||
default:
|
||||
ctx.PropertyErrorf(propertyName, "%q is not a cc_library or cc_library_shared module", depName)
|
||||
|
|
@ -2020,11 +2006,9 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
|
|||
switch ch := child.(type) {
|
||||
case *cc.Module:
|
||||
vctx.filesInfo = append(vctx.filesInfo, apexFileForExecutable(ctx, ch))
|
||||
addAconfigFiles(vctx, ctx, child)
|
||||
return true // track transitive dependencies
|
||||
case *rust.Module:
|
||||
vctx.filesInfo = append(vctx.filesInfo, apexFileForRustExecutable(ctx, ch))
|
||||
addAconfigFiles(vctx, ctx, child)
|
||||
return true // track transitive dependencies
|
||||
default:
|
||||
ctx.PropertyErrorf("binaries",
|
||||
|
|
@ -2064,7 +2048,6 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
|
|||
return false
|
||||
}
|
||||
vctx.filesInfo = append(vctx.filesInfo, af)
|
||||
addAconfigFiles(vctx, ctx, child)
|
||||
return true // track transitive dependencies
|
||||
default:
|
||||
ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
|
||||
|
|
@ -2073,14 +2056,11 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
|
|||
switch ap := child.(type) {
|
||||
case *java.AndroidApp:
|
||||
vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
|
||||
addAconfigFiles(vctx, ctx, child)
|
||||
return true // track transitive dependencies
|
||||
case *java.AndroidAppImport:
|
||||
vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
|
||||
addAconfigFiles(vctx, ctx, child)
|
||||
case *java.AndroidTestHelperApp:
|
||||
vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
|
||||
addAconfigFiles(vctx, ctx, child)
|
||||
case *java.AndroidAppSet:
|
||||
appDir := "app"
|
||||
if ap.Privileged() {
|
||||
|
|
@ -2094,7 +2074,6 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
|
|||
af := newApexFile(ctx, ap.OutputFile(), ap.BaseModuleName(), appDirName, appSet, ap)
|
||||
af.certificate = java.PresignedCertificate
|
||||
vctx.filesInfo = append(vctx.filesInfo, af)
|
||||
addAconfigFiles(vctx, ctx, child)
|
||||
default:
|
||||
ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
|
||||
}
|
||||
|
|
@ -2126,7 +2105,6 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
|
|||
for _, etcFile := range filesToCopy {
|
||||
vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, etcFile))
|
||||
}
|
||||
addAconfigFiles(vctx, ctx, child)
|
||||
} else {
|
||||
ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
|
||||
}
|
||||
|
|
@ -2138,20 +2116,9 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
|
|||
}
|
||||
case testTag:
|
||||
if ccTest, ok := child.(*cc.Module); ok {
|
||||
if ccTest.IsTestPerSrcAllTestsVariation() {
|
||||
// Multiple-output test module (where `test_per_src: true`).
|
||||
//
|
||||
// `ccTest` is the "" ("all tests") variation of a `test_per_src` module.
|
||||
// We do not add this variation to `filesInfo`, as it has no output;
|
||||
// however, we do add the other variations of this module as indirect
|
||||
// dependencies (see below).
|
||||
} else {
|
||||
// Single-output test module (where `test_per_src: false`).
|
||||
af := apexFileForExecutable(ctx, ccTest)
|
||||
af.class = nativeTest
|
||||
vctx.filesInfo = append(vctx.filesInfo, af)
|
||||
addAconfigFiles(vctx, ctx, child)
|
||||
}
|
||||
af := apexFileForExecutable(ctx, ccTest)
|
||||
af.class = nativeTest
|
||||
vctx.filesInfo = append(vctx.filesInfo, af)
|
||||
return true // track transitive dependencies
|
||||
} else {
|
||||
ctx.PropertyErrorf("tests", "%q is not a cc module", depName)
|
||||
|
|
@ -2231,26 +2198,15 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
|
|||
}
|
||||
|
||||
vctx.filesInfo = append(vctx.filesInfo, af)
|
||||
addAconfigFiles(vctx, ctx, child)
|
||||
return true // track transitive dependencies
|
||||
} else if rm, ok := child.(*rust.Module); ok {
|
||||
if !android.IsDepInSameApex(ctx, am, am) {
|
||||
return false
|
||||
}
|
||||
|
||||
af := apexFileForRustLibrary(ctx, rm)
|
||||
af.transitiveDep = true
|
||||
vctx.filesInfo = append(vctx.filesInfo, af)
|
||||
addAconfigFiles(vctx, ctx, child)
|
||||
return true // track transitive dependencies
|
||||
}
|
||||
} else if cc.IsTestPerSrcDepTag(depTag) {
|
||||
if ch, ok := child.(*cc.Module); ok {
|
||||
af := apexFileForExecutable(ctx, ch)
|
||||
// Handle modules created as `test_per_src` variations of a single test module:
|
||||
// use the name of the generated test binary (`fileToCopy`) instead of the name
|
||||
// of the original test module (`depName`, shared by all `test_per_src`
|
||||
// variations of that module).
|
||||
af.androidMkModuleName = filepath.Base(af.builtFile.String())
|
||||
// these are not considered transitive dep
|
||||
af.transitiveDep = false
|
||||
vctx.filesInfo = append(vctx.filesInfo, af)
|
||||
return true // track transitive dependencies
|
||||
}
|
||||
} else if cc.IsHeaderDepTag(depTag) {
|
||||
|
|
@ -2266,10 +2222,13 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
|
|||
}
|
||||
} else if rust.IsDylibDepTag(depTag) {
|
||||
if rustm, ok := child.(*rust.Module); ok && rustm.IsInstallableToApex() {
|
||||
if !android.IsDepInSameApex(ctx, am, am) {
|
||||
return false
|
||||
}
|
||||
|
||||
af := apexFileForRustLibrary(ctx, rustm)
|
||||
af.transitiveDep = true
|
||||
vctx.filesInfo = append(vctx.filesInfo, af)
|
||||
addAconfigFiles(vctx, ctx, child)
|
||||
return true // track transitive dependencies
|
||||
}
|
||||
} else if rust.IsRlibDepTag(depTag) {
|
||||
|
|
@ -2288,7 +2247,6 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
|
|||
return false
|
||||
}
|
||||
vctx.filesInfo = append(vctx.filesInfo, af)
|
||||
addAconfigFiles(vctx, ctx, child)
|
||||
return true // track transitive dependencies
|
||||
default:
|
||||
ctx.PropertyErrorf("bootclasspath_fragments",
|
||||
|
|
@ -2303,7 +2261,6 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
|
|||
if profileAf := apexFileForJavaModuleProfile(ctx, child.(javaModule)); profileAf != nil {
|
||||
vctx.filesInfo = append(vctx.filesInfo, *profileAf)
|
||||
}
|
||||
addAconfigFiles(vctx, ctx, child)
|
||||
return true // track transitive dependencies
|
||||
default:
|
||||
ctx.PropertyErrorf("systemserverclasspath_fragments",
|
||||
|
|
@ -2321,19 +2278,6 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
|
|||
return false
|
||||
}
|
||||
|
||||
func addAconfigFiles(vctx *visitorContext, ctx android.ModuleContext, module blueprint.Module) {
|
||||
if dep, ok := android.OtherModuleProvider(ctx, module, android.AconfigPropagatingProviderKey); ok {
|
||||
if len(dep.AconfigFiles) > 0 && dep.AconfigFiles[ctx.ModuleName()] != nil {
|
||||
vctx.aconfigFiles = append(vctx.aconfigFiles, dep.AconfigFiles[ctx.ModuleName()]...)
|
||||
}
|
||||
}
|
||||
|
||||
validationFlag := ctx.DeviceConfig().AconfigContainerValidation()
|
||||
if validationFlag == "error" || validationFlag == "warning" {
|
||||
android.VerifyAconfigBuildMode(ctx, ctx.ModuleName(), module, validationFlag == "error")
|
||||
}
|
||||
}
|
||||
|
||||
func (a *apexBundle) shouldCheckDuplicate(ctx android.ModuleContext) bool {
|
||||
// TODO(b/263308293) remove this
|
||||
if a.properties.IsCoverageVariant {
|
||||
|
|
@ -2415,12 +2359,15 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
// 3) some fields in apexBundle struct are configured
|
||||
a.installDir = android.PathForModuleInstall(ctx, "apex")
|
||||
a.filesInfo = vctx.filesInfo
|
||||
a.aconfigFiles = android.FirstUniquePaths(vctx.aconfigFiles)
|
||||
|
||||
a.setPayloadFsType(ctx)
|
||||
a.setSystemLibLink(ctx)
|
||||
a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 3.a) some artifacts are generated from the collected files
|
||||
a.filesInfo = append(a.filesInfo, a.buildAconfigFiles(ctx)...)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 4) generate the build rules to create the APEX. This is done in builder.go.
|
||||
a.buildManifest(ctx, vctx.provideNativeLibs, vctx.requireNativeLibs)
|
||||
|
|
@ -2434,6 +2381,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
a.providePrebuiltInfo(ctx)
|
||||
|
||||
a.required = a.RequiredModuleNames(ctx)
|
||||
a.required = append(a.required, a.VintfFragmentModuleNames(ctx)...)
|
||||
|
||||
a.setOutputFiles(ctx)
|
||||
}
|
||||
|
||||
// Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file
|
||||
|
|
@ -2462,6 +2412,18 @@ func (a *apexBundle) provideApexExportsInfo(ctx android.ModuleContext) {
|
|||
})
|
||||
}
|
||||
|
||||
// Set output files to outputFiles property, which is later used to set the
|
||||
// OutputFilesProvider
|
||||
func (a *apexBundle) setOutputFiles(ctx android.ModuleContext) {
|
||||
// default dist path
|
||||
ctx.SetOutputFiles(android.Paths{a.outputFile}, "")
|
||||
ctx.SetOutputFiles(android.Paths{a.outputFile}, android.DefaultDistTag)
|
||||
// uncompressed one
|
||||
if a.outputApexFile != nil {
|
||||
ctx.SetOutputFiles(android.Paths{a.outputApexFile}, imageApexSuffix)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
|
|
@ -2556,7 +2518,6 @@ func newApexBundle() *apexBundle {
|
|||
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
|
||||
android.InitDefaultableModule(module)
|
||||
android.InitOverridableModule(module, &module.overridableProperties.Overrides)
|
||||
multitree.InitExportableModule(module)
|
||||
return module
|
||||
}
|
||||
|
||||
|
|
@ -2721,12 +2682,12 @@ func (a *apexBundle) checkUpdatable(ctx android.ModuleContext) {
|
|||
if a.minSdkVersionValue(ctx) == "" {
|
||||
ctx.PropertyErrorf("updatable", "updatable APEXes should set min_sdk_version as well")
|
||||
}
|
||||
if a.minSdkVersion(ctx).IsCurrent() {
|
||||
ctx.PropertyErrorf("updatable", "updatable APEXes should not set min_sdk_version to current. Please use a finalized API level or a recognized in-development codename")
|
||||
}
|
||||
if a.UsePlatformApis() {
|
||||
ctx.PropertyErrorf("updatable", "updatable APEXes can't use platform APIs")
|
||||
}
|
||||
if proptools.Bool(a.properties.Use_vndk_as_stable) {
|
||||
ctx.PropertyErrorf("use_vndk_as_stable", "updatable APEXes can't use external VNDK libs")
|
||||
}
|
||||
if a.FutureUpdatable() {
|
||||
ctx.PropertyErrorf("future_updatable", "Already updatable. Remove `future_updatable: true:`")
|
||||
}
|
||||
|
|
@ -2779,6 +2740,12 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) {
|
|||
return
|
||||
}
|
||||
|
||||
// Temporarily bypass /product APEXes with a specific prefix.
|
||||
// TODO: b/352818241 - Remove this after APEX availability is enforced for /product APEXes.
|
||||
if a.ProductSpecific() && strings.HasPrefix(a.ApexVariationName(), "com.sdv.") {
|
||||
return
|
||||
}
|
||||
|
||||
// Coverage build adds additional dependencies for the coverage-only runtime libraries.
|
||||
// Requiring them and their transitive depencies with apex_available is not right
|
||||
// because they just add noise.
|
||||
|
|
@ -2813,13 +2780,24 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) {
|
|||
return false
|
||||
}
|
||||
|
||||
if to.AvailableFor(apexName) || baselineApexAvailable(apexName, toName) {
|
||||
if to.AvailableFor(apexName) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Let's give some hint for apex_available
|
||||
hint := fmt.Sprintf("%q", apexName)
|
||||
|
||||
if strings.HasPrefix(apexName, "com.") && !strings.HasPrefix(apexName, "com.android.") && strings.Count(apexName, ".") >= 2 {
|
||||
// In case of a partner APEX, prefix format might be an option.
|
||||
components := strings.Split(apexName, ".")
|
||||
components[len(components)-1] = "*"
|
||||
hint += fmt.Sprintf(" or %q", strings.Join(components, "."))
|
||||
}
|
||||
|
||||
ctx.ModuleErrorf("%q requires %q that doesn't list the APEX under 'apex_available'."+
|
||||
"\n\nDependency path:%s\n\n"+
|
||||
"Consider adding %q to 'apex_available' property of %q",
|
||||
fromName, toName, ctx.GetPathString(true), apexName, toName)
|
||||
"Consider adding %s to 'apex_available' property of %q",
|
||||
fromName, toName, ctx.GetPathString(true), hint, toName)
|
||||
// Visit this module's dependencies to check and report any issues with their availability.
|
||||
return true
|
||||
})
|
||||
|
|
@ -2856,80 +2834,12 @@ func isStaticExecutableAllowed(apex string, exec string) bool {
|
|||
}
|
||||
|
||||
// Collect information for opening IDE project files in java/jdeps.go.
|
||||
func (a *apexBundle) IDEInfo(dpInfo *android.IdeInfo) {
|
||||
func (a *apexBundle) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
|
||||
dpInfo.Deps = append(dpInfo.Deps, a.properties.Java_libs...)
|
||||
dpInfo.Deps = append(dpInfo.Deps, a.properties.Bootclasspath_fragments...)
|
||||
dpInfo.Deps = append(dpInfo.Deps, a.properties.ResolvedSystemserverclasspathFragments...)
|
||||
}
|
||||
|
||||
var (
|
||||
apexAvailBaseline = makeApexAvailableBaseline()
|
||||
inverseApexAvailBaseline = invertApexBaseline(apexAvailBaseline)
|
||||
)
|
||||
|
||||
func baselineApexAvailable(apex, moduleName string) bool {
|
||||
key := apex
|
||||
moduleName = normalizeModuleName(moduleName)
|
||||
|
||||
if val, ok := apexAvailBaseline[key]; ok && android.InList(moduleName, val) {
|
||||
return true
|
||||
}
|
||||
|
||||
key = android.AvailableToAnyApex
|
||||
if val, ok := apexAvailBaseline[key]; ok && android.InList(moduleName, val) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func normalizeModuleName(moduleName string) string {
|
||||
// Prebuilt modules (e.g. java_import, etc.) have "prebuilt_" prefix added by the build
|
||||
// system. Trim the prefix for the check since they are confusing
|
||||
moduleName = android.RemoveOptionalPrebuiltPrefix(moduleName)
|
||||
if strings.HasPrefix(moduleName, "libclang_rt.") {
|
||||
// This module has many arch variants that depend on the product being built.
|
||||
// We don't want to list them all
|
||||
moduleName = "libclang_rt"
|
||||
}
|
||||
if strings.HasPrefix(moduleName, "androidx.") {
|
||||
// TODO(b/156996905) Set apex_available/min_sdk_version for androidx support libraries
|
||||
moduleName = "androidx"
|
||||
}
|
||||
return moduleName
|
||||
}
|
||||
|
||||
// Transform the map of apex -> modules to module -> apexes.
|
||||
func invertApexBaseline(m map[string][]string) map[string][]string {
|
||||
r := make(map[string][]string)
|
||||
for apex, modules := range m {
|
||||
for _, module := range modules {
|
||||
r[module] = append(r[module], apex)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Retrieve the baseline of apexes to which the supplied module belongs.
|
||||
func BaselineApexAvailable(moduleName string) []string {
|
||||
return inverseApexAvailBaseline[normalizeModuleName(moduleName)]
|
||||
}
|
||||
|
||||
// This is a map from apex to modules, which overrides the apex_available setting for that
|
||||
// particular module to make it available for the apex regardless of its setting.
|
||||
// TODO(b/147364041): remove this
|
||||
func makeApexAvailableBaseline() map[string][]string {
|
||||
// The "Module separator"s below are employed to minimize merge conflicts.
|
||||
m := make(map[string][]string)
|
||||
//
|
||||
// Module separator
|
||||
//
|
||||
m["com.android.runtime"] = []string{
|
||||
"libz",
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func init() {
|
||||
android.AddNeverAllowRules(createBcpPermittedPackagesRules(qBcpPackages())...)
|
||||
android.AddNeverAllowRules(createBcpPermittedPackagesRules(rBcpPackages())...)
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ var (
|
|||
Command: "cat $out.rsp | xargs cat" +
|
||||
// Only track non-external dependencies, i.e. those that end up in the binary
|
||||
" | grep -v '(external)'" +
|
||||
// Allowlist androidx deps
|
||||
" | grep -v '^androidx\\.'" +
|
||||
" | grep -v '^prebuilt_androidx\\.'" +
|
||||
// Ignore comments in any of the files
|
||||
" | grep -v '^#'" +
|
||||
" | sort -u -f >$out",
|
||||
|
|
@ -85,7 +88,7 @@ func (s *apexDepsInfoSingleton) GenerateBuildActions(ctx android.SingletonContex
|
|||
updatableFlatLists := android.Paths{}
|
||||
ctx.VisitAllModules(func(module android.Module) {
|
||||
if binaryInfo, ok := module.(android.ApexBundleDepsInfoIntf); ok {
|
||||
apexInfo, _ := android.SingletonModuleProvider(ctx, module, android.ApexInfoProvider)
|
||||
apexInfo, _ := android.OtherModuleProvider(ctx, module, android.ApexInfoProvider)
|
||||
if path := binaryInfo.FlatListPath(); path != nil {
|
||||
if binaryInfo.Updatable() || apexInfo.Updatable {
|
||||
updatableFlatLists = append(updatableFlatLists, path)
|
||||
|
|
@ -152,7 +155,7 @@ func (a *apexPrebuiltInfo) GenerateBuildActions(ctx android.SingletonContext) {
|
|||
prebuiltInfos := []android.PrebuiltInfo{}
|
||||
|
||||
ctx.VisitAllModules(func(m android.Module) {
|
||||
prebuiltInfo, exists := android.SingletonModuleProvider(ctx, m, android.PrebuiltInfoProvider)
|
||||
prebuiltInfo, exists := android.OtherModuleProvider(ctx, m, android.PrebuiltInfoProvider)
|
||||
// Use prebuiltInfoProvider to filter out non apex soong modules.
|
||||
// Use HideFromMake to filter out the unselected variants of a specific apex.
|
||||
if exists && !m.IsHideFromMake() {
|
||||
|
|
|
|||
1559
apex/apex_test.go
1559
apex/apex_test.go
File diff suppressed because it is too large
Load diff
|
|
@ -53,11 +53,7 @@ func TestBootclasspathFragments_FragmentDependency(t *testing.T) {
|
|||
java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz"),
|
||||
java.FixtureConfigureApexBootJars("someapex:foo", "someapex:bar"),
|
||||
prepareForTestWithArtApex,
|
||||
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
|
||||
variables.BuildFlags = map[string]string{
|
||||
"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
|
||||
}
|
||||
}),
|
||||
android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"),
|
||||
java.PrepareForTestWithJavaSdkLibraryFiles,
|
||||
java.FixtureWithLastReleaseApis("foo", "baz"),
|
||||
).RunTestWithBp(t, `
|
||||
|
|
@ -108,6 +104,7 @@ func TestBootclasspathFragments_FragmentDependency(t *testing.T) {
|
|||
test: {
|
||||
enabled: true,
|
||||
},
|
||||
sdk_version: "core_current",
|
||||
}
|
||||
|
||||
java_library {
|
||||
|
|
@ -156,7 +153,7 @@ func TestBootclasspathFragments_FragmentDependency(t *testing.T) {
|
|||
|
||||
// Check stub dex paths exported by art.
|
||||
artFragment := result.Module("art-bootclasspath-fragment", "android_common")
|
||||
artInfo, _ := android.SingletonModuleProvider(result, artFragment, java.HiddenAPIInfoProvider)
|
||||
artInfo, _ := android.OtherModuleProvider(result, artFragment, java.HiddenAPIInfoProvider)
|
||||
|
||||
bazPublicStubs := "out/soong/.intermediates/baz.stubs.exportable/android_common/dex/baz.stubs.exportable.jar"
|
||||
bazSystemStubs := "out/soong/.intermediates/baz.stubs.exportable.system/android_common/dex/baz.stubs.exportable.system.jar"
|
||||
|
|
@ -169,7 +166,7 @@ func TestBootclasspathFragments_FragmentDependency(t *testing.T) {
|
|||
|
||||
// Check stub dex paths exported by other.
|
||||
otherFragment := result.Module("other-bootclasspath-fragment", "android_common")
|
||||
otherInfo, _ := android.SingletonModuleProvider(result, otherFragment, java.HiddenAPIInfoProvider)
|
||||
otherInfo, _ := android.OtherModuleProvider(result, otherFragment, java.HiddenAPIInfoProvider)
|
||||
|
||||
fooPublicStubs := "out/soong/.intermediates/foo.stubs.exportable/android_common/dex/foo.stubs.exportable.jar"
|
||||
fooSystemStubs := "out/soong/.intermediates/foo.stubs.exportable.system/android_common/dex/foo.stubs.exportable.system.jar"
|
||||
|
|
@ -401,11 +398,20 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) {
|
|||
|
||||
// Make sure that a preferred prebuilt with consistent contents doesn't affect the apex.
|
||||
addPrebuilt(true, "foo", "bar"),
|
||||
android.FixtureMergeMockFs(android.MockFS{
|
||||
"apex_contributions/Android.bp": []byte(`
|
||||
apex_contributions {
|
||||
name: "prebuilt_art_contributions",
|
||||
contents: ["prebuilt_com.android.art"],
|
||||
api_domain: "com.android.art",
|
||||
}
|
||||
`)}),
|
||||
android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ART", "prebuilt_art_contributions"),
|
||||
|
||||
java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"),
|
||||
).RunTest(t)
|
||||
|
||||
ensureExactDeapexedContents(t, result.TestContext, "prebuilt_com.android.art", "android_common", []string{
|
||||
ensureExactDeapexedContents(t, result.TestContext, "prebuilt_com.android.art", "android_common_com.android.art", []string{
|
||||
"etc/boot-image.prof",
|
||||
"javalib/bar.jar",
|
||||
"javalib/foo.jar",
|
||||
|
|
@ -498,6 +504,7 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) {
|
|||
java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
|
||||
dexpreopt.FixtureSetTestOnlyArtBootImageJars("com.android.art:foo", "com.android.art:bar"),
|
||||
java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"),
|
||||
android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ART", "prebuilt_art_contributions"),
|
||||
)
|
||||
|
||||
bp := `
|
||||
|
|
@ -555,6 +562,12 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) {
|
|||
src: "com.mycompany.android.art.apex",
|
||||
exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
|
||||
}
|
||||
|
||||
apex_contributions {
|
||||
name: "prebuilt_art_contributions",
|
||||
contents: ["prebuilt_com.android.art"],
|
||||
api_domain: "com.android.art",
|
||||
}
|
||||
`
|
||||
|
||||
t.Run("disabled alternative APEX", func(t *testing.T) {
|
||||
|
|
@ -564,27 +577,18 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) {
|
|||
`all_apex_contributions`,
|
||||
`dex2oatd`,
|
||||
`prebuilt_art-bootclasspath-fragment`,
|
||||
`prebuilt_com.android.art.apex.selector`,
|
||||
`prebuilt_com.android.art.deapexer`,
|
||||
})
|
||||
|
||||
java.CheckModuleDependencies(t, result.TestContext, "art-bootclasspath-fragment", "android_common_com.android.art", []string{
|
||||
`all_apex_contributions`,
|
||||
`dex2oatd`,
|
||||
`prebuilt_bar`,
|
||||
`prebuilt_com.android.art.deapexer`,
|
||||
`prebuilt_foo`,
|
||||
})
|
||||
|
||||
module := result.ModuleForTests("dex_bootjars", "android_common")
|
||||
checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
|
||||
})
|
||||
|
||||
t.Run("enabled alternative APEX", func(t *testing.T) {
|
||||
preparers.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
|
||||
"Multiple installable prebuilt APEXes provide ambiguous deapexers: prebuilt_com.android.art and prebuilt_com.mycompany.android.art")).
|
||||
RunTestWithBp(t, fmt.Sprintf(bp, ""))
|
||||
})
|
||||
}
|
||||
|
||||
// checkCopiesToPredefinedLocationForArt checks that the supplied modules are copied to the
|
||||
|
|
@ -692,7 +696,7 @@ func TestBootclasspathFragmentContentsNoName(t *testing.T) {
|
|||
// Make sure that the fragment provides the hidden API encoded dex jars to the APEX.
|
||||
fragment := result.Module("mybootclasspathfragment", "android_common_apex10000")
|
||||
|
||||
info, _ := android.SingletonModuleProvider(result, fragment, java.BootclasspathFragmentApexContentInfoProvider)
|
||||
info, _ := android.OtherModuleProvider(result, fragment, java.BootclasspathFragmentApexContentInfoProvider)
|
||||
|
||||
checkFragmentExportedDexJar := func(name string, expectedDexJar string) {
|
||||
module := result.Module(name, "android_common_apex10000")
|
||||
|
|
@ -731,11 +735,7 @@ func TestBootclasspathFragment_HiddenAPIList(t *testing.T) {
|
|||
|
||||
java.PrepareForTestWithJavaSdkLibraryFiles,
|
||||
java.FixtureWithLastReleaseApis("foo", "quuz"),
|
||||
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
|
||||
variables.BuildFlags = map[string]string{
|
||||
"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
|
||||
}
|
||||
}),
|
||||
android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"),
|
||||
).RunTestWithBp(t, `
|
||||
apex {
|
||||
name: "com.android.art",
|
||||
|
|
@ -757,6 +757,7 @@ func TestBootclasspathFragment_HiddenAPIList(t *testing.T) {
|
|||
],
|
||||
srcs: ["b.java"],
|
||||
compile_dex: true,
|
||||
sdk_version: "core_current",
|
||||
}
|
||||
|
||||
java_sdk_library {
|
||||
|
|
@ -841,6 +842,7 @@ func TestBootclasspathFragment_HiddenAPIList(t *testing.T) {
|
|||
`)
|
||||
|
||||
java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
|
||||
"all_apex_contributions",
|
||||
"art-bootclasspath-fragment",
|
||||
"bar",
|
||||
"dex2oatd",
|
||||
|
|
@ -930,6 +932,7 @@ func TestBootclasspathFragment_AndroidNonUpdatable_FromSource(t *testing.T) {
|
|||
],
|
||||
srcs: ["b.java"],
|
||||
compile_dex: true,
|
||||
sdk_version: "core_current",
|
||||
}
|
||||
|
||||
java_library {
|
||||
|
|
@ -1011,6 +1014,7 @@ func TestBootclasspathFragment_AndroidNonUpdatable_FromSource(t *testing.T) {
|
|||
`)
|
||||
|
||||
java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
|
||||
"all_apex_contributions",
|
||||
"android-non-updatable.stubs",
|
||||
"android-non-updatable.stubs.module_lib",
|
||||
"android-non-updatable.stubs.system",
|
||||
|
|
@ -1101,6 +1105,7 @@ func TestBootclasspathFragment_AndroidNonUpdatable_FromText(t *testing.T) {
|
|||
],
|
||||
srcs: ["b.java"],
|
||||
compile_dex: true,
|
||||
sdk_version: "core_current",
|
||||
}
|
||||
|
||||
java_library {
|
||||
|
|
@ -1182,6 +1187,7 @@ func TestBootclasspathFragment_AndroidNonUpdatable_FromText(t *testing.T) {
|
|||
`)
|
||||
|
||||
java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
|
||||
"all_apex_contributions",
|
||||
"android-non-updatable.stubs",
|
||||
"android-non-updatable.stubs.system",
|
||||
"android-non-updatable.stubs.test",
|
||||
|
|
@ -1253,6 +1259,7 @@ func TestBootclasspathFragment_AndroidNonUpdatable_AlwaysUsePrebuiltSdks(t *test
|
|||
],
|
||||
srcs: ["b.java"],
|
||||
compile_dex: true,
|
||||
sdk_version: "core_current",
|
||||
}
|
||||
|
||||
java_library {
|
||||
|
|
@ -1334,6 +1341,7 @@ func TestBootclasspathFragment_AndroidNonUpdatable_AlwaysUsePrebuiltSdks(t *test
|
|||
`)
|
||||
|
||||
java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
|
||||
"all_apex_contributions",
|
||||
"art-bootclasspath-fragment",
|
||||
"bar",
|
||||
"dex2oatd",
|
||||
|
|
|
|||
131
apex/builder.go
131
apex/builder.go
|
|
@ -83,6 +83,7 @@ func init() {
|
|||
pctx.HostBinToolVariable("assemble_vintf", "assemble_vintf")
|
||||
pctx.HostBinToolVariable("apex_elf_checker", "apex_elf_checker")
|
||||
pctx.HostBinToolVariable("aconfig", "aconfig")
|
||||
pctx.HostBinToolVariable("host_apex_verifier", "host_apex_verifier")
|
||||
}
|
||||
|
||||
type createStorageStruct struct {
|
||||
|
|
@ -249,6 +250,13 @@ var (
|
|||
Description: "run apex_linkerconfig_validation",
|
||||
}, "image_dir")
|
||||
|
||||
apexHostVerifierRule = pctx.StaticRule("apexHostVerifierRule", blueprint.RuleParams{
|
||||
Command: `${host_apex_verifier} --deapexer=${deapexer} --debugfs=${debugfs_static} ` +
|
||||
`--fsckerofs=${fsck_erofs} --apex=${in} && touch ${out}`,
|
||||
CommandDeps: []string{"${host_apex_verifier}", "${deapexer}", "${debugfs_static}", "${fsck_erofs}"},
|
||||
Description: "run host_apex_verifier",
|
||||
})
|
||||
|
||||
assembleVintfRule = pctx.StaticRule("assembleVintfRule", blueprint.RuleParams{
|
||||
Command: `rm -f $out && VINTF_IGNORE_TARGET_FCM_VERSION=true ${assemble_vintf} -i $in -o $out`,
|
||||
CommandDeps: []string{"${assemble_vintf}"},
|
||||
|
|
@ -262,6 +270,58 @@ var (
|
|||
}, "tool_path", "unwanted")
|
||||
)
|
||||
|
||||
func (a *apexBundle) buildAconfigFiles(ctx android.ModuleContext) []apexFile {
|
||||
var aconfigFiles android.Paths
|
||||
for _, file := range a.filesInfo {
|
||||
if file.module == nil {
|
||||
continue
|
||||
}
|
||||
if dep, ok := android.OtherModuleProvider(ctx, file.module, android.AconfigPropagatingProviderKey); ok {
|
||||
if len(dep.AconfigFiles) > 0 && dep.AconfigFiles[ctx.ModuleName()] != nil {
|
||||
aconfigFiles = append(aconfigFiles, dep.AconfigFiles[ctx.ModuleName()]...)
|
||||
}
|
||||
}
|
||||
|
||||
validationFlag := ctx.DeviceConfig().AconfigContainerValidation()
|
||||
if validationFlag == "error" || validationFlag == "warning" {
|
||||
android.VerifyAconfigBuildMode(ctx, ctx.ModuleName(), file.module, validationFlag == "error")
|
||||
}
|
||||
}
|
||||
aconfigFiles = android.FirstUniquePaths(aconfigFiles)
|
||||
|
||||
var files []apexFile
|
||||
if len(aconfigFiles) > 0 {
|
||||
apexAconfigFile := android.PathForModuleOut(ctx, "aconfig_flags.pb")
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: aconfig.AllDeclarationsRule,
|
||||
Inputs: aconfigFiles,
|
||||
Output: apexAconfigFile,
|
||||
Description: "combine_aconfig_declarations",
|
||||
Args: map[string]string{
|
||||
"cache_files": android.JoinPathsWithPrefix(aconfigFiles, "--cache "),
|
||||
},
|
||||
})
|
||||
files = append(files, newApexFile(ctx, apexAconfigFile, "aconfig_flags", "etc", etc, nil))
|
||||
|
||||
for _, info := range createStorageInfo {
|
||||
outputFile := android.PathForModuleOut(ctx, info.Output_file)
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: aconfig.CreateStorageRule,
|
||||
Inputs: aconfigFiles,
|
||||
Output: outputFile,
|
||||
Description: info.Desc,
|
||||
Args: map[string]string{
|
||||
"container": ctx.ModuleName(),
|
||||
"file_type": info.File_type,
|
||||
"cache_files": android.JoinPathsWithPrefix(aconfigFiles, "--cache "),
|
||||
},
|
||||
})
|
||||
files = append(files, newApexFile(ctx, outputFile, info.File_type, "etc", etc, nil))
|
||||
}
|
||||
}
|
||||
return files
|
||||
}
|
||||
|
||||
// buildManifest creates buile rules to modify the input apex_manifest.json to add information
|
||||
// gathered by the build system such as provided/required native libraries. Two output files having
|
||||
// different formats are generated. a.manifestJsonOut is JSON format for Q devices, and
|
||||
|
|
@ -595,7 +655,7 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) {
|
|||
if len(installMapSet) > 0 {
|
||||
var installs []string
|
||||
installs = append(installs, android.SortedKeys(installMapSet)...)
|
||||
a.SetLicenseInstallMap(installs)
|
||||
ctx.SetLicenseInstallMap(installs)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -644,48 +704,10 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) {
|
|||
outHostBinDir := ctx.Config().HostToolPath(ctx, "").String()
|
||||
prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
|
||||
|
||||
defaultReadOnlyFiles := []string{"apex_manifest.json", "apex_manifest.pb"}
|
||||
aconfigDest := imageDir.Join(ctx, "etc").String()
|
||||
if len(a.aconfigFiles) > 0 {
|
||||
apexAconfigFile := android.PathForModuleOut(ctx, "aconfig_flags.pb")
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: aconfig.AllDeclarationsRule,
|
||||
Inputs: a.aconfigFiles,
|
||||
Output: apexAconfigFile,
|
||||
Description: "combine_aconfig_declarations",
|
||||
Args: map[string]string{
|
||||
"cache_files": android.JoinPathsWithPrefix(a.aconfigFiles, "--cache "),
|
||||
},
|
||||
})
|
||||
|
||||
copyCommands = append(copyCommands, "cp -f "+apexAconfigFile.String()+" "+aconfigDest)
|
||||
implicitInputs = append(implicitInputs, apexAconfigFile)
|
||||
defaultReadOnlyFiles = append(defaultReadOnlyFiles, "etc/"+apexAconfigFile.Base())
|
||||
|
||||
for _, info := range createStorageInfo {
|
||||
outputFile := android.PathForModuleOut(ctx, info.Output_file)
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: aconfig.CreateStorageRule,
|
||||
Inputs: a.aconfigFiles,
|
||||
Output: outputFile,
|
||||
Description: info.Desc,
|
||||
Args: map[string]string{
|
||||
"container": ctx.ModuleName(),
|
||||
"file_type": info.File_type,
|
||||
"cache_files": android.JoinPathsWithPrefix(a.aconfigFiles, "--cache "),
|
||||
},
|
||||
})
|
||||
|
||||
copyCommands = append(copyCommands, "cp -f "+outputFile.String()+" "+aconfigDest)
|
||||
implicitInputs = append(implicitInputs, outputFile)
|
||||
defaultReadOnlyFiles = append(defaultReadOnlyFiles, "etc/"+outputFile.Base())
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
// Step 2: create canned_fs_config which encodes filemode,uid,gid of each files
|
||||
// in this APEX. The file will be used by apexer in later steps.
|
||||
cannedFsConfig := a.buildCannedFsConfig(ctx, defaultReadOnlyFiles)
|
||||
cannedFsConfig := a.buildCannedFsConfig(ctx)
|
||||
implicitInputs = append(implicitInputs, cannedFsConfig)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -767,18 +789,6 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) {
|
|||
implicitInputs = append(implicitInputs, noticeAssetPath)
|
||||
optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeAssetPath.String()))
|
||||
|
||||
// Apexes which are supposed to be installed in builtin dirs(/system, etc)
|
||||
// don't need hashtree for activation. Therefore, by removing hashtree from
|
||||
// apex bundle (filesystem image in it, to be specific), we can save storage.
|
||||
needHashTree := moduleMinSdkVersion.LessThanOrEqualTo(android.SdkVersion_Android10) ||
|
||||
a.shouldGenerateHashtree()
|
||||
if ctx.Config().ApexCompressionEnabled() && a.isCompressable() {
|
||||
needHashTree = true
|
||||
}
|
||||
if !needHashTree {
|
||||
optFlags = append(optFlags, "--no_hashtree")
|
||||
}
|
||||
|
||||
if a.testOnlyShouldSkipPayloadSign() {
|
||||
optFlags = append(optFlags, "--unsigned_payload")
|
||||
}
|
||||
|
|
@ -952,6 +962,9 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) {
|
|||
validations = append(validations,
|
||||
runApexElfCheckerUnwanted(ctx, unsignedOutputFile.OutputPath, a.properties.Unwanted_transitive_deps))
|
||||
}
|
||||
if !a.testApex && android.InList(a.payloadFsType, []fsType{ext4, erofs}) {
|
||||
validations = append(validations, runApexHostVerifier(ctx, unsignedOutputFile.OutputPath))
|
||||
}
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: rule,
|
||||
Description: "signapk",
|
||||
|
|
@ -1139,8 +1152,8 @@ func (a *apexBundle) buildLintReports(ctx android.ModuleContext) {
|
|||
a.lintReports = java.BuildModuleLintReportZips(ctx, depSetsBuilder.Build())
|
||||
}
|
||||
|
||||
func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext, defaultReadOnlyFiles []string) android.OutputPath {
|
||||
var readOnlyPaths = defaultReadOnlyFiles
|
||||
func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.OutputPath {
|
||||
var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"}
|
||||
var executablePaths []string // this also includes dirs
|
||||
var appSetDirs []string
|
||||
appSetFiles := make(map[string]android.Path)
|
||||
|
|
@ -1246,3 +1259,13 @@ func runApexElfCheckerUnwanted(ctx android.ModuleContext, apexFile android.Outpu
|
|||
})
|
||||
return timestamp
|
||||
}
|
||||
|
||||
func runApexHostVerifier(ctx android.ModuleContext, apexFile android.OutputPath) android.Path {
|
||||
timestamp := android.PathForModuleOut(ctx, "host_apex_verifier.timestamp")
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: apexHostVerifierRule,
|
||||
Input: apexFile,
|
||||
Output: timestamp,
|
||||
})
|
||||
return timestamp
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ func TestCreateClasspathElements(t *testing.T) {
|
|||
],
|
||||
srcs: ["b.java"],
|
||||
installable: true,
|
||||
sdk_version: "core_current",
|
||||
}
|
||||
|
||||
java_library {
|
||||
|
|
|
|||
337
apex/container_test.go
Normal file
337
apex/container_test.go
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
// 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 apex
|
||||
|
||||
import (
|
||||
"android/soong/android"
|
||||
"android/soong/java"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var checkContainerMatch = func(t *testing.T, name string, container string, expected bool, actual bool) {
|
||||
errorMessage := fmt.Sprintf("module %s container %s value differ", name, container)
|
||||
android.AssertBoolEquals(t, errorMessage, expected, actual)
|
||||
}
|
||||
|
||||
func TestApexDepsContainers(t *testing.T) {
|
||||
result := android.GroupFixturePreparers(
|
||||
prepareForApexTest,
|
||||
java.PrepareForTestWithJavaSdkLibraryFiles,
|
||||
java.FixtureWithLastReleaseApis("mybootclasspathlib", "bar"),
|
||||
).RunTestWithBp(t, `
|
||||
apex {
|
||||
name: "myapex",
|
||||
key: "myapex.key",
|
||||
bootclasspath_fragments: [
|
||||
"mybootclasspathfragment",
|
||||
],
|
||||
updatable: true,
|
||||
min_sdk_version: "30",
|
||||
}
|
||||
apex_key {
|
||||
name: "myapex.key",
|
||||
public_key: "testkey.avbpubkey",
|
||||
private_key: "testkey.pem",
|
||||
}
|
||||
bootclasspath_fragment {
|
||||
name: "mybootclasspathfragment",
|
||||
contents: [
|
||||
"mybootclasspathlib",
|
||||
],
|
||||
apex_available: [
|
||||
"myapex",
|
||||
],
|
||||
hidden_api: {
|
||||
split_packages: ["*"],
|
||||
},
|
||||
}
|
||||
java_sdk_library {
|
||||
name: "mybootclasspathlib",
|
||||
srcs: [
|
||||
"mybootclasspathlib.java",
|
||||
],
|
||||
apex_available: [
|
||||
"myapex",
|
||||
],
|
||||
compile_dex: true,
|
||||
static_libs: [
|
||||
"food",
|
||||
"baz",
|
||||
],
|
||||
libs: [
|
||||
"bar.stubs",
|
||||
],
|
||||
min_sdk_version: "30",
|
||||
sdk_version: "current",
|
||||
}
|
||||
java_library {
|
||||
name: "food",
|
||||
srcs:[
|
||||
"A.java",
|
||||
],
|
||||
apex_available: [
|
||||
"myapex",
|
||||
],
|
||||
min_sdk_version: "30",
|
||||
sdk_version: "core_current",
|
||||
}
|
||||
java_sdk_library {
|
||||
name: "bar",
|
||||
srcs:[
|
||||
"A.java",
|
||||
],
|
||||
min_sdk_version: "30",
|
||||
sdk_version: "core_current",
|
||||
}
|
||||
java_library {
|
||||
name: "baz",
|
||||
srcs:[
|
||||
"A.java",
|
||||
],
|
||||
apex_available: [
|
||||
"//apex_available:platform",
|
||||
"myapex",
|
||||
],
|
||||
min_sdk_version: "30",
|
||||
sdk_version: "core_current",
|
||||
}
|
||||
`)
|
||||
testcases := []struct {
|
||||
moduleName string
|
||||
variant string
|
||||
isSystemContainer bool
|
||||
isApexContainer bool
|
||||
}{
|
||||
{
|
||||
moduleName: "mybootclasspathlib",
|
||||
variant: "android_common_myapex",
|
||||
isSystemContainer: true,
|
||||
isApexContainer: true,
|
||||
},
|
||||
{
|
||||
moduleName: "mybootclasspathlib.impl",
|
||||
variant: "android_common_apex30",
|
||||
isSystemContainer: true,
|
||||
isApexContainer: true,
|
||||
},
|
||||
{
|
||||
moduleName: "mybootclasspathlib.stubs",
|
||||
variant: "android_common",
|
||||
isSystemContainer: true,
|
||||
isApexContainer: false,
|
||||
},
|
||||
{
|
||||
moduleName: "food",
|
||||
variant: "android_common_apex30",
|
||||
isSystemContainer: true,
|
||||
isApexContainer: true,
|
||||
},
|
||||
{
|
||||
moduleName: "bar",
|
||||
variant: "android_common",
|
||||
isSystemContainer: true,
|
||||
isApexContainer: false,
|
||||
},
|
||||
{
|
||||
moduleName: "baz",
|
||||
variant: "android_common_apex30",
|
||||
isSystemContainer: true,
|
||||
isApexContainer: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range testcases {
|
||||
m := result.ModuleForTests(c.moduleName, c.variant)
|
||||
containers, _ := android.OtherModuleProvider(result.TestContext.OtherModuleProviderAdaptor(), m.Module(), android.ContainersInfoProvider)
|
||||
belongingContainers := containers.BelongingContainers()
|
||||
checkContainerMatch(t, c.moduleName, "system", c.isSystemContainer, android.InList(android.SystemContainer, belongingContainers))
|
||||
checkContainerMatch(t, c.moduleName, "apex", c.isApexContainer, android.InList(android.ApexContainer, belongingContainers))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonUpdatableApexDepsContainers(t *testing.T) {
|
||||
result := android.GroupFixturePreparers(
|
||||
prepareForApexTest,
|
||||
java.PrepareForTestWithJavaSdkLibraryFiles,
|
||||
java.FixtureWithLastReleaseApis("mybootclasspathlib", "bar"),
|
||||
).RunTestWithBp(t, `
|
||||
apex {
|
||||
name: "myapex",
|
||||
key: "myapex.key",
|
||||
bootclasspath_fragments: [
|
||||
"mybootclasspathfragment",
|
||||
],
|
||||
updatable: false,
|
||||
}
|
||||
apex_key {
|
||||
name: "myapex.key",
|
||||
public_key: "testkey.avbpubkey",
|
||||
private_key: "testkey.pem",
|
||||
}
|
||||
bootclasspath_fragment {
|
||||
name: "mybootclasspathfragment",
|
||||
contents: [
|
||||
"mybootclasspathlib",
|
||||
],
|
||||
apex_available: [
|
||||
"myapex",
|
||||
],
|
||||
hidden_api: {
|
||||
split_packages: ["*"],
|
||||
},
|
||||
}
|
||||
java_sdk_library {
|
||||
name: "mybootclasspathlib",
|
||||
srcs: [
|
||||
"mybootclasspathlib.java",
|
||||
],
|
||||
apex_available: [
|
||||
"myapex",
|
||||
],
|
||||
compile_dex: true,
|
||||
static_libs: [
|
||||
"food",
|
||||
],
|
||||
libs: [
|
||||
"bar.stubs",
|
||||
],
|
||||
sdk_version: "current",
|
||||
}
|
||||
java_library {
|
||||
name: "food",
|
||||
srcs:[
|
||||
"A.java",
|
||||
],
|
||||
apex_available: [
|
||||
"myapex",
|
||||
],
|
||||
sdk_version: "core_current",
|
||||
}
|
||||
java_sdk_library {
|
||||
name: "bar",
|
||||
srcs:[
|
||||
"A.java",
|
||||
],
|
||||
sdk_version: "none",
|
||||
system_modules: "none",
|
||||
}
|
||||
`)
|
||||
testcases := []struct {
|
||||
moduleName string
|
||||
variant string
|
||||
isSystemContainer bool
|
||||
isApexContainer bool
|
||||
}{
|
||||
{
|
||||
moduleName: "mybootclasspathlib",
|
||||
variant: "android_common_myapex",
|
||||
isSystemContainer: true,
|
||||
isApexContainer: true,
|
||||
},
|
||||
{
|
||||
moduleName: "mybootclasspathlib.impl",
|
||||
variant: "android_common_apex10000",
|
||||
isSystemContainer: true,
|
||||
isApexContainer: true,
|
||||
},
|
||||
{
|
||||
moduleName: "mybootclasspathlib.stubs",
|
||||
variant: "android_common",
|
||||
isSystemContainer: true,
|
||||
isApexContainer: false,
|
||||
},
|
||||
{
|
||||
moduleName: "food",
|
||||
variant: "android_common_apex10000",
|
||||
isSystemContainer: true,
|
||||
isApexContainer: true,
|
||||
},
|
||||
{
|
||||
moduleName: "bar",
|
||||
variant: "android_common",
|
||||
isSystemContainer: true,
|
||||
isApexContainer: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range testcases {
|
||||
m := result.ModuleForTests(c.moduleName, c.variant)
|
||||
containers, _ := android.OtherModuleProvider(result.TestContext.OtherModuleProviderAdaptor(), m.Module(), android.ContainersInfoProvider)
|
||||
belongingContainers := containers.BelongingContainers()
|
||||
checkContainerMatch(t, c.moduleName, "system", c.isSystemContainer, android.InList(android.SystemContainer, belongingContainers))
|
||||
checkContainerMatch(t, c.moduleName, "apex", c.isApexContainer, android.InList(android.ApexContainer, belongingContainers))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdatableAndNonUpdatableApexesIdenticalMinSdkVersion(t *testing.T) {
|
||||
result := android.GroupFixturePreparers(
|
||||
prepareForApexTest,
|
||||
java.PrepareForTestWithJavaSdkLibraryFiles,
|
||||
android.FixtureMergeMockFs(android.MockFS{
|
||||
"system/sepolicy/apex/myapex_non_updatable-file_contexts": nil,
|
||||
"system/sepolicy/apex/myapex_updatable-file_contexts": nil,
|
||||
}),
|
||||
).RunTestWithBp(t, `
|
||||
apex {
|
||||
name: "myapex_non_updatable",
|
||||
key: "myapex_non_updatable.key",
|
||||
java_libs: [
|
||||
"foo",
|
||||
],
|
||||
updatable: false,
|
||||
min_sdk_version: "30",
|
||||
}
|
||||
apex_key {
|
||||
name: "myapex_non_updatable.key",
|
||||
public_key: "testkey.avbpubkey",
|
||||
private_key: "testkey.pem",
|
||||
}
|
||||
|
||||
apex {
|
||||
name: "myapex_updatable",
|
||||
key: "myapex_updatable.key",
|
||||
java_libs: [
|
||||
"foo",
|
||||
],
|
||||
updatable: true,
|
||||
min_sdk_version: "30",
|
||||
}
|
||||
apex_key {
|
||||
name: "myapex_updatable.key",
|
||||
public_key: "testkey.avbpubkey",
|
||||
private_key: "testkey.pem",
|
||||
}
|
||||
|
||||
java_library {
|
||||
name: "foo",
|
||||
srcs:[
|
||||
"A.java",
|
||||
],
|
||||
apex_available: [
|
||||
"myapex_non_updatable",
|
||||
"myapex_updatable",
|
||||
],
|
||||
min_sdk_version: "30",
|
||||
sdk_version: "current",
|
||||
}
|
||||
`)
|
||||
|
||||
fooApexVariant := result.ModuleForTests("foo", "android_common_apex30")
|
||||
containers, _ := android.OtherModuleProvider(result.TestContext.OtherModuleProviderAdaptor(), fooApexVariant.Module(), android.ContainersInfoProvider)
|
||||
belongingContainers := containers.BelongingContainers()
|
||||
checkContainerMatch(t, "foo", "system", true, android.InList(android.SystemContainer, belongingContainers))
|
||||
checkContainerMatch(t, "foo", "apex", true, android.InList(android.ApexContainer, belongingContainers))
|
||||
}
|
||||
|
|
@ -15,37 +15,9 @@
|
|||
package apex
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"android/soong/android"
|
||||
)
|
||||
|
||||
// Contains 'deapexer' a private module type used by 'prebuilt_apex' to make dex files contained
|
||||
// within a .apex file referenced by `prebuilt_apex` available for use by their associated
|
||||
// `java_import` modules.
|
||||
//
|
||||
// An 'apex' module references `java_library` modules from which .dex files are obtained that are
|
||||
// stored in the resulting `.apex` file. The resulting `.apex` file is then made available as a
|
||||
// prebuilt by referencing it from a `prebuilt_apex`. For each such `java_library` that is used by
|
||||
// modules outside the `.apex` file a `java_import` prebuilt is made available referencing a jar
|
||||
// that contains the Java classes.
|
||||
//
|
||||
// When building a Java module type, e.g. `java_module` or `android_app` against such prebuilts the
|
||||
// `java_import` provides the classes jar (jar containing `.class` files) against which the
|
||||
// module's `.java` files are compiled. That classes jar usually contains only stub classes. The
|
||||
// resulting classes jar is converted into a dex jar (jar containing `.dex` files). Then if
|
||||
// necessary the dex jar is further processed by `dexpreopt` to produce an optimized form of the
|
||||
// library specific to the current Android version. This process requires access to implementation
|
||||
// dex jars for each `java_import`. The `java_import` will obtain the implementation dex jar from
|
||||
// the `.apex` file in the associated `prebuilt_apex`.
|
||||
//
|
||||
// This is intentionally not registered by name as it is not intended to be used from within an
|
||||
// `Android.bp` file.
|
||||
|
||||
// DeapexerProperties specifies the properties supported by the deapexer module.
|
||||
//
|
||||
// As these are never intended to be supplied in a .bp file they use a different naming convention
|
||||
// to make it clear that they are different.
|
||||
type DeapexerProperties struct {
|
||||
// List of common modules that may need access to files exported by this module.
|
||||
//
|
||||
|
|
@ -72,46 +44,9 @@ type SelectedApexProperties struct {
|
|||
Selected_apex *string `android:"path" blueprint:"mutated"`
|
||||
}
|
||||
|
||||
type Deapexer struct {
|
||||
android.ModuleBase
|
||||
|
||||
properties DeapexerProperties
|
||||
selectedApexProperties SelectedApexProperties
|
||||
|
||||
inputApex android.Path
|
||||
}
|
||||
|
||||
// Returns the name of the deapexer module corresponding to an APEX module with the given name.
|
||||
func deapexerModuleName(apexModuleName string) string {
|
||||
return apexModuleName + ".deapexer"
|
||||
}
|
||||
|
||||
// Returns the name of the APEX module corresponding to an deapexer module with
|
||||
// the given name. This reverses deapexerModuleName.
|
||||
func apexModuleName(deapexerModuleName string) string {
|
||||
return strings.TrimSuffix(deapexerModuleName, ".deapexer")
|
||||
}
|
||||
|
||||
func privateDeapexerFactory() android.Module {
|
||||
module := &Deapexer{}
|
||||
module.AddProperties(&module.properties, &module.selectedApexProperties)
|
||||
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
|
||||
return module
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Deapexer) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||
p.inputApex = android.OptionalPathForModuleSrc(ctx, p.selectedApexProperties.Selected_apex).Path()
|
||||
|
||||
// deapex creates the build rules to deapex a prebuilt .apex file
|
||||
// it returns a pointer to a DeapexerInfo object
|
||||
func deapex(ctx android.ModuleContext, apexFile android.Path, deapexerProps DeapexerProperties) *android.DeapexerInfo {
|
||||
// Create and remember the directory into which the .apex file's contents will be unpacked.
|
||||
deapexerOutput := android.PathForModuleOut(ctx, "deapexer")
|
||||
|
||||
|
|
@ -119,7 +54,7 @@ func (p *Deapexer) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
|
||||
// Create mappings from apex relative path to the extracted file's path.
|
||||
exportedPaths := make(android.Paths, 0, len(exports))
|
||||
for _, path := range p.properties.ExportedFiles {
|
||||
for _, path := range deapexerProps.ExportedFiles {
|
||||
// Populate the exports that this makes available.
|
||||
extractedPath := deapexerOutput.Join(ctx, path)
|
||||
exports[path] = extractedPath
|
||||
|
|
@ -131,9 +66,8 @@ func (p *Deapexer) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
// 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, p.properties.CommonModules)
|
||||
di.AddDexpreoptProfileGuidedExportedModuleNames(p.properties.DexpreoptProfileGuidedModules...)
|
||||
android.SetProvider(ctx, android.DeapexerProvider, di)
|
||||
di := android.NewDeapexerInfo(ctx.ModuleName(), exports, deapexerProps.CommonModules)
|
||||
di.AddDexpreoptProfileGuidedExportedModuleNames(deapexerProps.DexpreoptProfileGuidedModules...)
|
||||
|
||||
// Create a sorted list of the files that this exports.
|
||||
exportedPaths = android.SortedUniquePaths(exportedPaths)
|
||||
|
|
@ -147,11 +81,13 @@ func (p *Deapexer) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
BuiltTool("deapexer").
|
||||
BuiltTool("debugfs").
|
||||
BuiltTool("fsck.erofs").
|
||||
Input(p.inputApex).
|
||||
Input(apexFile).
|
||||
Text(deapexerOutput.String())
|
||||
for _, p := range exportedPaths {
|
||||
command.Output(p.(android.WritablePath))
|
||||
}
|
||||
builder.Build("deapexer", "deapex "+apexModuleName(ctx.ModuleName()))
|
||||
builder.Build("deapexer", "deapex "+ctx.ModuleName())
|
||||
return &di
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,16 +127,29 @@ func testDexpreoptBoot(t *testing.T, ruleFile string, expectedInputs, expectedOu
|
|||
src: "com.android.art-arm.apex",
|
||||
exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
|
||||
}
|
||||
|
||||
apex_contributions {
|
||||
name: "prebuilt_art_contributions",
|
||||
contents: ["prebuilt_com.android.art"],
|
||||
api_domain: "com.android.art",
|
||||
}
|
||||
`
|
||||
|
||||
result := android.GroupFixturePreparers(
|
||||
fixture := android.GroupFixturePreparers(
|
||||
java.PrepareForTestWithDexpreopt,
|
||||
java.PrepareForTestWithJavaSdkLibraryFiles,
|
||||
java.FixtureWithLastReleaseApis("foo"),
|
||||
java.FixtureConfigureBootJars("com.android.art:core-oj", "platform:foo", "system_ext:bar", "platform:baz"),
|
||||
PrepareForTestWithApexBuildComponents,
|
||||
prepareForTestWithArtApex,
|
||||
).RunTestWithBp(t, fmt.Sprintf(bp, preferPrebuilt))
|
||||
)
|
||||
if preferPrebuilt {
|
||||
fixture = android.GroupFixturePreparers(
|
||||
fixture,
|
||||
android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ART", "prebuilt_art_contributions"),
|
||||
)
|
||||
}
|
||||
result := fixture.RunTestWithBp(t, fmt.Sprintf(bp, preferPrebuilt))
|
||||
|
||||
dexBootJars := result.ModuleForTests("dex_bootjars", "android_common")
|
||||
rule := dexBootJars.Output(ruleFile)
|
||||
|
|
@ -200,7 +213,7 @@ func TestDexpreoptBootJarsWithPrebuiltArtApex(t *testing.T) {
|
|||
"out/soong/dexpreopt_arm64/dex_bootjars_input/foo.jar",
|
||||
"out/soong/dexpreopt_arm64/dex_bootjars_input/bar.jar",
|
||||
"out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar",
|
||||
"out/soong/.intermediates/prebuilt_com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof",
|
||||
"out/soong/.intermediates/prebuilt_com.android.art/android_common_com.android.art/deapexer/etc/boot-image.prof",
|
||||
"out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof",
|
||||
"out/soong/dexpreopt/uffd_gc_flag.txt",
|
||||
}
|
||||
|
|
@ -384,12 +397,12 @@ func TestDexpreoptProfileWithMultiplePrebuiltArtApexes(t *testing.T) {
|
|||
{
|
||||
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/prebuilt_com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof",
|
||||
expectedProfile: "out/soong/.intermediates/prebuilt_com.android.art/android_common_com.android.art/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/prebuilt_com.android.art.v2.deapexer/android_common/deapexer/etc/boot-image.prof",
|
||||
expectedProfile: "out/soong/.intermediates/com.android.art.v2/android_common_com.android.art/deapexer/etc/boot-image.prof",
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
|
|
@ -399,11 +412,7 @@ func TestDexpreoptProfileWithMultiplePrebuiltArtApexes(t *testing.T) {
|
|||
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,
|
||||
}
|
||||
}),
|
||||
android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ART", tc.selectedArtApexContributions),
|
||||
).RunTestWithBp(t, bp)
|
||||
|
||||
dexBootJars := result.ModuleForTests("dex_bootjars", "android_common")
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ func TestPlatformBootclasspath_Fragments(t *testing.T) {
|
|||
).RunTest(t)
|
||||
|
||||
pbcp := result.Module("platform-bootclasspath", "android_common")
|
||||
info, _ := android.SingletonModuleProvider(result, pbcp, java.MonolithicHiddenAPIInfoProvider)
|
||||
info, _ := android.OtherModuleProvider(result, pbcp, java.MonolithicHiddenAPIInfoProvider)
|
||||
|
||||
for _, category := range java.HiddenAPIFlagFileCategories {
|
||||
name := category.PropertyName()
|
||||
|
|
@ -236,7 +236,7 @@ func TestPlatformBootclasspath_LegacyPrebuiltFragment(t *testing.T) {
|
|||
)
|
||||
|
||||
pbcp := result.Module("myplatform-bootclasspath", "android_common")
|
||||
info, _ := android.SingletonModuleProvider(result, pbcp, java.MonolithicHiddenAPIInfoProvider)
|
||||
info, _ := android.OtherModuleProvider(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())
|
||||
|
|
@ -254,11 +254,7 @@ func TestPlatformBootclasspathDependencies(t *testing.T) {
|
|||
java.FixtureWithLastReleaseApis("foo"),
|
||||
java.PrepareForTestWithDexpreopt,
|
||||
dexpreopt.FixtureDisableDexpreoptBootImages(false),
|
||||
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
|
||||
variables.BuildFlags = map[string]string{
|
||||
"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
|
||||
}
|
||||
}),
|
||||
android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"),
|
||||
).RunTestWithBp(t, `
|
||||
apex {
|
||||
name: "com.android.art",
|
||||
|
|
@ -297,6 +293,7 @@ func TestPlatformBootclasspathDependencies(t *testing.T) {
|
|||
],
|
||||
srcs: ["b.java"],
|
||||
installable: true,
|
||||
sdk_version: "core_current",
|
||||
}
|
||||
|
||||
// Add a java_import that is not preferred and so won't have an appropriate apex variant created
|
||||
|
|
@ -429,10 +426,9 @@ func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) {
|
|||
java.PrepareForTestWithJavaSdkLibraryFiles,
|
||||
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
|
||||
variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
|
||||
variables.BuildFlags = map[string]string{
|
||||
"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
|
||||
}
|
||||
}),
|
||||
android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"),
|
||||
|
||||
java.FixtureWithPrebuiltApis(map[string][]string{
|
||||
"current": {},
|
||||
"30": {"foo"},
|
||||
|
|
@ -796,6 +792,128 @@ func TestNonBootJarInFragment(t *testing.T) {
|
|||
`)
|
||||
}
|
||||
|
||||
// Skip bcp_fragment content validation of source apexes if prebuilts are active.
|
||||
func TestNonBootJarInPrebuilts(t *testing.T) {
|
||||
testCases := []struct {
|
||||
description string
|
||||
selectedApexContributions string
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
description: "source is active",
|
||||
selectedApexContributions: "",
|
||||
expectedError: "in contents must also be declared in PRODUCT_APEX_BOOT_JARS",
|
||||
},
|
||||
{
|
||||
description: "prebuilts are active",
|
||||
selectedApexContributions: "myapex.prebuilt.contributions",
|
||||
expectedError: "", // skip content validation of source bcp fragment
|
||||
},
|
||||
}
|
||||
bp := `
|
||||
// Source
|
||||
apex {
|
||||
name: "myapex",
|
||||
key: "myapex.key",
|
||||
bootclasspath_fragments: ["apex-fragment"],
|
||||
updatable: false,
|
||||
min_sdk_version: "29",
|
||||
}
|
||||
|
||||
override_apex {
|
||||
name: "myapex.override", // overrides the min_sdk_version, thereby creating different variants of its transitive deps
|
||||
base: "myapex",
|
||||
min_sdk_version: "34",
|
||||
}
|
||||
|
||||
apex_key {
|
||||
name: "myapex.key",
|
||||
public_key: "testkey.avbpubkey",
|
||||
private_key: "testkey.pem",
|
||||
}
|
||||
|
||||
java_library {
|
||||
name: "foo",
|
||||
srcs: ["b.java"],
|
||||
installable: true,
|
||||
apex_available: ["myapex"],
|
||||
permitted_packages: ["foo"],
|
||||
min_sdk_version: "29",
|
||||
}
|
||||
|
||||
java_library {
|
||||
name: "bar",
|
||||
srcs: ["b.java"],
|
||||
installable: true,
|
||||
apex_available: ["myapex"],
|
||||
permitted_packages: ["bar"],
|
||||
min_sdk_version: "29",
|
||||
}
|
||||
|
||||
bootclasspath_fragment {
|
||||
name: "apex-fragment",
|
||||
contents: ["foo", "bar"],
|
||||
apex_available:[ "myapex" ],
|
||||
hidden_api: {
|
||||
split_packages: ["*"],
|
||||
},
|
||||
}
|
||||
|
||||
platform_bootclasspath {
|
||||
name: "myplatform-bootclasspath",
|
||||
fragments: [{
|
||||
apex: "myapex",
|
||||
module:"apex-fragment",
|
||||
}],
|
||||
}
|
||||
|
||||
// prebuilts
|
||||
prebuilt_apex {
|
||||
name: "myapex",
|
||||
apex_name: "myapex",
|
||||
src: "myapex.apex",
|
||||
exported_bootclasspath_fragments: ["apex-fragment"],
|
||||
}
|
||||
|
||||
prebuilt_bootclasspath_fragment {
|
||||
name: "apex-fragment",
|
||||
contents: ["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",
|
||||
},
|
||||
}
|
||||
java_import {
|
||||
name: "foo",
|
||||
jars: ["foo.jar"],
|
||||
}
|
||||
|
||||
apex_contributions {
|
||||
name: "myapex.prebuilt.contributions",
|
||||
api_domain: "myapex",
|
||||
contents: ["prebuilt_myapex"],
|
||||
}
|
||||
`
|
||||
|
||||
for _, tc := range testCases {
|
||||
fixture := android.GroupFixturePreparers(
|
||||
prepareForTestWithPlatformBootclasspath,
|
||||
PrepareForTestWithApexBuildComponents,
|
||||
prepareForTestWithMyapex,
|
||||
java.FixtureConfigureApexBootJars("myapex:foo"),
|
||||
android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ADSERVICES", tc.selectedApexContributions),
|
||||
)
|
||||
if tc.expectedError != "" {
|
||||
fixture = fixture.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(tc.expectedError))
|
||||
}
|
||||
fixture.RunTestWithBp(t, bp)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Source and prebuilt apex provide different set of boot jars
|
||||
func TestNonBootJarMissingInPrebuiltFragment(t *testing.T) {
|
||||
bp := `
|
||||
|
|
@ -935,11 +1053,7 @@ func TestNonBootJarMissingInPrebuiltFragment(t *testing.T) {
|
|||
PrepareForTestWithApexBuildComponents,
|
||||
prepareForTestWithMyapex,
|
||||
java.FixtureConfigureApexBootJars(tc.configuredBootJars...),
|
||||
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
|
||||
variables.BuildFlags = map[string]string{
|
||||
"RELEASE_APEX_CONTRIBUTIONS_ART": "my_apex_contributions",
|
||||
}
|
||||
}),
|
||||
android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ART", "my_apex_contributions"),
|
||||
)
|
||||
if tc.errorExpected {
|
||||
fixture = fixture.ExtendWithErrorHandler(
|
||||
|
|
|
|||
423
apex/prebuilt.go
423
apex/prebuilt.go
|
|
@ -15,9 +15,6 @@
|
|||
package apex
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
|
@ -42,6 +39,11 @@ var (
|
|||
CommandDeps: []string{"${extract_apks}"},
|
||||
},
|
||||
"abis", "allow-prereleased", "sdk-version", "skip-sdk-check")
|
||||
decompressApex = pctx.StaticRule("decompressApex", blueprint.RuleParams{
|
||||
Command: `rm -rf $out && ${deapexer} decompress --copy-if-uncompressed --input ${in} --output ${out}`,
|
||||
CommandDeps: []string{"${deapexer}"},
|
||||
Description: "decompress $out",
|
||||
})
|
||||
)
|
||||
|
||||
type prebuilt interface {
|
||||
|
|
@ -65,10 +67,6 @@ type prebuiltCommon struct {
|
|||
// fragment for this apex for apexkeys.txt
|
||||
apexKeysPath android.WritablePath
|
||||
|
||||
// A list of apexFile objects created in prebuiltCommon.initApexFilesForAndroidMk which are used
|
||||
// to create make modules in prebuiltCommon.AndroidMkEntries.
|
||||
apexFilesForAndroidMk []apexFile
|
||||
|
||||
// Installed locations of symlinks for backward compatibility.
|
||||
compatSymlinks android.InstallPaths
|
||||
|
||||
|
|
@ -109,11 +107,6 @@ type PrebuiltCommonProperties struct {
|
|||
// from PRODUCT_PACKAGES.
|
||||
Overrides []string
|
||||
|
||||
// List of java libraries that are embedded inside this prebuilt APEX bundle and for which this
|
||||
// APEX bundle will create an APEX variant and provide dex implementation jars for use by
|
||||
// dexpreopt and boot jars package check.
|
||||
Exported_java_libs []string
|
||||
|
||||
// List of bootclasspath fragments inside this prebuilt APEX bundle and for which this APEX
|
||||
// bundle will create an APEX variant.
|
||||
Exported_bootclasspath_fragments []string
|
||||
|
|
@ -197,14 +190,12 @@ func (p *prebuiltCommon) initApexFilesForAndroidMk(ctx android.ModuleContext) {
|
|||
// 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())
|
||||
install.PackageFile(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// 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() {
|
||||
func (p *prebuiltCommon) dexpreoptSystemServerJars(ctx android.ModuleContext, di *android.DeapexerInfo) {
|
||||
if di == nil {
|
||||
return
|
||||
}
|
||||
// If this prebuilt apex has not been selected, return
|
||||
|
|
@ -213,10 +204,7 @@ func (p *prebuiltCommon) dexpreoptSystemServerJars(ctx android.ModuleContext) {
|
|||
}
|
||||
// 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())
|
||||
}
|
||||
// TODO: do not compute twice
|
||||
dc := dexpreopt.GetGlobalConfig(ctx)
|
||||
systemServerJarList := dc.AllApexSystemServerJars(ctx)
|
||||
|
||||
|
|
@ -231,11 +219,6 @@ func (p *prebuiltCommon) dexpreoptSystemServerJars(ctx android.ModuleContext) {
|
|||
}
|
||||
|
||||
func (p *prebuiltCommon) addRequiredModules(entries *android.AndroidMkEntries) {
|
||||
for _, fi := range p.apexFilesForAndroidMk {
|
||||
entries.AddStrings("LOCAL_REQUIRED_MODULES", fi.requiredModuleNames...)
|
||||
entries.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", fi.targetRequiredModuleNames...)
|
||||
entries.AddStrings("LOCAL_HOST_REQUIRED_MODULES", fi.hostRequiredModuleNames...)
|
||||
}
|
||||
entries.AddStrings("LOCAL_REQUIRED_MODULES", p.requiredModuleNames...)
|
||||
}
|
||||
|
||||
|
|
@ -267,77 +250,11 @@ func (p *prebuiltCommon) AndroidMkEntries() []android.AndroidMkEntries {
|
|||
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.
|
||||
apexName := p.BaseModuleName()
|
||||
for _, fi := range p.apexFilesForAndroidMk {
|
||||
entries := p.createEntriesForApexFile(fi, apexName)
|
||||
entriesList = append(entriesList, entries)
|
||||
}
|
||||
|
||||
return entriesList
|
||||
}
|
||||
|
||||
// createEntriesForApexFile creates an AndroidMkEntries for the supplied apexFile
|
||||
func (p *prebuiltCommon) createEntriesForApexFile(fi apexFile, apexName string) android.AndroidMkEntries {
|
||||
moduleName := fi.androidMkModuleName + "." + apexName
|
||||
entries := android.AndroidMkEntries{
|
||||
Class: fi.class.nameInMake(),
|
||||
OverrideName: moduleName,
|
||||
OutputFile: android.OptionalPathForPath(fi.builtFile),
|
||||
Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
|
||||
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
|
||||
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
|
||||
entries.SetString("LOCAL_MODULE_PATH", p.installDir.String())
|
||||
entries.SetString("LOCAL_SOONG_INSTALLED_MODULE", filepath.Join(p.installDir.String(), fi.stem()))
|
||||
entries.SetString("LOCAL_SOONG_INSTALL_PAIRS",
|
||||
fi.builtFile.String()+":"+filepath.Join(p.installDir.String(), fi.stem()))
|
||||
|
||||
// soong_java_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .jar Therefore
|
||||
// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
|
||||
// we will have foo.jar.jar
|
||||
entries.SetString("LOCAL_MODULE_STEM", strings.TrimSuffix(fi.stem(), ".jar"))
|
||||
entries.SetString("LOCAL_SOONG_DEX_JAR", fi.builtFile.String())
|
||||
entries.SetString("LOCAL_DEX_PREOPT", "false")
|
||||
},
|
||||
},
|
||||
ExtraFooters: []android.AndroidMkExtraFootersFunc{
|
||||
func(w io.Writer, name, prefix, moduleDir string) {
|
||||
// m <module_name> will build <module_name>.<apex_name> as well.
|
||||
if fi.androidMkModuleName != moduleName {
|
||||
fmt.Fprintf(w, ".PHONY: %s\n", fi.androidMkModuleName)
|
||||
fmt.Fprintf(w, "%s: %s\n", fi.androidMkModuleName, moduleName)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
return entries
|
||||
}
|
||||
|
||||
// prebuiltApexModuleCreator defines the methods that need to be implemented by prebuilt_apex and
|
||||
// apex_set in order to create the modules needed to provide access to the prebuilt .apex file.
|
||||
type prebuiltApexModuleCreator interface {
|
||||
createPrebuiltApexModules(ctx android.TopDownMutatorContext)
|
||||
}
|
||||
|
||||
// prebuiltApexModuleCreatorMutator is the mutator responsible for invoking the
|
||||
// prebuiltApexModuleCreator's createPrebuiltApexModules method.
|
||||
//
|
||||
// It is registered as a pre-arch mutator as it must run after the ComponentDepsMutator because it
|
||||
// will need to access dependencies added by that (exported modules) but must run before the
|
||||
// DepsMutator so that the deapexer module it creates can add dependencies onto itself from the
|
||||
// exported modules.
|
||||
func prebuiltApexModuleCreatorMutator(ctx android.TopDownMutatorContext) {
|
||||
module := ctx.Module()
|
||||
if creator, ok := module.(prebuiltApexModuleCreator); ok {
|
||||
creator.createPrebuiltApexModules(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *prebuiltCommon) hasExportedDeps() bool {
|
||||
return len(p.prebuiltCommonProperties.Exported_java_libs) > 0 ||
|
||||
len(p.prebuiltCommonProperties.Exported_bootclasspath_fragments) > 0 ||
|
||||
return len(p.prebuiltCommonProperties.Exported_bootclasspath_fragments) > 0 ||
|
||||
len(p.prebuiltCommonProperties.Exported_systemserverclasspath_fragments) > 0
|
||||
}
|
||||
|
||||
|
|
@ -345,11 +262,6 @@ func (p *prebuiltCommon) hasExportedDeps() bool {
|
|||
func (p *prebuiltCommon) prebuiltApexContentsDeps(ctx android.BottomUpMutatorContext) {
|
||||
module := ctx.Module()
|
||||
|
||||
for _, dep := range p.prebuiltCommonProperties.Exported_java_libs {
|
||||
prebuiltDep := android.PrebuiltNameFromSource(dep)
|
||||
ctx.AddDependency(module, exportedJavaLibTag, prebuiltDep)
|
||||
}
|
||||
|
||||
for _, dep := range p.prebuiltCommonProperties.Exported_bootclasspath_fragments {
|
||||
prebuiltDep := android.PrebuiltNameFromSource(dep)
|
||||
ctx.AddDependency(module, exportedBootclasspathFragmentTag, prebuiltDep)
|
||||
|
|
@ -467,34 +379,6 @@ func (p *prebuiltCommon) apexInfoMutator(mctx android.TopDownMutatorContext) {
|
|||
}
|
||||
}
|
||||
|
||||
// prebuiltApexSelectorModule is a private module type that is only created by the prebuilt_apex
|
||||
// module. It selects the apex to use and makes it available for use by prebuilt_apex and the
|
||||
// deapexer.
|
||||
type prebuiltApexSelectorModule struct {
|
||||
android.ModuleBase
|
||||
|
||||
apexFileProperties ApexFileProperties
|
||||
|
||||
inputApex android.Path
|
||||
}
|
||||
|
||||
func privateApexSelectorModuleFactory() android.Module {
|
||||
module := &prebuiltApexSelectorModule{}
|
||||
module.AddProperties(
|
||||
&module.apexFileProperties,
|
||||
)
|
||||
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
|
||||
return module
|
||||
}
|
||||
|
||||
func (p *prebuiltApexSelectorModule) Srcs() android.Paths {
|
||||
return android.Paths{p.inputApex}
|
||||
}
|
||||
|
||||
func (p *prebuiltApexSelectorModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||
p.inputApex = android.SingleSourcePathFromSupplier(ctx, p.apexFileProperties.prebuiltApexSelector, "src")
|
||||
}
|
||||
|
||||
type Prebuilt struct {
|
||||
prebuiltCommon
|
||||
|
||||
|
|
@ -511,7 +395,7 @@ type ApexFileProperties struct {
|
|||
// This cannot be marked as `android:"arch_variant"` because the `prebuilt_apex` is only mutated
|
||||
// for android_common. That is so that it will have the same arch variant as, and so be compatible
|
||||
// with, the source `apex` module type that it replaces.
|
||||
Src *string `android:"path"`
|
||||
Src proptools.Configurable[string] `android:"path,replace_instead_of_append"`
|
||||
Arch struct {
|
||||
Arm struct {
|
||||
Src *string `android:"path"`
|
||||
|
|
@ -537,11 +421,11 @@ type ApexFileProperties struct {
|
|||
// to use methods on it that are specific to the current module.
|
||||
//
|
||||
// See the ApexFileProperties.Src property.
|
||||
func (p *ApexFileProperties) prebuiltApexSelector(ctx android.BaseModuleContext, prebuilt android.Module) []string {
|
||||
func (p *ApexFileProperties) prebuiltApexSelector(ctx android.BaseModuleContext, prebuilt android.Module) string {
|
||||
multiTargets := prebuilt.MultiTargets()
|
||||
if len(multiTargets) != 1 {
|
||||
ctx.OtherModuleErrorf(prebuilt, "compile_multilib shouldn't be \"both\" for prebuilt_apex")
|
||||
return nil
|
||||
return ""
|
||||
}
|
||||
var src string
|
||||
switch multiTargets[0].Arch.ArchType {
|
||||
|
|
@ -561,7 +445,7 @@ func (p *ApexFileProperties) prebuiltApexSelector(ctx android.BaseModuleContext,
|
|||
src = String(p.Arch.X86_64.Src)
|
||||
}
|
||||
if src == "" {
|
||||
src = String(p.Src)
|
||||
src = p.Src.GetOrDefault(ctx, "")
|
||||
}
|
||||
|
||||
if src == "" {
|
||||
|
|
@ -574,7 +458,7 @@ func (p *ApexFileProperties) prebuiltApexSelector(ctx android.BaseModuleContext,
|
|||
// logic from reporting a more general, less useful message.
|
||||
}
|
||||
|
||||
return []string{src}
|
||||
return src
|
||||
}
|
||||
|
||||
type PrebuiltProperties struct {
|
||||
|
|
@ -587,48 +471,23 @@ func (a *Prebuilt) hasSanitizedSource(sanitizer string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (p *Prebuilt) OutputFiles(tag string) (android.Paths, error) {
|
||||
switch tag {
|
||||
case "":
|
||||
return android.Paths{p.outputApex}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported module reference tag %q", tag)
|
||||
}
|
||||
}
|
||||
|
||||
// prebuilt_apex imports an `.apex` file into the build graph as if it was built with apex.
|
||||
func PrebuiltFactory() android.Module {
|
||||
module := &Prebuilt{}
|
||||
module.AddProperties(&module.properties)
|
||||
module.initPrebuiltCommon(module, &module.properties.PrebuiltCommonProperties)
|
||||
module.prebuiltCommon.prebuiltCommonProperties = &module.properties.PrebuiltCommonProperties
|
||||
|
||||
// init the module as a prebuilt
|
||||
// even though this module type has srcs, use `InitPrebuiltModuleWithoutSrcs`, since the existing
|
||||
// InitPrebuiltModule* are not friendly with Sources of Configurable type.
|
||||
// The actual src will be evaluated in GenerateAndroidBuildActions.
|
||||
android.InitPrebuiltModuleWithoutSrcs(module)
|
||||
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
|
||||
|
||||
return module
|
||||
}
|
||||
|
||||
func createApexSelectorModule(ctx android.TopDownMutatorContext, name string, apexFileProperties *ApexFileProperties) {
|
||||
props := struct {
|
||||
Name *string
|
||||
}{
|
||||
Name: proptools.StringPtr(name),
|
||||
}
|
||||
|
||||
ctx.CreateModule(privateApexSelectorModuleFactory,
|
||||
&props,
|
||||
apexFileProperties,
|
||||
)
|
||||
}
|
||||
|
||||
// createDeapexerModuleIfNeeded will create a deapexer module if it is needed.
|
||||
//
|
||||
// A deapexer module is only needed when the prebuilt apex specifies one or more modules in either
|
||||
// the `exported_java_libs` or `exported_bootclasspath_fragments` properties as that indicates that
|
||||
// the listed modules need access to files from within the prebuilt .apex file.
|
||||
func (p *prebuiltCommon) createDeapexerModuleIfNeeded(ctx android.TopDownMutatorContext, deapexerName string, apexFileSource string) {
|
||||
// Only create the deapexer module if it is needed.
|
||||
if !p.hasExportedDeps() {
|
||||
return
|
||||
}
|
||||
|
||||
func (p *prebuiltCommon) getDeapexerPropertiesIfNeeded(ctx android.ModuleContext) DeapexerProperties {
|
||||
// Compute the deapexer properties from the transitive dependencies of this module.
|
||||
commonModules := []string{}
|
||||
dexpreoptProfileGuidedModules := []string{}
|
||||
|
|
@ -662,7 +521,7 @@ func (p *prebuiltCommon) createDeapexerModuleIfNeeded(ctx android.TopDownMutator
|
|||
})
|
||||
|
||||
// Create properties for deapexer module.
|
||||
deapexerProperties := &DeapexerProperties{
|
||||
deapexerProperties := DeapexerProperties{
|
||||
// Remove any duplicates from the common modules lists as a module may be included via a direct
|
||||
// dependency as well as transitive ones.
|
||||
CommonModules: android.SortedUniqueStrings(commonModules),
|
||||
|
|
@ -671,22 +530,7 @@ func (p *prebuiltCommon) createDeapexerModuleIfNeeded(ctx android.TopDownMutator
|
|||
|
||||
// Populate the exported files property in a fixed order.
|
||||
deapexerProperties.ExportedFiles = android.SortedUniqueStrings(exportedFiles)
|
||||
|
||||
props := struct {
|
||||
Name *string
|
||||
Selected_apex *string
|
||||
}{
|
||||
Name: proptools.StringPtr(deapexerName),
|
||||
Selected_apex: proptools.StringPtr(apexFileSource),
|
||||
}
|
||||
ctx.CreateModule(privateDeapexerFactory,
|
||||
&props,
|
||||
deapexerProperties,
|
||||
)
|
||||
}
|
||||
|
||||
func apexSelectorModuleName(baseModuleName string) string {
|
||||
return baseModuleName + ".apex.selector"
|
||||
return deapexerProperties
|
||||
}
|
||||
|
||||
func prebuiltApexExportedModuleName(ctx android.BottomUpMutatorContext, name string) string {
|
||||
|
|
@ -728,97 +572,50 @@ func (t exportedDependencyTag) RequiresFilesFromPrebuiltApex() {}
|
|||
var _ android.RequiresFilesFromPrebuiltApexTag = exportedDependencyTag{}
|
||||
|
||||
var (
|
||||
exportedJavaLibTag = exportedDependencyTag{name: "exported_java_libs"}
|
||||
exportedBootclasspathFragmentTag = exportedDependencyTag{name: "exported_bootclasspath_fragments"}
|
||||
exportedSystemserverclasspathFragmentTag = exportedDependencyTag{name: "exported_systemserverclasspath_fragments"}
|
||||
)
|
||||
|
||||
var _ prebuiltApexModuleCreator = (*Prebuilt)(nil)
|
||||
|
||||
// createPrebuiltApexModules creates modules necessary to export files from the prebuilt apex to the
|
||||
// build.
|
||||
//
|
||||
// If this needs to make files from within a `.apex` file available for use by other Soong modules,
|
||||
// e.g. make dex implementation jars available for java_import modules listed in exported_java_libs,
|
||||
// it does so as follows:
|
||||
//
|
||||
// 1. It creates a `deapexer` module that actually extracts the files from the `.apex` file and
|
||||
// makes them available for use by other modules, at both Soong and ninja levels.
|
||||
//
|
||||
// 2. It adds a dependency onto those modules and creates an apex specific variant similar to what
|
||||
// an `apex` module does. That ensures that code which looks for specific apex variant, e.g.
|
||||
// dexpreopt, will work the same way from source and prebuilt.
|
||||
//
|
||||
// 3. The `deapexer` module adds a dependency from the modules that require the exported files onto
|
||||
// itself so that they can retrieve the file paths to those files.
|
||||
//
|
||||
// It also creates a child module `selector` that is responsible for selecting the appropriate
|
||||
// input apex for both the prebuilt_apex and the deapexer. That is needed for a couple of reasons:
|
||||
//
|
||||
// 1. To dedup the selection logic so it only runs in one module.
|
||||
//
|
||||
// 2. To allow the deapexer to be wired up to a different source for the input apex, e.g. an
|
||||
// `apex_set`.
|
||||
//
|
||||
// prebuilt_apex
|
||||
// / | \
|
||||
// / | \
|
||||
// V V V
|
||||
// selector <--- deapexer <--- exported java lib
|
||||
func (p *Prebuilt) createPrebuiltApexModules(ctx android.TopDownMutatorContext) {
|
||||
apexSelectorModuleName := apexSelectorModuleName(p.Name())
|
||||
createApexSelectorModule(ctx, apexSelectorModuleName, &p.properties.ApexFileProperties)
|
||||
|
||||
apexFileSource := ":" + apexSelectorModuleName
|
||||
p.createDeapexerModuleIfNeeded(ctx, deapexerModuleName(p.Name()), apexFileSource)
|
||||
|
||||
// Add a source reference to retrieve the selected apex from the selector module.
|
||||
p.prebuiltCommonProperties.Selected_apex = proptools.StringPtr(apexFileSource)
|
||||
}
|
||||
|
||||
func (p *Prebuilt) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
|
||||
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.Name()))
|
||||
}
|
||||
}
|
||||
|
||||
var _ ApexInfoMutator = (*Prebuilt)(nil)
|
||||
|
||||
func (p *Prebuilt) ApexInfoMutator(mctx android.TopDownMutatorContext) {
|
||||
p.apexInfoMutator(mctx)
|
||||
}
|
||||
|
||||
// creates the build rules to deapex the prebuilt, and returns a deapexerInfo
|
||||
func (p *prebuiltCommon) getDeapexerInfo(ctx android.ModuleContext, apexFile android.Path) *android.DeapexerInfo {
|
||||
if !p.hasExportedDeps() {
|
||||
// nothing to do
|
||||
return nil
|
||||
}
|
||||
deapexerProps := p.getDeapexerPropertiesIfNeeded(ctx)
|
||||
return deapex(ctx, apexFile, deapexerProps)
|
||||
}
|
||||
|
||||
// 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
|
||||
func (p *prebuiltCommon) provideApexExportsInfo(ctx android.ModuleContext, di *android.DeapexerInfo) {
|
||||
if di == nil {
|
||||
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
|
||||
}
|
||||
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())
|
||||
}
|
||||
|
||||
exports := android.ApexExportsInfo{
|
||||
ApexName: p.ApexVariationName(),
|
||||
ProfilePathOnHost: di.PrebuiltExportPath(java.ProfileInstallPathInApex),
|
||||
LibraryNameToDexJarPathOnHost: javaModuleToDexPath,
|
||||
}
|
||||
android.SetProvider(ctx, android.ApexExportsInfoProvider, exports)
|
||||
}
|
||||
|
||||
// Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file
|
||||
|
|
@ -854,7 +651,7 @@ func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
|
||||
p.apexKeysPath = writeApexKeys(ctx, p)
|
||||
// TODO(jungjw): Check the key validity.
|
||||
p.inputApex = android.OptionalPathForModuleSrc(ctx, p.prebuiltCommonProperties.Selected_apex).Path()
|
||||
p.inputApex = android.PathForModuleSrc(ctx, p.properties.prebuiltApexSelector(ctx, ctx.Module()))
|
||||
p.installDir = android.PathForModuleInstall(ctx, "apex")
|
||||
p.installFilename = p.InstallFilename()
|
||||
if !strings.HasSuffix(p.installFilename, imageApexSuffix) {
|
||||
|
|
@ -872,11 +669,13 @@ func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
return
|
||||
}
|
||||
|
||||
deapexerInfo := p.getDeapexerInfo(ctx, p.inputApex)
|
||||
|
||||
// dexpreopt any system server jars if present
|
||||
p.dexpreoptSystemServerJars(ctx)
|
||||
p.dexpreoptSystemServerJars(ctx, deapexerInfo)
|
||||
|
||||
// provide info used for generating the boot image
|
||||
p.provideApexExportsInfo(ctx)
|
||||
p.provideApexExportsInfo(ctx, deapexerInfo)
|
||||
|
||||
p.providePrebuiltInfo(ctx)
|
||||
|
||||
|
|
@ -894,6 +693,8 @@ func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
p.installedFile = ctx.InstallFile(p.installDir, p.installFilename, p.inputApex, p.compatSymlinks...)
|
||||
p.provenanceMetaDataFile = provenance.GenerateArtifactProvenanceMetaData(ctx, p.inputApex, p.installedFile)
|
||||
}
|
||||
|
||||
ctx.SetOutputFiles(android.Paths{p.outputApex}, "")
|
||||
}
|
||||
|
||||
func (p *Prebuilt) ProvenanceMetaDataFile() android.OutputPath {
|
||||
|
|
@ -910,26 +711,11 @@ type prebuiltApexExtractorModule struct {
|
|||
extractedApex android.WritablePath
|
||||
}
|
||||
|
||||
func privateApexExtractorModuleFactory() android.Module {
|
||||
module := &prebuiltApexExtractorModule{}
|
||||
module.AddProperties(
|
||||
&module.properties,
|
||||
)
|
||||
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
|
||||
return module
|
||||
}
|
||||
|
||||
func (p *prebuiltApexExtractorModule) Srcs() android.Paths {
|
||||
return android.Paths{p.extractedApex}
|
||||
}
|
||||
|
||||
func (p *prebuiltApexExtractorModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||
srcsSupplier := func(ctx android.BaseModuleContext, prebuilt android.Module) []string {
|
||||
return p.properties.prebuiltSrcs(ctx)
|
||||
}
|
||||
// extract registers the build actions to extract an apex from .apks file
|
||||
// returns the path of the extracted apex
|
||||
func extract(ctx android.ModuleContext, apexSet android.Path, prerelease *bool) android.Path {
|
||||
defaultAllowPrerelease := ctx.Config().IsEnvTrue("SOONG_ALLOW_PRERELEASE_APEXES")
|
||||
apexSet := android.SingleSourcePathFromSupplier(ctx, srcsSupplier, "set")
|
||||
p.extractedApex = android.PathForModuleOut(ctx, "extracted", apexSet.Base())
|
||||
extractedApex := android.PathForModuleOut(ctx, "extracted", apexSet.Base())
|
||||
// Filter out NativeBridge archs (b/260115309)
|
||||
abis := java.SupportedAbis(ctx, true)
|
||||
ctx.Build(pctx,
|
||||
|
|
@ -937,14 +723,16 @@ func (p *prebuiltApexExtractorModule) GenerateAndroidBuildActions(ctx android.Mo
|
|||
Rule: extractMatchingApex,
|
||||
Description: "Extract an apex from an apex set",
|
||||
Inputs: android.Paths{apexSet},
|
||||
Output: p.extractedApex,
|
||||
Output: extractedApex,
|
||||
Args: map[string]string{
|
||||
"abis": strings.Join(abis, ","),
|
||||
"allow-prereleased": strconv.FormatBool(proptools.BoolDefault(p.properties.Prerelease, defaultAllowPrerelease)),
|
||||
"allow-prereleased": strconv.FormatBool(proptools.BoolDefault(prerelease, defaultAllowPrerelease)),
|
||||
"sdk-version": ctx.Config().PlatformSdkVersion().String(),
|
||||
"skip-sdk-check": strconv.FormatBool(ctx.Config().IsEnvTrue("SOONG_SKIP_APPSET_SDK_CHECK")),
|
||||
},
|
||||
})
|
||||
},
|
||||
)
|
||||
return extractedApex
|
||||
}
|
||||
|
||||
type ApexSet struct {
|
||||
|
|
@ -1009,61 +797,22 @@ func (a *ApexSet) hasSanitizedSource(sanitizer string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (a *ApexSet) OutputFiles(tag string) (android.Paths, error) {
|
||||
switch tag {
|
||||
case "":
|
||||
return android.Paths{a.outputApex}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported module reference tag %q", tag)
|
||||
}
|
||||
}
|
||||
|
||||
// prebuilt_apex imports an `.apex` file into the build graph as if it was built with apex.
|
||||
func apexSetFactory() android.Module {
|
||||
module := &ApexSet{}
|
||||
module.AddProperties(&module.properties)
|
||||
module.initPrebuiltCommon(module, &module.properties.PrebuiltCommonProperties)
|
||||
module.prebuiltCommon.prebuiltCommonProperties = &module.properties.PrebuiltCommonProperties
|
||||
|
||||
// init the module as a prebuilt
|
||||
// even though this module type has srcs, use `InitPrebuiltModuleWithoutSrcs`, since the existing
|
||||
// InitPrebuiltModule* are not friendly with Sources of Configurable type.
|
||||
// The actual src will be evaluated in GenerateAndroidBuildActions.
|
||||
android.InitPrebuiltModuleWithoutSrcs(module)
|
||||
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
|
||||
|
||||
return module
|
||||
}
|
||||
|
||||
func createApexExtractorModule(ctx android.TopDownMutatorContext, name string, apexExtractorProperties *ApexExtractorProperties) {
|
||||
props := struct {
|
||||
Name *string
|
||||
}{
|
||||
Name: proptools.StringPtr(name),
|
||||
}
|
||||
|
||||
ctx.CreateModule(privateApexExtractorModuleFactory,
|
||||
&props,
|
||||
apexExtractorProperties,
|
||||
)
|
||||
}
|
||||
|
||||
func apexExtractorModuleName(baseModuleName string) string {
|
||||
return baseModuleName + ".apex.extractor"
|
||||
}
|
||||
|
||||
var _ prebuiltApexModuleCreator = (*ApexSet)(nil)
|
||||
|
||||
// createPrebuiltApexModules creates modules necessary to export files from the apex set to other
|
||||
// modules.
|
||||
//
|
||||
// This effectively does for apex_set what Prebuilt.createPrebuiltApexModules does for a
|
||||
// prebuilt_apex except that instead of creating a selector module which selects one .apex file
|
||||
// from those provided this creates an extractor module which extracts the appropriate .apex file
|
||||
// from the zip file containing them.
|
||||
func (a *ApexSet) createPrebuiltApexModules(ctx android.TopDownMutatorContext) {
|
||||
apexExtractorModuleName := apexExtractorModuleName(a.Name())
|
||||
createApexExtractorModule(ctx, apexExtractorModuleName, &a.properties.ApexExtractorProperties)
|
||||
|
||||
apexFileSource := ":" + apexExtractorModuleName
|
||||
a.createDeapexerModuleIfNeeded(ctx, deapexerModuleName(a.Name()), apexFileSource)
|
||||
|
||||
// After passing the arch specific src properties to the creating the apex selector module
|
||||
a.prebuiltCommonProperties.Selected_apex = proptools.StringPtr(apexFileSource)
|
||||
}
|
||||
|
||||
func (a *ApexSet) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
|
||||
a.prebuiltApexContentsDeps(ctx)
|
||||
}
|
||||
|
|
@ -1086,11 +835,25 @@ func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
ctx.ModuleErrorf("filename should end in %s or %s for apex_set", imageApexSuffix, imageCapexSuffix)
|
||||
}
|
||||
|
||||
inputApex := android.OptionalPathForModuleSrc(ctx, a.prebuiltCommonProperties.Selected_apex).Path()
|
||||
var apexSet android.Path
|
||||
if srcs := a.properties.prebuiltSrcs(ctx); len(srcs) == 1 {
|
||||
apexSet = android.PathForModuleSrc(ctx, srcs[0])
|
||||
} else {
|
||||
ctx.ModuleErrorf("Expected exactly one source apex_set file, found %v\n", srcs)
|
||||
}
|
||||
|
||||
extractedApex := extract(ctx, apexSet, a.properties.Prerelease)
|
||||
|
||||
a.outputApex = android.PathForModuleOut(ctx, a.installFilename)
|
||||
|
||||
// Build the output APEX. If compression is not enabled, make sure the output is not compressed even if the input is compressed
|
||||
buildRule := android.Cp
|
||||
if !ctx.Config().ApexCompressionEnabled() {
|
||||
buildRule = decompressApex
|
||||
}
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: android.Cp,
|
||||
Input: inputApex,
|
||||
Rule: buildRule,
|
||||
Input: extractedApex,
|
||||
Output: a.outputApex,
|
||||
})
|
||||
|
||||
|
|
@ -1099,11 +862,13 @@ func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
return
|
||||
}
|
||||
|
||||
deapexerInfo := a.getDeapexerInfo(ctx, extractedApex)
|
||||
|
||||
// dexpreopt any system server jars if present
|
||||
a.dexpreoptSystemServerJars(ctx)
|
||||
a.dexpreoptSystemServerJars(ctx, deapexerInfo)
|
||||
|
||||
// provide info used for generating the boot image
|
||||
a.provideApexExportsInfo(ctx)
|
||||
a.provideApexExportsInfo(ctx, deapexerInfo)
|
||||
|
||||
a.providePrebuiltInfo(ctx)
|
||||
|
||||
|
|
@ -1121,6 +886,8 @@ func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
for _, overridden := range a.prebuiltCommonProperties.Overrides {
|
||||
a.compatSymlinks = append(a.compatSymlinks, makeCompatSymlinks(overridden, ctx)...)
|
||||
}
|
||||
|
||||
ctx.SetOutputFiles(android.Paths{a.outputApex}, "")
|
||||
}
|
||||
|
||||
type systemExtContext struct {
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ func TestSystemserverclasspathFragmentContents(t *testing.T) {
|
|||
apex_available: [
|
||||
"myapex",
|
||||
],
|
||||
sdk_version: "core_current",
|
||||
}
|
||||
|
||||
systemserverclasspath_fragment {
|
||||
|
|
@ -276,8 +277,6 @@ func TestPrebuiltSystemserverclasspathFragmentContents(t *testing.T) {
|
|||
java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{
|
||||
`all_apex_contributions`,
|
||||
`dex2oatd`,
|
||||
`prebuilt_myapex.apex.selector`,
|
||||
`prebuilt_myapex.deapexer`,
|
||||
`prebuilt_mysystemserverclasspathfragment`,
|
||||
})
|
||||
|
||||
|
|
@ -285,10 +284,9 @@ func TestPrebuiltSystemserverclasspathFragmentContents(t *testing.T) {
|
|||
`all_apex_contributions`,
|
||||
`prebuilt_bar`,
|
||||
`prebuilt_foo`,
|
||||
`prebuilt_myapex.deapexer`,
|
||||
})
|
||||
|
||||
ensureExactDeapexedContents(t, ctx, "prebuilt_myapex", "android_common", []string{
|
||||
ensureExactDeapexedContents(t, ctx, "myapex", "android_common_myapex", []string{
|
||||
"javalib/foo.jar",
|
||||
"javalib/bar.jar",
|
||||
"javalib/bar.jar.prof",
|
||||
|
|
@ -350,6 +348,7 @@ func TestSystemserverclasspathFragmentStandaloneContents(t *testing.T) {
|
|||
apex_available: [
|
||||
"myapex",
|
||||
],
|
||||
sdk_version: "core_current",
|
||||
}
|
||||
|
||||
systemserverclasspath_fragment {
|
||||
|
|
@ -437,10 +436,9 @@ func TestPrebuiltStandaloneSystemserverclasspathFragmentContents(t *testing.T) {
|
|||
`all_apex_contributions`,
|
||||
`prebuilt_bar`,
|
||||
`prebuilt_foo`,
|
||||
`prebuilt_myapex.deapexer`,
|
||||
})
|
||||
|
||||
ensureExactDeapexedContents(t, ctx, "prebuilt_myapex", "android_common", []string{
|
||||
ensureExactDeapexedContents(t, ctx, "myapex", "android_common_myapex", []string{
|
||||
"javalib/foo.jar",
|
||||
"javalib/bar.jar",
|
||||
"javalib/bar.jar.prof",
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue