Merge "Revert "Bump our Windows target to Windows 10."" into main
diff --git a/Android.bp b/Android.bp
index 432c7fc..523f55c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,5 +1,9 @@
package {
default_applicable_licenses: ["Android-Apache-2.0"],
+ default_visibility: [
+ "//build/soong:__subpackages__",
+ ],
+ default_team: "trendy_team_build",
}
subdirs = [
@@ -23,6 +27,8 @@
srcs: [
"doc.go",
],
+ // Used by plugins, though probably shouldn't be.
+ visibility: ["//visibility:public"],
}
//
@@ -40,6 +46,7 @@
enabled: true,
},
},
+ defaults_visibility: ["//visibility:public"],
}
//
@@ -51,6 +58,7 @@
vendor: true,
recovery_available: true,
min_sdk_version: "apex_inherit",
+ visibility: ["//visibility:public"],
}
cc_genrule {
@@ -75,6 +83,7 @@
cmd: "$(location) -s $(out) $(in)",
srcs: [":linker"],
out: ["linker.s"],
+ visibility: ["//bionic/libc"],
}
cc_genrule {
@@ -99,11 +108,18 @@
cmd: "$(location) -T $(out) $(in)",
srcs: [":linker"],
out: ["linker.script"],
+ visibility: ["//visibility:public"],
}
// Instantiate the dex_bootjars singleton module.
dex_bootjars {
name: "dex_bootjars",
+ visibility: ["//visibility:public"],
+}
+
+art_boot_images {
+ name: "art_boot_images",
+ visibility: ["//art:__subpackages__"],
}
// Pseudo-test that's run on checkbuilds to ensure that get_clang_version can
@@ -123,21 +139,48 @@
// container for apex_contributions selected using build flags
all_apex_contributions {
name: "all_apex_contributions",
+ visibility: ["//visibility:public"],
+}
+
+// Defaults to share configs between "baremetal" Soong modules, currently only
+// used for code running in kernel context within Android Virtualization
+// Framework guests.
+cc_defaults {
+ name: "cc_baremetal_defaults",
+ arch: {
+ arm64: {
+ cflags: [
+ // Prevent the compiler from optimizing code using SVE, as the
+ // baremetal environment might not have configured the hardware.
+ "-Xclang -target-feature",
+ "-Xclang -sve",
+ ],
+ },
+ },
+ defaults_visibility: ["//visibility:public"],
}
product_config {
name: "product_config",
- visibility: ["//device/google/cuttlefish/system_image"],
+ visibility: [
+ "//build/make/target/product/generic",
+ "//build/soong/fsgen",
+ ],
}
build_prop {
name: "system-build.prop",
stem: "build.prop",
product_config: ":product_config",
- // Currently, only microdroid and cf system image can refer to system-build.prop
+ footer_files: [
+ ":applied_backported_fixes",
+ ],
+ // Currently, only microdroid, Ravenwood, and cf system image can refer to system-build.prop
visibility: [
- "//device/google/cuttlefish/system_image",
+ "//build/soong/fsgen",
"//packages/modules/Virtualization/build/microdroid",
+ "//frameworks/base/ravenwood",
+ "//visibility:any_system_partition",
],
}
@@ -147,7 +190,10 @@
system_ext_specific: true,
product_config: ":product_config",
relative_install_path: "etc", // system_ext/etc/build.prop
- visibility: ["//visibility:private"],
+ visibility: [
+ "//build/make/target/product/gsi",
+ "//build/soong/fsgen",
+ ],
}
build_prop {
@@ -156,7 +202,10 @@
product_specific: true,
product_config: ":product_config",
relative_install_path: "etc", // product/etc/build.prop
- visibility: ["//visibility:private"],
+ visibility: [
+ "//build/make/target/product/gsi",
+ "//build/soong/fsgen",
+ ],
}
build_prop {
@@ -165,5 +214,49 @@
device_specific: true,
product_config: ":product_config",
relative_install_path: "etc", // odm/etc/build.prop
+ visibility: ["//build/soong/fsgen"],
+}
+
+build_prop {
+ name: "system_dlkm-build.prop",
+ stem: "build.prop",
+ system_dlkm_specific: true,
+ product_config: ":product_config",
+ relative_install_path: "etc", // system_dlkm/etc/build.prop
visibility: ["//visibility:private"],
}
+
+build_prop {
+ name: "vendor_dlkm-build.prop",
+ stem: "build.prop",
+ vendor_dlkm_specific: true,
+ product_config: ":product_config",
+ relative_install_path: "etc", // vendor_dlkm/etc/build.prop
+ visibility: ["//visibility:private"],
+}
+
+build_prop {
+ name: "odm_dlkm-build.prop",
+ stem: "build.prop",
+ odm_dlkm_specific: true,
+ product_config: ":product_config",
+ relative_install_path: "etc", // odm_dlkm/etc/build.prop
+ visibility: ["//visibility:private"],
+}
+
+build_prop {
+ name: "ramdisk-build.prop",
+ stem: "build.prop",
+ ramdisk: true,
+ product_config: ":product_config",
+ relative_install_path: "etc/ramdisk", // ramdisk/system/etc/ramdisk/build.prop
+ visibility: ["//visibility:private"],
+}
+
+all_apex_certs {
+ name: "all_apex_certs",
+ visibility: [
+ "//cts/tests/tests/security",
+ "//cts/hostsidetests/appsecurity",
+ ],
+}
diff --git a/README.md b/README.md
index ad282a5..6d1a2c5 100644
--- a/README.md
+++ b/README.md
@@ -673,8 +673,7 @@
SOONG_DELVE=2345 SOONG_DELVE_STEPS='build,modulegraph' m
```
results in only `build` (main build step) and `modulegraph` being run in the debugger.
-The allowed step names are `bp2build_files`, `bp2build_workspace`, `build`,
-`modulegraph`, `queryview`, `soong_docs`.
+The allowed step names are `build`, `soong_docs`.
Note setting or unsetting `SOONG_DELVE` causes a recompilation of `soong_build`. This
is because in order to debug the binary, it needs to be built with debug
diff --git a/aconfig/Android.bp b/aconfig/Android.bp
index 402cf16..6e2964a 100644
--- a/aconfig/Android.bp
+++ b/aconfig/Android.bp
@@ -25,7 +25,22 @@
"aconfig_declarations_test.go",
"aconfig_values_test.go",
"aconfig_value_set_test.go",
- "all_aconfig_declarations_test.go",
],
pluginFor: ["soong_build"],
}
+
+// All FlaggedApi flags associated with platform API.
+// By default this uses the platform APIs associated with android.jar
+// but other verticals/platforms can override via soong config setting.
+all_aconfig_declarations {
+ name: "all_aconfig_declarations",
+ api_signature_files: select(soong_config_variable("android_aconfig", "opt_platform_api_srcs"), {
+ default: [
+ ":frameworks-base-api-current.txt",
+ ":frameworks-base-api-system-current.txt",
+ ":frameworks-base-api-system-server-current.txt",
+ ":frameworks-base-api-module-lib-current.txt",
+ ],
+ }),
+ finalized_flags_file: ":latest-finalized-flags",
+}
diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go
index 9b638e7..9a9e568 100644
--- a/aconfig/aconfig_declarations.go
+++ b/aconfig/aconfig_declarations.go
@@ -15,12 +15,12 @@
package aconfig
import (
+ "android/soong/android"
"path/filepath"
"slices"
+ "strconv"
"strings"
- "android/soong/android"
-
"github.com/google/blueprint"
)
@@ -88,6 +88,13 @@
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.
@@ -178,6 +185,13 @@
defaultPermission = confPerm
}
}
+ var allowReadWrite bool
+ if requireAllReadOnly, ok := ctx.Config().GetBuildFlag("RELEASE_ACONFIG_REQUIRE_ALL_READ_ONLY"); ok {
+ // The build flag (RELEASE_ACONFIG_REQUIRE_ALL_READ_ONLY) is the negation of the aconfig flag
+ // (allow-read-write) for historical reasons.
+ // Bool build flags are always "" for false, and generally "true" for true.
+ allowReadWrite = requireAllReadOnly == ""
+ }
inputFiles := make([]android.Path, len(declarationFiles))
copy(inputFiles, declarationFiles)
inputFiles = append(inputFiles, valuesFiles[config]...)
@@ -187,6 +201,7 @@
"declarations": android.JoinPathsWithPrefix(declarationFiles, "--declarations "),
"values": joinAndPrefix(" --values ", values[config]),
"default-permission": optionalVariable(" --default-permission ", defaultPermission),
+ "allow-read-write": optionalVariable(" --allow-read-write ", strconv.FormatBool(allowReadWrite)),
}
if len(module.properties.Container) > 0 {
args["container"] = "--container " + module.properties.Container
@@ -219,11 +234,4 @@
android.SetProvider(ctx, android.AconfigReleaseDeclarationsProviderKey, providerData)
}
-func (module *DeclarationsModule) BuildActionProviderKeys() []blueprint.AnyProviderKey {
- return []blueprint.AnyProviderKey{
- android.AconfigDeclarationsProviderKey,
- android.AconfigReleaseDeclarationsProviderKey,
- }
-}
-
var _ blueprint.Incremental = &DeclarationsModule{}
diff --git a/aconfig/aconfig_value_set.go b/aconfig/aconfig_value_set.go
index 7ba76c0..d72ec48 100644
--- a/aconfig/aconfig_value_set.go
+++ b/aconfig/aconfig_value_set.go
@@ -16,6 +16,9 @@
import (
"android/soong/android"
+ "fmt"
+ "strings"
+
"github.com/google/blueprint"
)
@@ -27,6 +30,9 @@
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 @@
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)
diff --git a/aconfig/aconfig_value_set_test.go b/aconfig/aconfig_value_set_test.go
index 32c31cb..3b7281e 100644
--- a/aconfig/aconfig_value_set_test.go
+++ b/aconfig/aconfig_value_set_test.go
@@ -18,6 +18,8 @@
"testing"
"android/soong/android"
+
+ "github.com/google/blueprint"
)
func TestAconfigValueSet(t *testing.T) {
@@ -41,3 +43,112 @@
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)
+}
diff --git a/aconfig/all_aconfig_declarations.go b/aconfig/all_aconfig_declarations.go
index 6ad54da..ec20099 100644
--- a/aconfig/all_aconfig_declarations.go
+++ b/aconfig/all_aconfig_declarations.go
@@ -19,6 +19,8 @@
"slices"
"android/soong/android"
+
+ "github.com/google/blueprint/proptools"
)
// A singleton module that collects all of the aconfig flags declared in the
@@ -28,8 +30,11 @@
// Note that this is ALL aconfig_declarations modules present in the tree, not just
// 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{releaseMap: make(map[string]allAconfigReleaseDeclarationsSingleton)}
+func AllAconfigDeclarationsFactory() android.SingletonModule {
+ module := &allAconfigDeclarationsSingleton{releaseMap: make(map[string]allAconfigReleaseDeclarationsSingleton)}
+ module.AddProperties(&module.properties)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ return module
}
type allAconfigReleaseDeclarationsSingleton struct {
@@ -37,8 +42,16 @@
intermediateTextProtoPath android.OutputPath
}
+type allAconfigReleaseDeclarationsProperties struct {
+ Api_signature_files proptools.Configurable[[]string] `android:"arch_variant,path"`
+ Finalized_flags_file string `android:"arch_variant,path"`
+}
+
type allAconfigDeclarationsSingleton struct {
+ android.SingletonModuleBase
+
releaseMap map[string]allAconfigReleaseDeclarationsSingleton
+ properties allAconfigReleaseDeclarationsProperties
}
func (this *allAconfigDeclarationsSingleton) sortedConfigNames() []string {
@@ -50,7 +63,32 @@
return names
}
-func (this *allAconfigDeclarationsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+func (this *allAconfigDeclarationsSingleton) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ apiSignatureFiles := android.Paths{}
+ for _, apiSignatureFile := range this.properties.Api_signature_files.GetOrDefault(ctx, nil) {
+ if path := android.PathForModuleSrc(ctx, apiSignatureFile); path != nil {
+ apiSignatureFiles = append(apiSignatureFiles, path)
+ }
+ }
+ finalizedFlagsFile := android.PathForModuleSrc(ctx, this.properties.Finalized_flags_file)
+ parsedFlagsFile := android.PathForIntermediates(ctx, "all_aconfig_declarations.pb")
+
+ output := android.PathForIntermediates(ctx, "finalized-flags.txt")
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: RecordFinalizedFlagsRule,
+ Inputs: append(apiSignatureFiles, finalizedFlagsFile, parsedFlagsFile),
+ Output: output,
+ Args: map[string]string{
+ "api_signature_files": android.JoinPathsWithPrefix(apiSignatureFiles, "--api-signature-file "),
+ "finalized_flags_file": "--finalized-flags-file " + finalizedFlagsFile.String(),
+ "parsed_flags_file": "--parsed-flags-file " + parsedFlagsFile.String(),
+ },
+ })
+ ctx.Phony("all_aconfig_declarations", output)
+}
+
+func (this *allAconfigDeclarationsSingleton) GenerateSingletonBuildActions(ctx android.SingletonContext) {
for _, rcName := range append([]string{""}, ctx.Config().ReleaseAconfigExtraReleaseConfigs()...) {
// Find all of the aconfig_declarations modules
var packages = make(map[string]int)
@@ -65,15 +103,16 @@
})
var numOffendingPkg = 0
+ offendingPkgsMessage := ""
for pkg, cnt := range packages {
if cnt > 1 {
- fmt.Printf("%d aconfig_declarations found for package %s\n", cnt, pkg)
+ offendingPkgsMessage += fmt.Sprintf("%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."))
+ panic("Only one aconfig_declarations allowed for each package.\n" + offendingPkgsMessage)
}
// Generate build action for aconfig (binary proto output)
@@ -115,4 +154,5 @@
ctx.DistForGoalWithFilename(goal, this.releaseMap[rcName].intermediateTextProtoPath, assembleFileName(rcName, "flags.textproto"))
}
}
+ ctx.DistForGoalWithFilename("sdk", android.PathForIntermediates(ctx, "finalized-flags.txt"), "finalized-flags.txt")
}
diff --git a/aconfig/all_aconfig_declarations_test.go b/aconfig/all_aconfig_declarations_test.go
deleted file mode 100644
index 0b2021e..0000000
--- a/aconfig/all_aconfig_declarations_test.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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 aconfig
-
-import (
- "testing"
-
- "android/soong/android"
-)
-
-func TestTwoAconfigDeclarationsPerPackage(t *testing.T) {
- bp := `
- aconfig_declarations {
- name: "module_name.foo",
- package: "com.example.package",
- container: "com.android.foo",
- srcs: [
- "foo.aconfig",
- ],
- }
-
- aconfig_declarations {
- name: "module_name.bar",
- package: "com.example.package",
- container: "com.android.foo",
- srcs: [
- "bar.aconfig",
- ],
- }
- `
- errMsg := "Only one aconfig_declarations allowed for each package."
- android.GroupFixturePreparers(
- PrepareForTestWithAconfigBuildComponents).
- ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(errMsg)).
- RunTestWithBp(t, bp)
-}
diff --git a/aconfig/build_flags/Android.bp b/aconfig/build_flags/Android.bp
index b3c7339..139aeac 100644
--- a/aconfig/build_flags/Android.bp
+++ b/aconfig/build_flags/Android.bp
@@ -13,10 +13,11 @@
"soong-android",
],
srcs: [
- "all_build_flag_declarations.go",
"build_flags.go",
+ "build_flags_singleton.go",
"declarations.go",
"init.go",
+ "release_configs.go",
],
testSrcs: [
],
diff --git a/aconfig/build_flags/all_build_flag_declarations.go b/aconfig/build_flags/all_build_flag_declarations.go
deleted file mode 100644
index 5f02912..0000000
--- a/aconfig/build_flags/all_build_flag_declarations.go
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package build_flags
-
-import (
- "android/soong/android"
-)
-
-// A singleton module that collects all of the build flags declared in the
-// tree into a single combined file for export to the external flag setting
-// server (inside Google it's Gantry).
-//
-// Note that this is ALL build_declarations modules present in the tree, not just
-// 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 AllBuildFlagDeclarationsFactory() android.Singleton {
- return &allBuildFlagDeclarationsSingleton{}
-}
-
-type allBuildFlagDeclarationsSingleton struct {
- intermediateBinaryProtoPath android.OutputPath
- intermediateTextProtoPath android.OutputPath
-}
-
-func (this *allBuildFlagDeclarationsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
- // Find all of the build_flag_declarations modules
- var intermediateFiles android.Paths
- ctx.VisitAllModules(func(module android.Module) {
- decl, ok := android.OtherModuleProvider(ctx, module, BuildFlagDeclarationsProviderKey)
- if !ok {
- return
- }
- intermediateFiles = append(intermediateFiles, decl.IntermediateCacheOutputPath)
- })
-
- // Generate build action for build_flag (binary proto output)
- this.intermediateBinaryProtoPath = android.PathForIntermediates(ctx, "all_build_flag_declarations.pb")
- ctx.Build(pctx, android.BuildParams{
- Rule: allDeclarationsRule,
- Inputs: intermediateFiles,
- Output: this.intermediateBinaryProtoPath,
- Description: "all_build_flag_declarations",
- Args: map[string]string{
- "intermediates": android.JoinPathsWithPrefix(intermediateFiles, "--intermediate "),
- },
- })
- ctx.Phony("all_build_flag_declarations", this.intermediateBinaryProtoPath)
-
- // Generate build action for build_flag (text proto output)
- this.intermediateTextProtoPath = android.PathForIntermediates(ctx, "all_build_flag_declarations.textproto")
- ctx.Build(pctx, android.BuildParams{
- Rule: allDeclarationsRuleTextProto,
- Input: this.intermediateBinaryProtoPath,
- Output: this.intermediateTextProtoPath,
- Description: "all_build_flag_declarations_textproto",
- })
- ctx.Phony("all_build_flag_declarations_textproto", this.intermediateTextProtoPath)
-}
-
-func (this *allBuildFlagDeclarationsSingleton) MakeVars(ctx android.MakeVarsContext) {
- ctx.DistForGoal("droid", this.intermediateBinaryProtoPath)
- for _, goal := range []string{"docs", "droid", "sdk"} {
- ctx.DistForGoalWithFilename(goal, this.intermediateBinaryProtoPath, "build_flags/all_flags.pb")
- ctx.DistForGoalWithFilename(goal, this.intermediateTextProtoPath, "build_flags/all_flags.textproto")
- }
-}
diff --git a/aconfig/build_flags/build_flags.go b/aconfig/build_flags/build_flags.go
index e878b5a..94e1eb1 100644
--- a/aconfig/build_flags/build_flags.go
+++ b/aconfig/build_flags/build_flags.go
@@ -35,7 +35,7 @@
type buildFlags struct {
android.ModuleBase
- outputPath android.OutputPath
+ outputPath android.Path
}
func buildFlagsFactory() android.Module {
@@ -48,7 +48,7 @@
// Read the build_flags_<partition>.json file generated by soong
// 'release-config' command.
srcPath := android.PathForOutput(ctx, "release-config", fmt.Sprintf("build_flags_%s.json", m.PartitionTag(ctx.DeviceConfig())))
- m.outputPath = android.PathForModuleOut(ctx, outJsonFileName).OutputPath
+ outputPath := android.PathForModuleOut(ctx, outJsonFileName)
// The 'release-config' command is called for every build, and generates the
// build_flags_<partition>.json file.
@@ -56,11 +56,12 @@
ctx.Build(pctx, android.BuildParams{
Rule: android.CpIfChanged,
Input: srcPath,
- Output: m.outputPath,
+ Output: outputPath,
})
installPath := android.PathForModuleInstall(ctx, "etc")
- ctx.InstallFile(installPath, outJsonFileName, m.outputPath)
+ ctx.InstallFile(installPath, outJsonFileName, outputPath)
+ m.outputPath = outputPath
}
func (m *buildFlags) AndroidMkEntries() []android.AndroidMkEntries {
diff --git a/aconfig/build_flags/build_flags_singleton.go b/aconfig/build_flags/build_flags_singleton.go
new file mode 100644
index 0000000..3b40755
--- /dev/null
+++ b/aconfig/build_flags/build_flags_singleton.go
@@ -0,0 +1,123 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package build_flags
+
+import (
+ "android/soong/android"
+)
+
+// A singleton module that collects all of the build flags declared in the
+// tree into a single combined file for export to the external flag setting
+// server (inside Google it's Gantry).
+//
+// Note that this is ALL build_declarations modules present in the tree, not just
+// 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 AllBuildFlagDeclarationsFactory() android.Singleton {
+ return &allBuildFlagDeclarationsSingleton{}
+}
+
+type allBuildFlagDeclarationsSingleton struct {
+ flagsBinaryProtoPath android.OutputPath
+ flagsTextProtoPath android.OutputPath
+ configsBinaryProtoPath android.OutputPath
+ configsTextProtoPath android.OutputPath
+}
+
+func (this *allBuildFlagDeclarationsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ // Find all of the build_flag_declarations modules
+ var flagsFiles android.Paths
+ // Find all of the release_config_contribution modules
+ var contributionDirs android.Paths
+ ctx.VisitAllModules(func(module android.Module) {
+ decl, ok := android.OtherModuleProvider(ctx, module, BuildFlagDeclarationsProviderKey)
+ if ok {
+ flagsFiles = append(flagsFiles, decl.IntermediateCacheOutputPath)
+ }
+
+ contrib, ok := android.OtherModuleProvider(ctx, module, ReleaseConfigContributionsProviderKey)
+ if ok {
+ contributionDirs = append(contributionDirs, contrib.ContributionDir)
+ }
+ })
+
+ // Generate build action for build_flag (binary proto output)
+ this.flagsBinaryProtoPath = android.PathForIntermediates(ctx, "all_build_flag_declarations.pb")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: allDeclarationsRule,
+ Inputs: flagsFiles,
+ Output: this.flagsBinaryProtoPath,
+ Description: "all_build_flag_declarations",
+ Args: map[string]string{
+ "intermediates": android.JoinPathsWithPrefix(flagsFiles, "--intermediate "),
+ },
+ })
+ ctx.Phony("all_build_flag_declarations", this.flagsBinaryProtoPath)
+
+ // Generate build action for build_flag (text proto output)
+ this.flagsTextProtoPath = android.PathForIntermediates(ctx, "all_build_flag_declarations.textproto")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: allDeclarationsRuleTextProto,
+ Input: this.flagsBinaryProtoPath,
+ Output: this.flagsTextProtoPath,
+ Description: "all_build_flag_declarations_textproto",
+ })
+ ctx.Phony("all_build_flag_declarations_textproto", this.flagsTextProtoPath)
+
+ // Generate build action for release_configs (binary proto output)
+ this.configsBinaryProtoPath = android.PathForIntermediates(ctx, "all_release_config_contributions.pb")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: allReleaseConfigContributionsRule,
+ Inputs: contributionDirs,
+ Output: this.configsBinaryProtoPath,
+ Description: "all_release_config_contributions",
+ Args: map[string]string{
+ "dirs": android.JoinPathsWithPrefix(contributionDirs, "--dir "),
+ "format": "pb",
+ },
+ })
+ ctx.Phony("all_release_config_contributions", this.configsBinaryProtoPath)
+
+ this.configsTextProtoPath = android.PathForIntermediates(ctx, "all_release_config_contributions.textproto")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: allReleaseConfigContributionsRule,
+ Inputs: contributionDirs,
+ Output: this.configsTextProtoPath,
+ Description: "all_release_config_contributions_textproto",
+ Args: map[string]string{
+ "dirs": android.JoinPathsWithPrefix(contributionDirs, "--dir "),
+ "format": "textproto",
+ },
+ })
+ ctx.Phony("all_release_config_contributions_textproto", this.configsTextProtoPath)
+
+ // Add a simple target for ci/build_metadata to use.
+ ctx.Phony("release_config_metadata",
+ this.flagsBinaryProtoPath,
+ this.flagsTextProtoPath,
+ this.configsBinaryProtoPath,
+ this.configsTextProtoPath,
+ )
+}
+
+func (this *allBuildFlagDeclarationsSingleton) MakeVars(ctx android.MakeVarsContext) {
+ ctx.DistForGoal("droid", this.flagsBinaryProtoPath)
+ for _, goal := range []string{"docs", "droid", "sdk", "release_config_metadata"} {
+ ctx.DistForGoalWithFilename(goal, this.flagsBinaryProtoPath, "build_flags/all_flags.pb")
+ ctx.DistForGoalWithFilename(goal, this.flagsTextProtoPath, "build_flags/all_flags.textproto")
+ ctx.DistForGoalWithFilename(goal, this.configsBinaryProtoPath, "build_flags/all_release_config_contributions.pb")
+ ctx.DistForGoalWithFilename(goal, this.configsTextProtoPath, "build_flags/all_release_config_contributions.textproto")
+ }
+}
diff --git a/aconfig/build_flags/declarations.go b/aconfig/build_flags/declarations.go
index e927db2..4a54269 100644
--- a/aconfig/build_flags/declarations.go
+++ b/aconfig/build_flags/declarations.go
@@ -35,7 +35,7 @@
// Properties for "aconfig_declarations"
properties struct {
- // aconfig files, relative to this Android.bp file
+ // build flag declaration files, relative to this Android.bp file
Srcs []string `android:"path"`
}
}
diff --git a/aconfig/build_flags/init.go b/aconfig/build_flags/init.go
index dc1369c..a7575e8 100644
--- a/aconfig/build_flags/init.go
+++ b/aconfig/build_flags/init.go
@@ -65,15 +65,32 @@
"${buildFlagDeclarations}",
},
})
+
+ allReleaseConfigContributionsRule = pctx.AndroidStaticRule("all-release-config-contributions-dump",
+ blueprint.RuleParams{
+ Command: `${releaseConfigContributions} ${dirs} --format ${format} --output ${out}`,
+ CommandDeps: []string{
+ "${releaseConfigContributions}",
+ },
+ }, "dirs", "format")
+ allReleaseConfigContributionsRuleText = pctx.AndroidStaticRule("all-release-config-contributions-dumptext",
+ blueprint.RuleParams{
+ Command: `${releaseConfigContributions} ${dirs} --format ${format} --output ${out}`,
+ CommandDeps: []string{
+ "${releaseConfigContributions}",
+ },
+ }, "dirs", "format")
)
func init() {
RegisterBuildComponents(android.InitRegistrationContext)
pctx.Import("android/soong/android")
pctx.HostBinToolVariable("buildFlagDeclarations", "build-flag-declarations")
+ pctx.HostBinToolVariable("releaseConfigContributions", "release-config-contributions")
}
func RegisterBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("build_flag_declarations", DeclarationsFactory)
+ ctx.RegisterModuleType("release_config_contributions", ReleaseConfigContributionsFactory)
ctx.RegisterParallelSingletonType("all_build_flag_declarations", AllBuildFlagDeclarationsFactory)
}
diff --git a/aconfig/build_flags/release_configs.go b/aconfig/build_flags/release_configs.go
new file mode 100644
index 0000000..3fa8a7c
--- /dev/null
+++ b/aconfig/build_flags/release_configs.go
@@ -0,0 +1,78 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package build_flags
+
+import (
+ "path/filepath"
+
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+)
+
+type ReleaseConfigContributionsProviderData struct {
+ ContributionDir android.SourcePath
+}
+
+var ReleaseConfigContributionsProviderKey = blueprint.NewProvider[ReleaseConfigContributionsProviderData]()
+
+// Soong uses `release_config_contributions` modules to produce the
+// `build_flags/all_release_config_contributions.*` artifacts, listing *all* of
+// the directories in the source tree that contribute to each release config,
+// whether or not they are actually used for the lunch product.
+//
+// This artifact helps flagging automation determine in which directory a flag
+// should be placed by default.
+type ReleaseConfigContributionsModule struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+
+ // Properties for "release_config_contributions"
+ properties struct {
+ // The `release_configs/*.textproto` files provided by this
+ // directory, relative to this Android.bp file
+ Srcs []string `android:"path"`
+ }
+}
+
+func ReleaseConfigContributionsFactory() android.Module {
+ module := &ReleaseConfigContributionsModule{}
+
+ android.InitAndroidModule(module)
+ android.InitDefaultableModule(module)
+ module.AddProperties(&module.properties)
+
+ return module
+}
+
+func (module *ReleaseConfigContributionsModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ srcs := android.PathsForModuleSrc(ctx, module.properties.Srcs)
+ if len(srcs) == 0 {
+ return
+ }
+ contributionDir := filepath.Dir(filepath.Dir(srcs[0].String()))
+ for _, file := range srcs {
+ if filepath.Dir(filepath.Dir(file.String())) != contributionDir {
+ ctx.ModuleErrorf("Cannot include %s with %s contributions", file, contributionDir)
+ }
+ if filepath.Base(filepath.Dir(file.String())) != "release_configs" || file.Ext() != ".textproto" {
+ ctx.ModuleErrorf("Invalid contribution file %s", file)
+ }
+ }
+ android.SetProvider(ctx, ReleaseConfigContributionsProviderKey, ReleaseConfigContributionsProviderData{
+ ContributionDir: android.PathForSource(ctx, contributionDir),
+ })
+
+}
diff --git a/aconfig/codegen/aconfig_declarations_group.go b/aconfig/codegen/aconfig_declarations_group.go
index 13daf47..6811d06 100644
--- a/aconfig/codegen/aconfig_declarations_group.go
+++ b/aconfig/codegen/aconfig_declarations_group.go
@@ -59,7 +59,7 @@
func AconfigDeclarationsGroupFactory() android.Module {
module := &AconfigDeclarationsGroup{}
module.AddProperties(&module.properties)
- android.InitAndroidModule(module)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
return module
}
diff --git a/aconfig/codegen/aconfig_declarations_group_test.go b/aconfig/codegen/aconfig_declarations_group_test.go
index c69d21f..ef954ce 100644
--- a/aconfig/codegen/aconfig_declarations_group_test.go
+++ b/aconfig/codegen/aconfig_declarations_group_test.go
@@ -67,7 +67,7 @@
`)
// Check if aconfig_declarations_group module depends on the aconfig_library modules
- java.CheckModuleDependencies(t, result.TestContext, "my_group", "", []string{
+ java.CheckModuleDependencies(t, result.TestContext, "my_group", "android_common", []string{
`bar-java`,
`foo-java`,
})
diff --git a/aconfig/codegen/cc_aconfig_library.go b/aconfig/codegen/cc_aconfig_library.go
index ec0a6b6..f9c7b8c 100644
--- a/aconfig/codegen/cc_aconfig_library.go
+++ b/aconfig/codegen/cc_aconfig_library.go
@@ -63,7 +63,7 @@
callbacks := &CcAconfigLibraryCallbacks{
properties: &CcAconfigLibraryProperties{},
}
- return cc.GeneratedCcLibraryModuleFactory("cc_aconfig_library", callbacks)
+ return cc.GeneratedCcLibraryModuleFactory(callbacks)
}
func (this *CcAconfigLibraryCallbacks) GeneratorInit(ctx cc.BaseModuleContext) {
@@ -104,7 +104,7 @@
result := cc.GeneratedSource{}
// Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
- declarationsModules := ctx.GetDirectDepsWithTag(ccDeclarationsTag)
+ declarationsModules := ctx.GetDirectDepsProxyWithTag(ccDeclarationsTag)
if len(declarationsModules) != 1 {
panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
}
@@ -134,7 +134,7 @@
func (this *CcAconfigLibraryCallbacks) GeneratorBuildActions(ctx cc.ModuleContext, flags cc.Flags, deps cc.PathDeps) {
// Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
- declarationsModules := ctx.GetDirectDepsWithTag(ccDeclarationsTag)
+ declarationsModules := ctx.GetDirectDepsProxyWithTag(ccDeclarationsTag)
if len(declarationsModules) != 1 {
panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
}
@@ -156,7 +156,7 @@
Args: map[string]string{
"gendir": this.generatedDir.String(),
"mode": mode,
- "debug": strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorageCc()),
+ "debug": strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorage()),
},
})
diff --git a/aconfig/codegen/cc_aconfig_library_test.go b/aconfig/codegen/cc_aconfig_library_test.go
index 2f6c1a6..c308ed4 100644
--- a/aconfig/codegen/cc_aconfig_library_test.go
+++ b/aconfig/codegen/cc_aconfig_library_test.go
@@ -211,7 +211,7 @@
module := result.ModuleForTests("my_cc_library", "android_vendor_arm64_armv8-a_shared").Module()
- entry := android.AndroidMkEntriesForTest(t, result.TestContext, module)[0]
+ entry := android.AndroidMkInfoForTest(t, result.TestContext, module).PrimaryInfo
makeVar := entry.EntryMap["LOCAL_ACONFIG_FILES"]
android.EnsureListContainsSuffix(t, makeVar, "my_aconfig_declarations_foo/intermediate.pb")
diff --git a/aconfig/codegen/init.go b/aconfig/codegen/init.go
index 6182e14..385fa49 100644
--- a/aconfig/codegen/init.go
+++ b/aconfig/codegen/init.go
@@ -26,20 +26,25 @@
// For java_aconfig_library: Generate java library
javaRule = pctx.AndroidStaticRule("java_aconfig_library",
blueprint.RuleParams{
+ // LINT.IfChange
Command: `rm -rf ${out}.tmp` +
` && mkdir -p ${out}.tmp` +
` && ${aconfig} create-java-lib` +
` --mode ${mode}` +
` --cache ${in}` +
` --out ${out}.tmp` +
+ ` --allow-instrumentation ${debug}` +
+ ` --new-exported ${new_exported}` +
+ ` --check-api-level ${check_api_level}` +
` && $soong_zip -write_if_changed -jar -o ${out} -C ${out}.tmp -D ${out}.tmp` +
` && rm -rf ${out}.tmp`,
+ // LINT.ThenChange(/aconfig/init.go)
CommandDeps: []string{
"$aconfig",
"$soong_zip",
},
Restat: true,
- }, "mode")
+ }, "mode", "debug", "new_exported", "check_api_level")
// For cc_aconfig_library: Generate C++ library
cppRule = pctx.AndroidStaticRule("cc_aconfig_library",
@@ -64,11 +69,12 @@
` && ${aconfig} create-rust-lib` +
` --mode ${mode}` +
` --cache ${in}` +
+ ` --allow-instrumentation ${debug}` +
` --out ${gendir}`,
CommandDeps: []string{
"$aconfig",
},
- }, "gendir", "mode")
+ }, "gendir", "mode", "debug")
)
func init() {
diff --git a/aconfig/codegen/java_aconfig_library.go b/aconfig/codegen/java_aconfig_library.go
index 673ac2a..7b9da8e 100644
--- a/aconfig/codegen/java_aconfig_library.go
+++ b/aconfig/codegen/java_aconfig_library.go
@@ -20,6 +20,7 @@
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
+ "strconv"
)
type declarationsTagType struct {
@@ -71,6 +72,7 @@
module.AddSharedLibrary("aconfig-annotations-lib")
// TODO(b/303773055): Remove the annotation after access issue is resolved.
module.AddSharedLibrary("unsupportedappusage")
+ module.AddSharedLibrary("aconfig_storage_stub")
}
}
@@ -96,13 +98,24 @@
ctx.PropertyErrorf("mode", "exported mode requires its aconfig_declaration has exportable prop true")
}
+ var newExported bool
+ if useNewExported, ok := ctx.Config().GetBuildFlag("RELEASE_ACONFIG_NEW_EXPORTED"); ok {
+ // The build flag (RELEASE_ACONFIG_REQUIRE_ALL_READ_ONLY) is the negation of the aconfig flag
+ // (allow-read-write) for historical reasons.
+ // Bool build flags are always "" for false, and generally "true" for true.
+ newExported = useNewExported == "true"
+ }
+
ctx.Build(pctx, android.BuildParams{
Rule: javaRule,
Input: declarations.IntermediateCacheOutputPath,
Output: srcJarPath,
Description: "aconfig.srcjar",
Args: map[string]string{
- "mode": mode,
+ "mode": mode,
+ "debug": strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorage()),
+ "new_exported": strconv.FormatBool(newExported),
+ "check_api_level": strconv.FormatBool(ctx.Config().ReleaseAconfigCheckApiLevel()),
},
})
diff --git a/aconfig/codegen/java_aconfig_library_test.go b/aconfig/codegen/java_aconfig_library_test.go
index 87b54a4..d8372f3 100644
--- a/aconfig/codegen/java_aconfig_library_test.go
+++ b/aconfig/codegen/java_aconfig_library_test.go
@@ -260,7 +260,7 @@
aconfig_declarations {
name: "my_aconfig_declarations_bar",
package: "com.example.package.bar",
- container: "system_ext",
+ container: "vendor",
srcs: ["bar.aconfig"],
}
diff --git a/aconfig/codegen/rust_aconfig_library.go b/aconfig/codegen/rust_aconfig_library.go
index ad8d632..4b896c3 100644
--- a/aconfig/codegen/rust_aconfig_library.go
+++ b/aconfig/codegen/rust_aconfig_library.go
@@ -2,6 +2,7 @@
import (
"fmt"
+ "strconv"
"android/soong/android"
"android/soong/rust"
@@ -82,6 +83,7 @@
Args: map[string]string{
"gendir": generatedDir.String(),
"mode": mode,
+ "debug": strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorage()),
},
})
a.BaseSourceProvider.OutputFiles = android.Paths{generatedSource}
diff --git a/aconfig/exported_java_aconfig_library.go b/aconfig/exported_java_aconfig_library.go
index a64cac8..dd068d1 100644
--- a/aconfig/exported_java_aconfig_library.go
+++ b/aconfig/exported_java_aconfig_library.go
@@ -16,6 +16,7 @@
import (
"android/soong/android"
+ "strconv"
)
func ExportedJavaDeclarationsLibraryFactory() android.Singleton {
@@ -37,6 +38,16 @@
cacheFiles = append(cacheFiles, decl.IntermediateCacheOutputPath)
})
+ var newExported bool
+ if useNewExported, ok := ctx.Config().GetBuildFlag("RELEASE_ACONFIG_NEW_EXPORTED"); ok {
+ newExported = useNewExported == "true"
+ }
+
+ var newStorage bool
+ if useNewStorage, ok := ctx.Config().GetBuildFlag("RELEASE_READ_FROM_NEW_STORAGE"); ok {
+ newStorage = useNewStorage == "true"
+ }
+
// Generate build action for aconfig
this.intermediatePath = android.PathForIntermediates(ctx, "exported_java_aconfig_library.jar")
ctx.Build(pctx, android.BuildParams{
@@ -45,7 +56,10 @@
Output: this.intermediatePath,
Description: "exported_java_aconfig_library",
Args: map[string]string{
- "cache_files": android.JoinPathsWithPrefix(cacheFiles, " "),
+ "cache_files": android.JoinPathsWithPrefix(cacheFiles, " "),
+ "use_new_storage": strconv.FormatBool(newStorage),
+ "use_new_exported": strconv.FormatBool(newExported),
+ "check_api_level": strconv.FormatBool(ctx.Config().ReleaseAconfigCheckApiLevel()),
},
})
ctx.Phony("exported_java_aconfig_library", this.intermediatePath)
diff --git a/aconfig/init.go b/aconfig/init.go
index 5fa7e76..3dcec5c 100644
--- a/aconfig/init.go
+++ b/aconfig/init.go
@@ -15,8 +15,6 @@
package aconfig
import (
- "encoding/gob"
-
"android/soong/android"
"github.com/google/blueprint"
@@ -34,6 +32,7 @@
` ${declarations}` +
` ${values}` +
` ${default-permission}` +
+ ` ${allow-read-write}` +
` --cache ${out}.tmp` +
` && ( if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`,
// ` --build-id ${release_version}` +
@@ -41,7 +40,7 @@
"${aconfig}",
},
Restat: true,
- }, "release_version", "package", "container", "declarations", "values", "default-permission")
+ }, "release_version", "package", "container", "declarations", "values", "default-permission", "allow-read-write")
// For create-device-config-sysprops: Generate aconfig flag value map text file
aconfigTextRule = pctx.AndroidStaticRule("aconfig_text",
@@ -71,14 +70,21 @@
"${aconfig}",
},
}, "cache_files")
+ RecordFinalizedFlagsRule = pctx.AndroidStaticRule("RecordFinalizedFlagsRule",
+ blueprint.RuleParams{
+ Command: `${record-finalized-flags} ${parsed_flags_file} ${finalized_flags_file} ${api_signature_files} > ${out}`,
+ CommandDeps: []string{
+ "${record-finalized-flags}",
+ },
+ }, "api_signature_files", "finalized_flags_file", "parsed_flags_file")
CreateStorageRule = pctx.AndroidStaticRule("aconfig_create_storage",
blueprint.RuleParams{
- Command: `${aconfig} create-storage --container ${container} --file ${file_type} --out ${out} ${cache_files}`,
+ Command: `${aconfig} create-storage --container ${container} --file ${file_type} --out ${out} ${cache_files} --version ${version}`,
CommandDeps: []string{
"${aconfig}",
},
- }, "container", "file_type", "cache_files")
+ }, "container", "file_type", "cache_files", "version")
// For exported_java_aconfig_library: Generate a JAR from all
// java_aconfig_libraries to be consumed by apps built outside the
@@ -89,35 +95,40 @@
// exported flags (only). Finally collect all generated code
// into the ${out} JAR file.
blueprint.RuleParams{
+ // LINT.IfChange
Command: `rm -rf ${out}.tmp` +
`&& for cache in ${cache_files}; do ` +
` if [ -n "$$(${aconfig} dump-cache --dedup --cache $$cache --filter=is_exported:true --format='{fully_qualified_name}')" ]; then ` +
- ` ${aconfig} create-java-lib --cache $$cache --mode=exported --out ${out}.tmp; ` +
+ ` ${aconfig} create-java-lib` +
+ ` --cache $$cache` +
+ ` --mode=exported` +
+ ` --allow-instrumentation ${use_new_storage}` +
+ ` --new-exported ${use_new_exported}` +
+ ` --check-api-level ${check_api_level}` +
+ ` --out ${out}.tmp; ` +
` fi ` +
`done` +
`&& $soong_zip -write_if_changed -jar -o ${out} -C ${out}.tmp -D ${out}.tmp` +
`&& rm -rf ${out}.tmp`,
+ // LINT.ThenChange(/aconfig/codegen/init.go)
CommandDeps: []string{
"$aconfig",
"$soong_zip",
},
- }, "cache_files")
+ }, "cache_files", "use_new_storage", "use_new_exported", "check_api_level")
)
func init() {
RegisterBuildComponents(android.InitRegistrationContext)
pctx.HostBinToolVariable("aconfig", "aconfig")
pctx.HostBinToolVariable("soong_zip", "soong_zip")
-
- gob.Register(android.AconfigDeclarationsProviderData{})
- gob.Register(android.AconfigReleaseDeclarationsProviderData{})
- gob.Register(android.ModuleOutPath{})
+ pctx.HostBinToolVariable("record-finalized-flags", "record-finalized-flags")
}
func RegisterBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("aconfig_declarations", DeclarationsFactory)
ctx.RegisterModuleType("aconfig_values", ValuesFactory)
ctx.RegisterModuleType("aconfig_value_set", ValueSetFactory)
- ctx.RegisterParallelSingletonType("all_aconfig_declarations", AllAconfigDeclarationsFactory)
+ ctx.RegisterSingletonModuleType("all_aconfig_declarations", AllAconfigDeclarationsFactory)
ctx.RegisterParallelSingletonType("exported_java_aconfig_library", ExportedJavaDeclarationsLibraryFactory)
}
diff --git a/aidl_library/Android.bp b/aidl_library/Android.bp
index ec21504..3c386fb 100644
--- a/aidl_library/Android.bp
+++ b/aidl_library/Android.bp
@@ -20,6 +20,7 @@
name: "soong-aidl-library",
pkgPath: "android/soong/aidl_library",
deps: [
+ "blueprint-depset",
"soong-android",
],
srcs: [
@@ -29,4 +30,5 @@
"aidl_library_test.go",
],
pluginFor: ["soong_build"],
+ visibility: ["//visibility:public"],
}
diff --git a/aidl_library/aidl_library.go b/aidl_library/aidl_library.go
index 0141545..1e0ab30 100644
--- a/aidl_library/aidl_library.go
+++ b/aidl_library/aidl_library.go
@@ -17,6 +17,7 @@
import (
"android/soong/android"
"github.com/google/blueprint"
+ "github.com/google/blueprint/depset"
"github.com/google/blueprint/proptools"
)
@@ -58,17 +59,17 @@
// The direct aidl files of the module
Srcs android.Paths
// The include dirs to the direct aidl files and those provided from transitive aidl_library deps
- IncludeDirs android.DepSet[android.Path]
+ IncludeDirs depset.DepSet[android.Path]
// The direct hdrs and hdrs from transitive deps
- Hdrs android.DepSet[android.Path]
+ Hdrs depset.DepSet[android.Path]
}
// AidlLibraryProvider provides the srcs and the transitive include dirs
var AidlLibraryProvider = blueprint.NewProvider[AidlLibraryInfo]()
func (lib *AidlLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- includeDirsDepSetBuilder := android.NewDepSetBuilder[android.Path](android.PREORDER)
- hdrsDepSetBuilder := android.NewDepSetBuilder[android.Path](android.PREORDER)
+ includeDirsDepSetBuilder := depset.NewBuilder[android.Path](depset.PREORDER)
+ hdrsDepSetBuilder := depset.NewBuilder[android.Path](depset.PREORDER)
if len(lib.properties.Srcs) == 0 && len(lib.properties.Hdrs) == 0 {
ctx.ModuleErrorf("at least srcs or hdrs prop must be non-empty")
@@ -100,15 +101,15 @@
for _, dep := range ctx.GetDirectDepsWithTag(aidlLibraryTag) {
if info, ok := android.OtherModuleProvider(ctx, dep, AidlLibraryProvider); ok {
- includeDirsDepSetBuilder.Transitive(&info.IncludeDirs)
- hdrsDepSetBuilder.Transitive(&info.Hdrs)
+ includeDirsDepSetBuilder.Transitive(info.IncludeDirs)
+ hdrsDepSetBuilder.Transitive(info.Hdrs)
}
}
android.SetProvider(ctx, AidlLibraryProvider, AidlLibraryInfo{
Srcs: srcs,
- IncludeDirs: *includeDirsDepSetBuilder.Build(),
- Hdrs: *hdrsDepSetBuilder.Build(),
+ IncludeDirs: includeDirsDepSetBuilder.Build(),
+ Hdrs: hdrsDepSetBuilder.Build(),
})
}
diff --git a/android/Android.bp b/android/Android.bp
index 96e8133..d27a8fa 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -8,6 +8,8 @@
deps: [
"blueprint",
"blueprint-bootstrap",
+ "blueprint-depset",
+ "blueprint-gobtools",
"blueprint-metrics",
"sbox_proto",
"soong",
@@ -29,6 +31,7 @@
srcs: [
"aconfig_providers.go",
"all_teams.go",
+ "android_info.go",
"androidmk.go",
"apex.go",
"apex_contributions.go",
@@ -41,6 +44,7 @@
"build_prop.go",
"compliance_metadata.go",
"config.go",
+ "container_violations.go",
"container.go",
"test_config.go",
"configurable_properties.go",
@@ -49,8 +53,8 @@
"deapexer.go",
"defaults.go",
"defs.go",
- "depset_generic.go",
"deptag.go",
+ "dirgroup.go",
"early_module_context.go",
"expand.go",
"filegroup.go",
@@ -58,6 +62,7 @@
"gen_notice.go",
"hooks.go",
"image.go",
+ "init.go",
"license.go",
"license_kind.go",
"license_metadata.go",
@@ -69,10 +74,12 @@
"module.go",
"module_context.go",
"module_info_json.go",
+ "module_proxy.go",
"mutator.go",
"namespace.go",
"neverallow.go",
"ninja_deps.go",
+ "nothing.go",
"notices.go",
"onceper.go",
"override_module.go",
@@ -86,10 +93,13 @@
"prebuilt.go",
"prebuilt_build_tool.go",
"product_config.go",
+ "product_packages_file.go",
"proto.go",
"provider.go",
"raw_files.go",
+ "recovery_build_prop.go",
"register.go",
+ "removed_package.go",
"rule_builder.go",
"sandbox.go",
"sbom.go",
@@ -103,10 +113,12 @@
"test_asserts.go",
"test_suites.go",
"testing.go",
- "updatable_modules.go",
+ "transition.go",
"util.go",
"variable.go",
+ "vendor_api_levels.go",
"vintf_fragment.go",
+ "vintf_data.go",
"visibility.go",
],
testSrcs: [
@@ -116,11 +128,11 @@
"apex_test.go",
"arch_test.go",
"blueprint_e2e_test.go",
+ "build_prop_test.go",
"config_test.go",
"configured_jars_test.go",
"csuite_config_test.go",
"defaults_test.go",
- "depset_test.go",
"deptag_test.go",
"expand_test.go",
"filegroup_test.go",
@@ -147,9 +159,12 @@
"singleton_module_test.go",
"soong_config_modules_test.go",
"test_suites_test.go",
+ "transition_test.go",
"util_test.go",
"variable_test.go",
"vintf_fragment_test.go",
"visibility_test.go",
],
+ // Used by plugins
+ visibility: ["//visibility:public"],
}
diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go
index f0675dd..b698d24 100644
--- a/android/aconfig_providers.go
+++ b/android/aconfig_providers.go
@@ -92,11 +92,11 @@
if asError {
ctx.ModuleErrorf(msg)
} else {
- fmt.Printf("WARNING: " + msg)
+ fmt.Print("WARNING: " + msg)
}
} else {
if !asError {
- fmt.Printf("PASSED: " + msg)
+ fmt.Print("PASSED: " + msg)
}
}
}
@@ -107,7 +107,7 @@
mergedAconfigFiles := make(map[string]Paths)
mergedModeInfos := make(map[string]ModeInfo)
- ctx.VisitDirectDepsIgnoreBlueprint(func(module Module) {
+ ctx.VisitDirectDepsProxy(func(module ModuleProxy) {
if aconfig_dep, ok := OtherModuleProvider(ctx, module, CodegenInfoProvider); ok && len(aconfig_dep.ModeInfos) > 0 {
maps.Copy(mergedModeInfos, aconfig_dep.ModeInfos)
}
@@ -136,7 +136,7 @@
AconfigFiles: mergedAconfigFiles,
ModeInfos: mergedModeInfos,
})
- ctx.Module().base().aconfigFilePaths = getAconfigFilePaths(ctx.Module().base(), mergedAconfigFiles)
+ ctx.setAconfigPaths(getAconfigFilePaths(ctx.Module().base(), mergedAconfigFiles))
}
}
@@ -187,6 +187,20 @@
}
}
+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 {
@@ -219,7 +233,8 @@
} 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]...)
diff --git a/android/android_info.go b/android/android_info.go
new file mode 100644
index 0000000..9a68d10
--- /dev/null
+++ b/android/android_info.go
@@ -0,0 +1,92 @@
+// Copyright 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+var (
+ mergeAndRemoveComments = pctx.AndroidStaticRule("merge_and_remove_comments",
+ blueprint.RuleParams{
+ Command: "cat $in | grep -v '#' > $out",
+ },
+ )
+ androidInfoTxtToProp = pctx.AndroidStaticRule("android_info_txt_to_prop",
+ blueprint.RuleParams{
+ Command: "grep 'require version-' $in | sed -e 's/require version-/ro.build.expect./g' > $out",
+ },
+ )
+)
+
+type androidInfoProperties struct {
+ // Name of output file. Defaults to module name
+ Stem *string
+
+ // Paths of board-info.txt files.
+ Board_info_files []string `android:"path"`
+
+ // Name of bootloader board. If board_info_files is empty, `board={bootloader_board_name}` will
+ // be printed to output. Ignored if board_info_files is not empty.
+ Bootloader_board_name *string
+}
+
+type androidInfoModule struct {
+ ModuleBase
+
+ properties androidInfoProperties
+}
+
+func (p *androidInfoModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ if len(p.properties.Board_info_files) > 0 && p.properties.Bootloader_board_name != nil {
+ ctx.ModuleErrorf("Either Board_info_files or Bootloader_board_name should be set. Please remove one of them\n")
+ return
+ }
+ androidInfoTxtName := proptools.StringDefault(p.properties.Stem, ctx.ModuleName()+".txt")
+ androidInfoTxt := PathForModuleOut(ctx, androidInfoTxtName)
+ androidInfoProp := androidInfoTxt.ReplaceExtension(ctx, "prop")
+
+ if boardInfoFiles := PathsForModuleSrc(ctx, p.properties.Board_info_files); len(boardInfoFiles) > 0 {
+ ctx.Build(pctx, BuildParams{
+ Rule: mergeAndRemoveComments,
+ Inputs: boardInfoFiles,
+ Output: androidInfoTxt,
+ })
+ } else if bootloaderBoardName := proptools.String(p.properties.Bootloader_board_name); bootloaderBoardName != "" {
+ WriteFileRule(ctx, androidInfoTxt, "board="+bootloaderBoardName)
+ } else {
+ WriteFileRule(ctx, androidInfoTxt, "")
+ }
+
+ // Create android_info.prop
+ ctx.Build(pctx, BuildParams{
+ Rule: androidInfoTxtToProp,
+ Input: androidInfoTxt,
+ Output: androidInfoProp,
+ })
+
+ ctx.SetOutputFiles(Paths{androidInfoProp}, "")
+ ctx.SetOutputFiles(Paths{androidInfoTxt}, ".txt")
+}
+
+// android_info module generate a file named android-info.txt that contains various information
+// about the device we're building for. This file is typically packaged up with everything else.
+func AndroidInfoFactory() Module {
+ module := &androidInfoModule{}
+ module.AddProperties(&module.properties)
+ InitAndroidArchModule(module, DeviceSupported, MultilibCommon)
+ return module
+}
diff --git a/android/androidmk.go b/android/androidmk.go
index f6f4889..f862a96 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -34,7 +34,6 @@
"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 AndroidMkEntriesContext interface {
+ OtherModuleProviderContext
Config() Config
}
@@ -354,14 +354,15 @@
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 @@
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.
@@ -462,18 +463,18 @@
func generateDistContributionsForMake(distContributions *distContributions) []string {
var ret []string
for _, d := range distContributions.copiesForGoals {
- ret = append(ret, fmt.Sprintf(".PHONY: %s\n", d.goals))
+ ret = append(ret, fmt.Sprintf(".PHONY: %s", d.goals))
// Create dist-for-goals calls for each of the copy instructions.
for _, c := range d.copies {
if distContributions.licenseMetadataFile != nil {
ret = append(
ret,
- fmt.Sprintf("$(if $(strip $(ALL_TARGETS.%s.META_LIC)),,$(eval ALL_TARGETS.%s.META_LIC := %s))\n",
+ fmt.Sprintf("$(if $(strip $(ALL_TARGETS.%s.META_LIC)),,$(eval ALL_TARGETS.%s.META_LIC := %s))",
c.from.String(), c.from.String(), distContributions.licenseMetadataFile.String()))
}
ret = append(
ret,
- fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)\n", d.goals, c.from.String(), c.dest))
+ fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)", d.goals, c.from.String(), c.dest))
}
}
@@ -500,6 +501,7 @@
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) {
@@ -521,7 +523,7 @@
a.Target_required = append(a.Target_required, amod.TargetRequiredModuleNames()...)
for _, distString := range a.GetDistForGoals(mod) {
- fmt.Fprintf(&a.header, distString)
+ fmt.Fprintln(&a.header, distString)
}
fmt.Fprintf(&a.header, "\ninclude $(CLEAR_VARS) # type: %s, name: %s, variant: %s\n", ctx.ModuleType(mod), base.BaseModuleName(), ctx.ModuleSubDir(mod))
@@ -552,6 +554,14 @@
a.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", proptools.Bool(base.commonProperties.No_full_install))
}
+ 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)...)
}
@@ -590,10 +600,10 @@
}
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) {
@@ -691,11 +701,6 @@
type androidMkSingleton struct{}
func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) {
- // Skip if Soong wasn't invoked from Make.
- if !ctx.Config().KatiEnabled() {
- return
- }
-
var androidMkModulesList []blueprint.Module
ctx.VisitAllModulesBlueprint(func(module blueprint.Module) {
@@ -708,6 +713,12 @@
return ctx.ModuleName(androidMkModulesList[i]) < ctx.ModuleName(androidMkModulesList[j])
})
+ // If running in soong-only mode, do a different, more limited version of this singleton
+ if !ctx.Config().KatiEnabled() {
+ c.soongOnlyBuildActions(ctx, androidMkModulesList)
+ return
+ }
+
transMk := PathForOutput(ctx, "Android"+String(ctx.Config().productVariables.Make_suffix)+".mk")
if ctx.Failed() {
return
@@ -726,6 +737,162 @@
})
}
+// In soong-only mode, we don't do most of the androidmk stuff. But disted files are still largely
+// defined through the androidmk mechanisms, so this function is an alternate implementation of
+// the androidmk singleton that just focuses on getting the dist contributions
+func (c *androidMkSingleton) soongOnlyBuildActions(ctx SingletonContext, mods []blueprint.Module) {
+ allDistContributions, moduleInfoJSONs := getSoongOnlyDataFromMods(ctx, mods)
+
+ // Build module-info.json. Only in builds with HasDeviceProduct(), as we need a named
+ // device to have a TARGET_OUT folder.
+ if ctx.Config().HasDeviceProduct() {
+ preMergePath := PathForOutput(ctx, "module_info_pre_merging.json")
+ moduleInfoJSONPath := pathForInstall(ctx, Android, X86_64, "", "module-info.json")
+ if err := writeModuleInfoJSON(ctx, moduleInfoJSONs, preMergePath); err != nil {
+ ctx.Errorf("%s", err)
+ }
+ builder := NewRuleBuilder(pctx, ctx)
+ builder.Command().
+ BuiltTool("merge_module_info_json").
+ FlagWithOutput("-o ", moduleInfoJSONPath).
+ Input(preMergePath)
+ builder.Build("merge_module_info_json", "merge module info json")
+ ctx.Phony("module-info", moduleInfoJSONPath)
+ ctx.Phony("droidcore-unbundled", moduleInfoJSONPath)
+ allDistContributions = append(allDistContributions, distContributions{
+ copiesForGoals: []*copiesForGoals{{
+ goals: "general-tests droidcore-unbundled",
+ copies: []distCopy{{
+ from: moduleInfoJSONPath,
+ dest: "module-info.json",
+ }},
+ }},
+ })
+ }
+
+ // Build dist.mk for the packaging step to read and generate dist targets
+ distMkFile := absolutePath(filepath.Join(ctx.Config().katiPackageMkDir(), "dist.mk"))
+
+ var goalOutputPairs []string
+ var srcDstPairs []string
+ for _, contributions := range allDistContributions {
+ for _, copiesForGoal := range contributions.copiesForGoals {
+ goals := strings.Fields(copiesForGoal.goals)
+ for _, copy := range copiesForGoal.copies {
+ for _, goal := range goals {
+ goalOutputPairs = append(goalOutputPairs, fmt.Sprintf(" %s:%s", goal, copy.dest))
+ }
+ srcDstPairs = append(srcDstPairs, fmt.Sprintf(" %s:%s", copy.from.String(), copy.dest))
+ }
+ }
+ }
+ // There are duplicates in the lists that we need to remove
+ goalOutputPairs = SortedUniqueStrings(goalOutputPairs)
+ srcDstPairs = SortedUniqueStrings(srcDstPairs)
+ var buf strings.Builder
+ buf.WriteString("DIST_SRC_DST_PAIRS :=")
+ for _, srcDstPair := range srcDstPairs {
+ buf.WriteString(srcDstPair)
+ }
+ buf.WriteString("\nDIST_GOAL_OUTPUT_PAIRS :=")
+ for _, goalOutputPair := range goalOutputPairs {
+ buf.WriteString(goalOutputPair)
+ }
+ buf.WriteString("\n")
+
+ writeValueIfChanged(ctx, distMkFile, buf.String())
+}
+
+func writeValueIfChanged(ctx SingletonContext, path string, value string) {
+ if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil {
+ ctx.Errorf("%s\n", err)
+ return
+ }
+ previousValue := ""
+ rawPreviousValue, err := os.ReadFile(path)
+ if err == nil {
+ previousValue = string(rawPreviousValue)
+ }
+
+ if previousValue != value {
+ if err = os.WriteFile(path, []byte(value), 0666); err != nil {
+ ctx.Errorf("Failed to write: %v", err)
+ }
+ }
+}
+
+// getSoongOnlyDataFromMods gathers data from the given modules needed in soong-only builds.
+// Currently, this is the dist contributions, and the module-info.json contents.
+func getSoongOnlyDataFromMods(ctx fillInEntriesContext, mods []blueprint.Module) ([]distContributions, []*ModuleInfoJSON) {
+ var allDistContributions []distContributions
+ var moduleInfoJSONs []*ModuleInfoJSON
+ for _, mod := range mods {
+ if amod, ok := mod.(Module); ok && shouldSkipAndroidMkProcessing(ctx, amod.base()) {
+ continue
+ }
+ if info, ok := OtherModuleProvider(ctx, mod, AndroidMkInfoProvider); ok {
+ // Deep copy the provider info since we need to modify the info later
+ info := deepCopyAndroidMkProviderInfo(info)
+ info.PrimaryInfo.fillInEntries(ctx, mod)
+ if info.PrimaryInfo.disabled() {
+ continue
+ }
+ if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
+ moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON...)
+ }
+ if contribution := info.PrimaryInfo.getDistContributions(ctx, mod); contribution != nil {
+ allDistContributions = append(allDistContributions, *contribution)
+ }
+ for _, ei := range info.ExtraInfo {
+ ei.fillInEntries(ctx, mod)
+ if ei.disabled() {
+ continue
+ }
+ if contribution := ei.getDistContributions(ctx, mod); contribution != nil {
+ allDistContributions = append(allDistContributions, *contribution)
+ }
+ }
+ } else {
+ switch x := mod.(type) {
+ case AndroidMkDataProvider:
+ data := x.AndroidMk()
+
+ if data.Include == "" {
+ data.Include = "$(BUILD_PREBUILT)"
+ }
+
+ data.fillInData(ctx, mod)
+ if data.Entries.disabled() {
+ continue
+ }
+ if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
+ moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON...)
+ }
+ if contribution := data.Entries.getDistContributions(mod); contribution != nil {
+ allDistContributions = append(allDistContributions, *contribution)
+ }
+ case AndroidMkEntriesProvider:
+ entriesList := x.AndroidMkEntries()
+ for _, entries := range entriesList {
+ entries.fillInEntries(ctx, mod)
+ if entries.disabled() {
+ continue
+ }
+ if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
+ moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON...)
+ }
+ if contribution := entries.getDistContributions(mod); contribution != nil {
+ allDistContributions = append(allDistContributions, *contribution)
+ }
+ }
+ default:
+ // Not exported to make so no make variables to set.
+ }
+ }
+ }
+ return allDistContributions, moduleInfoJSONs
+}
+
func translateAndroidMk(ctx SingletonContext, absMkFile string, moduleInfoJSONPath WritablePath, mods []blueprint.Module) error {
buf := &bytes.Buffer{}
@@ -796,15 +963,18 @@
// 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 := OtherModuleProvider(ctx, mod, AndroidMkInfoProvider); ok {
+ err = translateAndroidMkEntriesInfoModule(ctx, w, moduleInfoJSONs, mod, info)
+ } 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 {
@@ -814,23 +984,6 @@
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{
@@ -903,6 +1056,7 @@
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
@@ -923,7 +1077,7 @@
if !data.Entries.disabled() {
if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
- *moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON)
+ *moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON...)
}
}
@@ -957,26 +1111,31 @@
entriesList := provider.AndroidMkEntries()
aconfigUpdateAndroidMkEntries(ctx, mod.(Module), &entriesList)
+ moduleInfoJSON, providesModuleInfoJSON := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider)
+
// Any new or special cases here need review to verify correct propagation of license information.
for _, entries := range entriesList {
entries.fillInEntries(ctx, mod)
entries.write(w)
- }
- if len(entriesList) > 0 && !entriesList[0].disabled() {
- if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
- *moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON)
+ if providesModuleInfoJSON && !entries.disabled() {
+ // append only the name matching moduleInfoJSON entry
+ for _, m := range moduleInfoJSON {
+ if m.RegisterNameOverride == entries.OverrideName && m.SubName == entries.SubName {
+ *moduleInfoJSONs = append(*moduleInfoJSONs, m)
+ }
+ }
}
}
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?
@@ -1052,3 +1211,557 @@
}
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
+}
+
+type AndroidMkProviderInfoProducer interface {
+ PrepareAndroidMKProviderInfo(config Config) *AndroidMkProviderInfo
+}
+
+// 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", 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 info.UncheckedModule {
+ helperInfo.SetBool("LOCAL_DONT_CHECK_MODULE", true)
+ } else if info.CheckbuildTarget != nil {
+ helperInfo.SetPath("LOCAL_CHECKED_MODULE", info.CheckbuildTarget)
+ } else {
+ helperInfo.SetOptionalPath("LOCAL_CHECKED_MODULE", a.OutputFile)
+ }
+
+ 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")
+ }
+
+ 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") + "\n"
+ combinedFooterString := strings.Join(a.FooterStrings, "\n") + "\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
+}
diff --git a/android/androidmk_test.go b/android/androidmk_test.go
index 72b8654..f63b227 100644
--- a/android/androidmk_test.go
+++ b/android/androidmk_test.go
@@ -46,7 +46,6 @@
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
@@ -196,8 +195,7 @@
$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))
$(call dist-for-goals,my_goal,one.out:one.out)
$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))
-$(call dist-for-goals,my_goal,two.out:other.out)
-`, strings.Join(makeOutput, ""))
+$(call dist-for-goals,my_goal,two.out:other.out)`, strings.Join(makeOutput, "\n"))
}
func TestGetDistForGoals(t *testing.T) {
@@ -236,28 +234,28 @@
`
expectedAndroidMkLines := []string{
- ".PHONY: my_second_goal\n",
- "$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))\n",
- "$(call dist-for-goals,my_second_goal,two.out:two.out)\n",
- "$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))\n",
- "$(call dist-for-goals,my_second_goal,three/four.out:four.out)\n",
- ".PHONY: my_third_goal\n",
- "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
- "$(call dist-for-goals,my_third_goal,one.out:test/dir/one.out)\n",
- ".PHONY: my_fourth_goal\n",
- "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
- "$(call dist-for-goals,my_fourth_goal,one.out:one.suffix.out)\n",
- ".PHONY: my_fifth_goal\n",
- "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
- "$(call dist-for-goals,my_fifth_goal,one.out:new-name)\n",
- ".PHONY: my_sixth_goal\n",
- "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
- "$(call dist-for-goals,my_sixth_goal,one.out:some/dir/new-name.suffix)\n",
- ".PHONY: my_goal my_other_goal\n",
- "$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))\n",
- "$(call dist-for-goals,my_goal my_other_goal,two.out:two.out)\n",
- "$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))\n",
- "$(call dist-for-goals,my_goal my_other_goal,three/four.out:four.out)\n",
+ ".PHONY: my_second_goal",
+ "$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))",
+ "$(call dist-for-goals,my_second_goal,two.out:two.out)",
+ "$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))",
+ "$(call dist-for-goals,my_second_goal,three/four.out:four.out)",
+ ".PHONY: my_third_goal",
+ "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))",
+ "$(call dist-for-goals,my_third_goal,one.out:test/dir/one.out)",
+ ".PHONY: my_fourth_goal",
+ "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))",
+ "$(call dist-for-goals,my_fourth_goal,one.out:one.suffix.out)",
+ ".PHONY: my_fifth_goal",
+ "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))",
+ "$(call dist-for-goals,my_fifth_goal,one.out:new-name)",
+ ".PHONY: my_sixth_goal",
+ "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))",
+ "$(call dist-for-goals,my_sixth_goal,one.out:some/dir/new-name.suffix)",
+ ".PHONY: my_goal my_other_goal",
+ "$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))",
+ "$(call dist-for-goals,my_goal my_other_goal,two.out:two.out)",
+ "$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))",
+ "$(call dist-for-goals,my_goal my_other_goal,three/four.out:four.out)",
}
ctx, module := buildContextAndCustomModuleFoo(t, bp)
@@ -276,7 +274,8 @@
)
}
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'",
diff --git a/android/apex.go b/android/apex.go
index 028be57..08c82eb 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -61,19 +61,6 @@
// that are merged together.
InApexVariants []string
- // List of APEX Soong module names that this module is part of. Note that the list includes
- // different variations of the same APEX. For example, if module `foo` is included in the
- // apex `com.android.foo`, and also if there is an override_apex module
- // `com.mycompany.android.foo` overriding `com.android.foo`, then this list contains both
- // `com.android.foo` and `com.mycompany.android.foo`. If the APEX Soong module is a
- // prebuilt, the name here doesn't have the `prebuilt_` prefix.
- InApexModules []string
-
- // Pointers to the ApexContents struct each of which is for apexBundle modules that this
- // module is part of. The ApexContents gives information about which modules the apexBundle
- // has and whether a module became part of the apexBundle via a direct dependency or not.
- ApexContents []*ApexContents
-
// True if this is for a prebuilt_apex.
//
// If true then this will customize the apex processing to make it suitable for handling
@@ -82,11 +69,14 @@
// See Prebuilt.ApexInfoMutator for more information.
ForPrebuiltApex bool
- // 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
+
+ // Returns the apex names that this module is available for
+ ApexAvailableFor []string
}
// AllApexInfo holds the ApexInfo of all apexes that include this module.
@@ -101,7 +91,6 @@
(*d)["Apex"] = map[string]interface{}{
"ApexVariationName": i.ApexVariationName,
"MinSdkVersion": i.MinSdkVersion,
- "InApexModules": i.InApexModules,
"InApexVariants": i.InApexVariants,
"ForPrebuiltApex": i.ForPrebuiltApex,
}
@@ -136,26 +125,18 @@
return false
}
-func (i ApexInfo) InApexModule(apexModuleName string) bool {
- for _, a := range i.InApexModules {
- if a == apexModuleName {
- return true
- }
- }
- 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 &&
+ slices.Equal(i.InApexVariants, otherApexInfo.InApexVariants)
}
-// 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 {
- ApexContents []*ApexContents
-}
-
-var ApexTestForInfoProvider = blueprint.NewMutatorProvider[ApexTestForInfo]("apex_test_for")
-
// ApexBundleInfo contains information about the dependencies of an apex
type ApexBundleInfo struct {
- Contents *ApexContents
}
var ApexBundleInfoProvider = blueprint.NewMutatorProvider[ApexBundleInfo]("apex_info")
@@ -165,15 +146,25 @@
// extracted from ApexModule to make it easier to define custom subsets of the ApexModule interface
// and improve code navigation within the IDE.
type DepIsInSameApex interface {
- // DepIsInSameApex tests if the other module 'dep' is considered as part of the same APEX as
- // this module. For example, a static lib dependency usually returns true here, while a
+ // OutgoingDepIsInSameApex tests if the module depended on via 'tag' is considered as part of
+ // the same APEX as this module. For example, a static lib dependency usually returns true here, while a
// shared lib dependency to a stub library returns false.
//
// This method must not be called directly without first ignoring dependencies whose tags
// implement ExcludeFromApexContentsTag. Calls from within the func passed to WalkPayloadDeps()
// are fine as WalkPayloadDeps() will ignore those dependencies automatically. Otherwise, use
// IsDepInSameApex instead.
- DepIsInSameApex(ctx BaseModuleContext, dep Module) bool
+ OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool
+
+ // IncomingDepIsInSameApex tests if this module depended on via 'tag' is considered as part of
+ // the same APEX as the depending module module. For example, a static lib dependency usually
+ // returns true here, while a shared lib dependency to a stub library returns false.
+ //
+ // This method must not be called directly without first ignoring dependencies whose tags
+ // implement ExcludeFromApexContentsTag. Calls from within the func passed to WalkPayloadDeps()
+ // are fine as WalkPayloadDeps() will ignore those dependencies automatically. Otherwise, use
+ // IsDepInSameApex instead.
+ IncomingDepIsInSameApex(tag blueprint.DependencyTag) bool
}
func IsDepInSameApex(ctx BaseModuleContext, module, dep Module) bool {
@@ -183,7 +174,14 @@
// apex as the parent.
return false
}
- return module.(DepIsInSameApex).DepIsInSameApex(ctx, dep)
+
+ if m, ok := module.(DepIsInSameApex); ok && !m.OutgoingDepIsInSameApex(depTag) {
+ return false
+ }
+ if d, ok := dep.(DepIsInSameApex); ok && !d.IncomingDepIsInSameApex(depTag) {
+ return false
+ }
+ return true
}
// ApexModule is the interface that a module type is expected to implement if the module has to be
@@ -213,15 +211,8 @@
// this after apex.apexMutator is run.
InAnyApex() bool
- // Returns true if this module is directly in any APEX. Call this AFTER apex.apexMutator is
- // run.
- DirectlyInAnyApex() bool
-
- // NotInPlatform tells whether or not this module is included in an APEX and therefore
- // shouldn't be exposed to the platform (i.e. outside of the APEX) directly. A module is
- // considered to be included in an APEX either when there actually is an APEX that
- // explicitly has the module as its dependency or the module is not available to the
- // platform, which indicates that the module belongs to at least one or more other APEXes.
+ // NotInPlatform returns true if the module is not available to the platform due to
+ // apex_available being set and not containing "//apex_available:platform".
NotInPlatform() bool
// Tests if this module could have APEX variants. Even when a module type implements
@@ -239,6 +230,12 @@
// apex_available property of the module.
AvailableFor(what string) bool
+ // Returns the apexes that are available for this module, valid values include
+ // "//apex_available:platform", "//apex_available:anyapex" and specific apexes.
+ // There are some differences between this one and the ApexAvailable on
+ // ApexModuleBase for cc, java library and sdkLibraryXml.
+ ApexAvailableFor() []string
+
// AlwaysRequiresPlatformApexVariant allows the implementing module to determine whether an
// APEX mutator should always be created for it.
//
@@ -254,12 +251,6 @@
// check-platform-availability mutator in the apex package.
SetNotAvailableForPlatform()
- // Returns the list of APEXes that this module is a test for. The module has access to the
- // private part of the listed APEXes even when it is not included in the APEXes. This by
- // default returns nil. A module type should override the default implementation. For
- // example, cc_test module type returns the value of test_for here.
- TestFor() []string
-
// Returns nil (success) if this module should support the given sdk version. Returns an
// error if not. No default implementation is provided for this method. A module type
// implementing this interface should provide an implementation. A module supports an sdk
@@ -284,35 +275,15 @@
// Default is ["//apex_available:platform"].
Apex_available []string
- // See ApexModule.InAnyApex()
- InAnyApex bool `blueprint:"mutated"`
-
- // See ApexModule.DirectlyInAnyApex()
- DirectlyInAnyApex bool `blueprint:"mutated"`
-
- // AnyVariantDirectlyInAnyApex is true in the primary variant of a module if _any_ variant
- // of the module is directly in any apex. This includes host, arch, asan, etc. variants. It
- // is unused in any variant that is not the primary variant. Ideally this wouldn't be used,
- // as it incorrectly mixes arch variants if only one arch is in an apex, but a few places
- // depend on it, for example when an ASAN variant is created before the apexMutator. Call
- // this after apex.apexMutator is run.
- AnyVariantDirectlyInAnyApex bool `blueprint:"mutated"`
-
// See ApexModule.NotAvailableForPlatform()
NotAvailableForPlatform bool `blueprint:"mutated"`
// See ApexModule.UniqueApexVariants()
UniqueApexVariationsForDeps bool `blueprint:"mutated"`
-
- // The test apexes that includes this apex variant
- TestApexes []string `blueprint:"mutated"`
}
// Marker interface that identifies dependencies that are excluded from APEX contents.
//
-// Unless the tag also implements the AlwaysRequireApexVariantTag this will prevent an apex variant
-// from being created for the module.
-//
// At the moment the sdk.sdkRequirementsMutator relies on the fact that the existing tags which
// implement this interface do not define dependencies onto members of an sdk_snapshot. If that
// changes then sdk.sdkRequirementsMutator will need fixing.
@@ -323,27 +294,6 @@
ExcludeFromApexContents()
}
-// Marker interface that identifies dependencies that always requires an APEX variant to be created.
-//
-// It is possible for a dependency to require an apex variant but exclude the module from the APEX
-// contents. See sdk.sdkMemberDependencyTag.
-type AlwaysRequireApexVariantTag interface {
- blueprint.DependencyTag
-
- // Return true if this tag requires that the target dependency has an apex variant.
- AlwaysRequireApexVariant() bool
-}
-
-// Marker interface that identifies dependencies that should inherit the DirectlyInAnyApex state
-// from the parent to the child. For example, stubs libraries are marked as DirectlyInAnyApex if
-// their implementation is in an apex.
-type CopyDirectlyInAnyApexTag interface {
- blueprint.DependencyTag
-
- // Method that differentiates this interface from others.
- CopyDirectlyInAnyApex()
-}
-
// Interface that identifies dependencies to skip Apex dependency check
type SkipApexAllowedDependenciesCheck interface {
// Returns true to skip the Apex dependency check, which limits the allowed dependency in build.
@@ -390,44 +340,35 @@
return CopyOf(availableToPlatformList)
}
+func (m *ApexModuleBase) ApexAvailableFor() []string {
+ return m.ApexAvailable()
+}
+
// Implements ApexModule
func (m *ApexModuleBase) BuildForApex(apex ApexInfo) {
m.apexInfosLock.Lock()
defer m.apexInfosLock.Unlock()
- for i, v := range m.apexInfos {
- if v.ApexVariationName == apex.ApexVariationName {
- if len(apex.InApexModules) != 1 {
- panic(fmt.Errorf("Newly created apexInfo must be for a single APEX"))
- }
- // Even when the ApexVariantNames are the same, the given ApexInfo might
- // actually be for different APEX. This can happen when an APEX is
- // overridden via override_apex. For example, there can be two apexes
- // `com.android.foo` (from the `apex` module type) and
- // `com.mycompany.android.foo` (from the `override_apex` module type), both
- // of which has the same ApexVariantName `com.android.foo`. Add the apex
- // name to the list so that it's not lost.
- if !InList(apex.InApexModules[0], v.InApexModules) {
- m.apexInfos[i].InApexModules = append(m.apexInfos[i].InApexModules, apex.InApexModules[0])
- }
- return
- }
+ if slices.ContainsFunc(m.apexInfos, func(existing ApexInfo) bool {
+ return existing.ApexVariationName == apex.ApexVariationName
+ }) {
+ return
}
m.apexInfos = append(m.apexInfos, apex)
}
// Implements ApexModule
func (m *ApexModuleBase) InAnyApex() bool {
- return m.ApexProperties.InAnyApex
-}
-
-// Implements ApexModule
-func (m *ApexModuleBase) DirectlyInAnyApex() bool {
- return m.ApexProperties.DirectlyInAnyApex
+ for _, apex_name := range m.ApexProperties.Apex_available {
+ if apex_name != AvailableToPlatform {
+ return true
+ }
+ }
+ return false
}
// Implements ApexModule
func (m *ApexModuleBase) NotInPlatform() bool {
- return m.ApexProperties.AnyVariantDirectlyInAnyApex || !m.AvailableFor(AvailableToPlatform)
+ return !m.AvailableFor(AvailableToPlatform)
}
// Implements ApexModule
@@ -443,18 +384,6 @@
}
// Implements ApexModule
-func (m *ApexModuleBase) TestFor() []string {
- // If needed, this will be overridden by concrete types inheriting
- // ApexModuleBase
- return nil
-}
-
-// Returns the test apexes that this module is included in.
-func (m *ApexModuleBase) TestApexes() []string {
- return m.ApexProperties.TestApexes
-}
-
-// Implements ApexModule
func (m *ApexModuleBase) UniqueApexVariations() bool {
// If needed, this will bel overridden by concrete types inheriting
// ApexModuleBase
@@ -462,7 +391,15 @@
}
// Implements ApexModule
-func (m *ApexModuleBase) DepIsInSameApex(ctx BaseModuleContext, dep Module) bool {
+func (m *ApexModuleBase) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
+ // By default, if there is a dependency from A to B, we try to include both in the same
+ // APEX, unless B is explicitly from outside of the APEX (i.e. a stubs lib). Thus, returning
+ // true. This is overridden by some module types like apex.ApexBundle, cc.Module,
+ // java.Module, etc.
+ return true
+}
+
+func (m *ApexModuleBase) IncomingDepIsInSameApex(tag blueprint.DependencyTag) bool {
// By default, if there is a dependency from A to B, we try to include both in the same
// APEX, unless B is explicitly from outside of the APEX (i.e. a stubs lib). Thus, returning
// true. This is overridden by some module types like apex.ApexBundle, cc.Module,
@@ -475,13 +412,6 @@
AvailableToAnyApex = "//apex_available:anyapex"
)
-var (
- AvailableToRecognziedWildcards = []string{
- AvailableToPlatform,
- AvailableToAnyApex,
- }
-)
-
// CheckAvailableForApex provides the default algorithm for checking the apex availability. When the
// availability is empty, it defaults to ["//apex_available:platform"] which means "available to the
// platform but not available to any APEX". When the list is not empty, `what` is matched against
@@ -511,13 +441,17 @@
if strings.HasSuffix(apex_name, ".*") && strings.HasPrefix(what, strings.TrimSuffix(apex_name, "*")) {
return true
}
+ // TODO b/383863941: Remove once legacy name is no longer used
+ if (apex_name == "com.android.btservices" && what == "com.android.bt") || (apex_name == "com.android.bt" && what == "com.android.btservices") {
+ return true
+ }
}
return false
}
// Implements ApexModule
func (m *ApexModuleBase) AvailableFor(what string) bool {
- return CheckAvailableForApex(what, m.ApexProperties.Apex_available)
+ return CheckAvailableForApex(what, m.ApexAvailableFor())
}
// Implements ApexModule
@@ -598,20 +532,14 @@
if index, exists := seen[mergedName]; exists {
// Variants having the same mergedName are deduped
merged[index].InApexVariants = append(merged[index].InApexVariants, variantName)
- merged[index].InApexModules = append(merged[index].InApexModules, apexInfo.InApexModules...)
- merged[index].ApexContents = append(merged[index].ApexContents, apexInfo.ApexContents...)
merged[index].Updatable = merged[index].Updatable || apexInfo.Updatable
// Platform APIs is allowed for this module only when all APEXes containing
// the module are with `use_platform_apis: true`.
merged[index].UsePlatformApis = merged[index].UsePlatformApis && apexInfo.UsePlatformApis
- merged[index].TestApexes = append(merged[index].TestApexes, apexInfo.TestApexes...)
} else {
seen[mergedName] = len(merged)
apexInfo.ApexVariationName = mergedName
apexInfo.InApexVariants = CopyOf(apexInfo.InApexVariants)
- apexInfo.InApexModules = CopyOf(apexInfo.InApexModules)
- apexInfo.ApexContents = append([]*ApexContents(nil), apexInfo.ApexContents...)
- apexInfo.TestApexes = CopyOf(apexInfo.TestApexes)
merged = append(merged, apexInfo)
}
aliases = append(aliases, [2]string{variantName, mergedName})
@@ -698,16 +626,7 @@
apexInfos, _ = mergeApexVariations(apexInfos)
}
- var inApex ApexMembership
- for _, a := range apexInfos {
- for _, apexContents := range a.ApexContents {
- inApex = inApex.merge(apexContents.contents[ctx.ModuleName()])
- }
- }
- 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
@@ -724,18 +643,10 @@
} else {
panic(fmt.Errorf("failed to find apexInfo for incoming variation %q", variation))
}
+ thisApexInfo.ApexAvailableFor = module.ApexAvailableFor()
SetProvider(ctx, ApexInfoProvider, thisApexInfo)
}
-
- // Set the value of TestApexes in every single apex variant.
- // This allows each apex variant to be aware of the test apexes in the user provided apex_available.
- var testApexes []string
- for _, a := range apexInfos {
- testApexes = append(testApexes, a.TestApexes...)
- }
- base.ApexProperties.TestApexes = testApexes
-
}
func ApexInfoMutator(ctx TopDownMutatorContext, module ApexModule) {
@@ -757,7 +668,7 @@
// variant.
func UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext, am ApexModule) {
// anyInSameApex returns true if the two ApexInfo lists contain any values in an
- // InApexVariants list in common. It is used instead of DepIsInSameApex because it needs to
+ // InApexVariants list in common. It is used instead of OutgoingDepIsInSameApex because it needs to
// determine if the dep is in the same APEX due to being directly included, not only if it
// is included _because_ it is a dependency.
anyInSameApex := func(a, b ApexModule) bool {
@@ -796,115 +707,6 @@
})
}
-// UpdateDirectlyInAnyApex uses the final module to store if any variant of this module is directly
-// in any APEX, and then copies the final value to all the modules. It also copies the
-// DirectlyInAnyApex value to any transitive dependencies with a CopyDirectlyInAnyApexTag
-// dependency tag.
-func UpdateDirectlyInAnyApex(mctx BottomUpMutatorContext, am ApexModule) {
- base := am.apexModuleBase()
- // Copy DirectlyInAnyApex and InAnyApex from any transitive dependencies with a
- // CopyDirectlyInAnyApexTag dependency tag.
- mctx.WalkDeps(func(child, parent Module) bool {
- if _, ok := mctx.OtherModuleDependencyTag(child).(CopyDirectlyInAnyApexTag); ok {
- depBase := child.(ApexModule).apexModuleBase()
- depBase.apexPropertiesLock.Lock()
- defer depBase.apexPropertiesLock.Unlock()
- depBase.ApexProperties.DirectlyInAnyApex = base.ApexProperties.DirectlyInAnyApex
- depBase.ApexProperties.InAnyApex = base.ApexProperties.InAnyApex
- return true
- }
- return false
- })
-
- if base.ApexProperties.DirectlyInAnyApex {
- // Variants of a module are always visited sequentially in order, so it is safe to
- // write to another variant of this module. For a BottomUpMutator the
- // PrimaryModule() is visited first and FinalModule() is visited last.
- mctx.FinalModule().(ApexModule).apexModuleBase().ApexProperties.AnyVariantDirectlyInAnyApex = true
- }
-
- // If this is the FinalModule (last visited module) copy
- // AnyVariantDirectlyInAnyApex to all the other variants
- if am == mctx.FinalModule().(ApexModule) {
- mctx.VisitAllModuleVariants(func(variant Module) {
- variant.(ApexModule).apexModuleBase().ApexProperties.AnyVariantDirectlyInAnyApex =
- base.ApexProperties.AnyVariantDirectlyInAnyApex
- })
- }
-}
-
-// ApexMembership tells how a module became part of an APEX.
-type ApexMembership int
-
-const (
- notInApex ApexMembership = 0
- indirectlyInApex = iota
- directlyInApex
-)
-
-// ApexContents gives an information about member modules of an apexBundle. Each apexBundle has an
-// apexContents, and modules in that apex have a provider containing the apexContents of each
-// apexBundle they are part of.
-type ApexContents struct {
- // map from a module name to its membership in this apexBundle
- contents map[string]ApexMembership
-}
-
-// NewApexContents creates and initializes an ApexContents that is suitable
-// for use with an apex module.
-// - contents is a map from a module name to information about its membership within
-// the apex.
-func NewApexContents(contents map[string]ApexMembership) *ApexContents {
- return &ApexContents{
- contents: contents,
- }
-}
-
-// Updates an existing membership by adding a new direct (or indirect) membership
-func (i ApexMembership) Add(direct bool) ApexMembership {
- if direct || i == directlyInApex {
- return directlyInApex
- }
- return indirectlyInApex
-}
-
-// Merges two membership into one. Merging is needed because a module can be a part of an apexBundle
-// in many different paths. For example, it could be dependend on by the apexBundle directly, but at
-// the same time, there might be an indirect dependency to the module. In that case, the more
-// specific dependency (the direct one) is chosen.
-func (i ApexMembership) merge(other ApexMembership) ApexMembership {
- if other == directlyInApex || i == directlyInApex {
- return directlyInApex
- }
-
- if other == indirectlyInApex || i == indirectlyInApex {
- return indirectlyInApex
- }
- return notInApex
-}
-
-// Tests whether a module named moduleName is directly included in the apexBundle where this
-// ApexContents is tagged.
-func (ac *ApexContents) DirectlyInApex(moduleName string) bool {
- return ac.contents[moduleName] == directlyInApex
-}
-
-// Tests whether a module named moduleName is included in the apexBundle where this ApexContent is
-// tagged.
-func (ac *ApexContents) InApex(moduleName string) bool {
- return ac.contents[moduleName] != notInApex
-}
-
-// Tests whether a module named moduleName is directly depended on by all APEXes in an ApexInfo.
-func DirectlyInAllApexes(apexInfo ApexInfo, moduleName string) bool {
- for _, contents := range apexInfo.ApexContents {
- if !contents.DirectlyInApex(moduleName) {
- return false
- }
- }
- return true
-}
-
////////////////////////////////////////////////////////////////////////////////////////////////////
//Below are routines for extra safety checks.
//
@@ -931,8 +733,8 @@
type DepNameToDepInfoMap map[string]ApexModuleDepInfo
type ApexBundleDepsInfo struct {
- flatListPath OutputPath
- fullListPath OutputPath
+ flatListPath Path
+ fullListPath Path
}
type ApexBundleDepsInfoIntf interface {
@@ -969,20 +771,22 @@
fmt.Fprintf(&flatContent, "%s\n", toName)
}
- d.fullListPath = PathForModuleOut(ctx, "depsinfo", "fulllist.txt").OutputPath
- WriteFileRule(ctx, d.fullListPath, fullContent.String())
+ fullListPath := PathForModuleOut(ctx, "depsinfo", "fulllist.txt")
+ WriteFileRule(ctx, fullListPath, fullContent.String())
+ d.fullListPath = fullListPath
- d.flatListPath = PathForModuleOut(ctx, "depsinfo", "flatlist.txt").OutputPath
- WriteFileRule(ctx, d.flatListPath, flatContent.String())
+ flatListPath := PathForModuleOut(ctx, "depsinfo", "flatlist.txt")
+ WriteFileRule(ctx, flatListPath, flatContent.String())
+ d.flatListPath = flatListPath
- ctx.Phony(fmt.Sprintf("%s-depsinfo", ctx.ModuleName()), d.fullListPath, d.flatListPath)
+ ctx.Phony(fmt.Sprintf("%s-depsinfo", ctx.ModuleName()), fullListPath, flatListPath)
}
// Function called while walking an APEX's payload dependencies.
//
// Return true if the `to` module should be visited, false otherwise.
-type PayloadDepsCallback func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool
-type WalkPayloadDepsFunc func(ctx ModuleContext, do PayloadDepsCallback)
+type PayloadDepsCallback func(ctx BaseModuleContext, from Module, to ApexModule, externalDep bool) bool
+type WalkPayloadDepsFunc func(ctx BaseModuleContext, do PayloadDepsCallback)
// ModuleWithMinSdkVersionCheck represents a module that implements min_sdk_version checks
type ModuleWithMinSdkVersionCheck interface {
@@ -1009,14 +813,14 @@
return
}
- walk(ctx, func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool {
+ walk(ctx, func(ctx BaseModuleContext, from Module, to ApexModule, externalDep bool) bool {
if externalDep {
// external deps are outside the payload boundary, which is "stable"
// interface. We don't have to check min_sdk_version for external
// dependencies.
return false
}
- if am, ok := from.(DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
+ if !IsDepInSameApex(ctx, from, to) {
return false
}
if m, ok := to.(ModuleWithMinSdkVersionCheck); ok {
@@ -1054,12 +858,6 @@
return apiLevel
}
-// Implemented by apexBundle.
-type ApexTestInterface interface {
- // Return true if the apex bundle is an apex_test
- IsTestApex() bool
-}
-
var ApexExportsInfoProvider = blueprint.NewProvider[ApexExportsInfo]()
// ApexExportsInfo contains information about the artifacts provided by apexes to dexpreopt and hiddenapi
diff --git a/android/apex_contributions.go b/android/apex_contributions.go
index 4cd8dda..ce34278 100644
--- a/android/apex_contributions.go
+++ b/android/apex_contributions.go
@@ -26,7 +26,7 @@
func RegisterApexContributionsBuildComponents(ctx RegistrationContext) {
ctx.RegisterModuleType("apex_contributions", apexContributionsFactory)
ctx.RegisterModuleType("apex_contributions_defaults", apexContributionsDefaultsFactory)
- ctx.RegisterSingletonModuleType("all_apex_contributions", allApexContributionsFactory)
+ ctx.RegisterModuleType("all_apex_contributions", allApexContributionsFactory)
}
type apexContributions struct {
@@ -87,10 +87,10 @@
// Based on product_config, it will create a dependency on the selected
// apex_contributions per mainline module
type allApexContributions struct {
- SingletonModuleBase
+ ModuleBase
}
-func allApexContributionsFactory() SingletonModule {
+func allApexContributionsFactory() Module {
module := &allApexContributions{}
InitAndroidModule(module)
return module
@@ -191,7 +191,7 @@
// This module type does not have any build actions.
func (a *allApexContributions) GenerateAndroidBuildActions(ctx ModuleContext) {
-}
-
-func (a *allApexContributions) GenerateSingletonBuildActions(ctx SingletonContext) {
+ if ctx.ModuleName() != "all_apex_contributions" {
+ ctx.ModuleErrorf("There can only be 1 all_apex_contributions module in build/soong")
+ }
}
diff --git a/android/apex_test.go b/android/apex_test.go
index 347bf7d..78597b2 100644
--- a/android/apex_test.go
+++ b/android/apex_test.go
@@ -37,7 +37,6 @@
ApexVariationName: "foo",
MinSdkVersion: FutureApiLevel,
InApexVariants: []string{"foo"},
- InApexModules: []string{"foo"},
ForPrebuiltApex: NotForPrebuiltApex,
},
},
@@ -46,7 +45,6 @@
ApexVariationName: "apex10000",
MinSdkVersion: FutureApiLevel,
InApexVariants: []string{"foo"},
- InApexModules: []string{"foo"},
ForPrebuiltApex: NotForPrebuiltApex,
},
},
@@ -61,14 +59,12 @@
ApexVariationName: "foo",
MinSdkVersion: FutureApiLevel,
InApexVariants: []string{"foo"},
- InApexModules: []string{"foo"},
ForPrebuiltApex: NotForPrebuiltApex,
},
{
ApexVariationName: "bar",
MinSdkVersion: FutureApiLevel,
InApexVariants: []string{"bar"},
- InApexModules: []string{"bar"},
ForPrebuiltApex: NotForPrebuiltApex,
},
},
@@ -77,7 +73,6 @@
ApexVariationName: "apex10000",
MinSdkVersion: FutureApiLevel,
InApexVariants: []string{"foo", "bar"},
- InApexModules: []string{"foo", "bar"},
}},
wantAliases: [][2]string{
{"foo", "apex10000"},
@@ -91,14 +86,12 @@
ApexVariationName: "foo",
MinSdkVersion: FutureApiLevel,
InApexVariants: []string{"foo"},
- InApexModules: []string{"foo"},
ForPrebuiltApex: NotForPrebuiltApex,
},
{
ApexVariationName: "bar",
MinSdkVersion: uncheckedFinalApiLevel(30),
InApexVariants: []string{"bar"},
- InApexModules: []string{"bar"},
ForPrebuiltApex: NotForPrebuiltApex,
},
},
@@ -107,14 +100,12 @@
ApexVariationName: "apex10000",
MinSdkVersion: FutureApiLevel,
InApexVariants: []string{"foo"},
- InApexModules: []string{"foo"},
ForPrebuiltApex: NotForPrebuiltApex,
},
{
ApexVariationName: "apex30",
MinSdkVersion: uncheckedFinalApiLevel(30),
InApexVariants: []string{"bar"},
- InApexModules: []string{"bar"},
ForPrebuiltApex: NotForPrebuiltApex,
},
},
@@ -130,7 +121,6 @@
ApexVariationName: "foo",
MinSdkVersion: FutureApiLevel,
InApexVariants: []string{"foo"},
- InApexModules: []string{"foo"},
ForPrebuiltApex: NotForPrebuiltApex,
},
{
@@ -138,7 +128,6 @@
MinSdkVersion: FutureApiLevel,
Updatable: true,
InApexVariants: []string{"bar"},
- InApexModules: []string{"bar"},
ForPrebuiltApex: NotForPrebuiltApex,
},
},
@@ -148,7 +137,6 @@
MinSdkVersion: FutureApiLevel,
Updatable: true,
InApexVariants: []string{"foo", "bar"},
- InApexModules: []string{"foo", "bar"},
ForPrebuiltApex: NotForPrebuiltApex,
},
},
@@ -164,7 +152,6 @@
ApexVariationName: "foo",
MinSdkVersion: FutureApiLevel,
InApexVariants: []string{"foo"},
- InApexModules: []string{"foo"},
ForPrebuiltApex: NotForPrebuiltApex,
},
{
@@ -172,7 +159,6 @@
MinSdkVersion: FutureApiLevel,
Updatable: true,
InApexVariants: []string{"bar"},
- InApexModules: []string{"bar"},
ForPrebuiltApex: NotForPrebuiltApex,
},
// This one should not be merged in with the others because it is for
@@ -182,7 +168,6 @@
MinSdkVersion: FutureApiLevel,
Updatable: true,
InApexVariants: []string{"baz"},
- InApexModules: []string{"baz"},
ForPrebuiltApex: ForPrebuiltApex,
},
},
@@ -192,7 +177,6 @@
MinSdkVersion: FutureApiLevel,
Updatable: true,
InApexVariants: []string{"foo", "bar"},
- InApexModules: []string{"foo", "bar"},
ForPrebuiltApex: NotForPrebuiltApex,
},
{
@@ -200,7 +184,6 @@
MinSdkVersion: FutureApiLevel,
Updatable: true,
InApexVariants: []string{"baz"},
- InApexModules: []string{"baz"},
ForPrebuiltApex: ForPrebuiltApex,
},
},
@@ -216,7 +199,6 @@
ApexVariationName: "foo",
MinSdkVersion: FutureApiLevel,
InApexVariants: []string{"foo"},
- InApexModules: []string{"foo"},
ForPrebuiltApex: NotForPrebuiltApex,
},
{
@@ -224,7 +206,6 @@
MinSdkVersion: FutureApiLevel,
UsePlatformApis: true,
InApexVariants: []string{"bar"},
- InApexModules: []string{"bar"},
ForPrebuiltApex: NotForPrebuiltApex,
},
},
@@ -233,7 +214,6 @@
ApexVariationName: "apex10000",
MinSdkVersion: FutureApiLevel,
InApexVariants: []string{"foo", "bar"},
- InApexModules: []string{"foo", "bar"},
ForPrebuiltApex: NotForPrebuiltApex,
},
},
@@ -250,7 +230,6 @@
MinSdkVersion: FutureApiLevel,
UsePlatformApis: true,
InApexVariants: []string{"foo"},
- InApexModules: []string{"foo"},
ForPrebuiltApex: NotForPrebuiltApex,
},
{
@@ -258,7 +237,6 @@
MinSdkVersion: FutureApiLevel,
UsePlatformApis: true,
InApexVariants: []string{"bar"},
- InApexModules: []string{"bar"},
ForPrebuiltApex: NotForPrebuiltApex,
},
},
@@ -268,7 +246,6 @@
MinSdkVersion: FutureApiLevel,
UsePlatformApis: true,
InApexVariants: []string{"foo", "bar"},
- InApexModules: []string{"foo", "bar"},
ForPrebuiltApex: NotForPrebuiltApex,
},
},
diff --git a/android/api_levels.go b/android/api_levels.go
index dc17238..2b1d01d 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -444,26 +444,27 @@
func getApiLevelsMapReleasedVersions() (map[string]int, error) {
return map[string]int{
- "G": 9,
- "I": 14,
- "J": 16,
- "J-MR1": 17,
- "J-MR2": 18,
- "K": 19,
- "L": 21,
- "L-MR1": 22,
- "M": 23,
- "N": 24,
- "N-MR1": 25,
- "O": 26,
- "O-MR1": 27,
- "P": 28,
- "Q": 29,
- "R": 30,
- "S": 31,
- "S-V2": 32,
- "Tiramisu": 33,
- "UpsideDownCake": 34,
+ "G": 9,
+ "I": 14,
+ "J": 16,
+ "J-MR1": 17,
+ "J-MR2": 18,
+ "K": 19,
+ "L": 21,
+ "L-MR1": 22,
+ "M": 23,
+ "N": 24,
+ "N-MR1": 25,
+ "O": 26,
+ "O-MR1": 27,
+ "P": 28,
+ "Q": 29,
+ "R": 30,
+ "S": 31,
+ "S-V2": 32,
+ "Tiramisu": 33,
+ "UpsideDownCake": 34,
+ "VanillaIceCream": 35,
}, nil
}
diff --git a/android/arch.go b/android/arch.go
index 6d896e5..3cd6e4b 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -23,7 +23,6 @@
"strings"
"github.com/google/blueprint"
- "github.com/google/blueprint/bootstrap"
"github.com/google/blueprint/proptools"
)
@@ -139,6 +138,16 @@
return a.Name
}
+func (a ArchType) Bitness() string {
+ if a.Multilib == "lib32" {
+ return "32"
+ }
+ if a.Multilib == "lib64" {
+ return "64"
+ }
+ panic("Bitness is not defined for the common variant")
+}
+
const COMMON_VARIANT = "common"
var (
@@ -397,45 +406,21 @@
// 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
@@ -443,53 +428,91 @@
}
}
- 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())
}
}
}
@@ -522,7 +545,7 @@
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
@@ -544,50 +567,37 @@
// "32": compile for only a single 32-bit Target supported by the OsClass.
// "64": compile for only a single 64-bit Target supported by the OsClass.
// "common": compile a for a single Target that will work on all Targets supported by the OsClass (for example Java).
-// "common_first": compile a for a Target that will work on all Targets supported by the OsClass
-// (same as "common"), plus a second Target for the preferred Target supported by the OsClass
-// (same as "first"). This is used for java_binary that produces a common .jar and a wrapper
-// executable script.
//
// Once the list of Targets is determined, the module is split into a variant for each Target.
//
// 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.
@@ -614,19 +624,18 @@
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
@@ -635,7 +644,7 @@
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)
}
@@ -643,7 +652,7 @@
// 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)
}
@@ -651,37 +660,106 @@
// 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 ""
+ }
+
+ 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
+ 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
@@ -698,7 +776,9 @@
// 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:
@@ -738,11 +818,7 @@
// !UseTargetVariants, as the module has opted into handling the arch-specific logic on
// its own.
if os == Darwin && multilib != "common" && multilib != "32" {
- if multilib == "common_first" {
- multilib = "darwin_universal_common_first"
- } else {
- multilib = "darwin_universal"
- }
+ multilib = "darwin_universal"
}
return multilib, ""
@@ -1282,7 +1358,7 @@
// Returns the structs corresponding to the properties specific to the given
// architecture and OS in archProperties.
-func getArchProperties(ctx BaseMutatorContext, archProperties interface{}, arch Arch, os OsType, nativeBridgeEnabled bool) []reflect.Value {
+func getArchProperties(ctx BaseModuleContext, archProperties interface{}, arch Arch, os OsType, nativeBridgeEnabled bool) []reflect.Value {
result := make([]reflect.Value, 0)
archPropValues := reflect.ValueOf(archProperties).Elem()
@@ -1854,13 +1930,6 @@
switch multilib {
case "common":
buildTargets = getCommonTargets(targets)
- case "common_first":
- buildTargets = getCommonTargets(targets)
- if prefer32 {
- buildTargets = append(buildTargets, FirstTarget(targets, "lib32", "lib64")...)
- } else {
- buildTargets = append(buildTargets, FirstTarget(targets, "lib64", "lib32")...)
- }
case "both":
if prefer32 {
buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib32")...)
@@ -1891,10 +1960,6 @@
// Reverse the targets so that the first architecture can depend on the second
// architecture module in order to merge the outputs.
ReverseSliceInPlace(buildTargets)
- case "darwin_universal_common_first":
- archTargets := filterMultilibTargets(targets, "lib64")
- ReverseSliceInPlace(archTargets)
- buildTargets = append(getCommonTargets(targets), archTargets...)
default:
return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", "64", "prefer32" or "first_prefer32" found %q`,
multilib)
diff --git a/android/arch_list.go b/android/arch_list.go
index f1289a3..389f194 100644
--- a/android/arch_list.go
+++ b/android/arch_list.go
@@ -26,8 +26,10 @@
"armv8-2a",
"armv8-2a-dotprod",
"armv9-a",
+ "armv9-2a",
},
X86: {
+ "alderlake",
"amberlake",
"atom",
"broadwell",
@@ -52,6 +54,7 @@
"x86_64",
},
X86_64: {
+ "alderlake",
"amberlake",
"broadwell",
"goldmont",
@@ -109,9 +112,6 @@
}
var archFeatures = map[ArchType][]string{
- Arm: {
- "neon",
- },
Arm64: {
"dotprod",
},
@@ -141,17 +141,6 @@
}
var androidArchFeatureMap = map[ArchType]map[string][]string{
- Arm: {
- "armv7-a-neon": {
- "neon",
- },
- "armv8-a": {
- "neon",
- },
- "armv8-2a": {
- "neon",
- },
- },
Arm64: {
"armv8-2a-dotprod": {
"dotprod",
@@ -159,8 +148,21 @@
"armv9-a": {
"dotprod",
},
+ "armv9-2a": {
+ "dotprod",
+ },
},
X86: {
+ "alderlake": {
+ "ssse3",
+ "sse4",
+ "sse4_1",
+ "sse4_2",
+ "avx",
+ "avx2",
+ "aes_ni",
+ "popcnt",
+ },
"amberlake": {
"ssse3",
"sse4",
@@ -337,6 +339,16 @@
"sse4_2",
"popcnt",
},
+ "alderlake": {
+ "ssse3",
+ "sse4",
+ "sse4_1",
+ "sse4_2",
+ "avx",
+ "avx2",
+ "aes_ni",
+ "popcnt",
+ },
"amberlake": {
"ssse3",
"sse4",
diff --git a/android/arch_test.go b/android/arch_test.go
index 6134a06..7914884 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -451,7 +451,7 @@
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)
}
@@ -560,15 +560,7 @@
prepareForArchTest,
// Test specific preparer
OptionalFixturePreparer(tt.preparer),
- // Prepare for native bridge test
- FixtureModifyConfig(func(config Config) {
- config.Targets[Android] = []Target{
- {Android, Arch{ArchType: X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false},
- {Android, Arch{ArchType: X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", "", false},
- {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeEnabled, "x86_64", "arm64", false},
- {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeEnabled, "x86", "arm", false},
- }
- }),
+ PrepareForNativeBridgeEnabled,
FixtureWithRootAndroidBp(bp),
).RunTest(t)
diff --git a/android/base_module_context.go b/android/base_module_context.go
index 5506000..4b90083 100644
--- a/android/base_module_context.go
+++ b/android/base_module_context.go
@@ -17,6 +17,7 @@
import (
"fmt"
"regexp"
+ "slices"
"strings"
"github.com/google/blueprint"
@@ -33,6 +34,8 @@
blueprintBaseModuleContext() blueprint.BaseModuleContext
+ EqualModules(m1, m2 Module) bool
+
// OtherModuleName returns the name of another Module. See BaseModuleContext.ModuleName for more information.
// It is intended for use inside the visit functions of Visit* and WalkDeps.
OtherModuleName(m blueprint.Module) string
@@ -85,6 +88,10 @@
// This method shouldn't be used directly, prefer the type-safe android.OtherModuleProvider instead.
otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
+ // OtherModuleIsAutoGenerated returns true if the module is auto generated by another module
+ // instead of being defined in Android.bp file.
+ OtherModuleIsAutoGenerated(m blueprint.Module) bool
+
// Provider returns the value for a provider for the current module. If the value is
// not set it returns nil and false. It panics if called before the appropriate
// mutator or GenerateBuildActions pass for the provider. The value returned may be a deep
@@ -103,44 +110,45 @@
GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module
+ GetDirectDepsProxyWithTag(tag blueprint.DependencyTag) []ModuleProxy
+
// GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if
// none exists. It panics if the dependency does not have the specified tag. It skips any
// dependencies that are not an android.Module.
- GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module
+ GetDirectDepWithTag(name string, tag blueprint.DependencyTag) Module
- // GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified
- // name, or nil if none exists. If there are multiple dependencies on the same module it returns
- // the first DependencyTag.
- GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
-
- // VisitDirectDepsBlueprint calls visit for each direct dependency. If there are multiple
- // direct dependencies on the same module visit will be called multiple times on that module
- // and OtherModuleDependencyTag will return a different tag for each.
- //
- // The Module passed to the visit function should not be retained outside of the visit
- // function, it may be invalidated by future mutators.
- VisitDirectDepsBlueprint(visit func(blueprint.Module))
-
- // VisitDirectDepsIgnoreBlueprint calls visit for each direct dependency. If there are multiple
- // direct dependencies on the same module visit will be called multiple times on that module
- // and OtherModuleDependencyTag will return a different tag for each. It silently ignores any
- // dependencies that are not an android.Module.
- //
- // The Module passed to the visit function should not be retained outside of the visit
- // function, it may be invalidated by future mutators.
- VisitDirectDepsIgnoreBlueprint(visit func(Module))
+ GetDirectDepProxyWithTag(name string, tag blueprint.DependencyTag) *ModuleProxy
// VisitDirectDeps calls visit for each direct dependency. If there are multiple
// direct dependencies on the same module visit will be called multiple times on that module
// and OtherModuleDependencyTag will return a different tag for each. It raises an error if any of the
- // dependencies are not an android.Module.
+ // dependencies are disabled.
//
// The Module passed to the visit function should not be retained outside of the visit
// function, it may be invalidated by future mutators.
VisitDirectDeps(visit func(Module))
+ // VisitDirectDepsProxy calls visit for each direct dependency. If there are multiple
+ // direct dependencies on the same module visit will be called multiple times on that module
+ // and OtherModuleDependencyTag will return a different tag for each. It raises an error if any of the
+ // dependencies are disabled.
+ //
+ // The ModuleProxy passed to the visit function should not be retained outside of the visit
+ // function, it may be invalidated by future mutators.
+ VisitDirectDepsProxy(visit func(proxy ModuleProxy))
+
+ // VisitDirectDepsProxyAllowDisabled calls visit for each direct dependency. If there are
+ // multiple direct dependencies on the same module visit will be called multiple times on
+ // that module and OtherModuleDependencyTag will return a different tag for each.
+ //
+ // The ModuleProxy passed to the visit function should not be retained outside of the visit function, it may be
+ // invalidated by future mutators.
+ VisitDirectDepsProxyAllowDisabled(visit func(proxy ModuleProxy))
+
VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module))
+ VisitDirectDepsProxyWithTag(tag blueprint.DependencyTag, visit func(proxy ModuleProxy))
+
// VisitDirectDepsIf calls pred for each direct dependency, and if pred returns true calls visit. If there are
// multiple direct dependencies on the same module pred and visit will be called multiple times on that module and
// OtherModuleDependencyTag will return a different tag for each. It skips any
@@ -164,16 +172,15 @@
// invalidated by future mutators.
WalkDeps(visit func(child, parent Module) bool)
- // WalkDepsBlueprint calls visit for each transitive dependency, traversing the dependency
- // tree in top down order. visit may be called multiple times for the same (child, parent)
- // pair if there are multiple direct dependencies between the child and parent with different
- // tags. OtherModuleDependencyTag will return the tag for the currently visited
- // (child, parent) pair. If visit returns false WalkDeps will not continue recursing down
- // to child.
+ // WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order. visit may
+ // be called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the
+ // child and parent with different tags. OtherModuleDependencyTag will return the tag for the currently visited
+ // (child, parent) pair. If visit returns false WalkDeps will not continue recursing down to child. It skips
+ // any dependencies that are not an android.Module.
//
// The Modules passed to the visit function should not be retained outside of the visit function, they may be
// invalidated by future mutators.
- WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool)
+ WalkDepsProxy(visit func(child, parent ModuleProxy) bool)
// GetWalkPath is supposed to be called in visit function passed in WalkDeps()
// and returns a top-down dependency path from a start module to current child module.
@@ -191,12 +198,24 @@
// singleton actions that are only done once for all variants of a module.
FinalModule() Module
+ // IsFinalModule returns if the current module is the last variant. Variants of a module are always visited in
+ // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all
+ // variants using VisitAllModuleVariants if the current module is the last one. This can be used to perform
+ // singleton actions that are only done once for all variants of a module.
+ IsFinalModule(module Module) bool
+
// VisitAllModuleVariants calls visit for each variant of the current module. Variants of a module are always
// visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read
- // from all variants if the current module == FinalModule(). Otherwise, care must be taken to not access any
+ // from all variants if the current module is the last one. Otherwise, care must be taken to not access any
// data modified by the current mutator.
VisitAllModuleVariants(visit func(Module))
+ // VisitAllModuleVariantProxies calls visit for each variant of the current module. Variants of a module are always
+ // visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read
+ // from all variants if the current module is the last one. Otherwise, care must be taken to not access any
+ // data modified by the current mutator.
+ VisitAllModuleVariantProxies(visit func(proxy ModuleProxy))
+
// GetTagPath is supposed to be called in visit function passed in WalkDeps()
// and returns a top-down dependency tags path from a start module to current child module.
// It has one less entry than GetWalkPath() as it contains the dependency tags that
@@ -234,15 +253,31 @@
}
-func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string {
- return b.bp.OtherModuleName(m)
+func getWrappedModule(module blueprint.Module) blueprint.Module {
+ if mp, isProxy := module.(*ModuleProxy); isProxy {
+ return mp.module
+ }
+ if mp, isProxy := module.(ModuleProxy); isProxy {
+ return mp.module
+ }
+ return module
}
-func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string { return b.bp.OtherModuleDir(m) }
+
+func (b *baseModuleContext) EqualModules(m1, m2 Module) bool {
+ return b.bp.EqualModules(getWrappedModule(m1), getWrappedModule(m2))
+}
+
+func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string {
+ return b.bp.OtherModuleName(getWrappedModule(m))
+}
+func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string {
+ return b.bp.OtherModuleDir(getWrappedModule(m))
+}
func (b *baseModuleContext) OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) {
- b.bp.OtherModuleErrorf(m, fmt, args...)
+ b.bp.OtherModuleErrorf(getWrappedModule(m), fmt, args...)
}
func (b *baseModuleContext) OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag {
- return b.bp.OtherModuleDependencyTag(m)
+ return b.bp.OtherModuleDependencyTag(getWrappedModule(m))
}
func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) }
func (b *baseModuleContext) OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool {
@@ -255,11 +290,15 @@
return b.bp.OtherModuleReverseDependencyVariantExists(name)
}
func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string {
- return b.bp.OtherModuleType(m)
+ return b.bp.OtherModuleType(getWrappedModule(m))
}
func (b *baseModuleContext) otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
- return b.bp.OtherModuleProvider(m, provider)
+ return b.bp.OtherModuleProvider(getWrappedModule(m), provider)
+}
+
+func (b *baseModuleContext) OtherModuleIsAutoGenerated(m blueprint.Module) bool {
+ return b.bp.OtherModuleIsAutoGenerated(m)
}
func (b *baseModuleContext) provider(provider blueprint.AnyProviderKey) (any, bool) {
@@ -270,8 +309,18 @@
b.bp.SetProvider(provider, value)
}
-func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
- return b.bp.GetDirectDepWithTag(name, tag)
+func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) Module {
+ if module := b.bp.GetDirectDepWithTag(name, tag); module != nil {
+ return module.(Module)
+ }
+ return nil
+}
+
+func (b *baseModuleContext) GetDirectDepProxyWithTag(name string, tag blueprint.DependencyTag) *ModuleProxy {
+ if module := b.bp.GetDirectDepProxyWithTag(name, tag); module != nil {
+ return &ModuleProxy{*module}
+ }
+ return nil
}
func (b *baseModuleContext) blueprintBaseModuleContext() blueprint.BaseModuleContext {
@@ -303,6 +352,7 @@
type AllowDisabledModuleDependency interface {
blueprint.DependencyTag
AllowDisabledModuleDependency(target Module) bool
+ AllowDisabledModuleDependencyProxy(ctx OtherModuleProviderContext, target ModuleProxy) bool
}
type AlwaysAllowDisabledModuleDependencyTag struct{}
@@ -311,7 +361,11 @@
return true
}
-func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool, ignoreBlueprint bool) Module {
+func (t AlwaysAllowDisabledModuleDependencyTag) AllowDisabledModuleDependencyProxy(OtherModuleProviderContext, ModuleProxy) bool {
+ return true
+}
+
+func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool) Module {
aModule, _ := module.(Module)
if !strict {
@@ -319,10 +373,7 @@
}
if aModule == nil {
- if !ignoreBlueprint {
- b.ModuleErrorf("module %q (%#v) not an android module", b.OtherModuleName(module), tag)
- }
- return nil
+ panic(fmt.Errorf("module %q (%#v) not an android module", b.OtherModuleName(module), tag))
}
if !aModule.Enabled(b) {
@@ -338,116 +389,119 @@
return aModule
}
-type dep struct {
- mod blueprint.Module
- tag blueprint.DependencyTag
+func (b *baseModuleContext) validateAndroidModuleProxy(
+ module blueprint.ModuleProxy, tag blueprint.DependencyTag, strict bool) *ModuleProxy {
+ aModule := ModuleProxy{module: module}
+
+ if !strict {
+ return &aModule
+ }
+
+ if !OtherModuleProviderOrDefault(b, module, CommonModuleInfoKey).Enabled {
+ if t, ok := tag.(AllowDisabledModuleDependency); !ok || !t.AllowDisabledModuleDependencyProxy(b, aModule) {
+ if b.Config().AllowMissingDependencies() {
+ b.AddMissingDependencies([]string{b.OtherModuleName(aModule)})
+ } else {
+ b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule))
+ }
+ }
+ return nil
+ }
+
+ return &aModule
}
-func (b *baseModuleContext) getDirectDepsInternal(name string, tag blueprint.DependencyTag) []dep {
- var deps []dep
- b.VisitDirectDepsBlueprint(func(module blueprint.Module) {
- if aModule, _ := module.(Module); aModule != nil {
- if aModule.base().BaseModuleName() == name {
- returnedTag := b.bp.OtherModuleDependencyTag(aModule)
- if tag == nil || returnedTag == tag {
- deps = append(deps, dep{aModule, returnedTag})
- }
- }
- } else if b.bp.OtherModuleName(module) == name {
+func (b *baseModuleContext) getDirectDepsInternal(name string, tag blueprint.DependencyTag) []Module {
+ var deps []Module
+ b.VisitDirectDeps(func(module Module) {
+ if module.base().BaseModuleName() == name {
returnedTag := b.bp.OtherModuleDependencyTag(module)
if tag == nil || returnedTag == tag {
- deps = append(deps, dep{module, returnedTag})
+ deps = append(deps, module)
}
}
})
return deps
}
-func (b *baseModuleContext) getDirectDepInternal(name string, tag blueprint.DependencyTag) (blueprint.Module, blueprint.DependencyTag) {
- deps := b.getDirectDepsInternal(name, tag)
- if len(deps) == 1 {
- return deps[0].mod, deps[0].tag
- } else if len(deps) >= 2 {
- panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
- name, b.ModuleName()))
- } else {
- return nil, nil
- }
-}
-
-func (b *baseModuleContext) getDirectDepFirstTag(name string) (blueprint.Module, blueprint.DependencyTag) {
- foundDeps := b.getDirectDepsInternal(name, nil)
- deps := map[blueprint.Module]bool{}
- for _, dep := range foundDeps {
- deps[dep.mod] = true
- }
- if len(deps) == 1 {
- return foundDeps[0].mod, foundDeps[0].tag
- } else if len(deps) >= 2 {
- // this could happen if two dependencies have the same name in different namespaces
- // TODO(b/186554727): this should not occur if namespaces are handled within
- // getDirectDepsInternal.
- panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
- name, b.ModuleName()))
- } else {
- return nil, nil
- }
+func (b *baseModuleContext) getDirectDepsProxyInternal(name string, tag blueprint.DependencyTag) []ModuleProxy {
+ var deps []ModuleProxy
+ b.VisitDirectDepsProxy(func(module ModuleProxy) {
+ if OtherModuleProviderOrDefault(b, module, CommonModuleInfoKey).BaseModuleName == name {
+ returnedTag := b.OtherModuleDependencyTag(module)
+ if tag == nil || returnedTag == tag {
+ deps = append(deps, module)
+ }
+ }
+ })
+ return deps
}
func (b *baseModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module {
var deps []Module
- b.VisitDirectDepsBlueprint(func(module blueprint.Module) {
- if aModule, _ := module.(Module); aModule != nil {
- if b.bp.OtherModuleDependencyTag(aModule) == tag {
- deps = append(deps, aModule)
- }
+ b.VisitDirectDeps(func(module Module) {
+ if b.bp.OtherModuleDependencyTag(module) == tag {
+ deps = append(deps, module)
}
})
return deps
}
-// GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified
-// name, or nil if none exists. If there are multiple dependencies on the same module it returns the
-// first DependencyTag.
-func (b *baseModuleContext) GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) {
- return b.getDirectDepFirstTag(name)
-}
-
-func (b *baseModuleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module)) {
- b.bp.VisitDirectDeps(visit)
+func (b *baseModuleContext) GetDirectDepsProxyWithTag(tag blueprint.DependencyTag) []ModuleProxy {
+ var deps []ModuleProxy
+ b.VisitDirectDepsProxy(func(module ModuleProxy) {
+ if b.OtherModuleDependencyTag(module) == tag {
+ deps = append(deps, module)
+ }
+ })
+ return deps
}
func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) {
- b.visitDirectDeps(visit, false)
-}
-
-func (b *baseModuleContext) VisitDirectDepsIgnoreBlueprint(visit func(Module)) {
- b.visitDirectDeps(visit, true)
-}
-
-func (b *baseModuleContext) visitDirectDeps(visit func(Module), ignoreBlueprint bool) {
b.bp.VisitDirectDeps(func(module blueprint.Module) {
- if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, ignoreBlueprint); aModule != nil {
+ if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
visit(aModule)
}
})
}
+func (b *baseModuleContext) VisitDirectDepsProxy(visit func(ModuleProxy)) {
+ b.bp.VisitDirectDepsProxy(func(module blueprint.ModuleProxy) {
+ if aModule := b.validateAndroidModuleProxy(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
+ visit(*aModule)
+ }
+ })
+}
+
+func (b *baseModuleContext) VisitDirectDepsProxyAllowDisabled(visit func(proxy ModuleProxy)) {
+ b.bp.VisitDirectDepsProxy(visitProxyAdaptor(visit))
+}
+
func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) {
b.bp.VisitDirectDeps(func(module blueprint.Module) {
if b.bp.OtherModuleDependencyTag(module) == tag {
- if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, false); aModule != nil {
+ if aModule := b.validateAndroidModule(module, tag, b.strictVisitDeps); aModule != nil {
visit(aModule)
}
}
})
}
+func (b *baseModuleContext) VisitDirectDepsProxyWithTag(tag blueprint.DependencyTag, visit func(proxy ModuleProxy)) {
+ b.bp.VisitDirectDepsProxy(func(module blueprint.ModuleProxy) {
+ if b.bp.OtherModuleDependencyTag(module) == tag {
+ if aModule := b.validateAndroidModuleProxy(module, tag, b.strictVisitDeps); aModule != nil {
+ visit(*aModule)
+ }
+ }
+ })
+}
+
func (b *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
b.bp.VisitDirectDepsIf(
// pred
func(module blueprint.Module) bool {
- if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, false); aModule != nil {
+ if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
return pred(aModule)
} else {
return false
@@ -461,7 +515,7 @@
func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
b.bp.VisitDepsDepthFirst(func(module blueprint.Module) {
- if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, false); aModule != nil {
+ if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
visit(aModule)
}
})
@@ -471,7 +525,7 @@
b.bp.VisitDepsDepthFirstIf(
// pred
func(module blueprint.Module) bool {
- if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, false); aModule != nil {
+ if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
return pred(aModule)
} else {
return false
@@ -483,10 +537,6 @@
})
}
-func (b *baseModuleContext) WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) {
- b.bp.WalkDeps(visit)
-}
-
func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) {
b.walkPath = []Module{b.Module()}
b.tagPath = []blueprint.DependencyTag{}
@@ -508,8 +558,25 @@
})
}
+func (b *baseModuleContext) WalkDepsProxy(visit func(ModuleProxy, ModuleProxy) bool) {
+ b.walkPath = []Module{ModuleProxy{blueprint.CreateModuleProxy(b.Module())}}
+ b.tagPath = []blueprint.DependencyTag{}
+ b.bp.WalkDepsProxy(func(child, parent blueprint.ModuleProxy) bool {
+ childAndroidModule := ModuleProxy{child}
+ parentAndroidModule := ModuleProxy{parent}
+ // record walkPath before visit
+ for b.walkPath[len(b.walkPath)-1] != parentAndroidModule {
+ b.walkPath = b.walkPath[0 : len(b.walkPath)-1]
+ b.tagPath = b.tagPath[0 : len(b.tagPath)-1]
+ }
+ b.walkPath = append(b.walkPath, childAndroidModule)
+ b.tagPath = append(b.tagPath, b.OtherModuleDependencyTag(childAndroidModule))
+ return visit(childAndroidModule, parentAndroidModule)
+ })
+}
+
func (b *baseModuleContext) GetWalkPath() []Module {
- return b.walkPath
+ return slices.Clone(b.walkPath)
}
func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag {
@@ -522,6 +589,10 @@
})
}
+func (b *baseModuleContext) VisitAllModuleVariantProxies(visit func(ModuleProxy)) {
+ b.bp.VisitAllModuleVariantProxies(visitProxyAdaptor(visit))
+}
+
func (b *baseModuleContext) PrimaryModule() Module {
return b.bp.PrimaryModule().(Module)
}
@@ -530,6 +601,10 @@
return b.bp.FinalModule().(Module)
}
+func (b *baseModuleContext) IsFinalModule(module Module) bool {
+ return b.bp.IsFinalModule(module)
+}
+
// IsMetaDependencyTag returns true for cross-cutting metadata dependencies.
func IsMetaDependencyTag(tag blueprint.DependencyTag) bool {
if tag == licenseKindTag {
diff --git a/android/build_prop.go b/android/build_prop.go
index 13d59f9..2f71bc0 100644
--- a/android/build_prop.go
+++ b/android/build_prop.go
@@ -15,12 +15,18 @@
package android
import (
+ "fmt"
+
"github.com/google/blueprint/proptools"
)
func init() {
- ctx := InitRegistrationContext
- ctx.RegisterModuleType("build_prop", buildPropFactory)
+ registerBuildPropComponents(InitRegistrationContext)
+}
+
+func registerBuildPropComponents(ctx RegistrationContext) {
+ ctx.RegisterModuleType("build_prop", BuildPropFactory)
+ ctx.RegisterModuleType("android_info", AndroidInfoFactory)
}
type buildPropProperties struct {
@@ -38,6 +44,10 @@
// Path to a JSON file containing product configs.
Product_config *string `android:"path"`
+ // Path to android-info.txt file containing board specific info.
+ // This is empty for build.prop of all partitions except vendor.
+ Android_info *string `android:"path"`
+
// Optional subdirectory under which this file is installed into
Relative_install_path *string
}
@@ -47,7 +57,7 @@
properties buildPropProperties
- outputFilePath OutputPath
+ outputFilePath Path
installPath InstallPath
}
@@ -63,6 +73,14 @@
return ctx.Config().SystemExtPropFiles(ctx)
} else if partition == "product" {
return ctx.Config().ProductPropFiles(ctx)
+ } else if partition == "odm" {
+ return ctx.Config().OdmPropFiles(ctx)
+ } else if partition == "vendor" {
+ if p.properties.Android_info != nil {
+ androidInfo := PathForModuleSrc(ctx, proptools.String(p.properties.Android_info))
+ return append(ctx.Config().VendorPropFiles(ctx), androidInfo)
+ }
+ return ctx.Config().VendorPropFiles(ctx)
}
return nil
}
@@ -93,30 +111,28 @@
return "product"
} else if p.SystemExtSpecific() {
return "system_ext"
+ } else if p.InstallInSystemDlkm() {
+ return "system_dlkm"
+ } else if p.InstallInVendorDlkm() {
+ return "vendor_dlkm"
+ } else if p.InstallInOdmDlkm() {
+ return "odm_dlkm"
+ } else if p.InstallInRamdisk() {
+ // From this hardcoding in make:
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/sysprop.mk;l=311;drc=274435657e4682e5cee3fffd11fb301ab32a828d
+ return "bootimage"
}
return "system"
}
-var validPartitions = []string{
- "system",
- "system_ext",
- "product",
- "odm",
-}
-
func (p *buildPropModule) GenerateAndroidBuildActions(ctx ModuleContext) {
- p.outputFilePath = PathForModuleOut(ctx, "build.prop").OutputPath
- if !ctx.Config().KatiEnabled() {
- WriteFileRule(ctx, p.outputFilePath, "# no build.prop if kati is disabled")
- ctx.SetOutputFiles(Paths{p.outputFilePath}, "")
- return
+ if !p.SocSpecific() && p.properties.Android_info != nil {
+ ctx.ModuleErrorf("Android_info cannot be set if build.prop is not installed in vendor partition")
}
+ outputFilePath := PathForModuleOut(ctx, "build.prop")
+
partition := p.partition(ctx.DeviceConfig())
- if !InList(partition, validPartitions) {
- ctx.PropertyErrorf("partition", "unsupported partition %q: only %q are supported", partition, validPartitions)
- return
- }
rule := NewRuleBuilder(pctx, ctx)
@@ -143,7 +159,7 @@
cmd.FlagWithInput("--product-config=", PathForModuleSrc(ctx, proptools.String(p.properties.Product_config)))
cmd.FlagWithArg("--partition=", partition)
cmd.FlagForEachInput("--prop-files=", p.propFiles(ctx))
- cmd.FlagWithOutput("--out=", p.outputFilePath)
+ cmd.FlagWithOutput("--out=", outputFilePath)
postProcessCmd := rule.Command().BuiltTool("post_process_props")
if ctx.DeviceConfig().BuildBrokenDupSysprop() {
@@ -156,17 +172,35 @@
// still need to pass an empty string to kernel-version-file-for-uffd-gc
postProcessCmd.FlagWithArg("--kernel-version-file-for-uffd-gc ", `""`)
}
- postProcessCmd.Text(p.outputFilePath.String())
+ postProcessCmd.Text(outputFilePath.String())
postProcessCmd.Flags(p.properties.Block_list)
- rule.Command().Text("echo").Text(proptools.NinjaAndShellEscape("# end of file")).FlagWithArg(">> ", p.outputFilePath.String())
+ for _, footer := range p.properties.Footer_files {
+ path := PathForModuleSrc(ctx, footer)
+ rule.appendText(outputFilePath, "####################################")
+ rule.appendTextf(outputFilePath, "# Adding footer from %v", footer)
+ rule.appendTextf(outputFilePath, "# with path %v", path)
+ rule.appendText(outputFilePath, "####################################")
+ rule.Command().Text("cat").FlagWithInput("", path).FlagWithArg(">> ", outputFilePath.String())
+ }
+
+ rule.appendText(outputFilePath, "# end of file")
rule.Build(ctx.ModuleName(), "generating build.prop")
p.installPath = PathForModuleInstall(ctx, proptools.String(p.properties.Relative_install_path))
- ctx.InstallFile(p.installPath, p.stem(), p.outputFilePath)
+ ctx.InstallFile(p.installPath, p.stem(), outputFilePath)
- ctx.SetOutputFiles(Paths{p.outputFilePath}, "")
+ ctx.SetOutputFiles(Paths{outputFilePath}, "")
+ p.outputFilePath = outputFilePath
+}
+
+func (r *RuleBuilder) appendText(path ModuleOutPath, text string) {
+ r.Command().Text("echo").Text(proptools.NinjaAndShellEscape(text)).FlagWithArg(">> ", path.String())
+}
+
+func (r *RuleBuilder) appendTextf(path ModuleOutPath, format string, a ...any) {
+ r.appendText(path, fmt.Sprintf(format, a...))
}
func (p *buildPropModule) AndroidMkEntries() []AndroidMkEntries {
@@ -185,7 +219,7 @@
// build_prop module generates {partition}/build.prop file. At first common build properties are
// printed based on Soong config variables. And then prop_files are printed as-is. Finally,
// post_process_props tool is run to check if the result build.prop is valid or not.
-func buildPropFactory() Module {
+func BuildPropFactory() Module {
module := &buildPropModule{}
module.AddProperties(&module.properties)
InitAndroidArchModule(module, DeviceSupported, MultilibCommon)
diff --git a/android/build_prop_test.go b/android/build_prop_test.go
new file mode 100644
index 0000000..e75975a
--- /dev/null
+++ b/android/build_prop_test.go
@@ -0,0 +1,41 @@
+// 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 (
+ "testing"
+)
+
+func TestPropFileInputs(t *testing.T) {
+ bp := `
+build_prop {
+ name: "vendor-build.prop",
+ stem: "build.prop",
+ vendor: true,
+ android_info: ":board-info",
+ //product_config: ":product_config",
+}
+android_info {
+ name: "board-info",
+ stem: "android-info.txt",
+}
+`
+
+ res := GroupFixturePreparers(
+ FixtureRegisterWithContext(registerBuildPropComponents),
+ ).RunTestWithBp(t, bp)
+ buildPropCmd := res.ModuleForTests("vendor-build.prop", "").Rule("vendor-build.prop_.vendor-build.prop").RuleParams.Command
+ AssertStringDoesContain(t, "Could not find android-info in prop files of vendor build.prop", buildPropCmd, "--prop-files=out/soong/.intermediates/board-info/android-info.prop")
+}
diff --git a/android/compliance_metadata.go b/android/compliance_metadata.go
index 4c92f71..dcf393d 100644
--- a/android/compliance_metadata.go
+++ b/android/compliance_metadata.go
@@ -23,6 +23,7 @@
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/gobtools"
)
var (
@@ -42,6 +43,7 @@
STATIC_DEP_FILES string
WHOLE_STATIC_DEPS string
WHOLE_STATIC_DEP_FILES string
+ HEADER_LIBS string
LICENSES string
// module_type=package
@@ -70,6 +72,7 @@
"static_dep_files",
"whole_static_deps",
"whole_static_dep_files",
+ "header_libs",
"licenses",
"pkg_default_applicable_licenses",
@@ -105,6 +108,8 @@
ComplianceMetadataProp.WHOLE_STATIC_DEPS,
// Space separated file paths of whole static dependencies
ComplianceMetadataProp.WHOLE_STATIC_DEP_FILES,
+ // Space separated modules name of header libs
+ ComplianceMetadataProp.HEADER_LIBS,
ComplianceMetadataProp.LICENSES,
// module_type=package
ComplianceMetadataProp.PKG_DEFAULT_APPLICABLE_LICENSES,
@@ -125,12 +130,34 @@
properties map[string]string
}
+type complianceMetadataInfoGob struct {
+ Properties map[string]string
+}
+
func NewComplianceMetadataInfo() *ComplianceMetadataInfo {
return &ComplianceMetadataInfo{
properties: map[string]string{},
}
}
+func (m *ComplianceMetadataInfo) ToGob() *complianceMetadataInfoGob {
+ return &complianceMetadataInfoGob{
+ Properties: m.properties,
+ }
+}
+
+func (m *ComplianceMetadataInfo) FromGob(data *complianceMetadataInfoGob) {
+ m.properties = data.Properties
+}
+
+func (c *ComplianceMetadataInfo) GobEncode() ([]byte, error) {
+ return gobtools.CustomGobEncode[complianceMetadataInfoGob](c)
+}
+
+func (c *ComplianceMetadataInfo) GobDecode(data []byte) error {
+ return gobtools.CustomGobDecode[complianceMetadataInfoGob](data, c)
+}
+
func (c *ComplianceMetadataInfo) SetStringValue(propertyName string, value string) {
if !slices.Contains(COMPLIANCE_METADATA_PROPS, propertyName) {
panic(fmt.Errorf("Unknown metadata property: %s.", propertyName))
@@ -189,8 +216,8 @@
installed = append(installed, ctx.installFiles...)
installed = append(installed, ctx.katiInstalls.InstallPaths()...)
installed = append(installed, ctx.katiSymlinks.InstallPaths()...)
- installed = append(installed, m.katiInitRcInstalls.InstallPaths()...)
- installed = append(installed, m.katiVintfInstalls.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)
@@ -213,8 +240,8 @@
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"`,
+ `([ -z "${make_metadata}" ] || ${sqlite3} $out ".import --csv ${make_metadata} make_metadata") && ` +
+ `([ -z "${make_modules}" ] || ${sqlite3} $out ".import --csv ${make_modules} make_modules")`,
CommandDeps: []string{"${sqlite3}"},
}, "make_metadata", "make_modules")
)
@@ -284,24 +311,29 @@
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")
+ var implicits []Path
+ args := make(map[string]string)
+
+ if ctx.Config().KatiEnabled() {
+ // Metadata generated in Make
+ makeMetadataCsv := PathForOutput(ctx, "compliance-metadata", deviceProduct, "make-metadata.csv")
+ makeModulesCsv := PathForOutput(ctx, "compliance-metadata", deviceProduct, "make-modules.csv")
+ implicits = append(implicits, makeMetadataCsv, makeModulesCsv)
+ args["make_metadata"] = makeMetadataCsv.String()
+ args["make_modules"] = makeModulesCsv.String()
+ } else {
+ args["make_metadata"] = ""
+ args["make_modules"] = ""
+ }
// 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(),
- },
+ Rule: importCsv,
+ Input: modulesCsv,
+ Implicits: implicits,
+ Output: complianceMetadataDb,
+ Args: args,
})
// Phony rule "compliance-metadata.db". "m compliance-metadata.db" to create the compliance metadata database.
diff --git a/android/config.go b/android/config.go
index d6d76a4..eda8e71 100644
--- a/android/config.go
+++ b/android/config.go
@@ -83,8 +83,8 @@
OutDir string
SoongOutDir string
SoongVariables string
+ KatiSuffix string
- BazelQueryViewDir string
ModuleGraphFile string
ModuleActionsFile string
DocFile string
@@ -99,11 +99,6 @@
// Don't use bazel at all during module analysis.
AnalysisNoBazel SoongBuildMode = iota
- // Generate BUILD files which faithfully represent the dependency graph of
- // blueprint modules. Individual BUILD targets will not, however, faitfhully
- // express build semantics.
- GenerateQueryView
-
// Create a JSON representation of the module graph and exit.
GenerateModuleGraph
@@ -173,6 +168,13 @@
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).
@@ -231,6 +233,11 @@
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 {
@@ -238,6 +245,13 @@
Bool(c.config.productVariables.ReleaseDefaultModuleBuildFromSource)
}
+func (c Config) ReleaseDefaultUpdatableModuleVersion() string {
+ if val, exists := c.GetBuildFlag("RELEASE_DEFAULT_UPDATABLE_MODULE_VERSION"); exists {
+ return val
+ }
+ panic("RELEASE_DEFAULT_UPDATABLE_MODULE_VERSION is missing from build flags.")
+}
+
func (c Config) ReleaseDisableVerifyOverlaps() bool {
return c.config.productVariables.GetBuildFlagBool("RELEASE_DISABLE_VERIFY_OVERLAPS_CHECK")
}
@@ -263,6 +277,27 @@
Bool(c.config.productVariables.HiddenapiExportableStubs)
}
+// Enable read flag from new storage
+func (c Config) ReleaseReadFromNewStorage() bool {
+ return c.config.productVariables.GetBuildFlagBool("RELEASE_READ_FROM_NEW_STORAGE")
+}
+
+func (c Config) ReleaseCreateAconfigStorageFile() bool {
+ return c.config.productVariables.GetBuildFlagBool("RELEASE_CREATE_ACONFIG_STORAGE_FILE")
+}
+
+func (c Config) ReleaseUseSystemFeatureBuildFlags() bool {
+ return c.config.productVariables.GetBuildFlagBool("RELEASE_USE_SYSTEM_FEATURE_BUILD_FLAGS")
+}
+
+func (c Config) ReleaseFingerprintAconfigPackages() bool {
+ return c.config.productVariables.GetBuildFlagBool("RELEASE_FINGERPRINT_ACONFIG_PACKAGES")
+}
+
+func (c Config) ReleaseAconfigCheckApiLevel() bool {
+ return c.config.productVariables.GetBuildFlagBool("RELEASE_ACONFIG_CHECK_API_LEVEL")
+}
+
// A DeviceConfig object represents the configuration for a particular device
// being built. For now there will only be one of these, but in the future there
// may be multiple devices being built.
@@ -296,6 +331,9 @@
AndroidCommonTarget Target // the Target for common modules for the Android device
AndroidFirstDeviceTarget Target // the first Target for modules for the Android device
+ // Flags for Partial Compile, derived from SOONG_PARTIAL_COMPILE.
+ partialCompileFlags partialCompileFlags
+
// multilibConflicts for an ArchType is true if there is earlier configured
// device architecture with the same multilib value.
multilibConflicts map[ArchType]bool
@@ -316,6 +354,7 @@
// Changes behavior based on whether Kati runs after soong_build, or if soong_build
// runs standalone.
katiEnabled bool
+ katiSuffix string
captureBuild bool // true for tests, saves build parameters for each module
ignoreEnvironment bool // true for tests, returns empty from all Getenv calls
@@ -345,6 +384,16 @@
ensureAllowlistIntegrity bool
}
+type partialCompileFlags struct {
+ // Is partial compilation enabled at all?
+ enabled bool
+
+ // Whether to use d8 instead of r8
+ use_d8 bool
+
+ // Add others as needed.
+}
+
type deviceConfig struct {
config *config
OncePer
@@ -354,6 +403,91 @@
SetDefaultConfig()
}
+// Parse SOONG_PARTIAL_COMPILE.
+//
+// SOONG_PARTIAL_COMPILE determines which features are enabled or disabled in
+// rule generation. Changing this environment variable causes reanalysis.
+//
+// SOONG_USE_PARTIAL_COMPILE determines whether or not we **use** PARTIAL_COMPILE.
+// Rule generation must support both cases, since changing it does not cause
+// reanalysis.
+//
+// The user-facing documentation shows:
+//
+// - empty or not set: "The current default state"
+// - "true" or "on": enable all stable partial compile features.
+// - "false" or "off": disable partial compile completely.
+//
+// What we actually allow is a comma separated list of tokens, whose first
+// character may be "+" (enable) or "-" (disable). If neither is present, "+"
+// is assumed. For example, "on,+use_d8" will enable partial compilation, and
+// additionally set the use_d8 flag (regardless of whether it is opt-in or
+// opt-out).
+//
+// To add a new feature to the list, add the field in the struct
+// `partialCompileFlags` above, and then add the name of the field in the
+// switch statement below.
+var defaultPartialCompileFlags = partialCompileFlags{
+ // Set any opt-out flags here. Opt-in flags are off by default.
+ enabled: false,
+}
+
+func (c *config) parsePartialCompileFlags(isEngBuild bool) (partialCompileFlags, error) {
+ if !isEngBuild {
+ return partialCompileFlags{}, nil
+ }
+ value := c.Getenv("SOONG_PARTIAL_COMPILE")
+ if value == "" {
+ return defaultPartialCompileFlags, nil
+ }
+
+ ret := defaultPartialCompileFlags
+ tokens := strings.Split(strings.ToLower(value), ",")
+ makeVal := func(state string, defaultValue bool) bool {
+ switch state {
+ case "":
+ return defaultValue
+ case "-":
+ return false
+ case "+":
+ return true
+ }
+ return false
+ }
+ for _, tok := range tokens {
+ var state string
+ if len(tok) == 0 {
+ continue
+ }
+ switch tok[0:1] {
+ case "":
+ // Ignore empty tokens.
+ continue
+ case "-", "+":
+ state = tok[0:1]
+ tok = tok[1:]
+ default:
+ // Treat `feature` as `+feature`.
+ state = "+"
+ }
+ switch tok {
+ case "true":
+ ret = defaultPartialCompileFlags
+ ret.enabled = true
+ case "false":
+ // Set everything to false.
+ ret = partialCompileFlags{}
+ case "enabled":
+ ret.enabled = makeVal(state, defaultPartialCompileFlags.enabled)
+ case "use_d8":
+ ret.use_d8 = makeVal(state, defaultPartialCompileFlags.use_d8)
+ default:
+ return partialCompileFlags{}, fmt.Errorf("Unknown SOONG_PARTIAL_COMPILE value: %v", tok)
+ }
+ }
+ return ret, nil
+}
+
func loadConfig(config *config) error {
return loadFromConfigFile(&config.productVariables, absolutePath(config.ProductVariablesFileName))
}
@@ -492,6 +626,7 @@
outDir: cmdArgs.OutDir,
soongOutDir: cmdArgs.SoongOutDir,
runGoTests: cmdArgs.RunGoTests,
+ katiSuffix: cmdArgs.KatiSuffix,
multilibConflicts: make(map[ArchType]bool),
moduleListFile: cmdArgs.ModuleListFile,
@@ -499,6 +634,8 @@
buildFromSourceStub: cmdArgs.BuildFromSourceStub,
}
+ variant, ok := os.LookupEnv("TARGET_BUILD_VARIANT")
+ isEngBuild := !ok || variant == "eng"
config.deviceConfig = &deviceConfig{
config: config,
@@ -540,6 +677,11 @@
return Config{}, err
}
+ config.partialCompileFlags, err = config.parsePartialCompileFlags(isEngBuild)
+ if err != nil {
+ return Config{}, err
+ }
+
// Make the CommonOS OsType available for all products.
targets[CommonOS] = []Target{commonTargetMap[CommonOS.Name]}
@@ -588,7 +730,6 @@
config.BuildMode = mode
}
}
- setBuildMode(cmdArgs.BazelQueryViewDir, GenerateQueryView)
setBuildMode(cmdArgs.ModuleGraphFile, GenerateModuleGraph)
setBuildMode(cmdArgs.DocFile, GenerateDocFile)
@@ -634,11 +775,7 @@
// BlueprintToolLocation returns the directory containing build system tools
// from Blueprint, like soong_zip and merge_zips.
func (c *config) HostToolDir() string {
- if c.KatiEnabled() {
- return filepath.Join(c.outDir, "host", c.PrebuiltOS(), "bin")
- } else {
- return filepath.Join(c.soongOutDir, "host", c.PrebuiltOS(), "bin")
- }
+ return filepath.Join(c.outDir, "host", c.PrebuiltOS(), "bin")
}
func (c *config) HostToolPath(ctx PathContext, tool string) Path {
@@ -741,7 +878,7 @@
}
func (c *config) TargetsJava21() bool {
- return c.IsEnvTrue("EXPERIMENTAL_TARGET_JAVA_VERSION_21")
+ return c.productVariables.GetBuildFlagBool("RELEASE_TARGET_JAVA_21")
}
// EnvDeps returns the environment variables this build depends on. The first
@@ -971,6 +1108,10 @@
return ApiLevelOrPanic(ctx, codename)
}
+func (c *config) PartialCompileFlags() partialCompileFlags {
+ return c.partialCompileFlags
+}
+
func (c *config) AppsDefaultVersionName() string {
return String(c.productVariables.AppsDefaultVersionName)
}
@@ -1183,7 +1324,16 @@
}
func (c *config) RunErrorProne() bool {
- return c.IsEnvTrue("RUN_ERROR_PRONE")
+ return c.IsEnvTrue("RUN_ERROR_PRONE") || c.RunErrorProneInline()
+}
+
+// Returns if the errorprone build should be run "inline", that is, using errorprone as part
+// of the main javac compilation instead of its own separate compilation. This is good for CI
+// but bad for local development, because if you toggle errorprone+inline on/off it will repeatedly
+// clobber java files from the old configuration.
+func (c *config) RunErrorProneInline() bool {
+ value := strings.ToLower(c.Getenv("RUN_ERROR_PRONE"))
+ return c.IsEnvTrue("RUN_ERROR_PRONE_INLINE") || value == "inline"
}
// XrefCorpusName returns the Kythe cross-reference corpus name.
@@ -1235,7 +1385,7 @@
}
func (c *config) LibartImgHostBaseAddress() string {
- return "0x60000000"
+ return "0x70000000"
}
func (c *config) LibartImgDeviceBaseAddress() string {
@@ -1261,6 +1411,7 @@
}
return false
}
+
func (c *config) EnforceRROExcludedOverlay(path string) bool {
excluded := c.productVariables.EnforceRROExcludedOverlays
if len(excluded) > 0 {
@@ -1269,6 +1420,11 @@
return false
}
+func (c *config) EnforceRROGlobally() bool {
+ enforceList := c.productVariables.EnforceRROTargets
+ return InList("*", enforceList)
+}
+
func (c *config) ExportedNamespaces() []string {
return append([]string(nil), c.productVariables.NamespacesToExport...)
}
@@ -1363,6 +1519,10 @@
return c.productVariables.GetBuildFlagBool("RELEASE_BOARD_API_LEVEL_FROZEN")
}
+func (c *config) katiPackageMkDir() string {
+ return filepath.Join(c.soongOutDir, "kati_packaging"+c.katiSuffix)
+}
+
func (c *deviceConfig) Arches() []Arch {
var arches []Arch
for _, target := range c.config.Targets[Android] {
@@ -1379,6 +1539,13 @@
return "64"
}
+func (c *deviceConfig) RecoveryPath() string {
+ if c.config.productVariables.RecoveryPath != nil {
+ return *c.config.productVariables.RecoveryPath
+ }
+ return "recovery"
+}
+
func (c *deviceConfig) VendorPath() string {
if c.config.productVariables.VendorPath != nil {
return *c.config.productVariables.VendorPath
@@ -1386,6 +1553,17 @@
return "vendor"
}
+func (c *deviceConfig) VendorDlkmPath() string {
+ if c.config.productVariables.VendorDlkmPath != nil {
+ return *c.config.productVariables.VendorDlkmPath
+ }
+ return "vendor_dlkm"
+}
+
+func (c *deviceConfig) BuildingVendorImage() bool {
+ return proptools.Bool(c.config.productVariables.BuildingVendorImage)
+}
+
func (c *deviceConfig) CurrentApiLevelForVendorModules() string {
return StringDefault(c.config.productVariables.DeviceCurrentApiLevelForVendorModules, "current")
}
@@ -1409,6 +1587,17 @@
return "odm"
}
+func (c *deviceConfig) BuildingOdmImage() bool {
+ return proptools.Bool(c.config.productVariables.BuildingOdmImage)
+}
+
+func (c *deviceConfig) OdmDlkmPath() string {
+ if c.config.productVariables.OdmDlkmPath != nil {
+ return *c.config.productVariables.OdmDlkmPath
+ }
+ return "odm_dlkm"
+}
+
func (c *deviceConfig) ProductPath() string {
if c.config.productVariables.ProductPath != nil {
return *c.config.productVariables.ProductPath
@@ -1416,6 +1605,10 @@
return "product"
}
+func (c *deviceConfig) BuildingProductImage() bool {
+ return proptools.Bool(c.config.productVariables.BuildingProductImage)
+}
+
func (c *deviceConfig) SystemExtPath() string {
if c.config.productVariables.SystemExtPath != nil {
return *c.config.productVariables.SystemExtPath
@@ -1423,6 +1616,35 @@
return "system_ext"
}
+func (c *deviceConfig) SystemDlkmPath() string {
+ if c.config.productVariables.SystemDlkmPath != nil {
+ return *c.config.productVariables.SystemDlkmPath
+ }
+ return "system_dlkm"
+}
+
+func (c *deviceConfig) OemPath() string {
+ if c.config.productVariables.OemPath != nil {
+ return *c.config.productVariables.OemPath
+ }
+ return "oem"
+}
+
+func (c *deviceConfig) UserdataPath() string {
+ if c.config.productVariables.UserdataPath != nil {
+ return *c.config.productVariables.UserdataPath
+ }
+ return "data"
+}
+
+func (c *deviceConfig) BuildingUserdataImage() bool {
+ return proptools.Bool(c.config.productVariables.BuildingUserdataImage)
+}
+
+func (c *deviceConfig) BuildingRecoveryImage() bool {
+ return proptools.Bool(c.config.productVariables.BuildingRecoveryImage)
+}
+
func (c *deviceConfig) BtConfigIncludeDir() string {
return String(c.config.productVariables.BtConfigIncludeDir)
}
@@ -1483,11 +1705,6 @@
}
}
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
}
@@ -1652,8 +1869,19 @@
return Bool(c.productVariables.CompressedApex) && !c.UnbundledBuildApps()
}
-func (c *config) ApexTrimEnabled() bool {
- return Bool(c.productVariables.TrimmedApex)
+func (c *config) DefaultApexPayloadType() string {
+ return StringDefault(c.productVariables.DefaultApexPayloadType, "ext4")
+}
+
+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 {
@@ -1668,14 +1896,6 @@
return Bool(c.productVariables.EnforceProductPartitionInterface)
}
-func (c *config) EnforceInterPartitionJavaSdkLibrary() bool {
- return Bool(c.productVariables.EnforceInterPartitionJavaSdkLibrary)
-}
-
-func (c *config) InterPartitionJavaLibraryAllowList() []string {
- return c.productVariables.InterPartitionJavaLibraryAllowList
-}
-
func (c *config) ProductHiddenAPIStubs() []string {
return c.productVariables.ProductHiddenAPIStubs
}
@@ -1821,10 +2041,6 @@
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
}
@@ -1951,23 +2167,47 @@
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")
+}
+
+func (c *config) UseR8FullModeByDefault() bool {
+ return c.productVariables.GetBuildFlagBool("RELEASE_R8_FULL_MODE_BY_DEFAULT")
+}
+
+func (c *config) UseR8OnlyRuntimeVisibleAnnotations() bool {
+ return c.productVariables.GetBuildFlagBool("RELEASE_R8_ONLY_RUNTIME_VISIBLE_ANNOTATIONS")
+}
+
+func (c *config) UseR8StoreStoreFenceConstructorInlining() bool {
+ return c.productVariables.GetBuildFlagBool("RELEASE_R8_STORE_STORE_FENCE_CONSTRUCTOR_INLINING")
+}
+
+func (c *config) UseDexV41() bool {
+ return c.productVariables.GetBuildFlagBool("RELEASE_USE_DEX_V41")
+}
+
var (
mainlineApexContributionBuildFlagsToApexNames = map[string]string{
"RELEASE_APEX_CONTRIBUTIONS_ADBD": "com.android.adbd",
"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "com.android.adservices",
"RELEASE_APEX_CONTRIBUTIONS_APPSEARCH": "com.android.appsearch",
"RELEASE_APEX_CONTRIBUTIONS_ART": "com.android.art",
- "RELEASE_APEX_CONTRIBUTIONS_BLUETOOTH": "com.android.btservices",
+ "RELEASE_APEX_CONTRIBUTIONS_BLUETOOTH": "com.android.bt",
"RELEASE_APEX_CONTRIBUTIONS_CAPTIVEPORTALLOGIN": "",
"RELEASE_APEX_CONTRIBUTIONS_CELLBROADCAST": "com.android.cellbroadcast",
"RELEASE_APEX_CONTRIBUTIONS_CONFIGINFRASTRUCTURE": "com.android.configinfrastructure",
"RELEASE_APEX_CONTRIBUTIONS_CONNECTIVITY": "com.android.tethering",
"RELEASE_APEX_CONTRIBUTIONS_CONSCRYPT": "com.android.conscrypt",
- "RELEASE_APEX_CONTRIBUTIONS_CRASHRECOVERY": "",
+ "RELEASE_APEX_CONTRIBUTIONS_CRASHRECOVERY": "com.android.crashrecovery",
"RELEASE_APEX_CONTRIBUTIONS_DEVICELOCK": "com.android.devicelock",
"RELEASE_APEX_CONTRIBUTIONS_DOCUMENTSUIGOOGLE": "",
"RELEASE_APEX_CONTRIBUTIONS_EXTSERVICES": "com.android.extservices",
@@ -1978,9 +2218,11 @@
"RELEASE_APEX_CONTRIBUTIONS_MODULE_METADATA": "",
"RELEASE_APEX_CONTRIBUTIONS_NETWORKSTACKGOOGLE": "",
"RELEASE_APEX_CONTRIBUTIONS_NEURALNETWORKS": "com.android.neuralnetworks",
+ "RELEASE_APEX_CONTRIBUTIONS_NFC": "com.android.nfcservices",
"RELEASE_APEX_CONTRIBUTIONS_ONDEVICEPERSONALIZATION": "com.android.ondevicepersonalization",
"RELEASE_APEX_CONTRIBUTIONS_PERMISSION": "com.android.permission",
"RELEASE_APEX_CONTRIBUTIONS_PRIMARY_LIBS": "",
+ "RELEASE_APEX_CONTRIBUTIONS_PROFILING": "com.android.profiling",
"RELEASE_APEX_CONTRIBUTIONS_REMOTEKEYPROVISIONING": "com.android.rkpd",
"RELEASE_APEX_CONTRIBUTIONS_RESOLV": "com.android.resolv",
"RELEASE_APEX_CONTRIBUTIONS_SCHEDULING": "com.android.scheduling",
@@ -1989,6 +2231,7 @@
"RELEASE_APEX_CONTRIBUTIONS_STATSD": "com.android.os.statsd",
"RELEASE_APEX_CONTRIBUTIONS_TELEMETRY_TVP": "",
"RELEASE_APEX_CONTRIBUTIONS_TZDATA": "com.android.tzdata",
+ "RELEASE_APEX_CONTRIBUTIONS_UPROBESTATS": "com.android.uprobestats",
"RELEASE_APEX_CONTRIBUTIONS_UWB": "com.android.uwb",
"RELEASE_APEX_CONTRIBUTIONS_WIFI": "com.android.wifi",
}
@@ -2050,6 +2293,14 @@
return PathsForSource(ctx, c.productVariables.ProductPropFiles)
}
+func (c *config) OdmPropFiles(ctx PathContext) Paths {
+ return PathsForSource(ctx, c.productVariables.OdmPropFiles)
+}
+
+func (c *config) VendorPropFiles(ctx PathContext) Paths {
+ return PathsForSource(ctx, c.productVariables.VendorPropFiles)
+}
+
func (c *config) EnableUffdGc() string {
return String(c.productVariables.EnableUffdGc)
}
@@ -2069,3 +2320,34 @@
func (c *config) BoardAvbSystemAddHashtreeFooterArgs() []string {
return c.productVariables.BoardAvbSystemAddHashtreeFooterArgs
}
+
+// Returns true if RELEASE_INSTALL_APEX_SYSTEMSERVER_DEXPREOPT_SAME_PARTITION is set to true.
+// If true, dexpreopt files of apex system server jars will be installed in the same partition as the parent apex.
+// If false, all these files will be installed in /system partition.
+func (c Config) InstallApexSystemServerDexpreoptSamePartition() bool {
+ return c.config.productVariables.GetBuildFlagBool("RELEASE_INSTALL_APEX_SYSTEMSERVER_DEXPREOPT_SAME_PARTITION")
+}
+
+func (c *config) DeviceMatrixFile() []string {
+ return c.productVariables.DeviceMatrixFile
+}
+
+func (c *config) ProductManifestFiles() []string {
+ return c.productVariables.ProductManifestFiles
+}
+
+func (c *config) SystemManifestFile() []string {
+ return c.productVariables.SystemManifestFile
+}
+
+func (c *config) SystemExtManifestFiles() []string {
+ return c.productVariables.SystemExtManifestFiles
+}
+
+func (c *config) DeviceManifestFiles() []string {
+ return c.productVariables.DeviceManifestFiles
+}
+
+func (c *config) OdmManifestFiles() []string {
+ return c.productVariables.OdmManifestFiles
+}
diff --git a/android/config_test.go b/android/config_test.go
index 7732168..4fdcc9c 100644
--- a/android/config_test.go
+++ b/android/config_test.go
@@ -77,7 +77,7 @@
func TestProductConfigAnnotations(t *testing.T) {
err := validateConfigAnnotations(&ProductVariables{})
if err != nil {
- t.Errorf(err.Error())
+ t.Error(err.Error())
}
}
@@ -212,3 +212,48 @@
assertStringEquals(t, "apex1:jarA", list5.String())
})
}
+
+func (p partialCompileFlags) updateEnabled(value bool) partialCompileFlags {
+ p.enabled = value
+ return p
+}
+
+func (p partialCompileFlags) updateUseD8(value bool) partialCompileFlags {
+ p.use_d8 = value
+ return p
+}
+
+func TestPartialCompile(t *testing.T) {
+ mockConfig := func(value string) *config {
+ c := &config{
+ env: map[string]string{
+ "SOONG_PARTIAL_COMPILE": value,
+ },
+ }
+ return c
+ }
+ tests := []struct {
+ value string
+ isEngBuild bool
+ expected partialCompileFlags
+ }{
+ {"", true, defaultPartialCompileFlags},
+ {"false", true, partialCompileFlags{}},
+ {"true", true, defaultPartialCompileFlags.updateEnabled(true)},
+ {"true", false, partialCompileFlags{}},
+ {"true,use_d8", true, defaultPartialCompileFlags.updateEnabled(true).updateUseD8(true)},
+ {"true,-use_d8", true, defaultPartialCompileFlags.updateEnabled(true).updateUseD8(false)},
+ {"use_d8,false", true, partialCompileFlags{}},
+ {"false,+use_d8", true, partialCompileFlags{}.updateUseD8(true)},
+ }
+
+ for _, test := range tests {
+ t.Run(test.value, func(t *testing.T) {
+ config := mockConfig(test.value)
+ flags, _ := config.parsePartialCompileFlags(test.isEngBuild)
+ if flags != test.expected {
+ t.Errorf("expected %v found %v", test.expected, flags)
+ }
+ })
+ }
+}
diff --git a/android/container.go b/android/container.go
index 10aff4d..eb2fc18 100644
--- a/android/container.go
+++ b/android/container.go
@@ -15,8 +15,10 @@
package android
import (
+ "fmt"
"reflect"
"slices"
+ "strings"
"github.com/google/blueprint"
)
@@ -29,28 +31,25 @@
// and the corresponding functions are called from [exceptionHandleFunctionsTable] map.
// ----------------------------------------------------------------------------
-type exceptionHandleFunc func(ModuleContext, Module, Module) bool
+type exceptionHandleFunc func(ModuleContext, Module, ModuleProxy) 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
+var depIsStubsModule exceptionHandleFunc = func(mctx ModuleContext, _ Module, dep ModuleProxy) bool {
+ return OtherModuleProviderOrDefault(mctx, dep, CommonModuleInfoKey).IsStubsModule
}
// Returns true if the dependency module belongs to any of the apexes.
-var depIsApexModule exceptionHandleFunc = func(mctx ModuleContext, _, dep Module) bool {
+var depIsApexModule exceptionHandleFunc = func(mctx ModuleContext, _ Module, dep ModuleProxy) 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 {
+var belongsToCommonApexes exceptionHandleFunc = func(mctx ModuleContext, m Module, dep ModuleProxy) bool {
mContainersInfo, _ := getContainerModuleInfo(mctx, m)
depContainersInfo, _ := getContainerModuleInfo(mctx, dep)
@@ -60,7 +59,7 @@
// 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 {
+var belongsToNonUpdatableApex exceptionHandleFunc = func(mctx ModuleContext, m Module, _ ModuleProxy) bool {
mContainersInfo, _ := getContainerModuleInfo(mctx, m)
return !mContainersInfo.UpdatableApex()
@@ -68,7 +67,7 @@
// 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 {
+var depIsNotDynamicDepTag exceptionHandleFunc = func(ctx ModuleContext, m Module, dep ModuleProxy) bool {
mInstallable, _ := m.(InstallableModule)
depTag := ctx.OtherModuleDependencyTag(dep)
return !InList(depTag, mInstallable.DynamicDependencyTags())
@@ -77,7 +76,7 @@
// 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 {
+var depIsNotStaticOrDynamicDepTag exceptionHandleFunc = func(ctx ModuleContext, m Module, dep ModuleProxy) bool {
mInstallable, _ := m.(InstallableModule)
depTag := ctx.OtherModuleDependencyTag(dep)
return !InList(depTag, append(mInstallable.StaticDependencyTags(), mInstallable.DynamicDependencyTags()...))
@@ -89,14 +88,22 @@
"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_stub",
+
// 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 {
+var depIsGloballyAllowlisted exceptionHandleFunc = func(_ ModuleContext, _ Module, dep ModuleProxy) bool {
return InList(dep.Name(), globallyAllowlistedDependencies)
}
@@ -187,10 +194,11 @@
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) {
+ mctx.VisitDirectDepsProxyWithTag(staticDepTag, func(dep ModuleProxy) {
if unstableInfo, ok := OtherModuleProvider(mctx, dep, unstableInfoProvider); ok {
unstableModule = unstableModule || unstableInfo.ContainsPlatformPrivateApis
}
@@ -219,7 +227,6 @@
// ----------------------------------------------------------------------------
type InstallableModule interface {
- ContainersInfo() ContainersInfo
StaticDependencyTags() []blueprint.DependencyTag
DynamicDependencyTags() []blueprint.DependencyTag
}
@@ -373,7 +380,7 @@
func (c *ContainersInfo) ApexNames() (ret []string) {
for _, apex := range c.belongingApexes {
- ret = append(ret, apex.InApexModules...)
+ ret = append(ret, apex.InApexVariants...)
}
slices.Sort(ret)
return ret
@@ -391,6 +398,40 @@
var ContainersInfoProvider = blueprint.NewProvider[ContainersInfo]()
+func satisfyAllowedExceptions(ctx ModuleContext, allowedExceptionLabels []exceptionHandleFuncLabel, m Module, dep ModuleProxy) bool {
+ for _, label := range allowedExceptionLabels {
+ if exceptionHandleFunctionsTable[label](ctx, m, dep) {
+ return true
+ }
+ }
+ return false
+}
+
+func (c *ContainersInfo) GetViolations(mctx ModuleContext, m Module, dep ModuleProxy, 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
@@ -412,8 +453,8 @@
}
func getContainerModuleInfo(ctx ModuleContext, module Module) (ContainersInfo, bool) {
- if ctx.Module() == module {
- return module.ContainersInfo(), true
+ if ctx.EqualModules(ctx.Module(), module) {
+ return ctx.getContainersInfo(), true
}
return OtherModuleProvider(ctx, module, ContainersInfoProvider)
@@ -428,7 +469,36 @@
if _, ok := ctx.Module().(InstallableModule); ok {
containersInfo := generateContainerInfo(ctx)
- ctx.Module().base().containersInfo = containersInfo
+ ctx.setContainersInfo(containersInfo)
SetProvider(ctx, ContainersInfoProvider, containersInfo)
}
}
+
+func checkContainerViolations(ctx ModuleContext) {
+ if _, ok := ctx.Module().(InstallableModule); ok {
+ containersInfo, _ := getContainerModuleInfo(ctx, ctx.Module())
+ ctx.VisitDirectDepsProxy(func(dep ModuleProxy) {
+ if !OtherModuleProviderOrDefault(ctx, dep, CommonModuleInfoKey).Enabled {
+ 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)
+ }
+ }
+ }
+ })
+ }
+}
diff --git a/android/container_violations.go b/android/container_violations.go
new file mode 100644
index 0000000..4c6386d
--- /dev/null
+++ b/android/container_violations.go
@@ -0,0 +1,1175 @@
+// 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
+
+var ContainerDependencyViolationAllowlist = map[string][]string{
+ "adservices-service-core": {
+ "gson", // apex [com.android.adservices, com.android.extservices] -> apex [com.android.virt]
+ },
+
+ "android.car-module.impl": {
+ "modules-utils-preconditions", // apex [com.android.car.framework] -> apex [com.android.adservices, com.android.appsearch, com.android.cellbroadcast, com.android.extservices, com.android.ondevicepersonalization, com.android.tethering, com.android.uwb, com.android.wifi, test_com.android.cellbroadcast, test_com.android.wifi]
+ },
+
+ "AppInstalledOnMultipleUsers": {
+ "framework", // cts -> unstable
+ },
+
+ "art-aconfig-flags-java-lib": {
+ "framework-api-annotations-lib", // apex [com.android.art, com.android.art.debug, com.android.art.testing, test_imgdiag_com.android.art, test_jitzygote_com.android.art] -> system
+ },
+
+ "Bluetooth": {
+ "app-compat-annotations", // apex [com.android.bt] -> system
+ "framework-bluetooth-pre-jarjar", // apex [com.android.bt] -> system
+ },
+
+ "bluetooth-nano-protos": {
+ "libprotobuf-java-nano", // apex [com.android.bt] -> apex [com.android.wifi, test_com.android.wifi]
+ },
+
+ "bluetooth.change-ids": {
+ "app-compat-annotations", // apex [com.android.bt] -> system
+ },
+
+ "CarServiceUpdatable": {
+ "modules-utils-os", // apex [com.android.car.framework] -> apex [com.android.permission, test_com.android.permission]
+ "modules-utils-preconditions", // apex [com.android.car.framework] -> apex [com.android.adservices, com.android.appsearch, com.android.cellbroadcast, com.android.extservices, com.android.ondevicepersonalization, com.android.tethering, com.android.uwb, com.android.wifi, test_com.android.cellbroadcast, test_com.android.wifi]
+ "modules-utils-shell-command-handler", // apex [com.android.car.framework] -> apex [com.android.adservices, com.android.art, com.android.art.debug, com.android.art.testing, com.android.bt, com.android.configinfrastructure, com.android.mediaprovider, com.android.nfcservices, com.android.permission, com.android.scheduling, com.android.tethering, com.android.uwb, com.android.wifi, test_com.android.mediaprovider, test_com.android.permission, test_com.android.wifi, test_imgdiag_com.android.art, test_jitzygote_com.android.art]
+ },
+
+ "cellbroadcastreceiver_aconfig_flags_lib": {
+ "ext", // apex [com.android.cellbroadcast, test_com.android.cellbroadcast] -> system
+ "framework", // apex [com.android.cellbroadcast, test_com.android.cellbroadcast] -> system
+ },
+
+ "connectivity-net-module-utils-bpf": {
+ "net-utils-device-common-struct-base", // apex [com.android.tethering] -> system
+ },
+
+ "conscrypt-aconfig-flags-lib": {
+ "aconfig-annotations-lib-sdk-none", // apex [com.android.conscrypt, test_com.android.conscrypt] -> system
+ },
+
+ "cronet_aml_base_base_java": {
+ "framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+ "jsr305", // apex [com.android.tethering] -> apex [com.android.adservices, com.android.devicelock, com.android.extservices, com.android.healthfitness, com.android.media, com.android.mediaprovider, test_com.android.media, test_com.android.mediaprovider]
+ },
+
+ "cronet_aml_build_android_build_java": {
+ "framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+ },
+
+ "cronet_aml_components_cronet_android_base_feature_overrides_java_proto": {
+ "framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+ },
+
+ "cronet_aml_components_cronet_android_cronet_api_java": {
+ "framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+ },
+
+ "cronet_aml_components_cronet_android_cronet_impl_common_java": {
+ "framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+ },
+
+ "cronet_aml_components_cronet_android_cronet_impl_native_java": {
+ "framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+ "jsr305", // apex [com.android.tethering] -> apex [com.android.adservices, com.android.devicelock, com.android.extservices, com.android.healthfitness, com.android.media, com.android.mediaprovider, test_com.android.media, test_com.android.mediaprovider]
+ },
+
+ "cronet_aml_components_cronet_android_cronet_jni_registration_java": {
+ "framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+ },
+
+ "cronet_aml_components_cronet_android_cronet_shared_java": {
+ "framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+ },
+
+ "cronet_aml_components_cronet_android_cronet_stats_log_java": {
+ "framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+ },
+
+ "cronet_aml_components_cronet_android_cronet_urlconnection_impl_java": {
+ "framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+ },
+
+ "cronet_aml_components_cronet_android_flags_java_proto": {
+ "framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+ },
+
+ "cronet_aml_components_cronet_android_request_context_config_java_proto": {
+ "framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+ },
+
+ "cronet_aml_net_android_net_java": {
+ "framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+ "jsr305", // apex [com.android.tethering] -> apex [com.android.adservices, com.android.devicelock, com.android.extservices, com.android.healthfitness, com.android.media, com.android.mediaprovider, test_com.android.media, test_com.android.mediaprovider]
+ },
+
+ "cronet_aml_net_android_net_thread_stats_uid_java": {
+ "framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+ },
+
+ "cronet_aml_third_party_jni_zero_jni_zero_java": {
+ "framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+ },
+
+ "cronet_aml_url_url_java": {
+ "framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+ },
+
+ "CtsAdservicesHostTestApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsAdServicesNotInAllowListEndToEndTests": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsAdServicesPermissionsAppOptOutEndToEndTests": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsAdServicesPermissionsNoPermEndToEndTests": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsAdServicesPermissionsValidEndToEndTests": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsAlarmManagerTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsAndroidAppTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsAppExitTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsAppFgsStartTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsAppFgsTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsAppFunctionTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsAppOpsTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsAppSearchTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsAppStartTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsAppTestStubsApp2": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsAudioHostTestApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsBackgroundActivityAppAllowCrossUidFlagDefault": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsBatterySavingTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsBluetoothTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsBootDisplayModeApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsBroadcastTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsBRSTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsCompanionDeviceManagerCoreTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsCompanionDeviceManagerMultiProcessTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsCompanionDeviceManagerUiAutomationTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsContentSuggestionsTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsContentTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsCredentialManagerBackupRestoreApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsCrossProfileEnabledApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsCrossProfileEnabledNoPermsApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsCrossProfileNotEnabledApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsCrossProfileUserEnabledApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsDeviceAndProfileOwnerApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsDeviceAndProfileOwnerApp23": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsDeviceAndProfileOwnerApp25": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsDeviceAndProfileOwnerApp30": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsDeviceLockTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsDeviceOwnerApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsDevicePolicySimTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsDevicePolicyTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsDocumentContentTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsDreamsTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsDrmTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsEmptyTestApp_RejectedByVerifier": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsEphemeralTestsEphemeralApp1": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsFgsBootCompletedTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsFgsBootCompletedTestCasesApi35": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsFgsStartTestHelperApi34": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsFgsStartTestHelperCurrent": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsFgsTimeoutTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsFileDescriptorTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsFingerprintTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsHostsideCompatChangeTestsApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsHostsideNetworkPolicyTestsApp2": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsIdentityTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsIkeTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsInstalledLoadingProgressDeviceTests": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsInstantAppTests": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsIntentSenderApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsJobSchedulerTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsKeystoreTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsLegacyNotification27TestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsLibcoreTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsLibcoreWycheproofConscryptTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsListeningPortsTest": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsLocationCoarseTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsLocationFineTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsLocationNoneTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsLocationPrivilegedTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsManagedProfileApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaAudioTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaCodecTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaDecoderTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaDrmFrameworkTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaEncoderTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaExtractorTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaMiscTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaMuxerTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaPerformanceClassTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaPlayerTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaProjectionSDK33TestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaProjectionSDK34TestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaProjectionTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaProviderTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaProviderTranscodeTests": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaRecorderTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ // TODO(b/387499846): Remove once migrated to sdk_version.
+ "CtsMediaRouterTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaRouterHostSideTestBluetoothPermissionsApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaRouterHostSideTestMediaRoutingControlApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaRouterHostSideTestModifyAudioRoutingApp": {
+ "framework", // cts -> unstable
+ },
+
+ // TODO(b/387500109): Remove once migrated to sdk_version.
+ "CtsMediaSessionTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMediaV2TestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMimeMapTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsModifyQuietModeEnabledApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsMusicRecognitionTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsNativeMediaAAudioTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsNetTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsNetTestCasesLegacyApi22": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsNetTestCasesMaxTargetSdk30": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsNetTestCasesMaxTargetSdk31": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsNetTestCasesMaxTargetSdk33": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsNetTestCasesUpdateStatsPermission": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsNfcTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsOnDeviceIntelligenceServiceTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsOnDevicePersonalizationTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsPackageInstallerApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsPackageManagerTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsPackageSchemeTestsWithoutVisibility": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsPackageSchemeTestsWithVisibility": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsPackageWatchdogTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsPermissionsSyncTestApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsPreservedSettingsApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsProtoTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsProviderTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsProxyMediaRouterTestHelperApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsRebootReadinessTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsResourcesLoaderTests": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsResourcesTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSandboxedAdIdManagerTests": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSandboxedAppSetIdManagerTests": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSandboxedFledgeManagerTests": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSandboxedMeasurementManagerTests": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSandboxedTopicsManagerTests": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSdkExtensionsTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSdkSandboxInprocessTests": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSecureElementTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSecurityTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSelinuxEphemeralTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSelinuxTargetSdk25TestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSelinuxTargetSdk27TestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSelinuxTargetSdk28TestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSelinuxTargetSdk29TestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSelinuxTargetSdk30TestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSelinuxTargetSdkCurrentTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSettingsDeviceOwnerApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSharedUserMigrationTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsShortFgsTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSimRestrictedApisTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSliceTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSpeechTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsStatsSecurityApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSuspendAppsTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsSystemUiTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsTareTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsTelephonyTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsTetheringTest": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsThreadNetworkTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsTvInputTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsTvTunerTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsUsageStatsTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsUsbManagerTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsUserRestrictionTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsUtilTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsUwbTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsVcnTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsVideoCodecTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsVideoTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsViewReceiveContentTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsVirtualDevicesAppLaunchTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsVirtualDevicesAudioTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsVirtualDevicesCameraTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsVirtualDevicesSensorTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsVirtualDevicesTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsWearableSensingServiceTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsWebViewCompatChangeApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsWidgetTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsWidgetTestCases29": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsWifiNonUpdatableTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsWifiTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsWindowManagerExternalApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsWindowManagerTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "CtsZipValidateApp": {
+ "framework", // cts -> unstable
+ },
+
+ "CVE-2021-0965": {
+ "framework", // cts -> unstable
+ },
+
+ "device_config_reboot_flags_java_lib": {
+ "ext", // apex [com.android.configinfrastructure] -> system
+ "framework", // apex [com.android.configinfrastructure] -> system
+ },
+
+ "devicelockcontroller-lib": {
+ "modules-utils-expresslog", // apex [com.android.devicelock] -> apex [com.android.bt, com.android.car.framework]
+ },
+
+ "FederatedCompute": {
+ "auto_value_annotations", // apex [com.android.ondevicepersonalization] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+ },
+
+ "framework-adservices.impl": {
+ "adservices_flags_lib", // apex [com.android.adservices, com.android.extservices] -> system
+ },
+
+ "framework-bluetooth.impl": {
+ "app-compat-annotations", // apex [com.android.bt] -> system
+ },
+
+ "framework-configinfrastructure.impl": {
+ "configinfra_framework_flags_java_lib", // apex [com.android.configinfrastructure] -> system
+ },
+
+ "framework-connectivity-t.impl": {
+ "app-compat-annotations", // apex [com.android.tethering] -> system
+ "framework-connectivity-pre-jarjar", // apex [com.android.tethering] -> system
+ },
+
+ // TODO(b/382743602): Remove "app-compat-annotations" and depend on the stub version jar
+ // TODO(b/382301972): Remove the violations and use jarjar_rename or jarjar_prefix
+ "framework-connectivity-b.impl": {
+ "app-compat-annotations", // apex [com.android.tethering] -> system
+ "framework-connectivity-pre-jarjar", // apex [com.android.tethering] -> system
+ },
+
+ "framework-connectivity.impl": {
+ "app-compat-annotations", // apex [com.android.tethering] -> system
+ },
+
+ "framework-ondevicepersonalization.impl": {
+ "app-compat-annotations", // apex [com.android.ondevicepersonalization] -> system
+ "ondevicepersonalization_flags_lib", // apex [com.android.ondevicepersonalization] -> system
+ },
+
+ "framework-pdf-v.impl": {
+ "app-compat-annotations", // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> system
+ "modules-utils-preconditions", // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> apex [com.android.adservices, com.android.appsearch, com.android.cellbroadcast, com.android.extservices, com.android.ondevicepersonalization, com.android.tethering, com.android.uwb, com.android.wifi, test_com.android.cellbroadcast, test_com.android.wifi]
+ },
+
+ "framework-pdf.impl": {
+ "modules-utils-preconditions", // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> apex [com.android.adservices, com.android.appsearch, com.android.cellbroadcast, com.android.extservices, com.android.ondevicepersonalization, com.android.tethering, com.android.uwb, com.android.wifi, test_com.android.cellbroadcast, test_com.android.wifi]
+ },
+
+ "framework-permission-s.impl": {
+ "app-compat-annotations", // apex [com.android.permission, test_com.android.permission] -> system
+ },
+
+ "framework-wifi.impl": {
+ "aconfig_storage_reader_java", // apex [com.android.wifi, test_com.android.wifi] -> system
+ "app-compat-annotations", // apex [com.android.wifi, test_com.android.wifi] -> system
+ },
+
+ "grpc-java-core-internal": {
+ "gson", // apex [com.android.adservices, com.android.devicelock, com.android.extservices] -> apex [com.android.virt]
+ "perfmark-api-lib", // apex [com.android.adservices, com.android.devicelock, com.android.extservices] -> system
+ },
+
+ "httpclient_impl": {
+ "httpclient_api", // apex [com.android.tethering] -> system
+ },
+
+ "IncrementalTestAppValidator": {
+ "framework", // cts -> unstable
+ },
+
+ "libcore-aconfig-flags-lib": {
+ "framework-api-annotations-lib", // apex [com.android.art, com.android.art.debug, com.android.art.testing, test_imgdiag_com.android.art, test_jitzygote_com.android.art] -> system
+ },
+
+ "loadlibrarytest_product_app": {
+ "libnativeloader_vendor_shared_lib", // product -> vendor
+ },
+
+ "loadlibrarytest_testlib": {
+ "libnativeloader_vendor_shared_lib", // system -> vendor
+ },
+
+ "MctsMediaCodecTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "MctsMediaDecoderTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "MctsMediaDrmFrameworkTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "MctsMediaEncoderTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "MctsMediaExtractorTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "MctsMediaMiscTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "MctsMediaMuxerTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "MctsMediaPlayerTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "MctsMediaRecorderTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ // TODO(b/387499846): Remove once migrated to sdk_version.
+ "MctsMediaRouterTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ // TODO(b/387500109): Remove once migrated to sdk_version.
+ "MctsMediaSessionTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "MctsMediaTranscodingTestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "MctsMediaV2TestCases": {
+ "framework", // cts -> unstable
+ },
+
+ "MediaProvider": {
+ "app-compat-annotations", // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> system
+ },
+
+ "mediaprovider_flags_java_lib": {
+ "ext", // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> system
+ "framework", // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> system
+ },
+
+ "MockSatelliteGatewayServiceApp": {
+ "framework", // cts -> unstable
+ },
+
+ "MockSatelliteServiceApp": {
+ "framework", // cts -> unstable
+ },
+
+ "net-utils-device-common-netlink": {
+ "net-utils-device-common-struct-base", // apex [com.android.tethering] -> system
+ },
+
+ "net-utils-device-common-struct": {
+ "net-utils-device-common-struct-base", // apex [com.android.tethering] -> system
+ },
+
+ "NfcNciApex": {
+ // TODO(b/383782511): Remove the violations once the infra is fixed.
+ "android.nfc.flags-aconfig-java", // apex [com.android.nfcservices] -> system
+ "android.permission.flags-aconfig-java", // apex [com.android.nfcservices] -> apex [com.android.permission, test_com.android.permission]
+ // TODO(b/383782511): Remove the violations once the infra is fixed.
+ "framework-nfc.impl", // apex [com.android.nfcservices] -> system
+ },
+
+ "okhttp-norepackage": {
+ "okhttp-android-util-log", // apex [com.android.adservices, com.android.devicelock, com.android.extservices] -> system
+ },
+
+ "ondevicepersonalization-plugin-lib": {
+ "auto_value_annotations", // apex [com.android.ondevicepersonalization] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+ },
+
+ "opencensus-java-api": {
+ "auto_value_annotations", // apex [com.android.devicelock] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+ },
+
+ "PermissionController-lib": {
+ "safety-center-annotations", // apex [com.android.permission, test_com.android.permission] -> system
+ },
+
+ "PlatformProperties": {
+ "sysprop-library-stub-platform", // apex [com.android.bt, com.android.nfcservices, com.android.tethering, com.android.virt, com.android.wifi, test_com.android.wifi] -> system
+ },
+
+ "safety-center-config": {
+ "safety-center-annotations", // apex [com.android.permission, test_com.android.permission] -> system
+ },
+
+ "safety-center-internal-data": {
+ "safety-center-annotations", // apex [com.android.permission, test_com.android.permission] -> system
+ },
+
+ "safety-center-pending-intents": {
+ "safety-center-annotations", // apex [com.android.permission, test_com.android.permission] -> system
+ },
+
+ "safety-center-persistence": {
+ "safety-center-annotations", // apex [com.android.permission, test_com.android.permission] -> system
+ },
+
+ "safety-center-resources-lib": {
+ "safety-center-annotations", // apex [com.android.permission, test_com.android.permission] -> system
+ },
+
+ "SdkSandboxManagerDisabledTests": {
+ "framework", // cts -> unstable
+ },
+
+ "SdkSandboxManagerTests": {
+ "framework", // cts -> unstable
+ },
+
+ "service-art.impl": {
+ "auto_value_annotations", // apex [com.android.art, com.android.art.debug, com.android.art.testing, test_imgdiag_com.android.art, test_jitzygote_com.android.art] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+ },
+
+ "service-bluetooth-pre-jarjar": {
+ "framework-bluetooth-pre-jarjar", // apex [com.android.bt] -> system
+ "service-bluetooth.change-ids", // apex [com.android.bt] -> system
+ },
+
+ "service-connectivity": {
+ "libprotobuf-java-nano", // apex [com.android.tethering] -> apex [com.android.wifi, test_com.android.wifi]
+ },
+
+ "service-connectivity-pre-jarjar": {
+ "framework-connectivity-pre-jarjar", // apex [com.android.tethering] -> system
+ },
+
+ "service-connectivity-protos": {
+ "libprotobuf-java-nano", // apex [com.android.tethering] -> apex [com.android.wifi, test_com.android.wifi]
+ },
+
+ "service-connectivity-tiramisu-pre-jarjar": {
+ "framework-connectivity-pre-jarjar", // apex [com.android.tethering] -> system
+ "framework-connectivity-t-pre-jarjar", // apex [com.android.tethering] -> system
+ },
+
+ // TODO(b/382301972): Remove the violations and use jarjar_rename or jarjar_prefix
+ "service-connectivity-b-pre-jarjar": {
+ "framework-connectivity-pre-jarjar", // apex [com.android.tethering] -> system
+ "framework-connectivity-b-pre-jarjar", // apex [com.android.tethering] -> system
+ "framework-connectivity-t-pre-jarjar", // apex [com.android.tethering] -> system
+ },
+
+ "service-entitlement": {
+ "auto_value_annotations", // apex [com.android.wifi, test_com.android.wifi] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+ },
+
+ "service-entitlement-api": {
+ "auto_value_annotations", // apex [com.android.wifi, test_com.android.wifi] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+ },
+
+ "service-entitlement-data": {
+ "auto_value_annotations", // apex [com.android.wifi, test_com.android.wifi] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+ },
+
+ "service-entitlement-impl": {
+ "auto_value_annotations", // apex [com.android.wifi, test_com.android.wifi] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+ },
+
+ "service-healthfitness.impl": {
+ "modules-utils-preconditions", // apex [com.android.healthfitness] -> apex [com.android.adservices, com.android.appsearch, com.android.cellbroadcast, com.android.extservices, com.android.ondevicepersonalization, com.android.tethering, com.android.uwb, com.android.wifi, test_com.android.cellbroadcast, test_com.android.wifi]
+ },
+
+ "service-networksecurity-pre-jarjar": {
+ "framework-connectivity-pre-jarjar", // apex [com.android.tethering] -> system
+ },
+
+ "service-permission.impl": {
+ "jsr305", // apex [com.android.permission, test_com.android.permission] -> apex [com.android.adservices, com.android.devicelock, com.android.extservices, com.android.healthfitness, com.android.media, com.android.mediaprovider, test_com.android.media, test_com.android.mediaprovider]
+ "safety-center-annotations", // apex [com.android.permission, test_com.android.permission] -> system
+ },
+
+ "service-remoteauth-pre-jarjar": {
+ "framework-connectivity-pre-jarjar", // apex [com.android.tethering] -> system
+ "framework-connectivity-t-pre-jarjar", // apex [com.android.tethering] -> system
+ },
+
+ "service-thread-pre-jarjar": {
+ "framework-connectivity-pre-jarjar", // apex [com.android.tethering] -> system
+ "framework-connectivity-t-pre-jarjar", // apex [com.android.tethering] -> system
+ },
+
+ "service-uwb-pre-jarjar": {
+ "framework-uwb-pre-jarjar", // apex [com.android.uwb] -> system
+ },
+
+ "service-wifi": {
+ "auto_value_annotations", // apex [com.android.wifi, test_com.android.wifi] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+ },
+
+ "TelephonyDeviceTest": {
+ "framework", // cts -> unstable
+ },
+
+ "tensorflowlite_java": {
+ "android-support-annotations", // apex [com.android.adservices, com.android.extservices, com.android.ondevicepersonalization] -> system
+ },
+
+ "TestExternalImsServiceApp": {
+ "framework", // cts -> unstable
+ },
+
+ "TestSmsRetrieverApp": {
+ "framework", // cts -> unstable
+ },
+
+ "TetheringApiCurrentLib": {
+ "connectivity-internal-api-util", // apex [com.android.tethering] -> system
+ },
+
+ "TetheringNext": {
+ "connectivity-internal-api-util", // apex [com.android.tethering] -> system
+ },
+
+ "tetheringstatsprotos": {
+ "ext", // apex [com.android.tethering] -> system
+ "framework", // apex [com.android.tethering] -> system
+ },
+
+ "uwb_aconfig_flags_lib": {
+ "ext", // apex [com.android.uwb] -> system
+ "framework", // apex [com.android.uwb] -> system
+ },
+
+ "uwb_androidx_backend": {
+ "android-support-annotations", // apex [com.android.tethering] -> system
+ },
+
+ "wifi-service-pre-jarjar": {
+ "app-compat-annotations", // apex [com.android.wifi, test_com.android.wifi] -> system
+ "auto_value_annotations", // apex [com.android.wifi, test_com.android.wifi] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+ "framework-wifi-pre-jarjar", // apex [com.android.wifi, test_com.android.wifi] -> system
+ "jsr305", // apex [com.android.wifi, test_com.android.wifi] -> apex [com.android.adservices, com.android.devicelock, com.android.extservices, com.android.healthfitness, com.android.media, com.android.mediaprovider, test_com.android.media, test_com.android.mediaprovider]
+ },
+}
diff --git a/android/csuite_config.go b/android/csuite_config.go
index 20bd035..26ad6e1 100644
--- a/android/csuite_config.go
+++ b/android/csuite_config.go
@@ -30,11 +30,11 @@
type CSuiteConfig struct {
ModuleBase
properties csuiteConfigProperties
- OutputFilePath OutputPath
+ OutputFilePath Path
}
func (me *CSuiteConfig) GenerateAndroidBuildActions(ctx ModuleContext) {
- me.OutputFilePath = PathForModuleOut(ctx, me.BaseModuleName()).OutputPath
+ me.OutputFilePath = PathForModuleOut(ctx, me.BaseModuleName())
}
func (me *CSuiteConfig) AndroidMkEntries() []AndroidMkEntries {
diff --git a/android/deapexer.go b/android/deapexer.go
index dcae3e4..4049d2b 100644
--- a/android/deapexer.go
+++ b/android/deapexer.go
@@ -15,7 +15,6 @@
package android
import (
- "fmt"
"strings"
"github.com/google/blueprint"
@@ -109,10 +108,6 @@
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,45 +164,6 @@
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, ok := OtherModuleProvider(ctx, m, DeapexerProvider)
- if !ok {
- ctx.ModuleErrorf("Expected all deps with DeapexerTag to have a DeapexerProvider, but module %q did not", m.Name())
- return
- }
- 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")
diff --git a/android/defaults.go b/android/defaults.go
index c0a2fc6..0fc1768 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -28,7 +28,7 @@
var DefaultsDepTag defaultsDependencyTag
type defaultsProperties struct {
- Defaults proptools.Configurable[[]string]
+ Defaults []string
}
type DefaultableModuleBase struct {
@@ -69,7 +69,7 @@
// 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 @@
// A restricted subset of context methods, similar to LoadHookContext.
type DefaultableHookContext interface {
EarlyModuleContext
+ OtherModuleProviderContext
CreateModule(ModuleFactory, ...interface{}) Module
AddMissingDependencies(missingDeps []string)
@@ -177,6 +178,7 @@
module.AddProperties(
&hostAndDeviceProperties{},
commonProperties,
+ &baseProperties{},
&ApexProperties{},
&distProperties{})
@@ -209,7 +211,7 @@
var _ Defaults = (*DefaultsModuleBase)(nil)
-func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContext,
+func (defaultable *DefaultableModuleBase) applyDefaults(ctx BottomUpMutatorContext,
defaultsList []Defaults) {
for _, defaults := range defaultsList {
@@ -226,7 +228,7 @@
// 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 +256,7 @@
}
}
-func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMutatorContext,
+func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx BottomUpMutatorContext,
defaults Defaults, defaultableProp interface{}) {
for _, def := range defaults.properties() {
@@ -272,19 +274,23 @@
}
func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) {
- ctx.BottomUp("defaults_deps", defaultsDepsMutator).Parallel()
- ctx.TopDown("defaults", defaultsMutator).Parallel()
+ ctx.BottomUp("defaults_deps", defaultsDepsMutator)
+ ctx.BottomUp("defaults", defaultsMutator).UsesCreateModule()
}
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 +301,7 @@
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",
diff --git a/android/defs.go b/android/defs.go
index 78cdea2..4dd267a 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -16,7 +16,6 @@
import (
"github.com/google/blueprint"
- "github.com/google/blueprint/bootstrap"
)
var (
@@ -52,6 +51,14 @@
},
"cpFlags", "extraCmds")
+ // A copy rule wrapped with bash.
+ CpWithBash = pctx.AndroidStaticRule("CpWithBash",
+ blueprint.RuleParams{
+ Command: "/bin/bash -c \"rm -f $out && cp $cpFlags $cpPreserveSymlinks $in $out$extraCmds\"",
+ Description: "cp $out",
+ },
+ "cpFlags", "extraCmds")
+
// A copy rule that doesn't preserve symlinks.
CpNoPreserveSymlink = pctx.AndroidStaticRule("CpNoPreserveSymlink",
blueprint.RuleParams{
@@ -75,6 +82,14 @@
},
"cpFlags", "extraCmds")
+ // A copy executable rule wrapped with bash
+ CpExecutableWithBash = pctx.AndroidStaticRule("CpExecutableWithBash",
+ blueprint.RuleParams{
+ Command: "/bin/bash -c \"(rm -f $out && cp $cpFlags $cpPreserveSymlinks $in $out ) && (chmod +x $out$extraCmds )\"",
+ Description: "cp $out",
+ },
+ "cpFlags", "extraCmds")
+
// A timestamp touch rule.
Touch = pctx.AndroidStaticRule("Touch",
blueprint.RuleParams{
@@ -90,6 +105,14 @@
},
"fromPath")
+ // A symlink rule wrapped with bash
+ SymlinkWithBash = pctx.AndroidStaticRule("SymlinkWithBash",
+ blueprint.RuleParams{
+ Command: "/bin/bash -c \"rm -f $out && ln -sfn $fromPath $out\"",
+ Description: "symlink $out",
+ },
+ "fromPath")
+
ErrorRule = pctx.AndroidStaticRule("Error",
blueprint.RuleParams{
Command: `echo "$error" && false`,
@@ -120,8 +143,3 @@
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())
-}
diff --git a/android/depset_generic.go b/android/depset_generic.go
deleted file mode 100644
index 45c1937..0000000
--- a/android/depset_generic.go
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright 2020 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"
-)
-
-// DepSet is designed to be conceptually compatible with Bazel's depsets:
-// https://docs.bazel.build/versions/master/skylark/depsets.html
-
-type DepSetOrder int
-
-const (
- PREORDER DepSetOrder = iota
- POSTORDER
- TOPOLOGICAL
-)
-
-func (o DepSetOrder) String() string {
- switch o {
- case PREORDER:
- return "PREORDER"
- case POSTORDER:
- return "POSTORDER"
- case TOPOLOGICAL:
- return "TOPOLOGICAL"
- default:
- panic(fmt.Errorf("Invalid DepSetOrder %d", o))
- }
-}
-
-type depSettableType comparable
-
-// A DepSet efficiently stores a slice of an arbitrary type from transitive dependencies without
-// copying. It is stored as a DAG of DepSet nodes, each of which has some direct contents and a list
-// of dependency DepSet nodes.
-//
-// A DepSet has an order that will be used to walk the DAG when ToList() is called. The order
-// can be POSTORDER, PREORDER, or TOPOLOGICAL. POSTORDER and PREORDER orders return a postordered
-// or preordered left to right flattened list. TOPOLOGICAL returns a list that guarantees that
-// elements of children are listed after all of their parents (unless there are duplicate direct
-// elements in the DepSet or any of its transitive dependencies, in which case the ordering of the
-// duplicated element is not guaranteed).
-//
-// A DepSet is created by NewDepSet or NewDepSetBuilder.Build from the slice for direct contents
-// and the *DepSets of dependencies. A DepSet is immutable once created.
-type DepSet[T depSettableType] struct {
- preorder bool
- reverse bool
- order DepSetOrder
- direct []T
- transitive []*DepSet[T]
-}
-
-// 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
- var transitiveCopy []*DepSet[T]
- for _, t := range transitive {
- if t.order != order {
- panic(fmt.Errorf("incompatible order, new DepSet is %s but transitive DepSet is %s",
- order, t.order))
- }
- }
-
- if order == TOPOLOGICAL {
- // TOPOLOGICAL is implemented as a postorder traversal followed by reversing the output.
- // Pre-reverse the inputs here so their order is maintained in the output.
- directCopy = ReverseSlice(direct)
- transitiveCopy = ReverseSlice(transitive)
- } else {
- directCopy = append([]T(nil), direct...)
- transitiveCopy = append([]*DepSet[T](nil), transitive...)
- }
-
- return &DepSet[T]{
- preorder: order == PREORDER,
- reverse: order == TOPOLOGICAL,
- order: order,
- direct: directCopy,
- transitive: transitiveCopy,
- }
-}
-
-// DepSetBuilder is used to create an immutable DepSet.
-type DepSetBuilder[T depSettableType] struct {
- order DepSetOrder
- direct []T
- transitive []*DepSet[T]
-}
-
-// NewDepSetBuilder returns a DepSetBuilder to create an immutable DepSet with the given order and
-// type, represented by a slice of type that will be in the DepSet.
-func NewDepSetBuilder[T depSettableType](order DepSetOrder) *DepSetBuilder[T] {
- return &DepSetBuilder[T]{
- order: order,
- }
-}
-
-// DirectSlice adds direct contents to the DepSet being built by a DepSetBuilder. Newly added direct
-// contents are to the right of any existing direct contents.
-func (b *DepSetBuilder[T]) DirectSlice(direct []T) *DepSetBuilder[T] {
- b.direct = append(b.direct, direct...)
- return b
-}
-
-// Direct adds direct contents to the DepSet being built by a DepSetBuilder. Newly added direct
-// contents are to the right of any existing direct contents.
-func (b *DepSetBuilder[T]) Direct(direct ...T) *DepSetBuilder[T] {
- b.direct = append(b.direct, direct...)
- return b
-}
-
-// Transitive adds transitive contents to the DepSet being built by a DepSetBuilder. Newly added
-// transitive contents are to the right of any existing transitive contents.
-func (b *DepSetBuilder[T]) Transitive(transitive ...*DepSet[T]) *DepSetBuilder[T] {
- for _, t := range transitive {
- if t.order != b.order {
- panic(fmt.Errorf("incompatible order, new DepSet is %s but transitive DepSet is %s",
- b.order, t.order))
- }
- }
- b.transitive = append(b.transitive, transitive...)
- return b
-}
-
-// Returns the DepSet being built by this DepSetBuilder. The DepSetBuilder retains its contents
-// for creating more depSets.
-func (b *DepSetBuilder[T]) Build() *DepSet[T] {
- return NewDepSet(b.order, b.direct, b.transitive)
-}
-
-// walk calls the visit method in depth-first order on a DepSet, preordered if d.preorder is set,
-// otherwise postordered.
-func (d *DepSet[T]) walk(visit func([]T)) {
- visited := make(map[*DepSet[T]]bool)
-
- var dfs func(d *DepSet[T])
- dfs = func(d *DepSet[T]) {
- visited[d] = true
- if d.preorder {
- visit(d.direct)
- }
- for _, dep := range d.transitive {
- if !visited[dep] {
- dfs(dep)
- }
- }
-
- if !d.preorder {
- visit(d.direct)
- }
- }
-
- dfs(d)
-}
-
-// ToList returns the DepSet flattened to a list. The order in the list is based on the order
-// of the DepSet. POSTORDER and PREORDER orders return a postordered or preordered left to right
-// flattened list. TOPOLOGICAL returns a list that guarantees that elements of children are listed
-// after all of their parents (unless there are duplicate direct elements in the DepSet or any of
-// its transitive dependencies, in which case the ordering of the duplicated element is not
-// guaranteed).
-func (d *DepSet[T]) ToList() []T {
- if d == nil {
- return nil
- }
- var list []T
- d.walk(func(paths []T) {
- list = append(list, paths...)
- })
- list = firstUniqueInPlace(list)
- if d.reverse {
- ReverseSliceInPlace(list)
- }
- return list
-}
diff --git a/android/depset_test.go b/android/depset_test.go
deleted file mode 100644
index 376dffa..0000000
--- a/android/depset_test.go
+++ /dev/null
@@ -1,295 +0,0 @@
-// Copyright 2020 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"
- "strings"
- "testing"
-)
-
-func ExampleDepSet_ToList_postordered() {
- a := NewDepSetBuilder[Path](POSTORDER).Direct(PathForTesting("a")).Build()
- b := NewDepSetBuilder[Path](POSTORDER).Direct(PathForTesting("b")).Transitive(a).Build()
- c := NewDepSetBuilder[Path](POSTORDER).Direct(PathForTesting("c")).Transitive(a).Build()
- d := NewDepSetBuilder[Path](POSTORDER).Direct(PathForTesting("d")).Transitive(b, c).Build()
-
- fmt.Println(Paths(d.ToList()).Strings())
- // Output: [a b c d]
-}
-
-func ExampleDepSet_ToList_preordered() {
- a := NewDepSetBuilder[Path](PREORDER).Direct(PathForTesting("a")).Build()
- b := NewDepSetBuilder[Path](PREORDER).Direct(PathForTesting("b")).Transitive(a).Build()
- c := NewDepSetBuilder[Path](PREORDER).Direct(PathForTesting("c")).Transitive(a).Build()
- d := NewDepSetBuilder[Path](PREORDER).Direct(PathForTesting("d")).Transitive(b, c).Build()
-
- fmt.Println(Paths(d.ToList()).Strings())
- // Output: [d b a c]
-}
-
-func ExampleDepSet_ToList_topological() {
- a := NewDepSetBuilder[Path](TOPOLOGICAL).Direct(PathForTesting("a")).Build()
- b := NewDepSetBuilder[Path](TOPOLOGICAL).Direct(PathForTesting("b")).Transitive(a).Build()
- c := NewDepSetBuilder[Path](TOPOLOGICAL).Direct(PathForTesting("c")).Transitive(a).Build()
- d := NewDepSetBuilder[Path](TOPOLOGICAL).Direct(PathForTesting("d")).Transitive(b, c).Build()
-
- fmt.Println(Paths(d.ToList()).Strings())
- // Output: [d b c a]
-}
-
-// Tests based on Bazel's ExpanderTestBase.java to ensure compatibility
-// https://github.com/bazelbuild/bazel/blob/master/src/test/java/com/google/devtools/build/lib/collect/nestedset/ExpanderTestBase.java
-func TestDepSet(t *testing.T) {
- a := PathForTesting("a")
- b := PathForTesting("b")
- c := PathForTesting("c")
- c2 := PathForTesting("c2")
- d := PathForTesting("d")
- e := PathForTesting("e")
-
- tests := []struct {
- name string
- depSet func(t *testing.T, order DepSetOrder) *DepSet[Path]
- postorder, preorder, topological []string
- }{
- {
- name: "simple",
- depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
- return NewDepSet[Path](order, Paths{c, a, b}, nil)
- },
- postorder: []string{"c", "a", "b"},
- preorder: []string{"c", "a", "b"},
- topological: []string{"c", "a", "b"},
- },
- {
- name: "simpleNoDuplicates",
- depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
- return NewDepSet[Path](order, Paths{c, a, a, a, b}, nil)
- },
- postorder: []string{"c", "a", "b"},
- preorder: []string{"c", "a", "b"},
- topological: []string{"c", "a", "b"},
- },
- {
- name: "nesting",
- depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
- subset := NewDepSet[Path](order, Paths{c, a, e}, nil)
- return NewDepSet[Path](order, Paths{b, d}, []*DepSet[Path]{subset})
- },
- postorder: []string{"c", "a", "e", "b", "d"},
- preorder: []string{"b", "d", "c", "a", "e"},
- topological: []string{"b", "d", "c", "a", "e"},
- },
- {
- name: "builderReuse",
- depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
- assertEquals := func(t *testing.T, w, g Paths) {
- t.Helper()
- if !reflect.DeepEqual(w, g) {
- t.Errorf("want %q, got %q", w, g)
- }
- }
- builder := NewDepSetBuilder[Path](order)
- assertEquals(t, nil, builder.Build().ToList())
-
- builder.Direct(b)
- assertEquals(t, Paths{b}, builder.Build().ToList())
-
- builder.Direct(d)
- assertEquals(t, Paths{b, d}, builder.Build().ToList())
-
- child := NewDepSetBuilder[Path](order).Direct(c, a, e).Build()
- builder.Transitive(child)
- return builder.Build()
- },
- postorder: []string{"c", "a", "e", "b", "d"},
- preorder: []string{"b", "d", "c", "a", "e"},
- topological: []string{"b", "d", "c", "a", "e"},
- },
- {
- name: "builderChaining",
- depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
- return NewDepSetBuilder[Path](order).Direct(b).Direct(d).
- Transitive(NewDepSetBuilder[Path](order).Direct(c, a, e).Build()).Build()
- },
- postorder: []string{"c", "a", "e", "b", "d"},
- preorder: []string{"b", "d", "c", "a", "e"},
- topological: []string{"b", "d", "c", "a", "e"},
- },
- {
- name: "transitiveDepsHandledSeparately",
- depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
- subset := NewDepSetBuilder[Path](order).Direct(c, a, e).Build()
- builder := NewDepSetBuilder[Path](order)
- // The fact that we add the transitive subset between the Direct(b) and Direct(d)
- // calls should not change the result.
- builder.Direct(b)
- builder.Transitive(subset)
- builder.Direct(d)
- return builder.Build()
- },
- postorder: []string{"c", "a", "e", "b", "d"},
- preorder: []string{"b", "d", "c", "a", "e"},
- topological: []string{"b", "d", "c", "a", "e"},
- },
- {
- name: "nestingNoDuplicates",
- depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
- subset := NewDepSetBuilder[Path](order).Direct(c, a, e).Build()
- return NewDepSetBuilder[Path](order).Direct(b, d, e).Transitive(subset).Build()
- },
- postorder: []string{"c", "a", "e", "b", "d"},
- preorder: []string{"b", "d", "e", "c", "a"},
- topological: []string{"b", "d", "c", "a", "e"},
- },
- {
- name: "chain",
- depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
- c := NewDepSetBuilder[Path](order).Direct(c).Build()
- b := NewDepSetBuilder[Path](order).Direct(b).Transitive(c).Build()
- a := NewDepSetBuilder[Path](order).Direct(a).Transitive(b).Build()
-
- return a
- },
- postorder: []string{"c", "b", "a"},
- preorder: []string{"a", "b", "c"},
- topological: []string{"a", "b", "c"},
- },
- {
- name: "diamond",
- depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
- d := NewDepSetBuilder[Path](order).Direct(d).Build()
- c := NewDepSetBuilder[Path](order).Direct(c).Transitive(d).Build()
- b := NewDepSetBuilder[Path](order).Direct(b).Transitive(d).Build()
- a := NewDepSetBuilder[Path](order).Direct(a).Transitive(b).Transitive(c).Build()
-
- return a
- },
- postorder: []string{"d", "b", "c", "a"},
- preorder: []string{"a", "b", "d", "c"},
- topological: []string{"a", "b", "c", "d"},
- },
- {
- name: "extendedDiamond",
- depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
- d := NewDepSetBuilder[Path](order).Direct(d).Build()
- e := NewDepSetBuilder[Path](order).Direct(e).Build()
- b := NewDepSetBuilder[Path](order).Direct(b).Transitive(d).Transitive(e).Build()
- c := NewDepSetBuilder[Path](order).Direct(c).Transitive(e).Transitive(d).Build()
- a := NewDepSetBuilder[Path](order).Direct(a).Transitive(b).Transitive(c).Build()
- return a
- },
- postorder: []string{"d", "e", "b", "c", "a"},
- preorder: []string{"a", "b", "d", "e", "c"},
- topological: []string{"a", "b", "c", "e", "d"},
- },
- {
- name: "extendedDiamondRightArm",
- depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
- d := NewDepSetBuilder[Path](order).Direct(d).Build()
- e := NewDepSetBuilder[Path](order).Direct(e).Build()
- b := NewDepSetBuilder[Path](order).Direct(b).Transitive(d).Transitive(e).Build()
- c2 := NewDepSetBuilder[Path](order).Direct(c2).Transitive(e).Transitive(d).Build()
- c := NewDepSetBuilder[Path](order).Direct(c).Transitive(c2).Build()
- a := NewDepSetBuilder[Path](order).Direct(a).Transitive(b).Transitive(c).Build()
- return a
- },
- postorder: []string{"d", "e", "b", "c2", "c", "a"},
- preorder: []string{"a", "b", "d", "e", "c", "c2"},
- topological: []string{"a", "b", "c", "c2", "e", "d"},
- },
- {
- name: "orderConflict",
- depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
- child1 := NewDepSetBuilder[Path](order).Direct(a, b).Build()
- child2 := NewDepSetBuilder[Path](order).Direct(b, a).Build()
- parent := NewDepSetBuilder[Path](order).Transitive(child1).Transitive(child2).Build()
- return parent
- },
- postorder: []string{"a", "b"},
- preorder: []string{"a", "b"},
- topological: []string{"b", "a"},
- },
- {
- name: "orderConflictNested",
- depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
- a := NewDepSetBuilder[Path](order).Direct(a).Build()
- b := NewDepSetBuilder[Path](order).Direct(b).Build()
- child1 := NewDepSetBuilder[Path](order).Transitive(a).Transitive(b).Build()
- child2 := NewDepSetBuilder[Path](order).Transitive(b).Transitive(a).Build()
- parent := NewDepSetBuilder[Path](order).Transitive(child1).Transitive(child2).Build()
- return parent
- },
- postorder: []string{"a", "b"},
- preorder: []string{"a", "b"},
- topological: []string{"b", "a"},
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- t.Run("postorder", func(t *testing.T) {
- depSet := tt.depSet(t, POSTORDER)
- if g, w := Paths(depSet.ToList()).Strings(), tt.postorder; !reflect.DeepEqual(g, w) {
- t.Errorf("expected ToList() = %q, got %q", w, g)
- }
- })
- t.Run("preorder", func(t *testing.T) {
- depSet := tt.depSet(t, PREORDER)
- if g, w := Paths(depSet.ToList()).Strings(), tt.preorder; !reflect.DeepEqual(g, w) {
- t.Errorf("expected ToList() = %q, got %q", w, g)
- }
- })
- t.Run("topological", func(t *testing.T) {
- depSet := tt.depSet(t, TOPOLOGICAL)
- if g, w := Paths(depSet.ToList()).Strings(), tt.topological; !reflect.DeepEqual(g, w) {
- t.Errorf("expected ToList() = %q, got %q", w, g)
- }
- })
- })
- }
-}
-
-func TestDepSetInvalidOrder(t *testing.T) {
- orders := []DepSetOrder{POSTORDER, PREORDER, TOPOLOGICAL}
-
- run := func(t *testing.T, order1, order2 DepSetOrder) {
- defer func() {
- if r := recover(); r != nil {
- if err, ok := r.(error); !ok {
- t.Fatalf("expected panic error, got %v", err)
- } else if !strings.Contains(err.Error(), "incompatible order") {
- t.Fatalf("expected incompatible order error, got %v", err)
- }
- }
- }()
- NewDepSet(order1, nil, []*DepSet[Path]{NewDepSet[Path](order2, nil, nil)})
- t.Fatal("expected panic")
- }
-
- for _, order1 := range orders {
- t.Run(order1.String(), func(t *testing.T) {
- for _, order2 := range orders {
- t.Run(order2.String(), func(t *testing.T) {
- if order1 != order2 {
- run(t, order1, order2)
- }
- })
- }
- })
- }
-}
diff --git a/android/dirgroup.go b/android/dirgroup.go
new file mode 100644
index 0000000..62fbaa5
--- /dev/null
+++ b/android/dirgroup.go
@@ -0,0 +1,62 @@
+// 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 (
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+func init() {
+ RegisterDirgroupBuildComponents(InitRegistrationContext)
+}
+
+func RegisterDirgroupBuildComponents(ctx RegistrationContext) {
+ ctx.RegisterModuleType("dirgroup", DirGroupFactory)
+}
+
+type dirGroupProperties struct {
+ // dirs lists directories that will be included in this dirgroup
+ Dirs proptools.Configurable[[]string] `android:"path"`
+}
+
+type dirGroup struct {
+ ModuleBase
+ DefaultableModuleBase
+ properties dirGroupProperties
+}
+
+type DirInfo struct {
+ Dirs DirectoryPaths
+}
+
+var DirProvider = blueprint.NewProvider[DirInfo]()
+
+// dirgroup contains a list of dirs that are referenced by other modules
+// properties using the syntax ":<name>". dirgroup are also be used to export
+// dirs across package boundaries. Currently the only allowed usage is genrule's
+// dir_srcs property.
+func DirGroupFactory() Module {
+ module := &dirGroup{}
+ module.AddProperties(&module.properties)
+ InitAndroidModule(module)
+ InitDefaultableModule(module)
+ return module
+}
+
+func (fg *dirGroup) GenerateAndroidBuildActions(ctx ModuleContext) {
+ dirs := DirectoryPathsForModuleSrc(ctx, fg.properties.Dirs.GetOrDefault(ctx, nil))
+ SetProvider(ctx, DirProvider, DirInfo{Dirs: dirs})
+}
diff --git a/android/early_module_context.go b/android/early_module_context.go
index 23f4c90..8d28285 100644
--- a/android/early_module_context.go
+++ b/android/early_module_context.go
@@ -21,15 +21,26 @@
"github.com/google/blueprint"
)
+// ModuleErrorContext provides only methods to report errors about the current module.
+type ModuleErrorContext interface {
+ // ModuleErrorf reports an error at the line number of the module type in the module definition.
+ ModuleErrorf(fmt string, args ...interface{})
+
+ // PropertyErrorf reports an error at the line number of a property in the module definition.
+ PropertyErrorf(property, fmt string, args ...interface{})
+}
+
// EarlyModuleContext provides methods that can be called early, as soon as the properties have
// been parsed into the module and before any mutators have run.
type EarlyModuleContext interface {
+ ModuleErrorContext
+
// Module returns the current module as a Module. It should rarely be necessary, as the module already has a
// reference to itself.
Module() Module
// ModuleName returns the name of the module. This is generally the value that was returned by Module.Name() when
- // the module was created, but may have been modified by calls to BaseMutatorContext.Rename.
+ // the module was created, but may have been modified by calls to BottomUpMutatorContext.Rename.
ModuleName() string
// ModuleDir returns the path to the directory that contains the definition of the module.
@@ -49,12 +60,6 @@
// Errorf reports an error at the specified position of the module definition file.
Errorf(pos scanner.Position, fmt string, args ...interface{})
- // ModuleErrorf reports an error at the line number of the module type in the module definition.
- ModuleErrorf(fmt string, args ...interface{})
-
- // PropertyErrorf reports an error at the line number of a property in the module definition.
- PropertyErrorf(property, fmt string, args ...interface{})
-
// OtherModulePropertyErrorf reports an error at the line number of a property in the given module definition.
OtherModulePropertyErrorf(module Module, property, fmt string, args ...interface{})
@@ -93,6 +98,10 @@
// Namespace returns the Namespace object provided by the NameInterface set by Context.SetNameInterface, or the
// default SimpleNameInterface if Context.SetNameInterface was not called.
Namespace() *Namespace
+
+ // HasMutatorFinished returns true if the given mutator has finished running.
+ // It will panic if given an invalid mutator name.
+ HasMutatorFinished(mutatorName string) bool
}
// Deprecated: use EarlyModuleContext instead
@@ -173,5 +182,9 @@
}
func (e *earlyModuleContext) OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{}) {
- e.EarlyModuleContext.OtherModulePropertyErrorf(module, property, fmt, args...)
+ e.EarlyModuleContext.OtherModulePropertyErrorf(getWrappedModule(module), property, fmt, args...)
+}
+
+func (e *earlyModuleContext) HasMutatorFinished(mutatorName string) bool {
+ return e.EarlyModuleContext.HasMutatorFinished(mutatorName)
}
diff --git a/android/filegroup.go b/android/filegroup.go
index ff0f74e..4daff8f 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -41,6 +41,14 @@
Exclude_srcs proptools.Configurable[[]string] `android:"path"`
+ // Sources the will be included in the filegroup, but any module dependencies will be added
+ // using the device os and the device's first architecture's variant.
+ Device_first_srcs proptools.Configurable[[]string] `android:"path_device_first"`
+
+ // Sources the will be included in the filegroup, but any module dependencies will be added
+ // using the device os and the common architecture's variant.
+ Device_common_srcs proptools.Configurable[[]string] `android:"path_device_common"`
+
// The base path to the files. May be used by other modules to determine which portion
// of the path to use. For example, when a filegroup is used as data in a cc_test rule,
// the base path is stripped off the path and the remaining path is used as the
@@ -90,11 +98,12 @@
}
func (fg *fileGroup) GenerateAndroidBuildActions(ctx ModuleContext) {
- fg.srcs = PathsForModuleSrcExcludes(ctx, fg.properties.Srcs.GetOrDefault(ctx, nil), fg.properties.Exclude_srcs.GetOrDefault(ctx, nil))
+ srcs := PathsForModuleSrcExcludes(ctx, fg.properties.Srcs.GetOrDefault(ctx, nil), fg.properties.Exclude_srcs.GetOrDefault(ctx, nil))
+ srcs = append(srcs, PathsForModuleSrc(ctx, fg.properties.Device_first_srcs.GetOrDefault(ctx, nil))...)
+ srcs = append(srcs, PathsForModuleSrc(ctx, fg.properties.Device_common_srcs.GetOrDefault(ctx, nil))...)
if fg.properties.Path != nil {
- fg.srcs = PathsWithModuleSrcSubDir(ctx, fg.srcs, String(fg.properties.Path))
+ srcs = PathsWithModuleSrcSubDir(ctx, srcs, String(fg.properties.Path))
}
- SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: fg.srcs.Strings()})
var aconfigDeclarations []string
var intermediateCacheOutputPaths Paths
@@ -108,6 +117,8 @@
maps.Copy(modeInfos, dep.ModeInfos)
}
})
+
+ fg.srcs = srcs
SetProvider(ctx, CodegenInfoProvider, CodegenInfo{
AconfigDeclarations: aconfigDeclarations,
IntermediateCacheOutputPaths: intermediateCacheOutputPaths,
@@ -139,3 +150,15 @@
return module
}
+
+// Collect information for opening IDE project files in java/jdeps.go.
+// Copied from build/soong/genrule/genrule.go
+func (fg *fileGroup) IDEInfo(ctx BaseModuleContext, dpInfo *IdeInfo) {
+ dpInfo.Srcs = append(dpInfo.Srcs, fg.Srcs().Strings()...)
+ for _, src := range fg.properties.Srcs.GetOrDefault(ctx, nil) {
+ if mod, _ := SrcIsModuleWithTag(src); mod != "" {
+ // Register the module name without any tags in `Deps`
+ dpInfo.Deps = append(dpInfo.Deps, mod)
+ }
+ }
+}
diff --git a/android/filegroup_test.go b/android/filegroup_test.go
index 14e9368..670037d 100644
--- a/android/filegroup_test.go
+++ b/android/filegroup_test.go
@@ -1,55 +1,9 @@
package android
import (
- "path/filepath"
"testing"
)
-func TestFileGroupWithPathProp(t *testing.T) {
- // TODO(b/247782695), TODO(b/242847534) Fix mixed builds for filegroups
- t.Skip("Re-enable once filegroups are corrected for mixed builds")
- outBaseDir := "outputbase"
- pathPrefix := outBaseDir + "/execroot/__main__"
- expectedOutputfile := filepath.Join(pathPrefix, "a/b/c/d/test.aidl")
-
- testCases := []struct {
- bp string
- rel string
- }{
- {
- bp: `
- filegroup {
- name: "baz",
- srcs: ["a/b/c/d/test.aidl"],
- path: "a/b",
- bazel_module: { label: "//:baz" },
- }
-`,
- rel: "c/d/test.aidl",
- },
- {
- bp: `
- filegroup {
- name: "baz",
- srcs: ["a/b/c/d/test.aidl"],
- bazel_module: { label: "//:baz" },
- }
-`,
- rel: "a/b/c/d/test.aidl",
- },
- }
-
- for _, testCase := range testCases {
- result := GroupFixturePreparers(
- PrepareForTestWithFilegroup,
- ).RunTestWithBp(t, testCase.bp)
-
- fg := result.Module("baz", "").(*fileGroup)
- AssertStringEquals(t, "src relativeRoot", testCase.rel, fg.srcs[0].Rel())
- AssertStringEquals(t, "src full path", expectedOutputfile, fg.srcs[0].String())
- }
-}
-
func TestFilegroupDefaults(t *testing.T) {
bp := FixtureAddTextFile("p/Android.bp", `
filegroup_defaults {
diff --git a/android/hooks.go b/android/hooks.go
index 2ad3b5f..5d509a4 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -37,6 +37,7 @@
AppendProperties(...interface{})
PrependProperties(...interface{})
CreateModule(ModuleFactory, ...interface{}) Module
+ CreateModuleInDirectory(ModuleFactory, string, ...interface{}) Module
registerScopedModuleType(name string, factory blueprint.ModuleFactory)
moduleFactories() map[string]blueprint.ModuleFactory
@@ -58,6 +59,16 @@
})
}
+func AddLoadHookWithPriority(m blueprint.Module, hook func(LoadHookContext), priority int) {
+ blueprint.AddLoadHookWithPriority(m, func(ctx blueprint.LoadHookContext) {
+ actx := &loadHookContext{
+ earlyModuleContext: m.(Module).base().earlyModuleContextFactory(ctx),
+ bp: ctx,
+ }
+ hook(actx)
+ }, priority)
+}
+
type loadHookContext struct {
earlyModuleContext
bp blueprint.LoadHookContext
@@ -89,16 +100,47 @@
l.appendPrependHelper(props, proptools.PrependMatchingProperties)
}
-func (l *loadHookContext) createModule(factory blueprint.ModuleFactory, name string, props ...interface{}) blueprint.Module {
- return l.bp.CreateModule(factory, name, props...)
+func (l *loadHookContext) createModule(factory blueprint.ModuleFactory, name string, props ...interface{}) Module {
+ return bpModuleToModule(l.bp.CreateModule(factory, name, props...))
+}
+
+func (l *loadHookContext) createModuleInDirectory(factory blueprint.ModuleFactory, name, moduleDir string, props ...interface{}) Module {
+ return bpModuleToModule(l.bp.CreateModuleInDirectory(factory, name, moduleDir, props...))
+}
+
+type specifyDirectory struct {
+ specified bool
+ directory string
+}
+
+func doesNotSpecifyDirectory() specifyDirectory {
+ return specifyDirectory{
+ specified: false,
+ directory: "",
+ }
+}
+
+func specifiesDirectory(directory string) specifyDirectory {
+ return specifyDirectory{
+ specified: true,
+ directory: directory,
+ }
}
type createModuleContext interface {
Module() Module
- createModule(blueprint.ModuleFactory, string, ...interface{}) blueprint.Module
+ HasMutatorFinished(mutatorName string) bool
+ createModule(blueprint.ModuleFactory, string, ...interface{}) Module
+ createModuleInDirectory(blueprint.ModuleFactory, string, string, ...interface{}) Module
}
-func createModule(ctx createModuleContext, factory ModuleFactory, ext string, props ...interface{}) Module {
+func createModule(ctx createModuleContext, factory ModuleFactory, ext string, specifyDirectory specifyDirectory, props ...interface{}) Module {
+ if ctx.HasMutatorFinished("defaults") {
+ // Creating modules late is oftentimes problematic, because they don't have earlier
+ // mutators run on them. Prevent making modules after the defaults mutator has run.
+ panic("Cannot create a module after the defaults mutator has finished")
+ }
+
inherited := []interface{}{&ctx.Module().base().commonProperties}
var typeName string
@@ -112,7 +154,12 @@
}
typeName = typeName + "_" + ext
- module := ctx.createModule(ModuleFactoryAdaptor(factory), typeName, append(inherited, props...)...).(Module)
+ var module Module
+ if specifyDirectory.specified {
+ module = ctx.createModuleInDirectory(ModuleFactoryAdaptor(factory), typeName, specifyDirectory.directory, append(inherited, props...)...).(Module)
+ } else {
+ module = ctx.createModule(ModuleFactoryAdaptor(factory), typeName, append(inherited, props...)...).(Module)
+ }
if ctx.Module().base().variableProperties != nil && module.base().variableProperties != nil {
src := ctx.Module().base().variableProperties
@@ -132,7 +179,11 @@
}
func (l *loadHookContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
- return createModule(l, factory, "_loadHookModule", props...)
+ return createModule(l, factory, "_loadHookModule", doesNotSpecifyDirectory(), props...)
+}
+
+func (l *loadHookContext) CreateModuleInDirectory(factory ModuleFactory, directory string, props ...interface{}) Module {
+ return createModule(l, factory, "_loadHookModule", specifiesDirectory(directory), props...)
}
func (l *loadHookContext) registerScopedModuleType(name string, factory blueprint.ModuleFactory) {
diff --git a/android/image.go b/android/image.go
index 6e5a551..78343db 100644
--- a/android/image.go
+++ b/android/image.go
@@ -14,44 +14,61 @@
package android
+type ImageInterfaceContext interface {
+ ArchModuleContext
+
+ Module() Module
+
+ ModuleErrorf(fmt string, args ...interface{})
+ PropertyErrorf(property, fmt string, args ...interface{})
+
+ DeviceSpecific() bool
+ SocSpecific() bool
+ ProductSpecific() bool
+ SystemExtSpecific() bool
+ Platform() bool
+
+ Config() Config
+}
+
// 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)
+ ImageMutatorBegin(ctx ImageInterfaceContext)
// VendorVariantNeeded should return true if the module needs a vendor variant (installed on the vendor image).
- VendorVariantNeeded(ctx BaseModuleContext) bool
+ VendorVariantNeeded(ctx ImageInterfaceContext) bool
// ProductVariantNeeded should return true if the module needs a product variant (installed on the product image).
- ProductVariantNeeded(ctx BaseModuleContext) bool
+ ProductVariantNeeded(ctx ImageInterfaceContext) bool
// CoreVariantNeeded should return true if the module needs a core variant (installed on the system image).
- CoreVariantNeeded(ctx BaseModuleContext) bool
+ CoreVariantNeeded(ctx ImageInterfaceContext) bool
// RamdiskVariantNeeded should return true if the module needs a ramdisk variant (installed on the
// ramdisk partition).
- RamdiskVariantNeeded(ctx BaseModuleContext) bool
+ RamdiskVariantNeeded(ctx ImageInterfaceContext) bool
// VendorRamdiskVariantNeeded should return true if the module needs a vendor ramdisk variant (installed on the
// vendor ramdisk partition).
- VendorRamdiskVariantNeeded(ctx BaseModuleContext) bool
+ VendorRamdiskVariantNeeded(ctx ImageInterfaceContext) bool
// DebugRamdiskVariantNeeded should return true if the module needs a debug ramdisk variant (installed on the
// debug ramdisk partition: $(PRODUCT_OUT)/debug_ramdisk).
- DebugRamdiskVariantNeeded(ctx BaseModuleContext) bool
+ DebugRamdiskVariantNeeded(ctx ImageInterfaceContext) bool
// RecoveryVariantNeeded should return true if the module needs a recovery variant (installed on the
// recovery partition).
- RecoveryVariantNeeded(ctx BaseModuleContext) bool
+ RecoveryVariantNeeded(ctx ImageInterfaceContext) bool
// ExtraImageVariations should return a list of the additional variations needed for the module. After the
// variants are created the SetImageVariation method will be called on each newly created variant with the
// its variation.
- ExtraImageVariations(ctx BaseModuleContext) []string
+ ExtraImageVariations(ctx ImageInterfaceContext) []string
// SetImageVariation is called for each newly created image variant. The receiver is the original
// module, "variation" is the name of the newly created variant. "variation" is set on the receiver.
- SetImageVariation(ctx BaseModuleContext, variation string)
+ SetImageVariation(ctx ImageInterfaceContext, variation string)
}
const (
@@ -81,16 +98,53 @@
DebugRamdiskVariation string = "debug_ramdisk"
)
+type imageInterfaceContextAdapter struct {
+ IncomingTransitionContext
+ kind moduleKind
+}
+
+var _ ImageInterfaceContext = (*imageInterfaceContextAdapter)(nil)
+
+func (e *imageInterfaceContextAdapter) Platform() bool {
+ return e.kind == platformModule
+}
+
+func (e *imageInterfaceContextAdapter) DeviceSpecific() bool {
+ return e.kind == deviceSpecificModule
+}
+
+func (e *imageInterfaceContextAdapter) SocSpecific() bool {
+ return e.kind == socSpecificModule
+}
+
+func (e *imageInterfaceContextAdapter) ProductSpecific() bool {
+ return e.kind == productSpecificModule
+}
+
+func (e *imageInterfaceContextAdapter) SystemExtSpecific() bool {
+ return e.kind == systemExtSpecificModule
+}
+
+// imageMutatorBeginMutator calls ImageMutatorBegin on all modules that may have image variants.
+// This happens right before the imageTransitionMutator runs. It's needed to initialize these
+// modules so that they return the correct results for all the other ImageInterface methods,
+// which the imageTransitionMutator will call. Transition mutators should also not mutate modules
+// (except in their Mutate() function), which this method does, so we run it in a separate mutator
+// first.
+func imageMutatorBeginMutator(ctx BottomUpMutatorContext) {
+ if m, ok := ctx.Module().(ImageInterface); ok && ctx.Os() == Android {
+ m.ImageMutatorBegin(ctx)
+ }
+}
+
// imageTransitionMutator creates variants for modules that implement the ImageInterface that
// allow them to build differently for each partition (recovery, core, vendor, etc.).
type imageTransitionMutator struct{}
-func (imageTransitionMutator) Split(ctx BaseModuleContext) []string {
+func getImageVariations(ctx ImageInterfaceContext) []string {
var variations []string
if m, ok := ctx.Module().(ImageInterface); ctx.Os() == Android && ok {
- m.ImageMutatorBegin(ctx)
-
if m.CoreVariantNeeded(ctx) {
variations = append(variations, CoreVariation)
}
@@ -124,6 +178,10 @@
return variations
}
+func (imageTransitionMutator) Split(ctx BaseModuleContext) []string {
+ return getImageVariations(ctx)
+}
+
func (imageTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
return sourceVariation
}
@@ -132,6 +190,16 @@
if _, ok := ctx.Module().(ImageInterface); ctx.Os() != Android || !ok {
return CoreVariation
}
+ variations := getImageVariations(&imageInterfaceContextAdapter{
+ IncomingTransitionContext: ctx,
+ kind: determineModuleKind(ctx.Module().base(), ctx),
+ })
+ // If there's only 1 possible variation, use that. This is a holdover from when blueprint,
+ // when adding dependencies, would use the only variant of a module regardless of its variations
+ // if only 1 variant existed.
+ if len(variations) == 1 {
+ return variations[0]
+ }
return incomingVariation
}
diff --git a/android/init.go b/android/init.go
new file mode 100644
index 0000000..d3a13d0
--- /dev/null
+++ b/android/init.go
@@ -0,0 +1,29 @@
+// 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(extraFilesZip{})
+ gob.Register(InstallPath{})
+ gob.Register(ModuleGenPath{})
+ gob.Register(ModuleObjPath{})
+ gob.Register(ModuleOutPath{})
+ gob.Register(OutputPath{})
+ gob.Register(PhonyPath{})
+ gob.Register(SourcePath{})
+ gob.Register(unstableInfo{})
+}
diff --git a/android/license.go b/android/license.go
index 5bffc25..7b4aeeb 100644
--- a/android/license.go
+++ b/android/license.go
@@ -18,6 +18,15 @@
"github.com/google/blueprint"
)
+type LicenseInfo struct {
+ PackageName *string
+ EffectiveLicenseText NamedPaths
+ EffectiveLicenseKinds []string
+ EffectiveLicenseConditions []string
+}
+
+var LicenseInfoProvider = blueprint.NewProvider[LicenseInfo]()
+
type licenseKindDependencyTag struct {
blueprint.BaseDependencyTag
}
@@ -69,16 +78,24 @@
func (m *licenseModule) GenerateAndroidBuildActions(ctx ModuleContext) {
// license modules have no licenses, but license_kinds must refer to license_kind modules
- mergeStringProps(&m.base().commonProperties.Effective_licenses, ctx.ModuleName())
namePathProps(&m.base().commonProperties.Effective_license_text, m.properties.Package_name, PathsForModuleSrc(ctx, m.properties.License_text)...)
- for _, module := range ctx.GetDirectDepsWithTag(licenseKindTag) {
- if lk, ok := module.(*licenseKindModule); ok {
- mergeStringProps(&m.base().commonProperties.Effective_license_conditions, lk.properties.Conditions...)
- mergeStringProps(&m.base().commonProperties.Effective_license_kinds, ctx.OtherModuleName(module))
+ var conditions []string
+ var kinds []string
+ for _, module := range ctx.GetDirectDepsProxyWithTag(licenseKindTag) {
+ if lk, ok := OtherModuleProvider(ctx, module, LicenseKindInfoProvider); ok {
+ conditions = append(conditions, lk.Conditions...)
+ kinds = append(kinds, ctx.OtherModuleName(module))
} else {
ctx.ModuleErrorf("license_kinds property %q is not a license_kind module", ctx.OtherModuleName(module))
}
}
+
+ SetProvider(ctx, LicenseInfoProvider, LicenseInfo{
+ PackageName: m.properties.Package_name,
+ EffectiveLicenseText: m.base().commonProperties.Effective_license_text,
+ EffectiveLicenseKinds: SortedUniqueStrings(kinds),
+ EffectiveLicenseConditions: SortedUniqueStrings(conditions),
+ })
}
func LicenseFactory() Module {
diff --git a/android/license_kind.go b/android/license_kind.go
index 838dedd..1ca6954 100644
--- a/android/license_kind.go
+++ b/android/license_kind.go
@@ -14,6 +14,14 @@
package android
+import "github.com/google/blueprint"
+
+type LicenseKindInfo struct {
+ Conditions []string
+}
+
+var LicenseKindInfoProvider = blueprint.NewProvider[LicenseKindInfo]()
+
func init() {
RegisterLicenseKindBuildComponents(InitRegistrationContext)
}
@@ -43,8 +51,10 @@
// Nothing to do.
}
-func (m *licenseKindModule) GenerateAndroidBuildActions(ModuleContext) {
- // Nothing to do.
+func (m *licenseKindModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ SetProvider(ctx, LicenseKindInfoProvider, LicenseKindInfo{
+ Conditions: m.properties.Conditions,
+ })
}
func LicenseKindFactory() Module {
diff --git a/android/license_metadata.go b/android/license_metadata.go
index cd69749..d15dfa8 100644
--- a/android/license_metadata.go
+++ b/android/license_metadata.go
@@ -19,6 +19,7 @@
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/depset"
"github.com/google/blueprint/proptools"
)
@@ -61,14 +62,10 @@
var allDepMetadataFiles Paths
var allDepMetadataArgs []string
var allDepOutputFiles Paths
- var allDepMetadataDepSets []*DepSet[Path]
+ var allDepMetadataDepSets []depset.DepSet[Path]
- ctx.VisitDirectDepsBlueprint(func(bpdep blueprint.Module) {
- dep, _ := bpdep.(Module)
- if dep == nil {
- return
- }
- if !dep.Enabled(ctx) {
+ ctx.VisitDirectDepsProxy(func(dep ModuleProxy) {
+ if !OtherModuleProviderOrDefault(ctx, dep, CommonModuleInfoKey).Enabled {
return
}
@@ -84,7 +81,7 @@
if info, ok := OtherModuleProvider(ctx, dep, LicenseMetadataProvider); ok {
allDepMetadataFiles = append(allDepMetadataFiles, info.LicenseMetadataPath)
- if isContainer || isInstallDepNeeded(dep, ctx.OtherModuleDependencyTag(dep)) {
+ if isContainer || isInstallDepNeeded(ctx, dep) {
allDepMetadataDepSets = append(allDepMetadataDepSets, info.LicenseMetadataDepSet)
}
@@ -137,7 +134,7 @@
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_text.Strings()), "-n "))
if isContainer {
- transitiveDeps := Paths(NewDepSet[Path](TOPOLOGICAL, nil, allDepMetadataDepSets).ToList())
+ transitiveDeps := Paths(depset.New[Path](depset.TOPOLOGICAL, nil, allDepMetadataDepSets).ToList())
args = append(args,
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(transitiveDeps.Strings()), "-d "))
orderOnlyDeps = append(orderOnlyDeps, transitiveDeps...)
@@ -152,7 +149,7 @@
// Install map
args = append(args,
- JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.licenseInstallMap), "-m "))
+ JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(ctx.licenseInstallMap), "-m "))
// Built files
if len(outputFiles) > 0 {
@@ -180,7 +177,7 @@
SetProvider(ctx, LicenseMetadataProvider, &LicenseMetadataInfo{
LicenseMetadataPath: licenseMetadataFile,
- LicenseMetadataDepSet: NewDepSet(TOPOLOGICAL, Paths{licenseMetadataFile}, allDepMetadataDepSets),
+ LicenseMetadataDepSet: depset.New(depset.TOPOLOGICAL, Paths{licenseMetadataFile}, allDepMetadataDepSets),
})
}
@@ -208,7 +205,7 @@
// LicenseMetadataInfo stores the license metadata path for a module.
type LicenseMetadataInfo struct {
LicenseMetadataPath Path
- LicenseMetadataDepSet *DepSet[Path]
+ LicenseMetadataDepSet depset.DepSet[Path]
}
// licenseAnnotationsFromTag returns the LicenseAnnotations for a tag (if any) converted into
diff --git a/android/licenses.go b/android/licenses.go
index be1eede..32d12c8 100644
--- a/android/licenses.go
+++ b/android/licenses.go
@@ -15,7 +15,10 @@
package android
import (
+ "fmt"
+ "path/filepath"
"reflect"
+ "strings"
"sync"
"github.com/google/blueprint"
@@ -106,19 +109,19 @@
//
// This goes before defaults expansion so the defaults can pick up the package default.
func RegisterLicensesPackageMapper(ctx RegisterMutatorsContext) {
- ctx.BottomUp("licensesPackageMapper", licensesPackageMapper).Parallel()
+ ctx.BottomUp("licensesPackageMapper", licensesPackageMapper)
}
// Registers the function that gathers the license dependencies for each module.
//
// This goes after defaults expansion so that it can pick up default licenses and before visibility enforcement.
func RegisterLicensesPropertyGatherer(ctx RegisterMutatorsContext) {
- ctx.BottomUp("licensesPropertyGatherer", licensesPropertyGatherer).Parallel()
+ ctx.BottomUp("licensesPropertyGatherer", licensesPropertyGatherer)
}
// Registers the function that verifies the licenses and license_kinds dependency types for each module.
func RegisterLicensesDependencyChecker(ctx RegisterMutatorsContext) {
- ctx.BottomUp("licensesPropertyChecker", licensesDependencyChecker).Parallel()
+ ctx.BottomUp("licensesPropertyChecker", licensesDependencyChecker)
}
// Maps each package to its default applicable licenses.
@@ -155,7 +158,25 @@
}
licenses := getLicenses(ctx, m)
- ctx.AddVariationDependencies(nil, licensesTag, licenses...)
+
+ var fullyQualifiedLicenseNames []string
+ for _, license := range licenses {
+ fullyQualifiedLicenseName := license
+ if !strings.HasPrefix(license, "//") {
+ licenseModuleDir := ctx.OtherModuleDir(m)
+ for licenseModuleDir != "." && !ctx.OtherModuleExists(fmt.Sprintf("//%s:%s", licenseModuleDir, license)) {
+ licenseModuleDir = filepath.Dir(licenseModuleDir)
+ }
+ if licenseModuleDir == "." {
+ fullyQualifiedLicenseName = license
+ } else {
+ fullyQualifiedLicenseName = fmt.Sprintf("//%s:%s", licenseModuleDir, license)
+ }
+ }
+ fullyQualifiedLicenseNames = append(fullyQualifiedLicenseNames, fullyQualifiedLicenseName)
+ }
+
+ ctx.AddVariationDependencies(nil, licensesTag, fullyQualifiedLicenseNames...)
}
// Verifies the license and license_kind dependencies are each the correct kind of module.
@@ -206,16 +227,18 @@
}
var licenses []string
- for _, module := range ctx.GetDirectDepsWithTag(licensesTag) {
- if l, ok := module.(*licenseModule); ok {
+ var texts NamedPaths
+ var conditions []string
+ var kinds []string
+ for _, module := range ctx.GetDirectDepsProxyWithTag(licensesTag) {
+ if l, ok := OtherModuleProvider(ctx, module, LicenseInfoProvider); ok {
licenses = append(licenses, ctx.OtherModuleName(module))
- if m.base().commonProperties.Effective_package_name == nil && l.properties.Package_name != nil {
- m.base().commonProperties.Effective_package_name = l.properties.Package_name
+ if m.base().commonProperties.Effective_package_name == nil && l.PackageName != nil {
+ m.base().commonProperties.Effective_package_name = l.PackageName
}
- mergeStringProps(&m.base().commonProperties.Effective_licenses, module.base().commonProperties.Effective_licenses...)
- mergeNamedPathProps(&m.base().commonProperties.Effective_license_text, module.base().commonProperties.Effective_license_text...)
- mergeStringProps(&m.base().commonProperties.Effective_license_kinds, module.base().commonProperties.Effective_license_kinds...)
- mergeStringProps(&m.base().commonProperties.Effective_license_conditions, module.base().commonProperties.Effective_license_conditions...)
+ texts = append(texts, l.EffectiveLicenseText...)
+ kinds = append(kinds, l.EffectiveLicenseKinds...)
+ conditions = append(conditions, l.EffectiveLicenseConditions...)
} else {
propertyName := "licenses"
primaryProperty := m.base().primaryLicensesProperty
@@ -226,17 +249,15 @@
}
}
+ m.base().commonProperties.Effective_license_text = SortedUniqueNamedPaths(texts)
+ m.base().commonProperties.Effective_license_kinds = SortedUniqueStrings(kinds)
+ m.base().commonProperties.Effective_license_conditions = SortedUniqueStrings(conditions)
+
// Make the license information available for other modules.
- licenseInfo := LicenseInfo{
+ licenseInfo := LicensesInfo{
Licenses: licenses,
}
- SetProvider(ctx, LicenseInfoProvider, licenseInfo)
-}
-
-// Update a property string array with a distinct union of its values and a list of new values.
-func mergeStringProps(prop *[]string, values ...string) {
- *prop = append(*prop, values...)
- *prop = SortedUniqueStrings(*prop)
+ SetProvider(ctx, LicensesInfoProvider, licenseInfo)
}
// Update a property NamedPath array with a distinct union of its values and a list of new values.
@@ -253,12 +274,6 @@
*prop = SortedUniqueNamedPaths(*prop)
}
-// Update a property NamedPath array with a distinct union of its values and a list of new values.
-func mergeNamedPathProps(prop *NamedPaths, values ...NamedPath) {
- *prop = append(*prop, values...)
- *prop = SortedUniqueNamedPaths(*prop)
-}
-
// Get the licenses property falling back to the package default.
func getLicenses(ctx BaseModuleContext, module Module) []string {
if exemptFromRequiredApplicableLicensesProperty(module) {
@@ -315,14 +330,14 @@
return true
}
-// LicenseInfo contains information about licenses for a specific module.
-type LicenseInfo struct {
+// LicensesInfo contains information about licenses for a specific module.
+type LicensesInfo struct {
// The list of license modules this depends upon, either explicitly or through default package
// configuration.
Licenses []string
}
-var LicenseInfoProvider = blueprint.NewProvider[LicenseInfo]()
+var LicensesInfoProvider = blueprint.NewProvider[LicensesInfo]()
func init() {
RegisterMakeVarsProvider(pctx, licensesMakeVarsProvider)
diff --git a/android/licenses_test.go b/android/licenses_test.go
index 8a81e12..0c371e8 100644
--- a/android/licenses_test.go
+++ b/android/licenses_test.go
@@ -7,15 +7,13 @@
)
var licensesTests = []struct {
- name string
- fs MockFS
- expectedErrors []string
- effectiveLicenses map[string][]string
- effectiveInheritedLicenses map[string][]string
- effectivePackage map[string]string
- effectiveNotices map[string][]string
- effectiveKinds map[string][]string
- effectiveConditions map[string][]string
+ name string
+ fs MockFS
+ expectedErrors []string
+ effectivePackage map[string]string
+ effectiveNotices map[string][]string
+ effectiveKinds map[string][]string
+ effectiveConditions map[string][]string
}{
{
name: "invalid module type without licenses property",
@@ -69,11 +67,6 @@
licenses: ["top_Apache2"],
}`),
},
- effectiveLicenses: map[string][]string{
- "libexample1": []string{"top_Apache2"},
- "libnested": []string{"top_Apache2"},
- "libother": []string{"top_Apache2"},
- },
effectiveKinds: map[string][]string{
"libexample1": []string{"notice"},
"libnested": []string{"notice"},
@@ -146,18 +139,6 @@
deps: ["libexample"],
}`),
},
- effectiveLicenses: map[string][]string{
- "libexample": []string{"nested_other", "top_other"},
- "libsamepackage": []string{},
- "libnested": []string{},
- "libother": []string{},
- },
- effectiveInheritedLicenses: map[string][]string{
- "libexample": []string{"nested_other", "top_other"},
- "libsamepackage": []string{"nested_other", "top_other"},
- "libnested": []string{"nested_other", "top_other"},
- "libother": []string{"nested_other", "top_other"},
- },
effectiveKinds: map[string][]string{
"libexample": []string{"nested_notice", "top_notice"},
"libsamepackage": []string{},
@@ -217,20 +198,6 @@
deps: ["libexample"],
}`),
},
- effectiveLicenses: map[string][]string{
- "libexample": []string{"other", "top_nested"},
- "libsamepackage": []string{},
- "libnested": []string{},
- "libother": []string{},
- "liboutsider": []string{},
- },
- effectiveInheritedLicenses: map[string][]string{
- "libexample": []string{"other", "top_nested"},
- "libsamepackage": []string{"other", "top_nested"},
- "libnested": []string{"other", "top_nested"},
- "libother": []string{"other", "top_nested"},
- "liboutsider": []string{"other", "top_nested"},
- },
effectiveKinds: map[string][]string{
"libexample": []string{},
"libsamepackage": []string{},
@@ -284,14 +251,6 @@
defaults: ["top_defaults"],
}`),
},
- effectiveLicenses: map[string][]string{
- "libexample": []string{"by_exception_only"},
- "libdefaults": []string{"notice"},
- },
- effectiveInheritedLicenses: map[string][]string{
- "libexample": []string{"by_exception_only"},
- "libdefaults": []string{"notice"},
- },
},
// Package default_applicable_licenses tests
@@ -326,14 +285,6 @@
deps: ["libexample"],
}`),
},
- effectiveLicenses: map[string][]string{
- "libexample": []string{"top_notice"},
- "liboutsider": []string{},
- },
- effectiveInheritedLicenses: map[string][]string{
- "libexample": []string{"top_notice"},
- "liboutsider": []string{"top_notice"},
- },
},
{
name: "package default_applicable_licenses not inherited to subpackages",
@@ -369,18 +320,6 @@
deps: ["libexample", "libother", "libnested"],
}`),
},
- effectiveLicenses: map[string][]string{
- "libexample": []string{"top_notice"},
- "libnested": []string{"outsider"},
- "libother": []string{},
- "liboutsider": []string{},
- },
- effectiveInheritedLicenses: map[string][]string{
- "libexample": []string{"top_notice"},
- "libnested": []string{"outsider"},
- "libother": []string{},
- "liboutsider": []string{"top_notice", "outsider"},
- },
},
{
name: "verify that prebuilt dependencies are included",
@@ -409,12 +348,6 @@
deps: [":module"],
}`),
},
- effectiveLicenses: map[string][]string{
- "other": []string{},
- },
- effectiveInheritedLicenses: map[string][]string{
- "other": []string{"prebuilt", "top_sources"},
- },
},
{
name: "verify that prebuilt dependencies are ignored for licenses reasons (preferred)",
@@ -444,13 +377,6 @@
deps: [":module"],
}`),
},
- effectiveLicenses: map[string][]string{
- "other": []string{},
- },
- effectiveInheritedLicenses: map[string][]string{
- "module": []string{"prebuilt", "top_sources"},
- "other": []string{"prebuilt", "top_sources"},
- },
},
}
@@ -470,10 +396,6 @@
ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)).
RunTest(t)
- if test.effectiveLicenses != nil {
- checkEffectiveLicenses(t, result, test.effectiveLicenses)
- }
-
if test.effectivePackage != nil {
checkEffectivePackage(t, result, test.effectivePackage)
}
@@ -489,114 +411,10 @@
if test.effectiveConditions != nil {
checkEffectiveConditions(t, result, test.effectiveConditions)
}
-
- if test.effectiveInheritedLicenses != nil {
- checkEffectiveInheritedLicenses(t, result, test.effectiveInheritedLicenses)
- }
})
}
}
-func checkEffectiveLicenses(t *testing.T, result *TestResult, effectiveLicenses map[string][]string) {
- actualLicenses := make(map[string][]string)
- result.Context.Context.VisitAllModules(func(m blueprint.Module) {
- if _, ok := m.(*licenseModule); ok {
- return
- }
- if _, ok := m.(*licenseKindModule); ok {
- return
- }
- if _, ok := m.(*packageModule); ok {
- return
- }
- module, ok := m.(Module)
- if !ok {
- t.Errorf("%q not a module", m.Name())
- return
- }
- base := module.base()
- if base == nil {
- return
- }
- actualLicenses[m.Name()] = base.commonProperties.Effective_licenses
- })
-
- for moduleName, expectedLicenses := range effectiveLicenses {
- licenses, ok := actualLicenses[moduleName]
- if !ok {
- licenses = []string{}
- }
- if !compareUnorderedStringArrays(expectedLicenses, licenses) {
- t.Errorf("effective licenses mismatch for module %q: expected %q, found %q", moduleName, expectedLicenses, licenses)
- }
- }
-}
-
-func checkEffectiveInheritedLicenses(t *testing.T, result *TestResult, effectiveInheritedLicenses map[string][]string) {
- actualLicenses := make(map[string][]string)
- result.Context.Context.VisitAllModules(func(m blueprint.Module) {
- if _, ok := m.(*licenseModule); ok {
- return
- }
- if _, ok := m.(*licenseKindModule); ok {
- return
- }
- if _, ok := m.(*packageModule); ok {
- return
- }
- module, ok := m.(Module)
- if !ok {
- t.Errorf("%q not a module", m.Name())
- return
- }
- base := module.base()
- if base == nil {
- return
- }
- inherited := make(map[string]bool)
- for _, l := range base.commonProperties.Effective_licenses {
- inherited[l] = true
- }
- result.Context.Context.VisitDepsDepthFirst(m, func(c blueprint.Module) {
- if _, ok := c.(*licenseModule); ok {
- return
- }
- if _, ok := c.(*licenseKindModule); ok {
- return
- }
- if _, ok := c.(*packageModule); ok {
- return
- }
- cmodule, ok := c.(Module)
- if !ok {
- t.Errorf("%q not a module", c.Name())
- return
- }
- cbase := cmodule.base()
- if cbase == nil {
- return
- }
- for _, l := range cbase.commonProperties.Effective_licenses {
- inherited[l] = true
- }
- })
- actualLicenses[m.Name()] = []string{}
- for l := range inherited {
- actualLicenses[m.Name()] = append(actualLicenses[m.Name()], l)
- }
- })
-
- for moduleName, expectedInheritedLicenses := range effectiveInheritedLicenses {
- licenses, ok := actualLicenses[moduleName]
- if !ok {
- licenses = []string{}
- }
- if !compareUnorderedStringArrays(expectedInheritedLicenses, licenses) {
- t.Errorf("effective inherited licenses mismatch for module %q: expected %q, found %q", moduleName, expectedInheritedLicenses, licenses)
- }
- }
-}
-
func checkEffectivePackage(t *testing.T, result *TestResult, effectivePackage map[string]string) {
actualPackage := make(map[string]string)
result.Context.Context.VisitAllModules(func(m blueprint.Module) {
diff --git a/android/logtags.go b/android/logtags.go
index 7929057..abc37f9 100644
--- a/android/logtags.go
+++ b/android/logtags.go
@@ -14,7 +14,11 @@
package android
-import "github.com/google/blueprint"
+import (
+ "strings"
+
+ "github.com/google/blueprint"
+)
func init() {
RegisterParallelSingletonType("logtags", LogtagsSingleton)
@@ -46,11 +50,20 @@
allLogtags = append(allLogtags, logtagsInfo.Logtags...)
}
})
+ allLogtags = SortedUniquePaths(allLogtags)
+ filteredLogTags := make([]Path, 0, len(allLogtags))
+ for _, p := range allLogtags {
+ // Logic copied from make:
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=987;drc=0585bb1bcf4c89065adaf709f48acc8b869fd3ce
+ if !strings.HasPrefix(p.String(), "vendor/") && !strings.HasPrefix(p.String(), "device/") && !strings.HasPrefix(p.String(), "out/") {
+ filteredLogTags = append(filteredLogTags, p)
+ }
+ }
builder := NewRuleBuilder(pctx, ctx)
builder.Command().
BuiltTool("merge-event-log-tags").
FlagWithOutput("-o ", MergedLogtagsPath(ctx)).
- Inputs(SortedUniquePaths(allLogtags))
+ Inputs(filteredLogTags)
builder.Build("all-event-log-tags.txt", "merge logtags")
}
diff --git a/android/makevars.go b/android/makevars.go
index 810eb38..8305d8e 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -281,8 +281,8 @@
if m.ExportedToMake() {
info := OtherModuleProviderOrDefault(ctx, m, InstallFilesProvider)
katiInstalls = append(katiInstalls, info.KatiInstalls...)
- katiInitRcInstalls = append(katiInitRcInstalls, m.base().katiInitRcInstalls...)
- katiVintfManifestInstalls = append(katiVintfManifestInstalls, m.base().katiVintfInstalls...)
+ katiInitRcInstalls = append(katiInitRcInstalls, info.KatiInitRcInstalls...)
+ katiVintfManifestInstalls = append(katiVintfManifestInstalls, info.KatiVintfInstalls...)
katiSymlinks = append(katiSymlinks, info.KatiSymlinks...)
}
})
diff --git a/android/module.go b/android/module.go
index e74af83..39a1654 100644
--- a/android/module.go
+++ b/android/module.go
@@ -24,6 +24,8 @@
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/depset"
+ "github.com/google/blueprint/gobtools"
"github.com/google/blueprint/proptools"
)
@@ -55,7 +57,7 @@
base() *ModuleBase
Disable()
- Enabled(ctx ConfigAndErrorContext) bool
+ Enabled(ctx ConfigurableEvaluatorContext) bool
Target() Target
MultiTargets() []Target
@@ -78,18 +80,20 @@
InstallInOdm() bool
InstallInProduct() bool
InstallInVendor() bool
+ InstallInSystemExt() bool
+ InstallInSystemDlkm() bool
+ InstallInVendorDlkm() bool
+ InstallInOdmDlkm() bool
InstallForceOS() (*OsType, *ArchType)
PartitionTag(DeviceConfig) string
HideFromMake()
IsHideFromMake() bool
+ SkipInstall()
IsSkipInstall() bool
MakeUninstallable()
ReplacedByPrebuilt()
IsReplacedByPrebuilt() bool
ExportedToMake() bool
- InitRc() Paths
- VintfFragments() Paths
- EffectiveLicenseKinds() []string
EffectiveLicenseFiles() Paths
AddProperties(props ...interface{})
@@ -108,19 +112,21 @@
// Get information about the properties that can contain visibility rules.
visibilityProperties() []visibilityProperty
- RequiredModuleNames(ctx ConfigAndErrorContext) []string
+ RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string
HostRequiredModuleNames() []string
TargetRequiredModuleNames() []string
- VintfFragmentModuleNames(ctx ConfigAndErrorContext) []string
+ VintfFragmentModuleNames(ctx ConfigurableEvaluatorContext) []string
+ VintfFragments(ctx ConfigurableEvaluatorContext) []string
- // TransitivePackagingSpecs returns the PackagingSpecs for this module and any transitive
- // dependencies with dependency tags for which IsInstallDepNeeded() returns true.
- TransitivePackagingSpecs() []PackagingSpec
+ ConfigurableEvaluator(ctx ConfigurableEvaluatorContext) proptools.ConfigurableEvaluator
- ConfigurableEvaluator(ctx ConfigAndErrorContext) proptools.ConfigurableEvaluator
+ // The usage of this method is experimental and should not be used outside of fsgen package.
+ // This will be removed once product packaging migration to Soong is complete.
+ DecodeMultilib(ctx ConfigContext) (string, string)
- // Get the information about the containers this module belongs to.
- ContainersInfo() ContainersInfo
+ // WARNING: This should not be used outside build/soong/fsgen
+ // Overrides returns the list of modules which should not be installed if this module is installed.
+ Overrides() []string
}
// Qualified id for a module
@@ -250,6 +256,8 @@
Name *string
}
+// Properties common to all modules inheriting from ModuleBase. These properties are automatically
+// inherited by sub-modules created with ctx.CreateModule()
type commonProperties struct {
// emit build rules for this module
//
@@ -308,8 +316,6 @@
// Describes the licenses applicable to this module. Must reference license modules.
Licenses []string
- // Flattened from direct license dependencies. Equal to Licenses unless particular module adds more.
- Effective_licenses []string `blueprint:"mutated"`
// Override of module name when reporting licenses
Effective_package_name *string `blueprint:"mutated"`
// Notice files
@@ -331,6 +337,7 @@
}
Android struct {
Compile_multilib *string
+ Enabled *bool
}
}
@@ -383,24 +390,24 @@
// Whether this module is installed to debug ramdisk
Debug_ramdisk *bool
+ // Install to partition system_dlkm when set to true.
+ System_dlkm_specific *bool
+
+ // Install to partition vendor_dlkm when set to true.
+ Vendor_dlkm_specific *bool
+
+ // Install to partition odm_dlkm when set to true.
+ Odm_dlkm_specific *bool
+
// Whether this module is built for non-native architectures (also known as native bridge binary)
Native_bridge_supported *bool `android:"arch_variant"`
// init.rc files to be installed if this module is installed
- Init_rc []string `android:"arch_variant,path"`
+ Init_rc proptools.Configurable[[]string] `android:"arch_variant,path"`
// VINTF manifest fragments to be installed if this module is installed
Vintf_fragments proptools.Configurable[[]string] `android:"path"`
- // names of other modules to install if this module is installed
- Required proptools.Configurable[[]string] `android:"arch_variant"`
-
- // names of other modules to install on host if this module is installed
- Host_required []string `android:"arch_variant"`
-
- // names of other modules to install on target if this module is installed
- Target_required []string `android:"arch_variant"`
-
// The OsType of artifacts that this module variant is responsible for creating.
//
// Set by osMutator
@@ -449,12 +456,6 @@
// Set at module initialization time by calling InitCommonOSAndroidMultiTargetsArchModule
CreateCommonOSVariant bool `blueprint:"mutated"`
- // If set to true then this variant is the CommonOS variant that has dependencies on its
- // OsType specific variants.
- //
- // Set by osMutator.
- CommonOSVariant bool `blueprint:"mutated"`
-
// When set to true, this module is not installed to the full install path (ex: under
// out/target/product/<name>/<partition>). It can be installed only to the packaging
// modules like android_filesystem.
@@ -501,6 +502,23 @@
// vintf_fragment Modules required from this module.
Vintf_fragment_modules proptools.Configurable[[]string] `android:"path"`
+
+ // List of module names that are prevented from being installed when this module gets
+ // installed.
+ Overrides []string
+}
+
+// Properties common to all modules inheriting from ModuleBase. Unlike commonProperties, these
+// properties are NOT automatically inherited by sub-modules created with ctx.CreateModule()
+type baseProperties struct {
+ // names of other modules to install if this module is installed
+ Required proptools.Configurable[[]string] `android:"arch_variant"`
+
+ // names of other modules to install on host if this module is installed
+ Host_required []string `android:"arch_variant"`
+
+ // names of other modules to install on target if this module is installed
+ Target_required []string `android:"arch_variant"`
}
type distProperties struct {
@@ -549,6 +567,13 @@
}
}
+func (t *CommonTestOptions) SetAndroidMkInfoEntries(entries *AndroidMkInfo) {
+ entries.SetBoolIfTrue("LOCAL_IS_UNIT_TEST", Bool(t.Unit_test))
+ if len(t.Tags) > 0 {
+ entries.AddStrings("LOCAL_TEST_OPTIONS_TAGS", t.Tags...)
+ }
+}
+
// The key to use in TaggedDistFiles when a Dist structure does not specify a
// tag property. This intentionally does not use "" as the default because that
// would mean that an empty tag would have a different meaning when used in a dist
@@ -615,10 +640,9 @@
type Multilib string
const (
- MultilibBoth Multilib = "both"
- MultilibFirst Multilib = "first"
- MultilibCommon Multilib = "common"
- MultilibCommonFirst Multilib = "common_first"
+ MultilibBoth Multilib = "both"
+ MultilibFirst Multilib = "first"
+ MultilibCommon Multilib = "common"
)
type HostOrDeviceSupported int
@@ -695,6 +719,7 @@
m.AddProperties(
&base.nameProperties,
&base.commonProperties,
+ &base.baseProperties,
&base.distProperties)
initProductVariableModule(m)
@@ -813,6 +838,7 @@
nameProperties nameProperties
commonProperties commonProperties
+ baseProperties baseProperties
distProperties distProperties
variableProperties interface{}
hostAndDeviceProperties hostAndDeviceProperties
@@ -835,16 +861,7 @@
// The primary licenses property, may be nil, records license metadata for the module.
primaryLicensesProperty applicableLicensesProperty
- noAddressSanitizer bool
- installFilesDepSet *DepSet[InstallPath]
- packagingSpecsDepSet *DepSet[PackagingSpec]
- // katiInitRcInstalls and katiVintfInstalls track the install rules created by Soong that are
- // allowed to have duplicates across modules and variants.
- katiInitRcInstalls katiInstalls
- katiVintfInstalls katiInstalls
-
- // The files to copy to the dist as explicitly specified in the .bp file.
- distFiles TaggedDistFiles
+ noAddressSanitizer bool
hooks hooks
@@ -854,34 +871,6 @@
buildParams []BuildParams
ruleParams map[blueprint.Rule]blueprint.RuleParams
variables map[string]string
-
- initRcPaths Paths
- vintfFragmentsPaths Paths
-
- installedInitRcPaths InstallPaths
- installedVintfFragmentsPaths InstallPaths
-
- // Merged Aconfig files for all transitive deps.
- aconfigFilePaths Paths
-
- // set of dependency module:location mappings used to populate the license metadata for
- // apex containers.
- licenseInstallMap []string
-
- // The path to the generated license metadata file for the module.
- licenseMetadataFile WritablePath
-
- // moduleInfoJSON can be filled out by GenerateAndroidBuildActions to write a JSON file that will
- // be included in the final module-info.json produced by Make.
- moduleInfoJSON *ModuleInfoJSON
-
- // complianceMetadataInfo is for different module types to dump metadata.
- // See android.ModuleContext interface.
- complianceMetadataInfo *ComplianceMetadataInfo
-
- // containersInfo stores the information about the containers and the information of the
- // apexes the module belongs to.
- containersInfo ContainersInfo
}
func (m *ModuleBase) AddJSONData(d *map[string]interface{}) {
@@ -1006,8 +995,9 @@
// 2. `boot_signer` is `required` by modules like `build_image` which is explicitly list as
// the top-level build goal (in the shell file that invokes Soong).
// 3. `boot_signer` depends on `bouncycastle-unbundled` which is in the missing git project.
- // 4. aosp_kernel-build-tools invokes soong with `--skip-make`. Therefore, the absence of
- // ALLOW_MISSING_DEPENDENCIES didn't cause a problem.
+ // 4. aosp_kernel-build-tools invokes soong with `--soong-only`. Therefore, the absence of
+ // ALLOW_MISSING_DEPENDENCIES didn't cause a problem, as previously only make processed required
+ // dependencies.
// 5. Now, since Soong understands `required` deps, it tries to build `boot_signer` and the
// absence of external/bouncycastle fails the build.
//
@@ -1065,7 +1055,7 @@
hostTargets = append(hostTargets, ctx.Config().BuildOSCommonTarget)
if ctx.Device() {
- for _, depName := range ctx.Module().RequiredModuleNames(ctx) {
+ for _, depName := range append(ctx.Module().RequiredModuleNames(ctx), ctx.Module().VintfFragmentModuleNames(ctx)...) {
for _, target := range deviceTargets {
addDep(target, depName)
}
@@ -1078,7 +1068,7 @@
}
if ctx.Host() {
- for _, depName := range ctx.Module().RequiredModuleNames(ctx) {
+ for _, depName := range append(ctx.Module().RequiredModuleNames(ctx), ctx.Module().VintfFragmentModuleNames(ctx)...) {
for _, target := range hostTargets {
// When a host module requires another host module, don't make a
// dependency if they have different OSes (i.e. hostcross).
@@ -1102,8 +1092,34 @@
}{}
func addVintfFragmentDeps(ctx BottomUpMutatorContext) {
+ // Vintf manifests in the recovery partition will be ignored.
+ if !ctx.Device() || ctx.Module().InstallInRecovery() {
+ return
+ }
+
+ deviceConfig := ctx.DeviceConfig()
+
mod := ctx.Module()
- ctx.AddDependency(mod, vintfDepTag, mod.VintfFragmentModuleNames(ctx)...)
+ vintfModules := ctx.AddDependency(mod, vintfDepTag, mod.VintfFragmentModuleNames(ctx)...)
+
+ modPartition := mod.PartitionTag(deviceConfig)
+ for _, vintf := range vintfModules {
+ if vintf == nil {
+ // TODO(b/372091092): Remove this. Having it gives us missing dependency errors instead
+ // of nil pointer dereference errors, but we should resolve the missing dependencies.
+ continue
+ }
+ if vintfModule, ok := vintf.(*vintfFragmentModule); ok {
+ vintfPartition := vintfModule.PartitionTag(deviceConfig)
+ if modPartition != vintfPartition {
+ ctx.ModuleErrorf("Module %q(%q) and Vintf_fragment %q(%q) are installed to different partitions.",
+ mod.Name(), modPartition,
+ vintfModule.Name(), vintfPartition)
+ }
+ } else {
+ ctx.ModuleErrorf("Only vintf_fragment type module should be listed in vintf_fragment_modules : %q", vintf.Name())
+ }
+ }
}
// AddProperties "registers" the provided props
@@ -1260,7 +1276,7 @@
// True if the current variant is a CommonOS variant, false otherwise.
func (m *ModuleBase) IsCommonOSVariant() bool {
- return m.commonProperties.CommonOSVariant
+ return m.commonProperties.CompileOS == CommonOS
}
// supportsTarget returns true if the given Target is supported by the current module.
@@ -1374,17 +1390,31 @@
if config.SystemExtPath() == "system_ext" {
partition = "system_ext"
}
+ } else if m.InstallInRamdisk() {
+ partition = "ramdisk"
+ } else if m.InstallInVendorRamdisk() {
+ partition = "vendor_ramdisk"
+ } else if m.InstallInRecovery() {
+ partition = "recovery"
}
return partition
}
-func (m *ModuleBase) Enabled(ctx ConfigAndErrorContext) bool {
+func (m *ModuleBase) Enabled(ctx ConfigurableEvaluatorContext) bool {
if m.commonProperties.ForcedDisabled {
return false
}
return m.commonProperties.Enabled.GetOrDefault(m.ConfigurableEvaluator(ctx), !m.Os().DefaultDisabled)
}
+// Returns a copy of the enabled property, useful for passing it on to sub-modules
+func (m *ModuleBase) EnabledProperty() proptools.Configurable[bool] {
+ if m.commonProperties.ForcedDisabled {
+ return proptools.NewSimpleConfigurable(false)
+ }
+ return m.commonProperties.Enabled.Clone()
+}
+
func (m *ModuleBase) Disable() {
m.commonProperties.ForcedDisabled = true
}
@@ -1418,6 +1448,7 @@
func (m *ModuleBase) MakeUninstallable() {
m.commonProperties.UninstallableApexPlatformVariant = true
m.HideFromMake()
+ m.SkipInstall()
}
func (m *ModuleBase) ReplacedByPrebuilt() {
@@ -1433,10 +1464,6 @@
return m.commonProperties.NamespaceExportedToMake
}
-func (m *ModuleBase) EffectiveLicenseKinds() []string {
- return m.commonProperties.Effective_license_kinds
-}
-
func (m *ModuleBase) EffectiveLicenseFiles() Paths {
result := make(Paths, 0, len(m.commonProperties.Effective_license_text))
for _, p := range m.commonProperties.Effective_license_text {
@@ -1447,19 +1474,21 @@
// computeInstallDeps finds the installed paths of all dependencies that have a dependency
// tag that is annotated as needing installation via the isInstallDepNeeded method.
-func (m *ModuleBase) computeInstallDeps(ctx ModuleContext) ([]*DepSet[InstallPath], []*DepSet[PackagingSpec]) {
- var installDeps []*DepSet[InstallPath]
- var packagingSpecs []*DepSet[PackagingSpec]
- ctx.VisitDirectDeps(func(dep Module) {
- if isInstallDepNeeded(dep, ctx.OtherModuleDependencyTag(dep)) {
+func (m *ModuleBase) computeInstallDeps(ctx ModuleContext) ([]depset.DepSet[InstallPath], []depset.DepSet[PackagingSpec]) {
+ var installDeps []depset.DepSet[InstallPath]
+ var packagingSpecs []depset.DepSet[PackagingSpec]
+ ctx.VisitDirectDepsProxy(func(dep ModuleProxy) {
+ if isInstallDepNeeded(ctx, dep) {
// Installation is still handled by Make, so anything hidden from Make is not
// installable.
- if !dep.IsHideFromMake() && !dep.IsSkipInstall() {
- installDeps = append(installDeps, dep.base().installFilesDepSet)
+ info := OtherModuleProviderOrDefault(ctx, dep, InstallFilesProvider)
+ commonInfo := OtherModuleProviderOrDefault(ctx, dep, CommonModuleInfoKey)
+ if !commonInfo.HideFromMake && !commonInfo.SkipInstall {
+ installDeps = append(installDeps, info.TransitiveInstallFiles)
}
// Add packaging deps even when the dependency is not installed so that uninstallable
// modules can still be packaged. Often the package will be installed instead.
- packagingSpecs = append(packagingSpecs, dep.base().packagingSpecsDepSet)
+ packagingSpecs = append(packagingSpecs, info.TransitivePackagingSpecs)
}
})
@@ -1468,17 +1497,13 @@
// isInstallDepNeeded returns true if installing the output files of the current module
// should also install the output files of the given dependency and dependency tag.
-func isInstallDepNeeded(dep Module, tag blueprint.DependencyTag) bool {
+func isInstallDepNeeded(ctx ModuleContext, dep ModuleProxy) bool {
// Don't add a dependency from the platform to a library provided by an apex.
- if dep.base().commonProperties.UninstallableApexPlatformVariant {
+ if OtherModuleProviderOrDefault(ctx, dep, CommonModuleInfoKey).UninstallableApexPlatformVariant {
return false
}
// Only install modules if the dependency tag is an InstallDepNeeded tag.
- return IsInstallDepNeededTag(tag)
-}
-
-func (m *ModuleBase) TransitivePackagingSpecs() []PackagingSpec {
- return m.packagingSpecsDepSet.ToList()
+ return IsInstallDepNeededTag(ctx.OtherModuleDependencyTag(dep))
}
func (m *ModuleBase) NoAddressSanitizer() bool {
@@ -1525,10 +1550,26 @@
return Bool(m.commonProperties.Vendor) || Bool(m.commonProperties.Soc_specific) || Bool(m.commonProperties.Proprietary)
}
+func (m *ModuleBase) InstallInSystemExt() bool {
+ return Bool(m.commonProperties.System_ext_specific)
+}
+
func (m *ModuleBase) InstallInRoot() bool {
return false
}
+func (m *ModuleBase) InstallInSystemDlkm() bool {
+ return Bool(m.commonProperties.System_dlkm_specific)
+}
+
+func (m *ModuleBase) InstallInVendorDlkm() bool {
+ return Bool(m.commonProperties.Vendor_dlkm_specific)
+}
+
+func (m *ModuleBase) InstallInOdmDlkm() bool {
+ return Bool(m.commonProperties.Odm_dlkm_specific)
+}
+
func (m *ModuleBase) InstallForceOS() (*OsType, *ArchType) {
return nil, nil
}
@@ -1578,71 +1619,79 @@
return m.base().commonProperties.ImageVariation == RecoveryVariation
}
-func (m *ModuleBase) RequiredModuleNames(ctx ConfigAndErrorContext) []string {
- return m.base().commonProperties.Required.GetOrDefault(m.ConfigurableEvaluator(ctx), nil)
+func (m *ModuleBase) RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string {
+ return m.base().baseProperties.Required.GetOrDefault(m.ConfigurableEvaluator(ctx), nil)
}
func (m *ModuleBase) HostRequiredModuleNames() []string {
- return m.base().commonProperties.Host_required
+ return m.base().baseProperties.Host_required
}
func (m *ModuleBase) TargetRequiredModuleNames() []string {
- return m.base().commonProperties.Target_required
+ return m.base().baseProperties.Target_required
}
-func (m *ModuleBase) VintfFragmentModuleNames(ctx ConfigAndErrorContext) []string {
+func (m *ModuleBase) VintfFragmentModuleNames(ctx ConfigurableEvaluatorContext) []string {
return m.base().commonProperties.Vintf_fragment_modules.GetOrDefault(m.ConfigurableEvaluator(ctx), nil)
}
-func (m *ModuleBase) InitRc() Paths {
- return append(Paths{}, m.initRcPaths...)
+func (m *ModuleBase) VintfFragments(ctx ConfigurableEvaluatorContext) []string {
+ return m.base().commonProperties.Vintf_fragments.GetOrDefault(m.ConfigurableEvaluator(ctx), nil)
}
-func (m *ModuleBase) VintfFragments() Paths {
- return append(Paths{}, m.vintfFragmentsPaths...)
-}
+func (m *ModuleBase) generateVariantTarget(ctx *moduleContext) {
+ namespacePrefix := ctx.Namespace().id
+ if namespacePrefix != "" {
+ namespacePrefix = namespacePrefix + "-"
+ }
-func (m *ModuleBase) CompileMultilib() *string {
- return m.base().commonProperties.Compile_multilib
-}
+ if !ctx.uncheckedModule {
+ name := namespacePrefix + ctx.ModuleName() + "-" + ctx.ModuleSubDir() + "-checkbuild"
+ ctx.Phony(name, ctx.checkbuildFiles...)
+ ctx.checkbuildTarget = PathForPhony(ctx, name)
+ }
-// SetLicenseInstallMap stores the set of dependency module:location mappings for files in an
-// apex container for use when generation the license metadata file.
-func (m *ModuleBase) SetLicenseInstallMap(installMap []string) {
- m.licenseInstallMap = append(m.licenseInstallMap, installMap...)
}
func (m *ModuleBase) generateModuleTarget(ctx *moduleContext) {
var allInstalledFiles InstallPaths
- var allCheckbuildFiles Paths
- ctx.VisitAllModuleVariants(func(module Module) {
- a := module.base()
- var checkBuilds Paths
- if a == m {
+ var allCheckbuildTargets Paths
+ var alloutputFiles Paths
+ ctx.VisitAllModuleVariantProxies(func(module ModuleProxy) {
+ var checkbuildTarget Path
+ var uncheckedModule bool
+ var skipAndroidMkProcessing bool
+ if ctx.EqualModules(m.module, module) {
allInstalledFiles = append(allInstalledFiles, ctx.installFiles...)
- checkBuilds = ctx.checkbuildFiles
+ checkbuildTarget = ctx.checkbuildTarget
+ uncheckedModule = ctx.uncheckedModule
+ skipAndroidMkProcessing = shouldSkipAndroidMkProcessing(ctx, m)
} else {
info := OtherModuleProviderOrDefault(ctx, module, InstallFilesProvider)
allInstalledFiles = append(allInstalledFiles, info.InstallFiles...)
- checkBuilds = info.CheckbuildFiles
+ checkbuildTarget = info.CheckbuildTarget
+ uncheckedModule = info.UncheckedModule
+ skipAndroidMkProcessing = OtherModuleProviderOrDefault(ctx, module, CommonModuleInfoKey).SkipAndroidMkProcessing
+ }
+ if outputFiles, err := outputFilesForModule(ctx, module, ""); err == nil {
+ alloutputFiles = append(alloutputFiles, outputFiles...)
}
// A module's -checkbuild phony targets should
// not be created if the module is not exported to make.
// Those could depend on the build target and fail to compile
// for the current build target.
- if !ctx.Config().KatiEnabled() || !shouldSkipAndroidMkProcessing(ctx, a) {
- allCheckbuildFiles = append(allCheckbuildFiles, checkBuilds...)
+ if (!ctx.Config().KatiEnabled() || !skipAndroidMkProcessing) && !uncheckedModule && checkbuildTarget != nil {
+ allCheckbuildTargets = append(allCheckbuildTargets, checkbuildTarget)
}
})
- var deps Paths
-
var namespacePrefix string
nameSpace := ctx.Namespace().Path
if nameSpace != "." {
namespacePrefix = strings.ReplaceAll(nameSpace, "/", ".") + "-"
}
+ var deps Paths
var info FinalModuleBuildTargetsInfo
if len(allInstalledFiles) > 0 {
@@ -1652,11 +1701,16 @@
deps = append(deps, info.InstallTarget)
}
- if len(allCheckbuildFiles) > 0 {
+ if len(allCheckbuildTargets) > 0 {
name := namespacePrefix + ctx.ModuleName() + "-checkbuild"
- ctx.Phony(name, allCheckbuildFiles...)
- info.CheckbuildTarget = PathForPhony(ctx, name)
- deps = append(deps, info.CheckbuildTarget)
+ ctx.Phony(name, allCheckbuildTargets...)
+ deps = append(deps, PathForPhony(ctx, name))
+ }
+
+ if len(alloutputFiles) > 0 {
+ name := namespacePrefix + ctx.ModuleName() + "-outputs"
+ ctx.Phony(name, alloutputFiles...)
+ deps = append(deps, PathForPhony(ctx, name))
}
if len(deps) > 0 {
@@ -1666,13 +1720,24 @@
}
ctx.Phony(namespacePrefix+ctx.ModuleName()+suffix, deps...)
+ if ctx.Device() {
+ // Generate a target suffix for use in atest etc.
+ ctx.Phony(namespacePrefix+ctx.ModuleName()+"-target"+suffix, deps...)
+ } else {
+ // Generate a host suffix for use in atest etc.
+ ctx.Phony(namespacePrefix+ctx.ModuleName()+"-host"+suffix, deps...)
+ if ctx.Target().HostCross {
+ // Generate a host-cross suffix for use in atest etc.
+ ctx.Phony(namespacePrefix+ctx.ModuleName()+"-host-cross"+suffix, deps...)
+ }
+ }
info.BlueprintDir = ctx.ModuleDir()
SetProvider(ctx, FinalModuleBuildTargetsProvider, info)
}
}
-func determineModuleKind(m *ModuleBase, ctx blueprint.EarlyModuleContext) moduleKind {
+func determineModuleKind(m *ModuleBase, ctx ModuleErrorContext) moduleKind {
var socSpecific = Bool(m.commonProperties.Vendor) || Bool(m.commonProperties.Proprietary) || Bool(m.commonProperties.Soc_specific)
var deviceSpecific = Bool(m.commonProperties.Device_specific)
var productSpecific = Bool(m.commonProperties.Product_specific)
@@ -1773,27 +1838,106 @@
}
type InstallFilesInfo struct {
- InstallFiles InstallPaths
- CheckbuildFiles Paths
- PackagingSpecs []PackagingSpec
+ InstallFiles InstallPaths
+ CheckbuildFiles Paths
+ CheckbuildTarget Path
+ UncheckedModule bool
+ PackagingSpecs []PackagingSpec
// katiInstalls tracks the install rules that were created by Soong but are being exported
// to Make to convert to ninja rules so that Make can add additional dependencies.
- KatiInstalls katiInstalls
- KatiSymlinks katiInstalls
- TestData []DataPath
+ KatiInstalls katiInstalls
+ KatiSymlinks katiInstalls
+ TestData []DataPath
+ TransitivePackagingSpecs depset.DepSet[PackagingSpec]
+ LicenseMetadataFile WritablePath
+
+ // The following fields are private before, make it private again once we have
+ // better solution.
+ TransitiveInstallFiles depset.DepSet[InstallPath]
+ // 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
+
+ // The files to copy to the dist as explicitly specified in the .bp file.
+ DistFiles TaggedDistFiles
}
-var FinalModuleBuildTargetsProvider = blueprint.NewProvider[FinalModuleBuildTargetsInfo]()
+var InstallFilesProvider = blueprint.NewProvider[InstallFilesInfo]()
+type SourceFilesInfo struct {
+ Srcs Paths
+}
+
+var SourceFilesInfoProvider = blueprint.NewProvider[SourceFilesInfo]()
+
+// FinalModuleBuildTargetsInfo is used by buildTargetSingleton to create checkbuild and
+// per-directory build targets. Only set on the final variant of each module
type FinalModuleBuildTargetsInfo struct {
- // Used by buildTargetSingleton to create checkbuild and per-directory build targets
- // Only set on the final variant of each module
InstallTarget WritablePath
CheckbuildTarget WritablePath
BlueprintDir string
}
-var InstallFilesProvider = blueprint.NewProvider[InstallFilesInfo]()
+var FinalModuleBuildTargetsProvider = blueprint.NewProvider[FinalModuleBuildTargetsInfo]()
+
+type CommonModuleInfo struct {
+ Enabled bool
+ // Whether the module has been replaced by a prebuilt
+ ReplacedByPrebuilt bool
+ // The Target of artifacts that this module variant is responsible for creating.
+ Target Target
+ SkipAndroidMkProcessing bool
+ BaseModuleName string
+ CanHaveApexVariants bool
+ MinSdkVersion string
+ SdkVersion string
+ NotAvailableForPlatform bool
+ // There some subtle differences between this one and the one above.
+ NotInPlatform bool
+ // UninstallableApexPlatformVariant is set by MakeUninstallable called by the apex
+ // mutator. MakeUninstallable also sets HideFromMake. UninstallableApexPlatformVariant
+ // is used to avoid adding install or packaging dependencies into libraries provided
+ // by apexes.
+ UninstallableApexPlatformVariant bool
+ HideFromMake bool
+ SkipInstall bool
+ IsStubsModule bool
+ Host bool
+}
+
+var CommonModuleInfoKey = blueprint.NewProvider[CommonModuleInfo]()
+
+type PrebuiltModuleInfo struct {
+ SourceExists bool
+ UsePrebuilt bool
+}
+
+var PrebuiltModuleInfoProvider = blueprint.NewProvider[PrebuiltModuleInfo]()
+
+type HostToolProviderInfo struct {
+ HostToolPath OptionalPath
+}
+
+var HostToolProviderInfoProvider = blueprint.NewProvider[HostToolProviderInfo]()
+
+type SourceFileGenerator interface {
+ GeneratedSourceFiles() Paths
+ GeneratedHeaderDirs() Paths
+ GeneratedDeps() Paths
+}
+
+type GeneratedSourceInfo struct {
+ GeneratedSourceFiles Paths
+ GeneratedHeaderDirs Paths
+ GeneratedDeps Paths
+}
+
+var GeneratedSourceInfoProvider = blueprint.NewProvider[GeneratedSourceInfo]()
func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) {
ctx := &moduleContext{
@@ -1805,14 +1949,17 @@
}
setContainerInfo(ctx)
+ if ctx.Config().Getenv("DISABLE_CONTAINER_CHECK") != "true" {
+ checkContainerViolations(ctx)
+ }
- m.licenseMetadataFile = PathForModuleOut(ctx, "meta_lic")
+ ctx.licenseMetadataFile = PathForModuleOut(ctx, "meta_lic")
dependencyInstallFiles, dependencyPackagingSpecs := m.computeInstallDeps(ctx)
- // set m.installFilesDepSet to only the transitive dependencies to be used as the dependencies
+ // set the TransitiveInstallFiles to only the transitive dependencies to be used as the dependencies
// of installed files of this module. It will be replaced by a depset including the installed
// files of this module at the end for use by modules that depend on this one.
- m.installFilesDepSet = NewDepSet[InstallPath](TOPOLOGICAL, nil, dependencyInstallFiles)
+ ctx.TransitiveInstallFiles = depset.New[InstallPath](depset.TOPOLOGICAL, nil, dependencyInstallFiles)
// Temporarily continue to call blueprintCtx.GetMissingDependencies() to maintain the previous behavior of never
// reporting missing dependency errors in Blueprint when AllowMissingDependencies == true.
@@ -1856,13 +2003,11 @@
checkDistProperties(ctx, fmt.Sprintf("dists[%d]", i), &m.distProperties.Dists[i])
}
+ var installFiles InstallFilesInfo
+
if m.Enabled(ctx) {
// ensure all direct android.Module deps are enabled
- ctx.VisitDirectDepsBlueprint(func(bm blueprint.Module) {
- if m, ok := bm.(Module); ok {
- ctx.validateAndroidModule(bm, ctx.OtherModuleDependencyTag(m), ctx.baseModuleContext.strictVisitDeps, false)
- }
- })
+ ctx.VisitDirectDepsProxy(func(m ModuleProxy) {})
if m.Device() {
// Handle any init.rc and vintf fragment files requested by the module. All files installed by this
@@ -1873,30 +2018,36 @@
// so only a single rule is created for each init.rc or vintf fragment file.
if !m.InVendorRamdisk() {
- m.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc)
+ ctx.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc.GetOrDefault(ctx, nil))
rcDir := PathForModuleInstall(ctx, "etc", "init")
- for _, src := range m.initRcPaths {
+ for _, src := range ctx.initRcPaths {
installedInitRc := rcDir.Join(ctx, src.Base())
- m.katiInitRcInstalls = append(m.katiInitRcInstalls, katiInstall{
+ ctx.katiInitRcInstalls = append(ctx.katiInitRcInstalls, katiInstall{
from: src,
to: installedInitRc,
})
ctx.PackageFile(rcDir, src.Base(), src)
- m.installedInitRcPaths = append(m.installedInitRcPaths, installedInitRc)
+ ctx.installedInitRcPaths = append(ctx.installedInitRcPaths, installedInitRc)
}
+ installFiles.InitRcPaths = ctx.initRcPaths
+ installFiles.KatiInitRcInstalls = ctx.katiInitRcInstalls
+ installFiles.InstalledInitRcPaths = ctx.installedInitRcPaths
}
- m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments.GetOrDefault(ctx, nil))
+ ctx.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments.GetOrDefault(ctx, nil))
vintfDir := PathForModuleInstall(ctx, "etc", "vintf", "manifest")
- for _, src := range m.vintfFragmentsPaths {
+ for _, src := range ctx.vintfFragmentsPaths {
installedVintfFragment := vintfDir.Join(ctx, src.Base())
- m.katiVintfInstalls = append(m.katiVintfInstalls, katiInstall{
+ ctx.katiVintfInstalls = append(ctx.katiVintfInstalls, katiInstall{
from: src,
to: installedVintfFragment,
})
ctx.PackageFile(vintfDir, src.Base(), src)
- m.installedVintfFragmentsPaths = append(m.installedVintfFragmentsPaths, installedVintfFragment)
+ ctx.installedVintfFragmentsPaths = append(ctx.installedVintfFragmentsPaths, installedVintfFragment)
}
+ installFiles.VintfFragmentsPaths = ctx.vintfFragmentsPaths
+ installFiles.KatiVintfInstalls = ctx.katiVintfInstalls
+ installFiles.InstalledVintfFragmentsPaths = ctx.installedVintfFragmentsPaths
}
licensesPropertyFlattener(ctx)
@@ -1918,73 +2069,38 @@
return
}
- incrementalAnalysis := false
- incrementalEnabled := false
- var cacheKey *blueprint.BuildActionCacheKey = nil
- var incrementalModule *blueprint.Incremental = nil
- if ctx.bp.GetIncrementalEnabled() {
- if im, ok := m.module.(blueprint.Incremental); ok {
- incrementalModule = &im
- incrementalEnabled = im.IncrementalSupported()
- incrementalAnalysis = ctx.bp.GetIncrementalAnalysis() && incrementalEnabled
- }
- }
- if incrementalEnabled {
- hash, err := proptools.CalculateHash(m.GetProperties())
- if err != nil {
- ctx.ModuleErrorf("failed to calculate properties hash: %s", err)
- return
- }
- cacheInput := new(blueprint.BuildActionCacheInput)
- cacheInput.PropertiesHash = hash
- ctx.VisitDirectDeps(func(module Module) {
- cacheInput.ProvidersHash =
- append(cacheInput.ProvidersHash, ctx.bp.OtherModuleProviderInitialValueHashes(module))
- })
- hash, err = proptools.CalculateHash(&cacheInput)
- if err != nil {
- ctx.ModuleErrorf("failed to calculate cache input hash: %s", err)
- return
- }
- cacheKey = &blueprint.BuildActionCacheKey{
- Id: ctx.bp.ModuleCacheKey(),
- InputHash: hash,
- }
+ m.module.GenerateAndroidBuildActions(ctx)
+ if ctx.Failed() {
+ return
}
- restored := false
- if incrementalAnalysis && cacheKey != nil {
- restored = ctx.bp.RestoreBuildActions(cacheKey)
- }
-
- if !restored {
- m.module.GenerateAndroidBuildActions(ctx)
- if ctx.Failed() {
- return
- }
- }
-
- if incrementalEnabled && cacheKey != nil {
- ctx.bp.CacheBuildActions(cacheKey, incrementalModule)
+ if x, ok := m.module.(IDEInfo); ok {
+ var result IdeInfo
+ x.IDEInfo(ctx, &result)
+ result.BaseModuleName = x.BaseModuleName()
+ SetProvider(ctx, IdeInfoProviderKey, result)
}
// Create the set of tagged dist files after calling GenerateAndroidBuildActions
// as GenerateTaggedDistFiles() calls OutputFiles(tag) and so relies on the
// output paths being set which must be done before or during
// GenerateAndroidBuildActions.
- m.distFiles = m.GenerateTaggedDistFiles(ctx)
+ installFiles.DistFiles = m.GenerateTaggedDistFiles(ctx)
if ctx.Failed() {
return
}
- SetProvider(ctx, InstallFilesProvider, InstallFilesInfo{
- InstallFiles: ctx.installFiles,
- CheckbuildFiles: ctx.checkbuildFiles,
- PackagingSpecs: ctx.packagingSpecs,
- KatiInstalls: ctx.katiInstalls,
- KatiSymlinks: ctx.katiSymlinks,
- TestData: ctx.testData,
- })
+ m.generateVariantTarget(ctx)
+
+ installFiles.LicenseMetadataFile = ctx.licenseMetadataFile
+ installFiles.InstallFiles = ctx.installFiles
+ installFiles.CheckbuildFiles = ctx.checkbuildFiles
+ installFiles.CheckbuildTarget = ctx.checkbuildTarget
+ installFiles.UncheckedModule = ctx.uncheckedModule
+ installFiles.PackagingSpecs = ctx.packagingSpecs
+ installFiles.KatiInstalls = ctx.katiInstalls
+ installFiles.KatiSymlinks = ctx.katiSymlinks
+ installFiles.TestData = ctx.testData
} else if ctx.Config().AllowMissingDependencies() {
// If the module is not enabled it will not create any build rules, nothing will call
// ctx.GetMissingDependencies(), and blueprint will consider the missing dependencies to be unhandled
@@ -1993,60 +2109,103 @@
ctx.GetMissingDependencies()
}
- if m == ctx.FinalModule().(Module).base() {
+ if sourceFileProducer, ok := m.module.(SourceFileProducer); ok {
+ SetProvider(ctx, SourceFilesInfoProvider, SourceFilesInfo{Srcs: sourceFileProducer.Srcs()})
+ }
+
+ if ctx.IsFinalModule(m.module) {
m.generateModuleTarget(ctx)
if ctx.Failed() {
return
}
}
- m.installFilesDepSet = NewDepSet[InstallPath](TOPOLOGICAL, ctx.installFiles, dependencyInstallFiles)
- m.packagingSpecsDepSet = NewDepSet[PackagingSpec](TOPOLOGICAL, ctx.packagingSpecs, dependencyPackagingSpecs)
+ ctx.TransitiveInstallFiles = depset.New[InstallPath](depset.TOPOLOGICAL, ctx.installFiles, dependencyInstallFiles)
+ installFiles.TransitiveInstallFiles = ctx.TransitiveInstallFiles
+ installFiles.TransitivePackagingSpecs = depset.New[PackagingSpec](depset.TOPOLOGICAL, ctx.packagingSpecs, dependencyPackagingSpecs)
- buildLicenseMetadata(ctx, m.licenseMetadataFile)
+ SetProvider(ctx, InstallFilesProvider, installFiles)
+ buildLicenseMetadata(ctx, ctx.licenseMetadataFile)
- if m.moduleInfoJSON != nil {
- var installed InstallPaths
- installed = append(installed, ctx.katiInstalls.InstallPaths()...)
- installed = append(installed, ctx.katiSymlinks.InstallPaths()...)
- installed = append(installed, m.katiInitRcInstalls.InstallPaths()...)
- installed = append(installed, m.katiVintfInstalls.InstallPaths()...)
- installedStrings := installed.Strings()
+ if len(ctx.moduleInfoJSON) > 0 {
+ for _, moduleInfoJSON := range ctx.moduleInfoJSON {
+ if moduleInfoJSON.Disabled {
+ continue
+ }
+ var installed InstallPaths
+ installed = append(installed, ctx.katiInstalls.InstallPaths()...)
+ installed = append(installed, ctx.katiSymlinks.InstallPaths()...)
+ installed = append(installed, ctx.katiInitRcInstalls.InstallPaths()...)
+ installed = append(installed, ctx.katiVintfInstalls.InstallPaths()...)
+ installedStrings := installed.Strings()
- var targetRequired, hostRequired []string
- if ctx.Host() {
- targetRequired = m.commonProperties.Target_required
- } else {
- hostRequired = m.commonProperties.Host_required
- }
+ var targetRequired, hostRequired []string
+ if ctx.Host() {
+ targetRequired = m.baseProperties.Target_required
+ } else {
+ hostRequired = m.baseProperties.Host_required
+ }
- var data []string
- for _, d := range ctx.testData {
- data = append(data, d.ToRelativeInstallPath())
- }
+ var data []string
+ for _, d := range ctx.testData {
+ data = append(data, d.ToRelativeInstallPath())
+ }
- if m.moduleInfoJSON.Uninstallable {
- installedStrings = nil
- if len(m.moduleInfoJSON.CompatibilitySuites) == 1 && m.moduleInfoJSON.CompatibilitySuites[0] == "null-suite" {
- m.moduleInfoJSON.CompatibilitySuites = nil
- m.moduleInfoJSON.TestConfig = nil
- m.moduleInfoJSON.AutoTestConfig = nil
- data = nil
+ if moduleInfoJSON.Uninstallable {
+ installedStrings = nil
+ if len(moduleInfoJSON.CompatibilitySuites) == 1 && moduleInfoJSON.CompatibilitySuites[0] == "null-suite" {
+ moduleInfoJSON.CompatibilitySuites = nil
+ moduleInfoJSON.TestConfig = nil
+ moduleInfoJSON.AutoTestConfig = nil
+ data = nil
+ }
+ }
+
+ // 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. This was inherited from
+ // AndroidMkEntries.AddCompatibilityTestSuites.
+ suites := moduleInfoJSON.CompatibilitySuites
+ if PrefixInList(suites, "mts-") && !InList("mts", suites) {
+ suites = append(suites, "mts")
+ }
+ if PrefixInList(suites, "mcts-") && !InList("mcts", suites) {
+ suites = append(suites, "mcts")
+ }
+ moduleInfoJSON.CompatibilitySuites = suites
+
+ required := append(m.RequiredModuleNames(ctx), m.VintfFragmentModuleNames(ctx)...)
+ required = append(required, moduleInfoJSON.ExtraRequired...)
+
+ registerName := moduleInfoJSON.RegisterNameOverride
+ if len(registerName) == 0 {
+ registerName = m.moduleInfoRegisterName(ctx, moduleInfoJSON.SubName)
+ }
+
+ moduleName := moduleInfoJSON.ModuleNameOverride
+ if len(moduleName) == 0 {
+ moduleName = m.BaseModuleName() + moduleInfoJSON.SubName
+ }
+
+ supportedVariants := moduleInfoJSON.SupportedVariantsOverride
+ if moduleInfoJSON.SupportedVariantsOverride == nil {
+ supportedVariants = []string{m.moduleInfoVariant(ctx)}
+ }
+
+ moduleInfoJSON.core = CoreModuleInfoJSON{
+ RegisterName: registerName,
+ Path: []string{ctx.ModuleDir()},
+ Installed: installedStrings,
+ ModuleName: moduleName,
+ SupportedVariants: supportedVariants,
+ TargetDependencies: targetRequired,
+ HostDependencies: hostRequired,
+ Data: data,
+ Required: required,
}
}
- m.moduleInfoJSON.core = CoreModuleInfoJSON{
- RegisterName: m.moduleInfoRegisterName(ctx, m.moduleInfoJSON.SubName),
- Path: []string{ctx.ModuleDir()},
- Installed: installedStrings,
- ModuleName: m.BaseModuleName() + m.moduleInfoJSON.SubName,
- SupportedVariants: []string{m.moduleInfoVariant(ctx)},
- TargetDependencies: targetRequired,
- HostDependencies: hostRequired,
- Data: data,
- Required: m.RequiredModuleNames(ctx),
- }
- SetProvider(ctx, ModuleInfoJSONProvider, m.moduleInfoJSON)
+ SetProvider(ctx, ModuleInfoJSONProvider, ctx.moduleInfoJSON)
}
m.buildParams = ctx.buildParams
@@ -2064,6 +2223,75 @@
})
}
buildComplianceMetadataProvider(ctx, m)
+
+ commonData := CommonModuleInfo{
+ ReplacedByPrebuilt: m.commonProperties.ReplacedByPrebuilt,
+ Target: m.commonProperties.CompileTarget,
+ SkipAndroidMkProcessing: shouldSkipAndroidMkProcessing(ctx, m),
+ BaseModuleName: m.BaseModuleName(),
+ UninstallableApexPlatformVariant: m.commonProperties.UninstallableApexPlatformVariant,
+ HideFromMake: m.commonProperties.HideFromMake,
+ SkipInstall: m.commonProperties.SkipInstall,
+ Host: m.Host(),
+ }
+ if mm, ok := m.module.(interface {
+ MinSdkVersion(ctx EarlyModuleContext) ApiLevel
+ }); ok {
+ ver := mm.MinSdkVersion(ctx)
+ if !ver.IsNone() {
+ commonData.MinSdkVersion = ver.String()
+ }
+ } else if mm, ok := m.module.(interface{ MinSdkVersion() string }); ok {
+ commonData.MinSdkVersion = mm.MinSdkVersion()
+ }
+
+ if mm, ok := m.module.(interface {
+ SdkVersion(ctx EarlyModuleContext) ApiLevel
+ }); ok {
+ ver := mm.SdkVersion(ctx)
+ if !ver.IsNone() {
+ commonData.SdkVersion = ver.String()
+ }
+ } else if mm, ok := m.module.(interface{ SdkVersion() string }); ok {
+ commonData.SdkVersion = mm.SdkVersion()
+ }
+
+ if m.commonProperties.ForcedDisabled {
+ commonData.Enabled = false
+ } else {
+ commonData.Enabled = m.commonProperties.Enabled.GetOrDefault(m.ConfigurableEvaluator(ctx), !m.Os().DefaultDisabled)
+ }
+ if am, ok := m.module.(ApexModule); ok {
+ commonData.CanHaveApexVariants = am.CanHaveApexVariants()
+ commonData.NotAvailableForPlatform = am.NotAvailableForPlatform()
+ commonData.NotInPlatform = am.NotInPlatform()
+ }
+ if st, ok := m.module.(StubsAvailableModule); ok {
+ commonData.IsStubsModule = st.IsStubsModule()
+ }
+ SetProvider(ctx, CommonModuleInfoKey, commonData)
+ if p, ok := m.module.(PrebuiltInterface); ok && p.Prebuilt() != nil {
+ SetProvider(ctx, PrebuiltModuleInfoProvider, PrebuiltModuleInfo{
+ SourceExists: p.Prebuilt().SourceExists(),
+ UsePrebuilt: p.Prebuilt().UsePrebuilt(),
+ })
+ }
+ if h, ok := m.module.(HostToolProvider); ok {
+ SetProvider(ctx, HostToolProviderInfoProvider, HostToolProviderInfo{
+ HostToolPath: h.HostToolPath()})
+ }
+
+ if p, ok := m.module.(AndroidMkProviderInfoProducer); ok && !commonData.SkipAndroidMkProcessing {
+ SetProvider(ctx, AndroidMkInfoProvider, p.PrepareAndroidMKProviderInfo(ctx.Config()))
+ }
+
+ if s, ok := m.module.(SourceFileGenerator); ok {
+ SetProvider(ctx, GeneratedSourceInfoProvider, GeneratedSourceInfo{
+ GeneratedSourceFiles: s.GeneratedSourceFiles(),
+ GeneratedHeaderDirs: s.GeneratedHeaderDirs(),
+ GeneratedDeps: s.GeneratedDeps(),
+ })
+ }
}
func SetJarJarPrefixHandler(handler func(ModuleContext)) {
@@ -2087,7 +2315,7 @@
arches = slices.DeleteFunc(arches, func(target Target) bool {
return target.NativeBridge != ctx.Target().NativeBridge
})
- if len(arches) > 0 && ctx.Arch().ArchType != arches[0].Arch.ArchType {
+ if len(arches) > 0 && ctx.Arch().ArchType != arches[0].Arch.ArchType && ctx.Arch().ArchType != Common {
if ctx.Arch().ArchType.Multilib == "lib32" {
suffix = "_32"
} else {
@@ -2109,10 +2337,6 @@
return variant
}
-func (m *ModuleBase) ContainersInfo() ContainersInfo {
- return m.containersInfo
-}
-
// Check the supplied dist structure to make sure that it is valid.
//
// property - the base property, e.g. dist or dists[1], which is combined with the
@@ -2147,8 +2371,47 @@
orderOnlyDeps Paths
executable bool
extraFiles *extraFilesZip
+ absFrom string
+}
- absFrom string
+type katiInstallGob struct {
+ From Path
+ To InstallPath
+ ImplicitDeps Paths
+ OrderOnlyDeps Paths
+ Executable bool
+ ExtraFiles *extraFilesZip
+ AbsFrom string
+}
+
+func (k *katiInstall) ToGob() *katiInstallGob {
+ return &katiInstallGob{
+ From: k.from,
+ To: k.to,
+ ImplicitDeps: k.implicitDeps,
+ OrderOnlyDeps: k.orderOnlyDeps,
+ Executable: k.executable,
+ ExtraFiles: k.extraFiles,
+ AbsFrom: k.absFrom,
+ }
+}
+
+func (k *katiInstall) FromGob(data *katiInstallGob) {
+ k.from = data.From
+ k.to = data.To
+ k.implicitDeps = data.ImplicitDeps
+ k.orderOnlyDeps = data.OrderOnlyDeps
+ k.executable = data.Executable
+ k.extraFiles = data.ExtraFiles
+ k.absFrom = data.AbsFrom
+}
+
+func (k *katiInstall) GobEncode() ([]byte, error) {
+ return gobtools.CustomGobEncode[katiInstallGob](k)
+}
+
+func (k *katiInstall) GobDecode(data []byte) error {
+ return gobtools.CustomGobDecode[katiInstallGob](data, k)
}
type extraFilesZip struct {
@@ -2156,6 +2419,31 @@
dir InstallPath
}
+type extraFilesZipGob struct {
+ Zip Path
+ Dir InstallPath
+}
+
+func (e *extraFilesZip) ToGob() *extraFilesZipGob {
+ return &extraFilesZipGob{
+ Zip: e.zip,
+ Dir: e.dir,
+ }
+}
+
+func (e *extraFilesZip) FromGob(data *extraFilesZipGob) {
+ e.zip = data.Zip
+ e.dir = data.Dir
+}
+
+func (e *extraFilesZip) GobEncode() ([]byte, error) {
+ return gobtools.CustomGobEncode[extraFilesZipGob](e)
+}
+
+func (e *extraFilesZip) GobDecode(data []byte) error {
+ return gobtools.CustomGobDecode[extraFilesZipGob](data, e)
+}
+
type katiInstalls []katiInstall
// BuiltInstalled returns the katiInstalls in the form used by $(call copy-many-files) in Make, a
@@ -2205,17 +2493,31 @@
return proptools.Bool(m.commonProperties.Native_bridge_supported)
}
-type ConfigAndErrorContext interface {
+func (m *ModuleBase) DecodeMultilib(ctx ConfigContext) (string, string) {
+ return decodeMultilib(ctx, m)
+}
+
+func (m *ModuleBase) Overrides() []string {
+ return m.commonProperties.Overrides
+}
+
+type ConfigContext interface {
+ Config() Config
+}
+
+type ConfigurableEvaluatorContext interface {
+ OtherModuleProviderContext
Config() Config
OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{})
+ HasMutatorFinished(mutatorName string) bool
}
type configurationEvalutor struct {
- ctx ConfigAndErrorContext
+ ctx ConfigurableEvaluatorContext
m Module
}
-func (m *ModuleBase) ConfigurableEvaluator(ctx ConfigAndErrorContext) proptools.ConfigurableEvaluator {
+func (m *ModuleBase) ConfigurableEvaluator(ctx ConfigurableEvaluatorContext) proptools.ConfigurableEvaluator {
return configurationEvalutor{
ctx: ctx,
m: m.module,
@@ -2229,6 +2531,12 @@
func (e configurationEvalutor) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue {
ctx := e.ctx
m := e.m
+
+ if !ctx.HasMutatorFinished("defaults") {
+ ctx.OtherModulePropertyErrorf(m, property, "Cannot evaluate configurable property before the defaults mutator has run")
+ return proptools.ConfigurableValueUndefined()
+ }
+
switch condition.FunctionName() {
case "release_flag":
if condition.NumArgs() != 1 {
@@ -2256,11 +2564,17 @@
}
variable := condition.Arg(0)
switch variable {
+ case "build_from_text_stub":
+ return proptools.ConfigurableValueBool(ctx.Config().BuildFromTextStub())
case "debuggable":
return proptools.ConfigurableValueBool(ctx.Config().Debuggable())
+ case "eng":
+ return proptools.ConfigurableValueBool(ctx.Config().Eng())
case "use_debug_art":
// TODO(b/234351700): Remove once ART does not have separated debug APEX
return proptools.ConfigurableValueBool(ctx.Config().UseDebugArt())
+ case "selinux_ignore_neverallows":
+ return proptools.ConfigurableValueBool(ctx.Config().SelinuxIgnoreNeverallows())
default:
// TODO(b/323382414): Might add these on a case-by-case basis
ctx.OtherModulePropertyErrorf(m, property, fmt.Sprintf("TODO(b/323382414): Product variable %q is not yet supported in selects", variable))
@@ -2285,6 +2599,8 @@
return proptools.ConfigurableValueString(v)
case "bool":
return proptools.ConfigurableValueBool(v == "true")
+ case "string_list":
+ return proptools.ConfigurableValueStringList(strings.Split(v, " "))
default:
panic("unhandled soong config variable type: " + ty)
}
@@ -2481,7 +2797,7 @@
// OutputFilesForModule returns the output file paths with the given tag. On error, including if the
// module produced zero paths, it reports errors to the ctx and returns nil.
-func OutputFilesForModule(ctx PathContext, module blueprint.Module, tag string) Paths {
+func OutputFilesForModule(ctx PathContext, module Module, tag string) Paths {
paths, err := outputFilesForModule(ctx, module, tag)
if err != nil {
reportPathError(ctx, err)
@@ -2492,7 +2808,7 @@
// OutputFileForModule returns the output file paths with the given tag. On error, including if the
// module produced zero or multiple paths, it reports errors to the ctx and returns nil.
-func OutputFileForModule(ctx PathContext, module blueprint.Module, tag string) Path {
+func OutputFileForModule(ctx PathContext, module Module, tag string) Path {
paths, err := outputFilesForModule(ctx, module, tag)
if err != nil {
reportPathError(ctx, err)
@@ -2525,20 +2841,35 @@
return paths[0]
}
-func outputFilesForModule(ctx PathContext, module blueprint.Module, tag string) (Paths, error) {
+type OutputFilesProviderModuleContext interface {
+ OtherModuleProviderContext
+ Module() Module
+ GetOutputFiles() OutputFilesInfo
+ EqualModules(m1, m2 Module) bool
+}
+
+func outputFilesForModule(ctx PathContext, module Module, tag string) (Paths, error) {
outputFilesFromProvider, err := outputFilesForModuleFromProvider(ctx, module, tag)
if outputFilesFromProvider != nil || err != OutputFilesProviderNotSet {
return outputFilesFromProvider, err
}
- if sourceFileProducer, ok := module.(SourceFileProducer); ok {
- if tag != "" {
- return nil, fmt.Errorf("module %q is a SourceFileProducer, which does not support tag %q", pathContextName(ctx, module), tag)
+
+ if octx, ok := ctx.(OutputFilesProviderModuleContext); ok {
+ if octx.EqualModules(octx.Module(), module) {
+ // It is the current module, we can access the srcs through interface
+ if sourceFileProducer, ok := module.(SourceFileProducer); ok {
+ return sourceFileProducer.Srcs(), nil
+ }
+ } else if sourceFiles, ok := OtherModuleProvider(octx, module, SourceFilesInfoProvider); ok {
+ if tag != "" {
+ return nil, fmt.Errorf("module %q is a SourceFileProducer, which does not support tag %q", pathContextName(ctx, module), tag)
+ }
+ paths := sourceFiles.Srcs
+ return paths, nil
}
- paths := sourceFileProducer.Srcs()
- return paths, nil
- } else {
- return nil, fmt.Errorf("module %q is not a SourceFileProducer or having valid output file for tag %q", pathContextName(ctx, module), tag)
}
+
+ return nil, fmt.Errorf("module %q is not a SourceFileProducer or having valid output file for tag %q", pathContextName(ctx, module), tag)
}
// This method uses OutputFilesProvider for output files
@@ -2547,26 +2878,19 @@
// from outputFiles property of module base, to avoid both setting and
// reading OutputFilesProvider before GenerateBuildActions is finished.
// If a module doesn't have the OutputFilesProvider, nil is returned.
-func outputFilesForModuleFromProvider(ctx PathContext, module blueprint.Module, tag string) (Paths, error) {
+func outputFilesForModuleFromProvider(ctx PathContext, module Module, tag string) (Paths, error) {
var outputFiles OutputFilesInfo
fromProperty := false
- type OutputFilesProviderModuleContext interface {
- OtherModuleProviderContext
- Module() Module
- GetOutputFiles() OutputFilesInfo
- }
-
if mctx, isMctx := ctx.(OutputFilesProviderModuleContext); isMctx {
- if mctx.Module() != module {
+ if !mctx.EqualModules(mctx.Module(), module) {
outputFiles, _ = OtherModuleProvider(mctx, module, OutputFilesProvider)
} else {
outputFiles = mctx.GetOutputFiles()
fromProperty = true
}
} else if cta, isCta := ctx.(*singletonContextAdaptor); isCta {
- providerData, _ := cta.otherModuleProvider(module, OutputFilesProvider)
- outputFiles, _ = providerData.(OutputFilesInfo)
+ outputFiles, _ = OtherModuleProvider(cta, module, OutputFilesProvider)
} else {
return nil, fmt.Errorf("unsupported context %q in method outputFilesForModuleFromProvider", reflect.TypeOf(ctx))
}
@@ -2745,7 +3069,7 @@
// Collect information for opening IDE project files in java/jdeps.go.
type IDEInfo interface {
- IDEInfo(ideInfo *IdeInfo)
+ IDEInfo(ctx BaseModuleContext, ideInfo *IdeInfo)
BaseModuleName() string
}
@@ -2757,7 +3081,9 @@
IDECustomizedModuleName() string
}
+// Collect information for opening IDE project files in java/jdeps.go.
type IdeInfo struct {
+ BaseModuleName string `json:"-"`
Deps []string `json:"dependencies,omitempty"`
Srcs []string `json:"srcs,omitempty"`
Aidl_include_dirs []string `json:"aidl_include_dirs,omitempty"`
@@ -2771,6 +3097,31 @@
Libs []string `json:"libs,omitempty"`
}
+// Merge merges two IdeInfos and produces a new one, leaving the origional unchanged
+func (i IdeInfo) Merge(other IdeInfo) IdeInfo {
+ return IdeInfo{
+ Deps: mergeStringLists(i.Deps, other.Deps),
+ Srcs: mergeStringLists(i.Srcs, other.Srcs),
+ Aidl_include_dirs: mergeStringLists(i.Aidl_include_dirs, other.Aidl_include_dirs),
+ Jarjar_rules: mergeStringLists(i.Jarjar_rules, other.Jarjar_rules),
+ Jars: mergeStringLists(i.Jars, other.Jars),
+ Classes: mergeStringLists(i.Classes, other.Classes),
+ Installed_paths: mergeStringLists(i.Installed_paths, other.Installed_paths),
+ SrcJars: mergeStringLists(i.SrcJars, other.SrcJars),
+ Paths: mergeStringLists(i.Paths, other.Paths),
+ Static_libs: mergeStringLists(i.Static_libs, other.Static_libs),
+ Libs: mergeStringLists(i.Libs, other.Libs),
+ }
+}
+
+// mergeStringLists appends the two string lists together and returns a new string list,
+// leaving the originals unchanged. Duplicate strings will be deduplicated.
+func mergeStringLists(a, b []string) []string {
+ return FirstUniqueStrings(Concat(a, b))
+}
+
+var IdeInfoProviderKey = blueprint.NewProvider[IdeInfo]()
+
func CheckBlueprintSyntax(ctx BaseModuleContext, filename string, contents string) []error {
bpctx := ctx.blueprintBaseModuleContext()
return blueprint.CheckBlueprintSyntax(bpctx.ModuleFactories(), filename, contents)
diff --git a/android/module_context.go b/android/module_context.go
index e9fbb8c..a3dad93 100644
--- a/android/module_context.go
+++ b/android/module_context.go
@@ -18,10 +18,13 @@
"fmt"
"path"
"path/filepath"
+ "slices"
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/depset"
"github.com/google/blueprint/proptools"
+ "github.com/google/blueprint/uniquelist"
)
// BuildParameters describes the set of potential parameters to build a Ninja rule.
@@ -73,7 +76,7 @@
// Validations is a slice of output path for a validation action. Validation outputs imply lower
// non-blocking priority to building non-validation outputs.
Validations Paths
- // Whether to skip outputting a default target statement which will be built by Ninja when no
+ // Whether to output a default target statement which will be built by Ninja when no
// targets are specified on Ninja's command line.
Default bool
// Args is a key value mapping for replacements of variables within the Rule
@@ -85,7 +88,9 @@
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 +112,79 @@
// 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
@@ -181,9 +197,12 @@
InstallInOdm() bool
InstallInProduct() bool
InstallInVendor() bool
+ InstallInSystemDlkm() bool
+ InstallInVendorDlkm() bool
+ InstallInOdmDlkm() bool
InstallForceOS() (*OsType, *ArchType)
- RequiredModuleNames(ctx ConfigAndErrorContext) []string
+ RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string
HostRequiredModuleNames() []string
TargetRequiredModuleNames() []string
@@ -212,32 +231,65 @@
// the module-info.json generated by Make, and Make will not generate its own data for this module.
ModuleInfoJSON() *ModuleInfoJSON
+ // Simiar to ModuleInfoJSON, ExtraModuleInfoJSON also returns a pointer to the ModuleInfoJSON struct.
+ // This should only be called by a module that generates multiple AndroidMkEntries struct.
+ ExtraModuleInfoJSON() *ModuleInfoJSON
+
// 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
+ TransitiveInstallFiles depset.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
@@ -245,6 +297,21 @@
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{}
@@ -281,7 +348,7 @@
OrderOnly: params.OrderOnly.Strings(),
Validations: params.Validations.Strings(),
Args: params.Args,
- Optional: !params.Default,
+ Default: params.Default,
}
if params.Depfile != nil {
@@ -377,9 +444,28 @@
return missingDeps
}
-func (m *moduleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
- module, _ := m.getDirectDepInternal(name, tag)
- return module
+func (m *moduleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) Module {
+ deps := m.getDirectDepsInternal(name, tag)
+ if len(deps) == 1 {
+ return deps[0]
+ } else if len(deps) >= 2 {
+ panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
+ name, m.ModuleName()))
+ } else {
+ return nil
+ }
+}
+
+func (m *moduleContext) GetDirectDepProxyWithTag(name string, tag blueprint.DependencyTag) *ModuleProxy {
+ deps := m.getDirectDepsProxyInternal(name, tag)
+ if len(deps) == 1 {
+ return &deps[0]
+ } else if len(deps) >= 2 {
+ panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
+ name, m.ModuleName()))
+ } else {
+ return nil
+ }
}
func (m *moduleContext) ModuleSubDir() string {
@@ -434,15 +520,23 @@
return m.module.InstallInVendor()
}
+func (m *moduleContext) InstallInSystemDlkm() bool {
+ return m.module.InstallInSystemDlkm()
+}
+
+func (m *moduleContext) InstallInVendorDlkm() bool {
+ return m.module.InstallInVendorDlkm()
+}
+
+func (m *moduleContext) InstallInOdmDlkm() bool {
+ return m.module.InstallInOdmDlkm()
+}
+
func (m *moduleContext) skipInstall() bool {
if m.module.base().commonProperties.SkipInstall {
return true
}
- if m.module.base().commonProperties.HideFromMake {
- return true
- }
-
// We'll need a solution for choosing which of modules with the same name in different
// namespaces to install. For now, reuse the list of namespaces exported to Make as the
// list of namespaces to install in a Soong-only build.
@@ -461,6 +555,10 @@
return false
}
+ if m.module.base().commonProperties.HideFromMake {
+ return false
+ }
+
if proptools.Bool(m.module.base().commonProperties.No_full_install) {
return false
}
@@ -470,17 +568,22 @@
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,
})
@@ -488,32 +591,54 @@
func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec {
fullInstallPath := installPath.Join(m, name)
- return m.packageFile(fullInstallPath, srcPath, false)
+ return m.packageFile(fullInstallPath, srcPath, false, false)
}
-func (m *moduleContext) getAconfigPaths() *Paths {
- return &m.module.base().aconfigFilePaths
+func (m *moduleContext) getAconfigPaths() Paths {
+ return m.aconfigFilePaths
}
-func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool) PackagingSpec {
+func (m *moduleContext) setAconfigPaths(paths Paths) {
+ m.aconfigFilePaths = paths
+}
+
+func (m *moduleContext) getOwnerAndOverrides() (string, []string) {
+ owner := m.ModuleName()
+ overrides := slices.Clone(m.Module().base().commonProperties.Overrides)
+ if b, ok := m.Module().(OverridableModule); ok {
+ if b.GetOverriddenBy() != "" {
+ // overriding variant of base module
+ overrides = append(overrides, m.ModuleName()) // com.android.foo
+ owner = m.Module().Name() // com.company.android.foo
+ }
+ }
+ return owner, overrides
+}
+
+func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool, requiresFullInstall bool) PackagingSpec {
licenseFiles := m.Module().EffectiveLicenseFiles()
+ owner, overrides := m.getOwnerAndOverrides()
spec := PackagingSpec{
relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
srcPath: srcPath,
symlinkTarget: "",
executable: executable,
- effectiveLicenseFiles: &licenseFiles,
+ effectiveLicenseFiles: uniquelist.Make(licenseFiles),
partition: fullInstallPath.partition,
skipInstall: m.skipInstall(),
- aconfigPaths: m.getAconfigPaths(),
+ aconfigPaths: uniquelist.Make(m.getAconfigPaths()),
archType: m.target.Arch.ArchType,
+ overrides: uniquelist.Make(overrides),
+ owner: owner,
+ requiresFullInstall: requiresFullInstall,
+ fullInstallPath: fullInstallPath,
}
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 {
@@ -521,9 +646,11 @@
}
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())...)
+ if m.config.KatiEnabled() {
+ deps = append(deps, m.installedInitRcPaths...)
+ deps = append(deps, m.installedVintfFragmentsPaths...)
+ }
var implicitDeps, orderOnlyDeps Paths
@@ -535,22 +662,24 @@
orderOnlyDeps = InstallPaths(deps).Paths()
}
- if m.Config().KatiEnabled() {
- // When creating the install rule in Soong but embedding in Make, write the rule to a
- // makefile instead of directly to the ninja file so that main.mk can add the
- // dependencies from the `required` property that are hard to resolve in Soong.
- m.katiInstalls = append(m.katiInstalls, katiInstall{
- from: srcPath,
- to: fullInstallPath,
- implicitDeps: implicitDeps,
- orderOnlyDeps: orderOnlyDeps,
- executable: executable,
- extraFiles: extraZip,
- })
- } else {
- rule := Cp
+ // When creating the install rule in Soong but embedding in Make, write the rule to a
+ // makefile instead of directly to the ninja file so that main.mk can add the
+ // dependencies from the `required` property that are hard to resolve in Soong.
+ // In soong-only builds, the katiInstall will still be created for semi-legacy code paths
+ // such as module-info.json or compliance, but it will not be used for actually installing
+ // the file.
+ m.katiInstalls = append(m.katiInstalls, katiInstall{
+ from: srcPath,
+ to: fullInstallPath,
+ implicitDeps: implicitDeps,
+ orderOnlyDeps: orderOnlyDeps,
+ executable: executable,
+ extraFiles: extraZip,
+ })
+ if !m.Config().KatiEnabled() {
+ rule := CpWithBash
if executable {
- rule = CpExecutable
+ rule = CpExecutableWithBash
}
extraCmds := ""
@@ -568,9 +697,9 @@
Input: srcPath,
Implicits: implicitDeps,
OrderOnly: orderOnlyDeps,
- Default: !m.Config().KatiEnabled(),
Args: map[string]string{
"extraCmds": extraCmds,
+ "cpFlags": "-f",
},
})
}
@@ -578,9 +707,11 @@
m.installFiles = append(m.installFiles, fullInstallPath)
}
- m.packageFile(fullInstallPath, srcPath, executable)
+ m.packageFile(fullInstallPath, srcPath, executable, m.requiresFullInstall())
- m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
+ if checkbuild {
+ m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
+ }
return fullInstallPath
}
@@ -595,25 +726,26 @@
}
if m.requiresFullInstall() {
- if m.Config().KatiEnabled() {
- // When creating the symlink rule in Soong but embedding in Make, write the rule to a
- // makefile instead of directly to the ninja file so that main.mk can add the
- // dependencies from the `required` property that are hard to resolve in Soong.
- m.katiSymlinks = append(m.katiSymlinks, katiInstall{
- from: srcPath,
- to: fullInstallPath,
- })
- } else {
+ // When creating the symlink rule in Soong but embedding in Make, write the rule to a
+ // makefile instead of directly to the ninja file so that main.mk can add the
+ // dependencies from the `required` property that are hard to resolve in Soong.
+ // In soong-only builds, the katiInstall will still be created for semi-legacy code paths
+ // such as module-info.json or compliance, but it will not be used for actually installing
+ // the file.
+ m.katiSymlinks = append(m.katiSymlinks, katiInstall{
+ from: srcPath,
+ to: fullInstallPath,
+ })
+ if !m.Config().KatiEnabled() {
// The symlink doesn't need updating when the target is modified, but we sometimes
// have a dependency on a symlink to a binary instead of to the binary directly, and
// the mtime of the symlink must be updated when the binary is modified, so use a
// normal dependency here instead of an order-only dependency.
m.Build(pctx, BuildParams{
- Rule: Symlink,
+ Rule: SymlinkWithBash,
Description: "install symlink " + fullInstallPath.Base(),
Output: fullInstallPath,
Input: srcPath,
- Default: !m.Config().KatiEnabled(),
Args: map[string]string{
"fromPath": relPath,
},
@@ -621,18 +753,22 @@
}
m.installFiles = append(m.installFiles, fullInstallPath)
- m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
}
+ owner, overrides := m.getOwnerAndOverrides()
m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
- relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
- srcPath: nil,
- symlinkTarget: relPath,
- executable: false,
- partition: fullInstallPath.partition,
- skipInstall: m.skipInstall(),
- aconfigPaths: m.getAconfigPaths(),
- archType: m.target.Arch.ArchType,
+ relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
+ srcPath: nil,
+ symlinkTarget: relPath,
+ executable: false,
+ partition: fullInstallPath.partition,
+ skipInstall: m.skipInstall(),
+ aconfigPaths: uniquelist.Make(m.getAconfigPaths()),
+ archType: m.target.Arch.ArchType,
+ overrides: uniquelist.Make(overrides),
+ owner: owner,
+ requiresFullInstall: m.requiresFullInstall(),
+ fullInstallPath: fullInstallPath,
})
return fullInstallPath
@@ -645,20 +781,21 @@
m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true)
if m.requiresFullInstall() {
- if m.Config().KatiEnabled() {
- // When creating the symlink rule in Soong but embedding in Make, write the rule to a
- // makefile instead of directly to the ninja file so that main.mk can add the
- // dependencies from the `required` property that are hard to resolve in Soong.
- m.katiSymlinks = append(m.katiSymlinks, katiInstall{
- absFrom: absPath,
- to: fullInstallPath,
- })
- } else {
+ // When creating the symlink rule in Soong but embedding in Make, write the rule to a
+ // makefile instead of directly to the ninja file so that main.mk can add the
+ // dependencies from the `required` property that are hard to resolve in Soong.
+ // In soong-only builds, the katiInstall will still be created for semi-legacy code paths
+ // such as module-info.json or compliance, but it will not be used for actually installing
+ // the file.
+ m.katiSymlinks = append(m.katiSymlinks, katiInstall{
+ absFrom: absPath,
+ to: fullInstallPath,
+ })
+ if !m.Config().KatiEnabled() {
m.Build(pctx, BuildParams{
Rule: Symlink,
Description: "install symlink " + fullInstallPath.Base() + " -> " + absPath,
Output: fullInstallPath,
- Default: !m.Config().KatiEnabled(),
Args: map[string]string{
"fromPath": absPath,
},
@@ -668,15 +805,20 @@
m.installFiles = append(m.installFiles, fullInstallPath)
}
+ owner, overrides := m.getOwnerAndOverrides()
m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
- relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
- srcPath: nil,
- symlinkTarget: absPath,
- executable: false,
- partition: fullInstallPath.partition,
- skipInstall: m.skipInstall(),
- aconfigPaths: m.getAconfigPaths(),
- archType: m.target.Arch.ArchType,
+ relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
+ srcPath: nil,
+ symlinkTarget: absPath,
+ executable: false,
+ partition: fullInstallPath.partition,
+ skipInstall: m.skipInstall(),
+ aconfigPaths: uniquelist.Make(m.getAconfigPaths()),
+ archType: m.target.Arch.ArchType,
+ overrides: uniquelist.Make(overrides),
+ owner: owner,
+ requiresFullInstall: m.requiresFullInstall(),
+ fullInstallPath: fullInstallPath,
})
return fullInstallPath
@@ -688,35 +830,55 @@
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 {
- return moduleInfoJSON
+ if len(m.moduleInfoJSON) == 0 {
+ moduleInfoJSON := &ModuleInfoJSON{}
+ m.moduleInfoJSON = append(m.moduleInfoJSON, moduleInfoJSON)
}
+ return m.moduleInfoJSON[0]
+}
+
+func (m *moduleContext) ExtraModuleInfoJSON() *ModuleInfoJSON {
+ if len(m.moduleInfoJSON) == 0 {
+ panic("call ModuleInfoJSON() instead")
+ }
+
moduleInfoJSON := &ModuleInfoJSON{}
- m.module.base().moduleInfoJSON = moduleInfoJSON
+ m.moduleInfoJSON = append(m.moduleInfoJSON, moduleInfoJSON)
return moduleInfoJSON
}
func (m *moduleContext) SetOutputFiles(outputFiles Paths, tag string) {
+ for _, outputFile := range outputFiles {
+ if outputFile == nil {
+ panic("outputfiles cannot be nil")
+ }
+ }
if tag == "" {
if len(m.outputFiles.DefaultOutputFiles) > 0 {
m.ModuleErrorf("Module %s default OutputFiles cannot be overwritten", m.ModuleName())
@@ -738,13 +900,15 @@
return m.outputFiles
}
+func (m *moduleContext) SetLicenseInstallMap(installMap []string) {
+ m.licenseInstallMap = append(m.licenseInstallMap, installMap...)
+}
+
func (m *moduleContext) ComplianceMetadataInfo() *ComplianceMetadataInfo {
- if complianceMetadataInfo := m.module.base().complianceMetadataInfo; complianceMetadataInfo != nil {
- return complianceMetadataInfo
+ if m.complianceMetadataInfo == nil {
+ m.complianceMetadataInfo = NewComplianceMetadataInfo()
}
- complianceMetadataInfo := NewComplianceMetadataInfo()
- m.module.base().complianceMetadataInfo = complianceMetadataInfo
- return complianceMetadataInfo
+ return m.complianceMetadataInfo
}
// Returns a list of paths expanded from globs and modules referenced using ":module" syntax. The property must
@@ -773,7 +937,7 @@
return OptionalPath{}
}
-func (m *moduleContext) RequiredModuleNames(ctx ConfigAndErrorContext) []string {
+func (m *moduleContext) RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string {
return m.module.RequiredModuleNames(ctx)
}
@@ -784,3 +948,11 @@
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
+}
diff --git a/android/module_info_json.go b/android/module_info_json.go
index ee552dc..f7bffdb 100644
--- a/android/module_info_json.go
+++ b/android/module_info_json.go
@@ -6,6 +6,7 @@
"slices"
"github.com/google/blueprint"
+ "github.com/google/blueprint/gobtools"
)
type CoreModuleInfoJSON struct {
@@ -20,8 +21,7 @@
Required []string `json:"required,omitempty"` // $(sort $(ALL_MODULES.$(m).REQUIRED_FROM_TARGET))
}
-type ModuleInfoJSON struct {
- core CoreModuleInfoJSON
+type ExtraModuleInfoJSON struct {
SubName string `json:"-"`
Uninstallable bool `json:"-"`
Class []string `json:"class,omitempty"` // $(sort $(ALL_MODULES.$(m).CLASS))
@@ -34,7 +34,7 @@
SrcJars []string `json:"srcjars,omitempty"` // $(sort $(ALL_MODULES.$(m).SRCJARS))
ClassesJar []string `json:"classes_jar,omitempty"` // $(sort $(ALL_MODULES.$(m).CLASSES_JAR))
TestMainlineModules []string `json:"test_mainline_modules,omitempty"` // $(sort $(ALL_MODULES.$(m).TEST_MAINLINE_MODULES))
- IsUnitTest bool `json:"is_unit_test,omitempty"` // $(ALL_MODULES.$(m).IS_UNIT_TEST)
+ IsUnitTest string `json:"is_unit_test,omitempty"` // $(ALL_MODULES.$(m).IS_UNIT_TEST)
TestOptionsTags []string `json:"test_options_tags,omitempty"` // $(sort $(ALL_MODULES.$(m).TEST_OPTIONS_TAGS))
RuntimeDependencies []string `json:"runtime_dependencies,omitempty"` // $(sort $(ALL_MODULES.$(m).LOCAL_RUNTIME_LIBRARIES))
StaticDependencies []string `json:"static_dependencies,omitempty"` // $(sort $(ALL_MODULES.$(m).LOCAL_STATIC_LIBRARIES))
@@ -43,6 +43,17 @@
CompatibilitySuites []string `json:"compatibility_suites,omitempty"` // $(sort $(ALL_MODULES.$(m).COMPATIBILITY_SUITES))
AutoTestConfig []string `json:"auto_test_config,omitempty"` // $(ALL_MODULES.$(m).auto_test_config)
TestConfig []string `json:"test_config,omitempty"` // $(strip $(ALL_MODULES.$(m).TEST_CONFIG) $(ALL_MODULES.$(m).EXTRA_TEST_CONFIGS)
+ ExtraRequired []string `json:"-"`
+
+ SupportedVariantsOverride []string `json:"-"`
+ Disabled bool `json:"-"`
+ RegisterNameOverride string `json:"-"`
+ ModuleNameOverride string `json:"-"`
+}
+
+type ModuleInfoJSON struct {
+ core CoreModuleInfoJSON
+ ExtraModuleInfoJSON
}
//ALL_DEPS.$(LOCAL_MODULE).ALL_DEPS := $(sort \
@@ -60,7 +71,7 @@
type combinedModuleInfoJSON struct {
*CoreModuleInfoJSON
- *ModuleInfoJSON
+ *ExtraModuleInfoJSON
}
func encodeModuleInfoJSON(w io.Writer, moduleInfoJSON *ModuleInfoJSON) error {
@@ -99,7 +110,27 @@
sortAndUnique(&moduleInfoJSONCopy.TestConfig)
encoder := json.NewEncoder(w)
- return encoder.Encode(combinedModuleInfoJSON{&moduleInfoJSONCopy.core, &moduleInfoJSONCopy})
+ return encoder.Encode(combinedModuleInfoJSON{&moduleInfoJSONCopy.core, &moduleInfoJSONCopy.ExtraModuleInfoJSON})
}
-var ModuleInfoJSONProvider = blueprint.NewProvider[*ModuleInfoJSON]()
+func (p *ModuleInfoJSON) ToGob() *combinedModuleInfoJSON {
+ return &combinedModuleInfoJSON{
+ CoreModuleInfoJSON: &p.core,
+ ExtraModuleInfoJSON: &p.ExtraModuleInfoJSON,
+ }
+}
+
+func (p *ModuleInfoJSON) FromGob(data *combinedModuleInfoJSON) {
+ p.core = *data.CoreModuleInfoJSON
+ p.ExtraModuleInfoJSON = *data.ExtraModuleInfoJSON
+}
+
+func (m *ModuleInfoJSON) GobEncode() ([]byte, error) {
+ return gobtools.CustomGobEncode[combinedModuleInfoJSON](m)
+}
+
+func (m *ModuleInfoJSON) GobDecode(data []byte) error {
+ return gobtools.CustomGobDecode[combinedModuleInfoJSON](data, m)
+}
+
+var ModuleInfoJSONProvider = blueprint.NewProvider[[]*ModuleInfoJSON]()
diff --git a/android/module_proxy.go b/android/module_proxy.go
new file mode 100644
index 0000000..77abc11
--- /dev/null
+++ b/android/module_proxy.go
@@ -0,0 +1,233 @@
+package android
+
+import (
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+type ModuleProxy struct {
+ module blueprint.ModuleProxy
+}
+
+var _ Module = (*ModuleProxy)(nil)
+
+func (m ModuleProxy) IsNil() bool {
+ return m.module.IsNil()
+}
+
+func (m ModuleProxy) Name() string {
+ return m.module.Name()
+}
+
+func (m ModuleProxy) GenerateBuildActions(context blueprint.ModuleContext) {
+ m.module.GenerateBuildActions(context)
+}
+
+func (m ModuleProxy) GenerateAndroidBuildActions(context ModuleContext) {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) ComponentDepsMutator(ctx BottomUpMutatorContext) {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) DepsMutator(context BottomUpMutatorContext) {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) base() *ModuleBase {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) Disable() {
+
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) Enabled(ctx ConfigurableEvaluatorContext) bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) Target() Target {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) MultiTargets() []Target {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) ImageVariation() blueprint.Variation {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) Owner() string {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInData() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInTestcases() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInSanitizerDir() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInRamdisk() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInVendorRamdisk() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInDebugRamdisk() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInRecovery() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInRoot() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInOdm() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInProduct() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInVendor() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInSystemExt() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInSystemDlkm() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInVendorDlkm() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInOdmDlkm() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallForceOS() (*OsType, *ArchType) {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) PartitionTag(d DeviceConfig) string {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) HideFromMake() {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) IsHideFromMake() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) SkipInstall() {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) IsSkipInstall() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) MakeUninstallable() {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) ReplacedByPrebuilt() {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) IsReplacedByPrebuilt() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) ExportedToMake() bool {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) EffectiveLicenseFiles() Paths {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) AddProperties(props ...interface{}) {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) GetProperties() []interface{} {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) BuildParamsForTests() []BuildParams {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) VariablesForTests() map[string]string {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) String() string {
+ return m.module.String()
+}
+
+func (m ModuleProxy) qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleName {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) visibilityProperties() []visibilityProperty {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) HostRequiredModuleNames() []string {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) TargetRequiredModuleNames() []string {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) VintfFragmentModuleNames(ctx ConfigurableEvaluatorContext) []string {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) ConfigurableEvaluator(ctx ConfigurableEvaluatorContext) proptools.ConfigurableEvaluator {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) DecodeMultilib(ctx ConfigContext) (string, string) {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) Overrides() []string {
+ panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) VintfFragments(ctx ConfigurableEvaluatorContext) []string {
+ panic("method is not implemented on ModuleProxy")
+}
diff --git a/android/module_test.go b/android/module_test.go
index 92041ec..6e6d449 100644
--- a/android/module_test.go
+++ b/android/module_test.go
@@ -327,21 +327,21 @@
outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) }
installRule := func(name string) TestingBuildParams {
- return module(name, false).Output(filepath.Join("out/soong/target/product/test_device/system", name))
+ return module(name, false).Output(filepath.Join("out/target/product/test_device/system", name))
}
symlinkRule := func(name string) TestingBuildParams {
- return module(name, false).Output(filepath.Join("out/soong/target/product/test_device/system/symlinks", name))
+ return module(name, false).Output(filepath.Join("out/target/product/test_device/system/symlinks", name))
}
hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) }
hostInstallRule := func(name string) TestingBuildParams {
- return module(name, true).Output(filepath.Join("out/soong/host/linux-x86", name))
+ return module(name, true).Output(filepath.Join("out/host/linux-x86", name))
}
hostSymlinkRule := func(name string) TestingBuildParams {
- return module(name, true).Output(filepath.Join("out/soong/host/linux-x86/symlinks", name))
+ return module(name, true).Output(filepath.Join("out/host/linux-x86/symlinks", name))
}
assertInputs := func(params TestingBuildParams, inputs ...Path) {
@@ -722,6 +722,7 @@
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"},
@@ -997,6 +998,10 @@
return OutputFilesInfo{}
}
+func (p *pathContextAddMissingDependenciesWrapper) EqualModules(m1, m2 Module) bool {
+ return m1 == m2
+}
+
func TestOutputFileForModule(t *testing.T) {
testcases := []struct {
name string
@@ -1079,3 +1084,29 @@
})
}
}
+
+func TestVintfFragmentModulesChecksPartition(t *testing.T) {
+ bp := `
+ vintf_fragment {
+ name: "vintfModA",
+ src: "test_vintf_file",
+ vendor: true,
+ }
+ deps {
+ name: "modA",
+ vintf_fragment_modules: [
+ "vintfModA",
+ ]
+ }
+ `
+
+ testPreparer := GroupFixturePreparers(
+ PrepareForTestWithAndroidBuildComponents,
+ prepareForModuleTests,
+ )
+
+ testPreparer.
+ ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(
+ "Module .+ and Vintf_fragment .+ are installed to different partitions.")).
+ RunTestWithBp(t, bp)
+}
diff --git a/android/mutator.go b/android/mutator.go
index 38fb857..16b9ba0 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -26,17 +26,17 @@
// run Pre-deps mutators
// run depsMutator
// run PostDeps mutators
-// run FinalDeps mutators (CreateVariations disallowed in this phase)
+// run FinalDeps mutators (TransitionMutators disallowed in this phase)
// continue on to GenerateAndroidBuildActions
// collateGloballyRegisteredMutators constructs the list of mutators that have been registered
// with the InitRegistrationContext and will be used at runtime.
func collateGloballyRegisteredMutators() sortableComponents {
- return collateRegisteredMutators(preArch, preDeps, postDeps, finalDeps)
+ return collateRegisteredMutators(preArch, preDeps, postDeps, postApex, finalDeps)
}
// collateRegisteredMutators constructs a single list of mutators from the separate lists.
-func collateRegisteredMutators(preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc) sortableComponents {
+func collateRegisteredMutators(preArch, preDeps, postDeps, postApex, finalDeps []RegisterMutatorFunc) sortableComponents {
mctx := ®isterMutatorsContext{}
register := func(funcs []RegisterMutatorFunc) {
@@ -53,6 +53,8 @@
register(postDeps)
+ register(postApex)
+
mctx.finalPhase = true
register(finalDeps)
@@ -68,7 +70,7 @@
TopDown(name string, m TopDownMutator) MutatorHandle
BottomUp(name string, m BottomUpMutator) MutatorHandle
BottomUpBlueprint(name string, m blueprint.BottomUpMutator) MutatorHandle
- Transition(name string, m TransitionMutator)
+ Transition(name string, m TransitionMutator) TransitionMutatorHandle
}
type RegisterMutatorFunc func(RegisterMutatorsContext)
@@ -148,9 +150,10 @@
}
func registerArchMutator(ctx RegisterMutatorsContext) {
- ctx.BottomUpBlueprint("os", osMutator).Parallel()
+ ctx.Transition("os", &osTransitionMutator{})
+ ctx.BottomUp("image_begin", imageMutatorBeginMutator)
ctx.Transition("image", &imageTransitionMutator{})
- ctx.BottomUpBlueprint("arch", archMutator).Parallel()
+ ctx.Transition("arch", &archTransitionMutator{})
}
var preDeps = []RegisterMutatorFunc{
@@ -166,6 +169,8 @@
RegisterOverridePostDepsMutators,
}
+var postApex = []RegisterMutatorFunc{}
+
var finalDeps = []RegisterMutatorFunc{}
func PreArchMutators(f RegisterMutatorFunc) {
@@ -180,29 +185,18 @@
postDeps = append(postDeps, f)
}
-func FinalDepsMutators(f RegisterMutatorFunc) {
- finalDeps = append(finalDeps, f)
+func PostApexMutators(f RegisterMutatorFunc) {
+ postApex = append(postApex, f)
}
-type BaseMutatorContext interface {
- BaseModuleContext
-
- // MutatorName returns the name that this mutator was registered with.
- MutatorName() string
-
- // 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)
+func FinalDepsMutators(f RegisterMutatorFunc) {
+ finalDeps = append(finalDeps, f)
}
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
+ BaseModuleContext
}
type topDownMutatorContext struct {
@@ -213,64 +207,40 @@
type BottomUpMutator func(BottomUpMutatorContext)
type BottomUpMutatorContext interface {
- BaseMutatorContext
+ BaseModuleContext
// AddDependency adds a dependency to the given module. It returns a slice of modules for each
// dependency (some entries may be nil).
//
- // If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
- // new dependencies have had the current mutator called on them. If the mutator is not
- // parallel this method does not affect the ordering of the current mutator pass, but will
- // be ordered correctly for all future mutator passes.
- AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []blueprint.Module
+ // This method will pause until the new dependencies have had the current mutator called on them.
+ AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []Module
// AddReverseDependency adds a dependency from the destination to the given module.
// Does not affect the ordering of the current mutator pass, but will be ordered
// correctly for all future mutator passes. All reverse dependencies for a destination module are
// collected until the end of the mutator pass, sorted by name, and then appended to the destination
- // module's dependency list.
+ // module's dependency list. May only be called by mutators that were marked with
+ // UsesReverseDependencies during registration.
AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string)
- // CreateVariations splits a module into multiple variants, one for each name in the variationNames
- // parameter. It returns a list of new modules in the same order as the variationNames
- // list.
- //
- // If any of the dependencies of the module being operated on were already split
- // by calling CreateVariations with the same name, the dependency will automatically
- // be updated to point the matching variant.
- //
- // If a module is split, and then a module depending on the first module is not split
- // when the Mutator is later called on it, the dependency of the depending module will
- // automatically be updated to point to the first variant.
- CreateVariations(...string) []Module
-
- // CreateLocationVariations splits a module into multiple variants, one for each name in the variantNames
- // parameter. It returns a list of new modules in the same order as the variantNames
- // list.
- //
- // Local variations do not affect automatic dependency resolution - dependencies added
- // to the split module via deps or DynamicDependerModule must exactly match a variant
- // that contains all the non-local variations.
- CreateLocalVariations(...string) []Module
-
- // SetDependencyVariation sets all dangling dependencies on the current module to point to the variation
- // with given name. This function ignores the default variation set by SetDefaultDependencyVariation.
- SetDependencyVariation(string)
-
- // SetDefaultDependencyVariation sets the default variation when a dangling reference is detected
- // during the subsequent calls on Create*Variations* functions. To reset, set it to nil.
- SetDefaultDependencyVariation(*string)
-
// AddVariationDependencies adds deps as dependencies of the current module, but uses the variations
// argument to select which variant of the dependency to use. It returns a slice of modules for
// each dependency (some entries may be nil). A variant of the dependency must exist that matches
// all the non-local variations of the current module, plus the variations argument.
//
- // If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
- // new dependencies have had the current mutator called on them. If the mutator is not
- // parallel this method does not affect the ordering of the current mutator pass, but will
- // be ordered correctly for all future mutator passes.
- AddVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag, names ...string) []blueprint.Module
+ // This method will pause until the new dependencies have had the current mutator called on them.
+ AddVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag, names ...string) []Module
+
+ // AddReverseVariationDependency adds a dependency from the named module to the current
+ // module. The given variations will be added to the current module's varations, and then the
+ // result will be used to find the correct variation of the depending module, which must exist.
+ //
+ // Does not affect the ordering of the current mutator pass, but will be ordered
+ // correctly for all future mutator passes. All reverse dependencies for a destination module are
+ // collected until the end of the mutator pass, sorted by name, and then appended to the destination
+ // module's dependency list. May only be called by mutators that were marked with
+ // UsesReverseDependencies during registration.
+ AddReverseVariationDependency([]blueprint.Variation, blueprint.DependencyTag, string)
// AddFarVariationDependencies adds deps as dependencies of the current module, but uses the
// variations argument to select which variant of the dependency to use. It returns a slice of
@@ -281,52 +251,31 @@
// Unlike AddVariationDependencies, the variations of the current module are ignored - the
// dependency only needs to match the supplied variations.
//
- // If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
- // new dependencies have had the current mutator called on them. If the mutator is not
- // parallel this method does not affect the ordering of the current mutator pass, but will
- // be ordered correctly for all future mutator passes.
- AddFarVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string) []blueprint.Module
-
- // AddInterVariantDependency adds a dependency between two variants of the same module. Variants are always
- // ordered in the same orderas they were listed in CreateVariations, and AddInterVariantDependency does not change
- // that ordering, but it associates a DependencyTag with the dependency and makes it visible to VisitDirectDeps,
- // WalkDeps, etc.
- AddInterVariantDependency(tag blueprint.DependencyTag, from, to blueprint.Module)
+ // This method will pause until the new dependencies have had the current mutator called on them.
+ AddFarVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string) []Module
// ReplaceDependencies finds all the variants of the module with the specified name, then
// replaces all dependencies onto those variants with the current variant of this module.
- // Replacements don't take effect until after the mutator pass is finished.
+ // Replacements don't take effect until after the mutator pass is finished. May only
+ // be called by mutators that were marked with UsesReplaceDependencies during registration.
ReplaceDependencies(string)
// ReplaceDependenciesIf finds all the variants of the module with the specified name, then
// replaces all dependencies onto those variants with the current variant of this module
// as long as the supplied predicate returns true.
- // Replacements don't take effect until after the mutator pass is finished.
+ // Replacements don't take effect until after the mutator pass is finished. May only
+ // be called by mutators that were marked with UsesReplaceDependencies during registration.
ReplaceDependenciesIf(string, blueprint.ReplaceDependencyPredicate)
- // AliasVariation takes a variationName that was passed to CreateVariations for this module,
- // and creates an alias from the current variant (before the mutator has run) to the new
- // variant. The alias will be valid until the next time a mutator calls CreateVariations or
- // CreateLocalVariations on this module without also calling AliasVariation. The alias can
- // be used to add dependencies on the newly created variant using the variant map from
- // before CreateVariations was run.
- AliasVariation(variationName string)
+ // 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. May only be called
+ // by mutators that were marked with UsesRename during registration.
+ Rename(name string)
- // CreateAliasVariation takes a toVariationName that was passed to CreateVariations for this
- // module, and creates an alias from a new fromVariationName variant the toVariationName
- // variant. The alias will be valid until the next time a mutator calls CreateVariations or
- // CreateLocalVariations on this module without also calling AliasVariation. The alias can
- // be used to add dependencies on the toVariationName variant using the fromVariationName
- // variant.
- CreateAliasVariation(fromVariationName, toVariationName string)
-
- // SetVariationProvider sets the value for a provider for the given newly created variant of
- // the current module, i.e. one of the Modules returned by CreateVariations.. It panics if
- // not called during the appropriate mutator or GenerateBuildActions pass for the provider,
- // if the value is not of the appropriate type, or if the module is not a newly created
- // variant of the current module. The value should not be modified after being passed to
- // SetVariationProvider.
- SetVariationProvider(module blueprint.Module, provider blueprint.AnyProviderKey, value interface{})
+ // 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. May only
+ // be called by mutators that were marked with UsesCreateModule during registration.
+ CreateModule(ModuleFactory, ...interface{}) Module
}
// An outgoingTransitionContextImpl and incomingTransitionContextImpl is created for every dependency of every module
@@ -388,237 +337,7 @@
return mutator
}
-type IncomingTransitionContext interface {
- ArchModuleContext
- ModuleProviderContext
-
- // Module returns the target of the dependency edge for which the transition
- // is being computed
- Module() Module
-
- // Config returns the configuration for the build.
- 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 {
- ArchModuleContext
- ModuleProviderContext
-
- // Module returns the target of the dependency edge for which the transition
- // is being computed
- Module() Module
-
- // DepTag() Returns the dependency tag through which this dependency is
- // reached
- DepTag() blueprint.DependencyTag
-
- // Config returns the configuration for the build.
- Config() Config
-
- DeviceConfig() DeviceConfig
-}
-
-// TransitionMutator implements a top-down mechanism where a module tells its
-// direct dependencies what variation they should be built in but the dependency
-// has the final say.
-//
-// When implementing a transition mutator, one needs to implement four methods:
-// - Split() that tells what variations a module has by itself
-// - OutgoingTransition() where a module tells what it wants from its
-// dependency
-// - IncomingTransition() where a module has the final say about its own
-// variation
-// - Mutate() that changes the state of a module depending on its variation
-//
-// That the effective variation of module B when depended on by module A is the
-// composition the outgoing transition of module A and the incoming transition
-// of module B.
-//
-// the outgoing transition should not take the properties of the dependency into
-// account, only those of the module that depends on it. For this reason, the
-// dependency is not even passed into it as an argument. Likewise, the incoming
-// transition should not take the properties of the depending module into
-// account and is thus not informed about it. This makes for a nice
-// decomposition of the decision logic.
-//
-// A given transition mutator only affects its own variation; other variations
-// stay unchanged along the dependency edges.
-//
-// Soong makes sure that all modules are created in the desired variations and
-// that dependency edges are set up correctly. This ensures that "missing
-// variation" errors do not happen and allows for more flexible changes in the
-// value of the variation among dependency edges (as oppposed to bottom-up
-// mutators where if module A in variation X depends on module B and module B
-// has that variation X, A must depend on variation X of B)
-//
-// The limited power of the context objects passed to individual mutators
-// methods also makes it more difficult to shoot oneself in the foot. Complete
-// safety is not guaranteed because no one prevents individual transition
-// mutators from mutating modules in illegal ways and for e.g. Split() or
-// Mutate() to run their own visitations of the transitive dependency of the
-// module and both of these are bad ideas, but it's better than no guardrails at
-// all.
-//
-// This model is pretty close to Bazel's configuration transitions. The mapping
-// between concepts in Soong and Bazel is as follows:
-// - Module == configured target
-// - Variant == configuration
-// - Variation name == configuration flag
-// - Variation == configuration flag value
-// - Outgoing transition == attribute transition
-// - Incoming transition == rule transition
-//
-// The Split() method does not have a Bazel equivalent and Bazel split
-// transitions do not have a Soong equivalent.
-//
-// Mutate() does not make sense in Bazel due to the different models of the
-// two systems: when creating new variations, Soong clones the old module and
-// thus some way is needed to change it state whereas Bazel creates each
-// configuration of a given configured target anew.
-type TransitionMutator interface {
- // Split returns the set of variations that should be created for a module no
- // matter who depends on it. Used when Make depends on a particular variation
- // or when the module knows its variations just based on information given to
- // it in the Blueprint file. This method should not mutate the module it is
- // called on.
- Split(ctx BaseModuleContext) []string
-
- // OutgoingTransition is called on a module to determine which variation it wants
- // from its direct dependencies. The dependency itself can override this decision.
- // This method should not mutate the module itself.
- OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string
-
- // IncomingTransition is called on a module to determine which variation it should
- // be in based on the variation modules that depend on it want. This gives the module
- // a final say about its own variations. This method should not mutate the module
- // itself.
- IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string
-
- // Mutate is called after a module was split into multiple variations on each variation.
- // It should not split the module any further but adding new dependencies is
- // fine. Unlike all the other methods on TransitionMutator, this method is
- // allowed to mutate the module.
- Mutate(ctx BottomUpMutatorContext, variation string)
-}
-
-type androidTransitionMutator struct {
- finalPhase bool
- mutator TransitionMutator
- name string
-}
-
-func (a *androidTransitionMutator) Split(ctx blueprint.BaseModuleContext) []string {
- if m, ok := ctx.Module().(Module); ok {
- moduleContext := m.base().baseModuleContextFactory(ctx)
- return a.mutator.Split(&moduleContext)
- } else {
- return []string{""}
- }
-}
-
-type outgoingTransitionContextImpl struct {
- archModuleContext
- bp blueprint.OutgoingTransitionContext
-}
-
-func (c *outgoingTransitionContextImpl) Module() Module {
- return c.bp.Module().(Module)
-}
-
-func (c *outgoingTransitionContextImpl) DepTag() blueprint.DependencyTag {
- return c.bp.DepTag()
-}
-
-func (c *outgoingTransitionContextImpl) Config() Config {
- return c.bp.Config().(Config)
-}
-
-func (c *outgoingTransitionContextImpl) DeviceConfig() DeviceConfig {
- return DeviceConfig{c.bp.Config().(Config).deviceConfig}
-}
-
-func (c *outgoingTransitionContextImpl) provider(provider blueprint.AnyProviderKey) (any, bool) {
- return c.bp.Provider(provider)
-}
-
-func (a *androidTransitionMutator) OutgoingTransition(bpctx blueprint.OutgoingTransitionContext, sourceVariation string) string {
- if m, ok := bpctx.Module().(Module); ok {
- ctx := outgoingTransitionContextPool.Get().(*outgoingTransitionContextImpl)
- defer outgoingTransitionContextPool.Put(ctx)
- *ctx = outgoingTransitionContextImpl{
- archModuleContext: m.base().archModuleContextFactory(bpctx),
- bp: bpctx,
- }
- return a.mutator.OutgoingTransition(ctx, sourceVariation)
- } else {
- return ""
- }
-}
-
-type incomingTransitionContextImpl struct {
- archModuleContext
- bp blueprint.IncomingTransitionContext
-}
-
-func (c *incomingTransitionContextImpl) Module() Module {
- return c.bp.Module().(Module)
-}
-
-func (c *incomingTransitionContextImpl) Config() Config {
- return c.bp.Config().(Config)
-}
-
-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)
-}
-
-func (a *androidTransitionMutator) IncomingTransition(bpctx blueprint.IncomingTransitionContext, incomingVariation string) string {
- if m, ok := bpctx.Module().(Module); ok {
- ctx := incomingTransitionContextPool.Get().(*incomingTransitionContextImpl)
- defer incomingTransitionContextPool.Put(ctx)
- *ctx = incomingTransitionContextImpl{
- archModuleContext: m.base().archModuleContextFactory(bpctx),
- bp: bpctx,
- }
- return a.mutator.IncomingTransition(ctx, incomingVariation)
- } else {
- return ""
- }
-}
-
-func (a *androidTransitionMutator) Mutate(ctx blueprint.BottomUpMutatorContext, variation string) {
- if am, ok := ctx.Module().(Module); ok {
- if variation != "" {
- // TODO: this should really be checking whether the TransitionMutator affected this module, not
- // the empty variant, but TransitionMutator has no concept of skipping a module.
- base := am.base()
- base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, a.name)
- base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variation)
- }
-
- mctx := bottomUpMutatorContextFactory(ctx, am, a.finalPhase)
- defer bottomUpMutatorContextPool.Put(mctx)
- a.mutator.Mutate(mctx, variation)
- }
-}
-
-func (x *registerMutatorsContext) Transition(name string, m TransitionMutator) {
+func (x *registerMutatorsContext) Transition(name string, m TransitionMutator) TransitionMutatorHandle {
atm := &androidTransitionMutator{
finalPhase: x.finalPhase,
mutator: m,
@@ -626,8 +345,10 @@
}
mutator := &mutator{
name: name,
- transitionMutator: atm}
+ transitionMutator: atm,
+ }
x.mutators = append(x.mutators, mutator)
+ return mutator
}
func (x *registerMutatorsContext) mutatorName(name string) string {
@@ -664,24 +385,114 @@
} else if mutator.topDownMutator != nil {
handle = blueprintCtx.RegisterTopDownMutator(mutator.name, mutator.topDownMutator)
} else if mutator.transitionMutator != nil {
- blueprintCtx.RegisterTransitionMutator(mutator.name, mutator.transitionMutator)
+ handle := blueprintCtx.RegisterTransitionMutator(mutator.name, mutator.transitionMutator)
+ if mutator.neverFar {
+ handle.NeverFar()
+ }
}
- if mutator.parallel {
- handle.Parallel()
+
+ // Forward booleans set on the MutatorHandle to the blueprint.MutatorHandle.
+ if mutator.usesRename {
+ handle.UsesRename()
+ }
+ if mutator.usesReverseDependencies {
+ handle.UsesReverseDependencies()
+ }
+ if mutator.usesReplaceDependencies {
+ handle.UsesReplaceDependencies()
+ }
+ if mutator.usesCreateModule {
+ handle.UsesCreateModule()
+ }
+ if mutator.mutatesDependencies {
+ handle.MutatesDependencies()
+ }
+ if mutator.mutatesGlobalState {
+ handle.MutatesGlobalState()
}
}
type MutatorHandle interface {
+ // Parallel sets the mutator to visit modules in parallel while maintaining ordering. Calling any
+ // method on the mutator context is thread-safe, but the mutator must handle synchronization
+ // for any modifications to global state or any modules outside the one it was invoked on.
+ // Deprecated: all Mutators are parallel by default.
Parallel() MutatorHandle
+
+ // UsesRename marks the mutator as using the BottomUpMutatorContext.Rename method, which prevents
+ // coalescing adjacent mutators into a single mutator pass.
+ UsesRename() MutatorHandle
+
+ // UsesReverseDependencies marks the mutator as using the BottomUpMutatorContext.AddReverseDependency
+ // method, which prevents coalescing adjacent mutators into a single mutator pass.
+ UsesReverseDependencies() MutatorHandle
+
+ // UsesReplaceDependencies marks the mutator as using the BottomUpMutatorContext.ReplaceDependencies
+ // method, which prevents coalescing adjacent mutators into a single mutator pass.
+ UsesReplaceDependencies() MutatorHandle
+
+ // UsesCreateModule marks the mutator as using the BottomUpMutatorContext.CreateModule method,
+ // which prevents coalescing adjacent mutators into a single mutator pass.
+ UsesCreateModule() MutatorHandle
+
+ // MutatesDependencies marks the mutator as modifying properties in dependencies, which prevents
+ // coalescing adjacent mutators into a single mutator pass.
+ MutatesDependencies() MutatorHandle
+
+ // MutatesGlobalState marks the mutator as modifying global state, which prevents coalescing
+ // adjacent mutators into a single mutator pass.
+ MutatesGlobalState() MutatorHandle
+}
+
+type TransitionMutatorHandle interface {
+ // NeverFar causes the variations created by this mutator to never be ignored when adding
+ // far variation dependencies. Normally, far variation dependencies ignore all the variants
+ // of the source module, and only use the variants explicitly requested by the
+ // AddFarVariationDependencies call.
+ NeverFar() MutatorHandle
}
func (mutator *mutator) Parallel() MutatorHandle {
- mutator.parallel = true
+ return mutator
+}
+
+func (mutator *mutator) UsesRename() MutatorHandle {
+ mutator.usesRename = true
+ return mutator
+}
+
+func (mutator *mutator) UsesReverseDependencies() MutatorHandle {
+ mutator.usesReverseDependencies = true
+ return mutator
+}
+
+func (mutator *mutator) UsesReplaceDependencies() MutatorHandle {
+ mutator.usesReplaceDependencies = true
+ return mutator
+}
+
+func (mutator *mutator) UsesCreateModule() MutatorHandle {
+ mutator.usesCreateModule = true
+ return mutator
+}
+
+func (mutator *mutator) MutatesDependencies() MutatorHandle {
+ mutator.mutatesDependencies = true
+ return mutator
+}
+
+func (mutator *mutator) MutatesGlobalState() MutatorHandle {
+ mutator.mutatesGlobalState = true
+ return mutator
+}
+
+func (mutator *mutator) NeverFar() MutatorHandle {
+ mutator.neverFar = true
return mutator
}
func RegisterComponentsMutator(ctx RegisterMutatorsContext) {
- ctx.BottomUp("component-deps", componentDepsMutator).Parallel()
+ ctx.BottomUp("component-deps", componentDepsMutator)
}
// A special mutator that runs just prior to the deps mutator to allow the dependencies
@@ -699,7 +510,7 @@
}
func registerDepsMutator(ctx RegisterMutatorsContext) {
- ctx.BottomUp("deps", depsMutator).Parallel()
+ ctx.BottomUp("deps", depsMutator).UsesReverseDependencies()
}
// android.topDownMutatorContext either has to embed blueprint.TopDownMutatorContext, in which case every method that
@@ -708,42 +519,28 @@
// non-overridden method has to be forwarded. There are fewer non-overridden methods, so use the latter. The following
// methods forward to the identical blueprint versions for topDownMutatorContext and bottomUpMutatorContext.
-func (t *topDownMutatorContext) MutatorName() string {
- return t.bp.MutatorName()
-}
-
-func (t *topDownMutatorContext) Rename(name string) {
- t.bp.Rename(name)
- t.Module().base().commonProperties.DebugName = name
-}
-
-func (t *topDownMutatorContext) createModule(factory blueprint.ModuleFactory, name string, props ...interface{}) blueprint.Module {
- return t.bp.CreateModule(factory, name, props...)
-}
-
-func (t *topDownMutatorContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
- return createModule(t, factory, "_topDownMutatorModule", props...)
-}
-
-func (t *topDownMutatorContext) createModuleWithoutInheritance(factory ModuleFactory, props ...interface{}) Module {
- module := t.bp.CreateModule(ModuleFactoryAdaptor(factory), "", props...).(Module)
- return module
-}
-
-func (b *bottomUpMutatorContext) MutatorName() string {
- return b.bp.MutatorName()
-}
-
func (b *bottomUpMutatorContext) Rename(name string) {
b.bp.Rename(name)
b.Module().base().commonProperties.DebugName = name
}
-func (b *bottomUpMutatorContext) AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []blueprint.Module {
+func (b *bottomUpMutatorContext) createModule(factory blueprint.ModuleFactory, name string, props ...interface{}) Module {
+ return bpModuleToModule(b.bp.CreateModule(factory, name, props...))
+}
+
+func (b *bottomUpMutatorContext) createModuleInDirectory(factory blueprint.ModuleFactory, name string, _ string, props ...interface{}) Module {
+ panic("createModuleInDirectory is not implemented for bottomUpMutatorContext")
+}
+
+func (b *bottomUpMutatorContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
+ return createModule(b, factory, "_bottomUpMutatorModule", doesNotSpecifyDirectory(), props...)
+}
+
+func (b *bottomUpMutatorContext) AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []Module {
if b.baseModuleContext.checkedMissingDeps() {
panic("Adding deps not allowed after checking for missing deps")
}
- return b.bp.AddDependency(module, tag, name...)
+ return bpModulesToModules(b.bp.AddDependency(module, tag, name...))
}
func (b *bottomUpMutatorContext) AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string) {
@@ -753,69 +550,28 @@
b.bp.AddReverseDependency(module, tag, name)
}
-func (b *bottomUpMutatorContext) CreateVariations(variations ...string) []Module {
- if b.finalPhase {
- panic("CreateVariations not allowed in FinalDepsMutators")
+func (b *bottomUpMutatorContext) AddReverseVariationDependency(variations []blueprint.Variation, tag blueprint.DependencyTag, name string) {
+ if b.baseModuleContext.checkedMissingDeps() {
+ panic("Adding deps not allowed after checking for missing deps")
}
-
- modules := b.bp.CreateVariations(variations...)
-
- aModules := make([]Module, len(modules))
- for i := range variations {
- aModules[i] = modules[i].(Module)
- base := aModules[i].base()
- base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, b.MutatorName())
- base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variations[i])
- }
-
- return aModules
-}
-
-func (b *bottomUpMutatorContext) CreateLocalVariations(variations ...string) []Module {
- if b.finalPhase {
- panic("CreateLocalVariations not allowed in FinalDepsMutators")
- }
-
- modules := b.bp.CreateLocalVariations(variations...)
-
- aModules := make([]Module, len(modules))
- for i := range variations {
- aModules[i] = modules[i].(Module)
- base := aModules[i].base()
- base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, b.MutatorName())
- base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variations[i])
- }
-
- return aModules
-}
-
-func (b *bottomUpMutatorContext) SetDependencyVariation(variation string) {
- b.bp.SetDependencyVariation(variation)
-}
-
-func (b *bottomUpMutatorContext) SetDefaultDependencyVariation(variation *string) {
- b.bp.SetDefaultDependencyVariation(variation)
+ b.bp.AddReverseVariationDependency(variations, tag, name)
}
func (b *bottomUpMutatorContext) AddVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag,
- names ...string) []blueprint.Module {
+ names ...string) []Module {
if b.baseModuleContext.checkedMissingDeps() {
panic("Adding deps not allowed after checking for missing deps")
}
- return b.bp.AddVariationDependencies(variations, tag, names...)
+ return bpModulesToModules(b.bp.AddVariationDependencies(variations, tag, names...))
}
func (b *bottomUpMutatorContext) AddFarVariationDependencies(variations []blueprint.Variation,
- tag blueprint.DependencyTag, names ...string) []blueprint.Module {
+ tag blueprint.DependencyTag, names ...string) []Module {
if b.baseModuleContext.checkedMissingDeps() {
panic("Adding deps not allowed after checking for missing deps")
}
- return b.bp.AddFarVariationDependencies(variations, tag, names...)
-}
-
-func (b *bottomUpMutatorContext) AddInterVariantDependency(tag blueprint.DependencyTag, from, to blueprint.Module) {
- b.bp.AddInterVariantDependency(tag, from, to)
+ return bpModulesToModules(b.bp.AddFarVariationDependencies(variations, tag, names...))
}
func (b *bottomUpMutatorContext) ReplaceDependencies(name string) {
@@ -832,14 +588,17 @@
b.bp.ReplaceDependenciesIf(name, predicate)
}
-func (b *bottomUpMutatorContext) AliasVariation(variationName string) {
- b.bp.AliasVariation(variationName)
+func bpModulesToModules(bpModules []blueprint.Module) []Module {
+ modules := make([]Module, len(bpModules))
+ for i, bpModule := range bpModules {
+ modules[i] = bpModuleToModule(bpModule)
+ }
+ return modules
}
-func (b *bottomUpMutatorContext) CreateAliasVariation(fromVariationName, toVariationName string) {
- b.bp.CreateAliasVariation(fromVariationName, toVariationName)
-}
-
-func (b *bottomUpMutatorContext) SetVariationProvider(module blueprint.Module, provider blueprint.AnyProviderKey, value interface{}) {
- b.bp.SetVariationProvider(module, provider, value)
+func bpModuleToModule(bpModule blueprint.Module) Module {
+ if bpModule != nil {
+ return bpModule.(Module)
+ }
+ return nil
}
diff --git a/android/mutator_test.go b/android/mutator_test.go
index 21eebd2..60a6119 100644
--- a/android/mutator_test.go
+++ b/android/mutator_test.go
@@ -17,6 +17,8 @@
import (
"fmt"
"strings"
+ "sync"
+ "sync/atomic"
"testing"
"github.com/google/blueprint"
@@ -81,97 +83,6 @@
AssertDeepEquals(t, "foo missing deps", []string{"added_missing_dep", "regular_missing_dep"}, foo.missingDeps)
}
-func TestModuleString(t *testing.T) {
- bp := `
- test {
- name: "foo",
- }
- `
-
- var moduleStrings []string
-
- GroupFixturePreparers(
- 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.TopDown("rename_top_down", func(ctx TopDownMutatorContext) {
- moduleStrings = append(moduleStrings, ctx.Module().String())
- ctx.Rename(ctx.Module().base().Name() + "_renamed1")
- })
- })
-
- ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
- ctx.BottomUp("pre_deps", func(ctx BottomUpMutatorContext) {
- moduleStrings = append(moduleStrings, ctx.Module().String())
- ctx.CreateVariations("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.BottomUp("rename_bottom_up", func(ctx BottomUpMutatorContext) {
- moduleStrings = append(moduleStrings, ctx.Module().String())
- ctx.Rename(ctx.Module().base().Name() + "_renamed2")
- })
- ctx.BottomUp("final", func(ctx BottomUpMutatorContext) {
- moduleStrings = append(moduleStrings, ctx.Module().String())
- })
- })
-
- ctx.RegisterModuleType("test", mutatorTestModuleFactory)
- }),
- FixtureWithRootAndroidBp(bp),
- ).RunTest(t)
-
- want := []string{
- // Initial name.
- "foo{}",
-
- // After pre_arch (reversed because rename_top_down is TopDown so it visits in reverse order).
- "foo{pre_arch:b}",
- "foo{pre_arch:a}",
-
- // After rename_top_down.
- "foo_renamed1{pre_arch:a}",
- "foo_renamed1{pre_arch:b}",
-
- // 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}",
- "foo_renamed1{pre_arch:b,pre_deps:d}",
-
- // After post_deps.
- "foo_renamed1{pre_arch:a,pre_deps:c,post_deps:e}",
- "foo_renamed1{pre_arch:a,pre_deps:c,post_deps:f}",
- "foo_renamed1{pre_arch:a,pre_deps:d,post_deps:e}",
- "foo_renamed1{pre_arch:a,pre_deps:d,post_deps:f}",
- "foo_renamed1{pre_arch:b,pre_deps:c,post_deps:e}",
- "foo_renamed1{pre_arch:b,pre_deps:c,post_deps:f}",
- "foo_renamed1{pre_arch:b,pre_deps:d,post_deps:e}",
- "foo_renamed1{pre_arch:b,pre_deps:d,post_deps:f}",
-
- // After rename_bottom_up.
- "foo_renamed2{pre_arch:a,pre_deps:c,post_deps:e}",
- "foo_renamed2{pre_arch:a,pre_deps:c,post_deps:f}",
- "foo_renamed2{pre_arch:a,pre_deps:d,post_deps:e}",
- "foo_renamed2{pre_arch:a,pre_deps:d,post_deps:f}",
- "foo_renamed2{pre_arch:b,pre_deps:c,post_deps:e}",
- "foo_renamed2{pre_arch:b,pre_deps:c,post_deps:f}",
- "foo_renamed2{pre_arch:b,pre_deps:d,post_deps:e}",
- "foo_renamed2{pre_arch:b,pre_deps:d,post_deps:f}",
- }
-
- AssertDeepEquals(t, "module String() values", want, moduleStrings)
-}
-
func TestFinalDepsPhase(t *testing.T) {
bp := `
test {
@@ -185,7 +96,7 @@
}
`
- finalGot := map[string]int{}
+ finalGot := sync.Map{}
GroupFixturePreparers(
FixtureRegisterWithContext(func(ctx RegistrationContext) {
@@ -202,8 +113,10 @@
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"}
+ },
})
})
@@ -214,9 +127,11 @@
}
})
ctx.BottomUp("final", func(ctx BottomUpMutatorContext) {
- finalGot[ctx.Module().String()] += 1
+ counter, _ := finalGot.LoadOrStore(ctx.Module().String(), &atomic.Int64{})
+ counter.(*atomic.Int64).Add(1)
ctx.VisitDirectDeps(func(mod Module) {
- finalGot[fmt.Sprintf("%s -> %s", ctx.Module().String(), mod)] += 1
+ counter, _ := finalGot.LoadOrStore(fmt.Sprintf("%s -> %s", ctx.Module().String(), mod), &atomic.Int64{})
+ counter.(*atomic.Int64).Add(1)
})
})
})
@@ -239,31 +154,11 @@
"foo{variant:b} -> common_dep_2{variant:a}": 1,
}
- AssertDeepEquals(t, "final", finalWant, finalGot)
-}
+ finalGotMap := make(map[string]int)
+ finalGot.Range(func(k, v any) bool {
+ finalGotMap[k.(string)] = int(v.(*atomic.Int64).Load())
+ return true
+ })
-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.RegisterModuleType("test", mutatorTestModuleFactory)
- }),
- FixtureWithRootAndroidBp(`test {name: "foo"}`),
- ).RunTest(t)
+ AssertDeepEquals(t, "final", finalWant, finalGotMap)
}
diff --git a/android/namespace.go b/android/namespace.go
index ebf85a1..9ba5025 100644
--- a/android/namespace.go
+++ b/android/namespace.go
@@ -332,7 +332,7 @@
if isAbs {
// if the user gave a fully-qualified name, we don't need to look for other
// modules that they might have been referring to
- return fmt.Errorf(text)
+ return fmt.Errorf("%s", text)
}
// determine which namespaces the module can be found in
@@ -368,7 +368,7 @@
text += fmt.Sprintf("\nOr did you mean %q?", guess)
}
- return fmt.Errorf(text)
+ return fmt.Errorf("%s", text)
}
func (r *NameResolver) GetNamespace(ctx blueprint.NamespaceContext) blueprint.Namespace {
@@ -457,7 +457,7 @@
}
func RegisterNamespaceMutator(ctx RegisterMutatorsContext) {
- ctx.BottomUp("namespace_deps", namespaceMutator).Parallel()
+ ctx.BottomUp("namespace_deps", namespaceMutator).MutatesGlobalState()
}
func namespaceMutator(ctx BottomUpMutatorContext) {
diff --git a/android/namespace_test.go b/android/namespace_test.go
index ea51c6e..0327e78 100644
--- a/android/namespace_test.go
+++ b/android/namespace_test.go
@@ -646,7 +646,7 @@
ctx.RegisterModuleType("test_module", newTestModule)
ctx.Context.RegisterModuleType("blueprint_test_module", newBlueprintTestModule)
ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
- ctx.BottomUp("rename", renameMutator)
+ ctx.BottomUp("rename", renameMutator).UsesRename()
})
}),
)
@@ -709,9 +709,6 @@
}
func (m *testModule) DepsMutator(ctx BottomUpMutatorContext) {
- if m.properties.Rename != "" {
- ctx.Rename(m.properties.Rename)
- }
for _, d := range m.properties.Deps {
ctx.AddDependency(ctx.Module(), nil, d)
}
diff --git a/android/neverallow.go b/android/neverallow.go
index 0f363e7..d345ee8 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -44,7 +44,7 @@
// - it has none of the "Without" properties matched (same rules as above)
func registerNeverallowMutator(ctx RegisterMutatorsContext) {
- ctx.BottomUp("neverallow", neverallowMutator).Parallel()
+ ctx.BottomUp("neverallow", neverallowMutator)
}
var neverallows = []Rule{}
@@ -55,11 +55,16 @@
AddNeverAllowRules(createJavaDeviceForHostRules()...)
AddNeverAllowRules(createCcSdkVariantRules()...)
AddNeverAllowRules(createUncompressDexRules()...)
- AddNeverAllowRules(createInitFirstStageRules()...)
+ AddNeverAllowRules(createInstallInRootAllowingRules()...)
AddNeverAllowRules(createProhibitFrameworkAccessRules()...)
AddNeverAllowRules(createCcStubsRule())
- AddNeverAllowRules(createJavaExcludeStaticLibsRule())
AddNeverAllowRules(createProhibitHeaderOnlyRule())
+ AddNeverAllowRules(createLimitNdkExportRule()...)
+ AddNeverAllowRules(createLimitDirgroupRule()...)
+ AddNeverAllowRules(createFilesystemIsAutoGeneratedRule())
+ AddNeverAllowRules(createKotlinPluginRule()...)
+ AddNeverAllowRules(createPrebuiltEtcBpDefineRule())
+ AddNeverAllowRules(createAutogenRroBpDefineRule())
}
// Add a NeverAllow rule to the set of rules to apply.
@@ -182,6 +187,7 @@
"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",
@@ -224,21 +230,27 @@
func createUncompressDexRules() []Rule {
return []Rule{
NeverAllow().
- NotIn("art").
+ NotIn("art", "cts/hostsidetests/compilation").
WithMatcher("uncompress_dex", isSetMatcherInstance).
Because("uncompress_dex is only allowed for certain jars for test in art."),
}
}
-func createInitFirstStageRules() []Rule {
+func createInstallInRootAllowingRules() []Rule {
return []Rule{
NeverAllow().
Without("name", "init_first_stage_defaults").
Without("name", "init_first_stage").
Without("name", "init_first_stage.microdroid").
+ Without("name", "librecovery_ui_ext").
With("install_in_root", "true").
NotModuleType("prebuilt_root").
- Because("install_in_root is only for init_first_stage."),
+ NotModuleType("prebuilt_vendor").
+ NotModuleType("prebuilt_sbin").
+ NotModuleType("prebuilt_system").
+ NotModuleType("prebuilt_first_stage_ramdisk").
+ NotModuleType("prebuilt_res").
+ Because("install_in_root is only for init_first_stage or librecovery_ui_ext."),
}
}
@@ -251,14 +263,6 @@
}
}
-func createJavaExcludeStaticLibsRule() Rule {
- return NeverAllow().
- NotIn("build/soong", "libcore", "frameworks/base/api").
- ModuleType("java_library").
- WithMatcher("exclude_static_libs", isSetMatcherInstance).
- Because("exclude_static_libs property is only allowed for java modules defined in build/soong, libcore, and frameworks/base/api")
-}
-
func createProhibitHeaderOnlyRule() Rule {
return NeverAllow().
Without("name", "framework-minus-apex-headers").
@@ -266,6 +270,119 @@
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 createLimitDirgroupRule() []Rule {
+ reason := "dirgroup module and dir_srcs / keep_gendir property of genrule is allowed only to Trusty build rule."
+ return []Rule{
+ NeverAllow().
+ ModuleType("dirgroup").
+ WithMatcher("visibility", NotInList([]string{"//trusty/vendor/google/aosp/scripts", "//trusty/vendor/google/proprietary/scripts"})).Because(reason),
+ NeverAllow().
+ ModuleType("dirgroup").
+ WithoutMatcher("visibility", InAllowedList([]string{"//trusty/vendor/google/aosp/scripts", "//trusty/vendor/google/proprietary/scripts"})).Because(reason),
+ NeverAllow().
+ ModuleType("genrule").
+ // TODO: remove the 4 below targets once new targets are submitted
+ Without("name", "trusty-arm64.lk.elf.gen").
+ Without("name", "trusty-arm64-virt-test-debug.lk.elf.gen").
+ Without("name", "trusty-x86_64.lk.elf.gen").
+ Without("name", "trusty-x86_64-test.lk.elf.gen").
+ // trusty vm target names moving forward
+ Without("name", "trusty-test_vm-arm64.elf.gen").
+ Without("name", "trusty-test_vm-x86.elf.gen").
+ Without("name", "trusty-security_vm-arm64.elf.gen").
+ Without("name", "trusty-security_vm-x86.elf.gen").
+ Without("name", "trusty-widevine_vm-arm64.elf.gen").
+ Without("name", "trusty-widevine_vm-x86.elf.gen").
+ WithMatcher("dir_srcs", isSetMatcherInstance).Because(reason),
+ NeverAllow().
+ ModuleType("genrule").
+ // TODO: remove the 4 below targets once new targets are submitted
+ Without("name", "trusty-arm64.lk.elf.gen").
+ Without("name", "trusty-arm64-virt-test-debug.lk.elf.gen").
+ Without("name", "trusty-x86_64.lk.elf.gen").
+ Without("name", "trusty-x86_64-test.lk.elf.gen").
+ // trusty vm target names moving forward
+ Without("name", "trusty-test_vm-arm64.elf.gen").
+ Without("name", "trusty-test_vm-x86.elf.gen").
+ Without("name", "trusty-security_vm-arm64.elf.gen").
+ Without("name", "trusty-security_vm-x86.elf.gen").
+ Without("name", "trusty-widevine_vm-arm64.elf.gen").
+ Without("name", "trusty-widevine_vm-x86.elf.gen").
+ With("keep_gendir", "true").Because(reason),
+ }
+}
+
+func createFilesystemIsAutoGeneratedRule() Rule {
+ return NeverAllow().
+ NotIn("build/soong/fsgen").
+ ModuleType("filesystem", "android_system_image").
+ WithMatcher("is_auto_generated", isSetMatcherInstance).
+ Because("is_auto_generated property is only allowed for filesystem modules in build/soong/fsgen directory")
+}
+
+func createKotlinPluginRule() []Rule {
+ kotlinPluginProjectsAllowedList := []string{
+ "external/kotlinc",
+ }
+
+ return []Rule{
+ NeverAllow().
+ NotIn(kotlinPluginProjectsAllowedList...).
+ ModuleType("kotlin_plugin").
+ Because("kotlin_plugin can only be used in allowed projects"),
+ }
+}
+
+// These module types are introduced to convert PRODUCT_COPY_FILES to Soong,
+// and is only intended to be used by filesystem_creator.
+func createPrebuiltEtcBpDefineRule() Rule {
+ return NeverAllow().
+ ModuleType(
+ "prebuilt_usr_srec",
+ "prebuilt_priv_app",
+ "prebuilt_rfs",
+ "prebuilt_framework",
+ "prebuilt_wlc_upt",
+ "prebuilt_odm",
+ "prebuilt_vendor_dlkm",
+ "prebuilt_bt_firmware",
+ "prebuilt_tvservice",
+ "prebuilt_optee",
+ "prebuilt_tvconfig",
+ "prebuilt_vendor",
+ "prebuilt_sbin",
+ "prebuilt_system",
+ "prebuilt_first_stage_ramdisk",
+ ).
+ DefinedInBpFile().
+ Because("module type not allowed to be defined in bp file")
+}
+
+func createAutogenRroBpDefineRule() Rule {
+ return NeverAllow().
+ ModuleType(
+ "autogen_runtime_resource_overlay",
+ ).
+ DefinedInBpFile().
+ Because("Module type will be autogenerated by soong. Use runtime_resource_overlay instead")
+}
+
func neverallowMutator(ctx BottomUpMutatorContext) {
m, ok := ctx.Module().(Module)
if !ok {
@@ -287,7 +404,7 @@
continue
}
- if !n.appliesToProperties(properties) {
+ if !n.appliesToProperties(ctx, properties) {
continue
}
@@ -299,6 +416,10 @@
continue
}
+ if !n.appliesToBpDefinedModule(ctx) {
+ continue
+ }
+
ctx.ModuleErrorf("violates " + n.String())
}
}
@@ -369,6 +490,18 @@
return ".not-in-list(" + strings.Join(m.allowed, ",") + ")"
}
+type InListMatcher struct {
+ allowed []string
+}
+
+func (m *InListMatcher) Test(value string) bool {
+ return InList(value, m.allowed)
+}
+
+func (m *InListMatcher) String() string {
+ return ".in-list(" + strings.Join(m.allowed, ",") + ")"
+}
+
type isSetMatcher struct{}
func (m *isSetMatcher) Test(value string) bool {
@@ -422,6 +555,8 @@
WithoutMatcher(properties string, matcher ValueMatcher) Rule
+ DefinedInBpFile() Rule
+
Because(reason string) Rule
}
@@ -443,6 +578,8 @@
unlessProps ruleProperties
onlyBootclasspathJar bool
+
+ definedInBp bool
}
// Create a new NeverAllow rule.
@@ -516,6 +653,13 @@
return r
}
+// DefinedInBpFile specifies that this rule applies to modules that are defined
+// in bp files, and does not apply to modules that are auto generated by other modules.
+func (r *rule) DefinedInBpFile() Rule {
+ r.definedInBp = true
+ return r
+}
+
func selectMatcher(expected string) ValueMatcher {
if expected == "*" {
return anyMatcherInstance
@@ -601,15 +745,25 @@
}
func (r *rule) appliesToModuleType(moduleType string) bool {
+ // Remove prefix for auto-generated modules
+ moduleType = strings.TrimSuffix(moduleType, "__loadHookModule")
+ moduleType = strings.TrimSuffix(moduleType, "__bottomUpMutatorModule")
return (len(r.moduleTypes) == 0 || InList(moduleType, r.moduleTypes)) && !InList(moduleType, r.unlessModuleTypes)
}
-func (r *rule) appliesToProperties(properties []interface{}) bool {
- includeProps := hasAllProperties(properties, r.props)
- excludeProps := hasAnyProperty(properties, r.unlessProps)
+func (r *rule) appliesToProperties(ctx BottomUpMutatorContext, properties []interface{}) bool {
+ includeProps := hasAllProperties(ctx, properties, r.props)
+ excludeProps := hasAnyProperty(ctx, properties, r.unlessProps)
return includeProps && !excludeProps
}
+func (r *rule) appliesToBpDefinedModule(ctx BottomUpMutatorContext) bool {
+ if !r.definedInBp {
+ return true
+ }
+ return !ctx.OtherModuleIsAutoGenerated(ctx.Module()) == r.definedInBp
+}
+
func StartsWith(prefix string) ValueMatcher {
return &startsWithMatcher{prefix}
}
@@ -626,6 +780,10 @@
return ¬InListMatcher{allowed}
}
+func InAllowedList(allowed []string) ValueMatcher {
+ return &InListMatcher{allowed}
+}
+
// assorted utils
func cleanPaths(paths []string) []string {
@@ -644,25 +802,25 @@
return names
}
-func hasAnyProperty(properties []interface{}, props []ruleProperty) bool {
+func hasAnyProperty(ctx BottomUpMutatorContext, properties []interface{}, props []ruleProperty) bool {
for _, v := range props {
- if hasProperty(properties, v) {
+ if hasProperty(ctx, properties, v) {
return true
}
}
return false
}
-func hasAllProperties(properties []interface{}, props []ruleProperty) bool {
+func hasAllProperties(ctx BottomUpMutatorContext, properties []interface{}, props []ruleProperty) bool {
for _, v := range props {
- if !hasProperty(properties, v) {
+ if !hasProperty(ctx, properties, v) {
return false
}
}
return true
}
-func hasProperty(properties []interface{}, prop ruleProperty) bool {
+func hasProperty(ctx BottomUpMutatorContext, properties []interface{}, prop ruleProperty) bool {
for _, propertyStruct := range properties {
propertiesValue := reflect.ValueOf(propertyStruct).Elem()
for _, v := range prop.fields {
@@ -679,14 +837,14 @@
return prop.matcher.Test(value)
}
- if matchValue(propertiesValue, check) {
+ if matchValue(ctx, propertiesValue, check) {
return true
}
}
return false
}
-func matchValue(value reflect.Value, check func(string) bool) bool {
+func matchValue(ctx BottomUpMutatorContext, value reflect.Value, check func(string) bool) bool {
if !value.IsValid() {
return false
}
@@ -698,19 +856,26 @@
value = value.Elem()
}
- switch value.Kind() {
- case reflect.String:
- return check(value.String())
- case reflect.Bool:
- return check(strconv.FormatBool(value.Bool()))
- case reflect.Int:
- return check(strconv.FormatInt(value.Int(), 10))
- case reflect.Slice:
- slice, ok := value.Interface().([]string)
- if !ok {
- panic("Can only handle slice of string")
+ switch v := value.Interface().(type) {
+ case string:
+ return check(v)
+ case bool:
+ return check(strconv.FormatBool(v))
+ case int:
+ return check(strconv.FormatInt((int64)(v), 10))
+ case []string:
+ for _, v := range v {
+ if check(v) {
+ return true
+ }
}
- for _, v := range slice {
+ return false
+ case proptools.Configurable[string]:
+ return check(v.GetOrDefault(ctx, ""))
+ case proptools.Configurable[bool]:
+ return check(strconv.FormatBool(v.GetOrDefault(ctx, false)))
+ case proptools.Configurable[[]string]:
+ for _, v := range v.GetOrDefault(ctx, nil) {
if check(v) {
return true
}
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index b2620ef..c74d5ff 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -344,23 +344,6 @@
`module "outside_allowed_list": violates neverallow`,
},
},
- // Test for the rule restricting use of exclude_static_libs
- {
- name: `"exclude_static_libs" outside allowed directory`,
- fs: map[string][]byte{
- "a/b/Android.bp": []byte(`
- java_library {
- name: "baz",
- exclude_static_libs: [
- "bar",
- ],
- }
- `),
- },
- expectedErrors: []string{
- `exclude_static_libs property is only allowed for java modules defined in build/soong, libcore, and frameworks/base/api`,
- },
- },
// Test for only allowing headers_only for framework-minus-apex-headers
{
name: `"headers_only" outside framework-minus-apex-headers modules`,
@@ -376,6 +359,35 @@
`headers_only can only be used for generating framework-minus-apex headers for non-updatable modules`,
},
},
+ // Test for the rule restricting use of is_auto_generated
+ {
+ name: `"is_auto_generated" outside allowed directory`,
+ fs: map[string][]byte{
+ "a/b/Android.bp": []byte(`
+ filesystem {
+ name: "baaz",
+ is_auto_generated: true,
+ }
+ `),
+ },
+ expectedErrors: []string{
+ `is_auto_generated property is only allowed for filesystem modules in build/soong/fsgen directory`,
+ },
+ },
+ // Test for the rule restricting use of prebuilt_* module
+ {
+ name: `"prebuilt_usr_srec" defined in Android.bp file`,
+ fs: map[string][]byte{
+ "a/b/Android.bp": []byte(`
+ prebuilt_usr_srec {
+ name: "foo",
+ }
+ `),
+ },
+ expectedErrors: []string{
+ `module type not allowed to be defined in bp file`,
+ },
+ },
}
var prepareForNeverAllowTest = GroupFixturePreparers(
@@ -384,6 +396,8 @@
ctx.RegisterModuleType("java_library", newMockJavaLibraryModule)
ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule)
ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule)
+ ctx.RegisterModuleType("filesystem", newMockFilesystemModule)
+ ctx.RegisterModuleType("prebuilt_usr_srec", newMockPrebuiltUsrSrecModule)
}),
)
@@ -483,3 +497,16 @@
func (p *mockJavaLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
}
+
+type mockPrebuiltUsrSrecModule struct {
+ ModuleBase
+}
+
+func (p *mockPrebuiltUsrSrecModule) GenerateAndroidBuildActions(ModuleContext) {
+}
+
+func newMockPrebuiltUsrSrecModule() Module {
+ m := &mockPrebuiltUsrSrecModule{}
+ InitAndroidModule(m)
+ return m
+}
diff --git a/android/nothing.go b/android/nothing.go
new file mode 100644
index 0000000..18bf85b
--- /dev/null
+++ b/android/nothing.go
@@ -0,0 +1,34 @@
+// Copyright 2025 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() {
+ RegisterParallelSingletonType("nothing_singleton", nothingSingletonFactory)
+}
+
+func nothingSingletonFactory() Singleton {
+ return ¬hingSingleton{}
+}
+
+type nothingSingleton struct{}
+
+func (s *nothingSingleton) GenerateBuildActions(ctx SingletonContext) {
+ rule := NewRuleBuilder(pctx, ctx)
+ rule.SetPhonyOutput()
+ rule.Command().
+ Text("echo Successfully read the makefiles.").
+ ImplicitOutput(PathForPhony(ctx, "nothing"))
+ rule.Build("nothing", "nothing")
+}
diff --git a/android/notices.go b/android/notices.go
index b9c1682..3c41d92 100644
--- a/android/notices.go
+++ b/android/notices.go
@@ -36,10 +36,22 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
// 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...)
diff --git a/android/override_module.go b/android/override_module.go
index f69f963..50ddc9b 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -234,17 +234,18 @@
// Mutators for override/overridable modules. All the fun happens in these functions. It is critical
// to keep them in this order and not put any order mutators between them.
func RegisterOverridePostDepsMutators(ctx RegisterMutatorsContext) {
- ctx.BottomUp("override_deps", overrideModuleDepsMutator).Parallel()
+ ctx.BottomUp("override_deps", overrideModuleDepsMutator).MutatesDependencies() // modifies deps via addOverride
ctx.Transition("override", &overrideTransitionMutator{})
+ ctx.BottomUp("override_apply", overrideApplyMutator).MutatesDependencies()
// overridableModuleDepsMutator calls OverridablePropertiesDepsMutator so that overridable modules can
// add deps from overridable properties.
- ctx.BottomUp("overridable_deps", overridableModuleDepsMutator).Parallel()
+ ctx.BottomUp("overridable_deps", overridableModuleDepsMutator)
// Because overridableModuleDepsMutator is run after PrebuiltPostDepsMutator,
// prebuilt's ReplaceDependencies doesn't affect to those deps added by overridable properties.
// By running PrebuiltPostDepsMutator again after overridableModuleDepsMutator, deps via overridable properties
// can be replaced with prebuilts.
- ctx.BottomUp("replace_deps_on_prebuilts_for_overridable_deps_again", PrebuiltPostDepsMutator).Parallel()
- ctx.BottomUp("replace_deps_on_override", replaceDepsOnOverridingModuleMutator).Parallel()
+ ctx.BottomUp("replace_deps_on_prebuilts_for_overridable_deps_again", PrebuiltPostDepsMutator).UsesReplaceDependencies()
+ ctx.BottomUp("replace_deps_on_override", replaceDepsOnOverridingModuleMutator).UsesReplaceDependencies()
}
type overrideBaseDependencyTag struct {
@@ -330,6 +331,9 @@
}
func (overrideTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
+}
+
+func overrideApplyMutator(ctx BottomUpMutatorContext) {
if o, ok := ctx.Module().(OverrideModule); ok {
overridableDeps := ctx.GetDirectDepsWithTag(overrideBaseDepTag)
if len(overridableDeps) > 1 {
diff --git a/android/packaging.go b/android/packaging.go
index c247ed2..d216c0c 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -18,10 +18,11 @@
"fmt"
"path/filepath"
"sort"
- "strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/gobtools"
"github.com/google/blueprint/proptools"
+ "github.com/google/blueprint/uniquelist"
)
// PackagingSpec abstracts a request to place a built artifact at a certain path in a package. A
@@ -42,7 +43,7 @@
// Whether relPathInPackage should be marked as executable or not
executable bool
- effectiveLicenseFiles *Paths
+ effectiveLicenseFiles uniquelist.UniqueList[Path]
partition string
@@ -52,10 +53,77 @@
skipInstall bool
// Paths of aconfig files for the built artifact
- aconfigPaths *Paths
+ aconfigPaths uniquelist.UniqueList[Path]
// ArchType of the module which produced this packaging spec
archType ArchType
+
+ // List of module names that this packaging spec overrides
+ overrides uniquelist.UniqueList[string]
+
+ // Name of the module where this packaging spec is output of
+ owner string
+
+ // If the ninja rule creating the FullInstallPath has already been emitted or not. Do not use,
+ // for the soong-only migration.
+ requiresFullInstall bool
+
+ // The path to the installed file in out/target/product. This is for legacy purposes, with
+ // tools that want to interact with these files outside of the build. You should not use it
+ // inside of the build. Will be nil if this module doesn't require a "full install".
+ fullInstallPath InstallPath
+}
+
+type packagingSpecGob struct {
+ RelPathInPackage string
+ SrcPath Path
+ SymlinkTarget string
+ Executable bool
+ EffectiveLicenseFiles Paths
+ Partition string
+ SkipInstall bool
+ AconfigPaths Paths
+ ArchType ArchType
+ Overrides []string
+ Owner string
+}
+
+func (p *PackagingSpec) ToGob() *packagingSpecGob {
+ return &packagingSpecGob{
+ RelPathInPackage: p.relPathInPackage,
+ SrcPath: p.srcPath,
+ SymlinkTarget: p.symlinkTarget,
+ Executable: p.executable,
+ EffectiveLicenseFiles: p.effectiveLicenseFiles.ToSlice(),
+ Partition: p.partition,
+ SkipInstall: p.skipInstall,
+ AconfigPaths: p.aconfigPaths.ToSlice(),
+ ArchType: p.archType,
+ Overrides: p.overrides.ToSlice(),
+ Owner: p.owner,
+ }
+}
+
+func (p *PackagingSpec) FromGob(data *packagingSpecGob) {
+ p.relPathInPackage = data.RelPathInPackage
+ p.srcPath = data.SrcPath
+ p.symlinkTarget = data.SymlinkTarget
+ p.executable = data.Executable
+ p.effectiveLicenseFiles = uniquelist.Make(data.EffectiveLicenseFiles)
+ p.partition = data.Partition
+ p.skipInstall = data.SkipInstall
+ p.aconfigPaths = uniquelist.Make(data.AconfigPaths)
+ p.archType = data.ArchType
+ p.overrides = uniquelist.Make(data.Overrides)
+ p.owner = data.Owner
+}
+
+func (p *PackagingSpec) GobEncode() ([]byte, error) {
+ return gobtools.CustomGobEncode[packagingSpecGob](p)
+}
+
+func (p *PackagingSpec) GobDecode(data []byte) error {
+ return gobtools.CustomGobDecode[packagingSpecGob](data, p)
}
func (p *PackagingSpec) Equals(other *PackagingSpec) bool {
@@ -96,23 +164,42 @@
}
func (p *PackagingSpec) EffectiveLicenseFiles() Paths {
- if p.effectiveLicenseFiles == nil {
- return Paths{}
- }
- return *p.effectiveLicenseFiles
+ return p.effectiveLicenseFiles.ToSlice()
}
func (p *PackagingSpec) Partition() string {
return p.partition
}
+func (p *PackagingSpec) SetPartition(partition string) {
+ p.partition = partition
+}
+
func (p *PackagingSpec) SkipInstall() bool {
return p.skipInstall
}
// Paths of aconfig files for the built artifact
func (p *PackagingSpec) GetAconfigPaths() Paths {
- return *p.aconfigPaths
+ return p.aconfigPaths.ToSlice()
+}
+
+// The path to the installed file in out/target/product. This is for legacy purposes, with
+// tools that want to interact with these files outside of the build. You should not use it
+// inside of the build. Will be nil if this module doesn't require a "full install".
+func (p *PackagingSpec) FullInstallPath() InstallPath {
+ return p.fullInstallPath
+}
+
+// If the ninja rule creating the FullInstallPath has already been emitted or not. Do not use,
+// for the soong-only migration.
+func (p *PackagingSpec) RequiresFullInstall() bool {
+ return p.requiresFullInstall
+}
+
+// The source file to be copied to the FullInstallPath. Do not use, for the soong-only migration.
+func (p *PackagingSpec) SrcPath() Path {
+ return p.srcPath
}
type PackageModule interface {
@@ -127,6 +214,7 @@
// GatherPackagingSpecs gathers PackagingSpecs of transitive dependencies.
GatherPackagingSpecs(ctx ModuleContext) map[string]PackagingSpec
GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec
+ GatherPackagingSpecsWithFilterAndModifier(ctx ModuleContext, filter func(PackagingSpec) bool, modifier func(*PackagingSpec)) map[string]PackagingSpec
// CopyDepsToZip zips the built artifacts of the dependencies into the given zip file and
// returns zip entries in it. This is expected to be called in GenerateAndroidBuildActions,
@@ -148,38 +236,49 @@
// If this is set to true by a module type inheriting PackagingBase, the deps property
// collects the first target only even with compile_multilib: true.
DepsCollectFirstTargetOnly bool
+
+ // If this is set to try by a module type inheriting PackagingBase, the module type is
+ // allowed to utilize High_priority_deps.
+ AllowHighPriorityDeps bool
}
-type depsProperty struct {
+type DepsProperty struct {
+ // Deps that have higher priority in packaging when there is a packaging conflict.
+ // For example, if multiple files are being installed to same filepath, the install file
+ // of the module listed in this property will have a higher priority over those in other
+ // deps properties.
+ High_priority_deps []string `android:"arch_variant"`
+
// Modules to include in this package
Deps proptools.Configurable[[]string] `android:"arch_variant"`
}
type packagingMultilibProperties struct {
- First depsProperty `android:"arch_variant"`
- Common depsProperty `android:"arch_variant"`
- Lib32 depsProperty `android:"arch_variant"`
- Lib64 depsProperty `android:"arch_variant"`
- Both depsProperty `android:"arch_variant"`
- Prefer32 depsProperty `android:"arch_variant"`
+ First DepsProperty `android:"arch_variant"`
+ Common DepsProperty `android:"arch_variant"`
+ Lib32 DepsProperty `android:"arch_variant"`
+ Lib64 DepsProperty `android:"arch_variant"`
+ Both DepsProperty `android:"arch_variant"`
+ Prefer32 DepsProperty `android:"arch_variant"`
}
type packagingArchProperties struct {
- Arm64 depsProperty
- Arm depsProperty
- X86_64 depsProperty
- X86 depsProperty
+ Arm64 DepsProperty
+ Arm DepsProperty
+ X86_64 DepsProperty
+ X86 DepsProperty
}
type PackagingProperties struct {
- Deps proptools.Configurable[[]string] `android:"arch_variant"`
- Multilib packagingMultilibProperties `android:"arch_variant"`
+ DepsProperty
+
+ Multilib packagingMultilibProperties `android:"arch_variant"`
Arch packagingArchProperties
}
func InitPackageModule(p PackageModule) {
base := p.packagingBase()
- p.AddProperties(&base.properties)
+ p.AddProperties(&base.properties, &base.properties.DepsProperty)
}
func (p *PackagingBase) packagingBase() *PackagingBase {
@@ -190,55 +289,72 @@
// the current archicture when this module is not configured for multi target. When configured for
// multi target, deps is selected for each of the targets and is NOT selected for the current
// architecture which would be Common.
-func (p *PackagingBase) getDepsForArch(ctx BaseModuleContext, arch ArchType) []string {
- get := func(prop proptools.Configurable[[]string]) []string {
- return prop.GetOrDefault(ctx, nil)
+// It returns two lists, the normal and high priority deps, respectively.
+func (p *PackagingBase) getDepsForArch(ctx BaseModuleContext, arch ArchType) ([]string, []string) {
+ var normalDeps []string
+ var highPriorityDeps []string
+
+ get := func(prop DepsProperty) {
+ normalDeps = append(normalDeps, prop.Deps.GetOrDefault(ctx, nil)...)
+ highPriorityDeps = append(highPriorityDeps, prop.High_priority_deps...)
+ }
+ has := func(prop DepsProperty) bool {
+ return len(prop.Deps.GetOrDefault(ctx, nil)) > 0 || len(prop.High_priority_deps) > 0
}
- var ret []string
if arch == ctx.Target().Arch.ArchType && len(ctx.MultiTargets()) == 0 {
- ret = append(ret, get(p.properties.Deps)...)
+ get(p.properties.DepsProperty)
} else if arch.Multilib == "lib32" {
- ret = append(ret, get(p.properties.Multilib.Lib32.Deps)...)
+ get(p.properties.Multilib.Lib32)
// multilib.prefer32.deps are added for lib32 only when they support 32-bit arch
- for _, dep := range get(p.properties.Multilib.Prefer32.Deps) {
+ for _, dep := range p.properties.Multilib.Prefer32.Deps.GetOrDefault(ctx, nil) {
if checkIfOtherModuleSupportsLib32(ctx, dep) {
- ret = append(ret, dep)
+ normalDeps = append(normalDeps, dep)
+ }
+ }
+ for _, dep := range p.properties.Multilib.Prefer32.High_priority_deps {
+ if checkIfOtherModuleSupportsLib32(ctx, dep) {
+ highPriorityDeps = append(highPriorityDeps, dep)
}
}
} else if arch.Multilib == "lib64" {
- ret = append(ret, get(p.properties.Multilib.Lib64.Deps)...)
+ get(p.properties.Multilib.Lib64)
// multilib.prefer32.deps are added for lib64 only when they don't support 32-bit arch
- for _, dep := range get(p.properties.Multilib.Prefer32.Deps) {
+ for _, dep := range p.properties.Multilib.Prefer32.Deps.GetOrDefault(ctx, nil) {
if !checkIfOtherModuleSupportsLib32(ctx, dep) {
- ret = append(ret, dep)
+ normalDeps = append(normalDeps, dep)
+ }
+ }
+ for _, dep := range p.properties.Multilib.Prefer32.High_priority_deps {
+ if !checkIfOtherModuleSupportsLib32(ctx, dep) {
+ highPriorityDeps = append(highPriorityDeps, dep)
}
}
} else if arch == Common {
- ret = append(ret, get(p.properties.Multilib.Common.Deps)...)
+ get(p.properties.Multilib.Common)
}
if p.DepsCollectFirstTargetOnly {
- if len(get(p.properties.Multilib.First.Deps)) > 0 {
+ if has(p.properties.Multilib.First) {
ctx.PropertyErrorf("multilib.first.deps", "not supported. use \"deps\" instead")
}
for i, t := range ctx.MultiTargets() {
if t.Arch.ArchType == arch {
- ret = append(ret, get(p.properties.Multilib.Both.Deps)...)
+ get(p.properties.Multilib.Both)
if i == 0 {
- ret = append(ret, get(p.properties.Deps)...)
+ get(p.properties.DepsProperty)
}
}
}
} else {
- if len(get(p.properties.Multilib.Both.Deps)) > 0 {
+ if has(p.properties.Multilib.Both) {
ctx.PropertyErrorf("multilib.both.deps", "not supported. use \"deps\" instead")
}
for i, t := range ctx.MultiTargets() {
if t.Arch.ArchType == arch {
- ret = append(ret, get(p.properties.Deps)...)
+ get(p.properties.DepsProperty)
if i == 0 {
- ret = append(ret, get(p.properties.Multilib.First.Deps)...)
+ get(p.properties.Multilib.First)
}
}
}
@@ -247,17 +363,21 @@
if ctx.Arch().ArchType == Common {
switch arch {
case Arm64:
- ret = append(ret, get(p.properties.Arch.Arm64.Deps)...)
+ get(p.properties.Arch.Arm64)
case Arm:
- ret = append(ret, get(p.properties.Arch.Arm.Deps)...)
+ get(p.properties.Arch.Arm)
case X86_64:
- ret = append(ret, get(p.properties.Arch.X86_64.Deps)...)
+ get(p.properties.Arch.X86_64)
case X86:
- ret = append(ret, get(p.properties.Arch.X86.Deps)...)
+ get(p.properties.Arch.X86)
}
}
- return FirstUniqueStrings(ret)
+ if len(highPriorityDeps) > 0 && !p.AllowHighPriorityDeps {
+ ctx.ModuleErrorf("Usage of high_priority_deps is not allowed for %s module type", ctx.ModuleType())
+ }
+
+ return FirstUniqueStrings(normalDeps), FirstUniqueStrings(highPriorityDeps)
}
func getSupportedTargets(ctx BaseModuleContext) []Target {
@@ -301,6 +421,8 @@
IsPackagingItem() bool
}
+var _ PackagingItem = (*PackagingItemAlwaysDepTag)(nil)
+
// DepTag provides default implementation of PackagingItem interface.
// PackagingBase-derived modules can define their own dependency tag by embedding this, which
// can be passed to AddDeps() or AddDependencies().
@@ -312,20 +434,60 @@
return true
}
+type highPriorityDepTag struct {
+ blueprint.BaseDependencyTag
+ PackagingItemAlwaysDepTag
+}
+
// See PackageModule.AddDeps
func (p *PackagingBase) AddDeps(ctx BottomUpMutatorContext, depTag blueprint.DependencyTag) {
+ addDep := func(t Target, dep string, highPriority bool) {
+ if p.IgnoreMissingDependencies && !ctx.OtherModuleExists(dep) {
+ return
+ }
+ targetVariation := t.Variations()
+ sharedVariation := blueprint.Variation{
+ Mutator: "link",
+ Variation: "shared",
+ }
+ // If a shared variation exists, use that. Static variants do not provide any standalone files
+ // for packaging.
+ if ctx.OtherModuleFarDependencyVariantExists([]blueprint.Variation{sharedVariation}, dep) {
+ targetVariation = append(targetVariation, sharedVariation)
+ }
+ depTagToUse := depTag
+ if highPriority {
+ depTagToUse = highPriorityDepTag{}
+ }
+
+ ctx.AddFarVariationDependencies(targetVariation, depTagToUse, dep)
+ }
for _, t := range getSupportedTargets(ctx) {
- for _, dep := range p.getDepsForArch(ctx, t.Arch.ArchType) {
- if p.IgnoreMissingDependencies && !ctx.OtherModuleExists(dep) {
- continue
- }
- ctx.AddFarVariationDependencies(t.Variations(), depTag, dep)
+ normalDeps, highPriorityDeps := p.getDepsForArch(ctx, t.Arch.ArchType)
+ for _, dep := range normalDeps {
+ addDep(t, dep, false)
+ }
+ for _, dep := range highPriorityDeps {
+ addDep(t, dep, true)
}
}
}
-func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec {
- m := make(map[string]PackagingSpec)
+// See PackageModule.GatherPackagingSpecs
+func (p *PackagingBase) GatherPackagingSpecsWithFilterAndModifier(ctx ModuleContext, filter func(PackagingSpec) bool, modifier func(*PackagingSpec)) map[string]PackagingSpec {
+ // packaging specs gathered from the dep that are not high priorities.
+ var regularPriorities []PackagingSpec
+
+ // all packaging specs gathered from the high priority deps.
+ var highPriorities []PackagingSpec
+
+ // Name of the dependency which requested the packaging spec.
+ // If this dep is overridden, the packaging spec will not be installed via this dependency chain.
+ // (the packaging spec might still be installed if there are some other deps which depend on it).
+ var depNames []string
+
+ // list of module names overridden
+ var overridden []string
var arches []ArchType
for _, target := range getSupportedTargets(ctx) {
@@ -342,11 +504,13 @@
return false
}
- ctx.VisitDirectDeps(func(child Module) {
- if pi, ok := ctx.OtherModuleDependencyTag(child).(PackagingItem); !ok || !pi.IsPackagingItem() {
+ ctx.VisitDirectDepsProxy(func(child ModuleProxy) {
+ depTag := ctx.OtherModuleDependencyTag(child)
+ if pi, ok := depTag.(PackagingItem); !ok || !pi.IsPackagingItem() {
return
}
- for _, ps := range child.TransitivePackagingSpecs() {
+ for _, ps := range OtherModuleProviderOrDefault(
+ ctx, child, InstallFilesProvider).TransitivePackagingSpecs.ToList() {
if !filterArch(ps) {
continue
}
@@ -356,21 +520,75 @@
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
+
+ if modifier != nil {
+ modifier(&ps)
}
- m[dstPath] = ps
+ if _, ok := depTag.(highPriorityDepTag); ok {
+ highPriorities = append(highPriorities, ps)
+ } else {
+ regularPriorities = append(regularPriorities, ps)
+ }
+
+ depNames = append(depNames, child.Name())
+ overridden = append(overridden, ps.overrides.ToSlice()...)
}
})
+
+ filterOverridden := func(input []PackagingSpec) []PackagingSpec {
+ // input minus packaging specs that are overridden
+ var filtered []PackagingSpec
+ for index, ps := range input {
+ if ps.owner != "" && InList(ps.owner, overridden) {
+ continue
+ }
+ // The dependency which requested this packaging spec has been overridden.
+ if InList(depNames[index], overridden) {
+ continue
+ }
+ filtered = append(filtered, ps)
+ }
+ return filtered
+ }
+
+ filteredRegularPriority := filterOverridden(regularPriorities)
+
+ m := make(map[string]PackagingSpec)
+ for _, ps := range filteredRegularPriority {
+ 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
+ }
+
+ filteredHighPriority := filterOverridden(highPriorities)
+ highPriorityPs := make(map[string]PackagingSpec)
+ for _, ps := range filteredHighPriority {
+ dstPath := ps.relPathInPackage
+ if existingPs, ok := highPriorityPs[dstPath]; ok {
+ if !existingPs.Equals(&ps) {
+ ctx.ModuleErrorf("packaging conflict at %v:\n%v\n%v", dstPath, existingPs, ps)
+ }
+ continue
+ }
+ highPriorityPs[dstPath] = ps
+ m[dstPath] = ps
+ }
+
return m
}
// See PackageModule.GatherPackagingSpecs
+func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec {
+ return p.GatherPackagingSpecsWithFilterAndModifier(ctx, filter, nil)
+}
+
+// See PackageModule.GatherPackagingSpecs
func (p *PackagingBase) GatherPackagingSpecs(ctx ModuleContext) map[string]PackagingSpec {
return p.GatherPackagingSpecsWithFilter(ctx, nil)
}
@@ -398,10 +616,6 @@
}
seenDir := make(map[string]bool)
- preparerPath := PathForModuleOut(ctx, "preparer.sh")
- cmd := builder.Command().Tool(preparerPath)
- var sb strings.Builder
- sb.WriteString("set -e\n")
dirs := make([]WritablePath, 0, len(dirsToSpecs))
for dir, _ := range dirsToSpecs {
@@ -420,22 +634,19 @@
entries = append(entries, ps.relPathInPackage)
if _, ok := seenDir[destDir]; !ok {
seenDir[destDir] = true
- sb.WriteString(fmt.Sprintf("mkdir -p %s\n", destDir))
+ builder.Command().Textf("mkdir -p %s", destDir)
}
if ps.symlinkTarget == "" {
- cmd.Implicit(ps.srcPath)
- sb.WriteString(fmt.Sprintf("cp %s %s\n", ps.srcPath, destPath))
+ builder.Command().Text("cp").Input(ps.srcPath).Text(destPath)
} else {
- sb.WriteString(fmt.Sprintf("ln -sf %s %s\n", ps.symlinkTarget, destPath))
+ builder.Command().Textf("ln -sf %s %s", ps.symlinkTarget, destPath)
}
if ps.executable {
- sb.WriteString(fmt.Sprintf("chmod a+x %s\n", destPath))
+ builder.Command().Textf("chmod a+x %s", destPath)
}
}
}
- WriteExecutableFileRuleVerbatim(ctx, preparerPath, sb.String())
-
return entries
}
diff --git a/android/packaging_test.go b/android/packaging_test.go
index 19b46fe..9c6760c 100644
--- a/android/packaging_test.go
+++ b/android/packaging_test.go
@@ -28,6 +28,7 @@
props struct {
Deps []string
Skip_install *bool
+ Overrides []string
}
}
@@ -63,7 +64,7 @@
ModuleBase
PackagingBase
properties struct {
- Install_deps []string `android:`
+ Install_deps []string
}
entries []string
}
@@ -117,6 +118,7 @@
}
result := GroupFixturePreparers(
+ PrepareForTestWithDefaults,
PrepareForTestWithArchMutator,
FixtureRegisterWithContext(func(ctx RegistrationContext) {
ctx.RegisterModuleType("component", componentTestModuleFactory)
@@ -650,3 +652,64 @@
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)
+ }
+}
diff --git a/android/path_properties.go b/android/path_properties.go
index 6210aee..55a4dc0 100644
--- a/android/path_properties.go
+++ b/android/path_properties.go
@@ -18,6 +18,7 @@
"fmt"
"reflect"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -27,7 +28,7 @@
// to the output file of the referenced module.
func registerPathDepsMutator(ctx RegisterMutatorsContext) {
- ctx.BottomUp("pathdeps", pathDepsMutator).Parallel()
+ ctx.BottomUp("pathdeps", pathDepsMutator)
}
// The pathDepsMutator automatically adds dependencies on any module that is listed with the
@@ -38,20 +39,35 @@
// squashed into the real modules.
return
}
+ if !ctx.Module().Enabled(ctx) {
+ return
+ }
props := ctx.Module().base().GetProperties()
addPathDepsForProps(ctx, props)
}
func addPathDepsForProps(ctx BottomUpMutatorContext, props []interface{}) {
// Iterate through each property struct of the module extracting the contents of all properties
- // tagged with `android:"path"`.
+ // tagged with `android:"path"` or one of the variant-specifying tags.
var pathProperties []string
+ var pathDeviceFirstProperties []string
+ var pathDeviceFirstPrefer32Properties []string
+ var pathDeviceCommonProperties []string
+ var pathCommonOsProperties []string
for _, ps := range props {
- pathProperties = append(pathProperties, pathPropertiesForPropertyStruct(ctx, ps)...)
+ pathProperties = append(pathProperties, taggedPropertiesForPropertyStruct(ctx, ps, "path")...)
+ pathDeviceFirstProperties = append(pathDeviceFirstProperties, taggedPropertiesForPropertyStruct(ctx, ps, "path_device_first")...)
+ pathDeviceFirstPrefer32Properties = append(pathDeviceFirstPrefer32Properties, taggedPropertiesForPropertyStruct(ctx, ps, "path_device_first_prefer32")...)
+ pathDeviceCommonProperties = append(pathDeviceCommonProperties, taggedPropertiesForPropertyStruct(ctx, ps, "path_device_common")...)
+ pathCommonOsProperties = append(pathCommonOsProperties, taggedPropertiesForPropertyStruct(ctx, ps, "path_common_os")...)
}
// Remove duplicates to avoid multiple dependencies.
pathProperties = FirstUniqueStrings(pathProperties)
+ pathDeviceFirstProperties = FirstUniqueStrings(pathDeviceFirstProperties)
+ pathDeviceFirstPrefer32Properties = FirstUniqueStrings(pathDeviceFirstPrefer32Properties)
+ pathDeviceCommonProperties = FirstUniqueStrings(pathDeviceCommonProperties)
+ pathCommonOsProperties = FirstUniqueStrings(pathCommonOsProperties)
// Add dependencies to anything that is a module reference.
for _, s := range pathProperties {
@@ -59,12 +75,54 @@
ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(m, t), m)
}
}
+ // For properties tagged "path_device_first", use the first arch device variant when adding
+ // dependencies. This allows host modules to have some properties that add dependencies on
+ // device modules.
+ for _, s := range pathDeviceFirstProperties {
+ if m, t := SrcIsModuleWithTag(s); m != "" {
+ ctx.AddVariationDependencies(ctx.Config().AndroidFirstDeviceTarget.Variations(), sourceOrOutputDepTag(m, t), m)
+ }
+ }
+ // properties tagged path_device_first_prefer32 get the first 32 bit target if one is available,
+ // otherwise they use the first 64 bit target
+ if len(pathDeviceFirstPrefer32Properties) > 0 {
+ var targets []Target
+ if ctx.Config().IgnorePrefer32OnDevice() {
+ targets, _ = decodeMultilibTargets("first", ctx.Config().Targets[Android], false)
+ } else {
+ targets, _ = decodeMultilibTargets("first_prefer32", ctx.Config().Targets[Android], false)
+ }
+ if len(targets) == 0 {
+ ctx.ModuleErrorf("Could not find a first_prefer32 target")
+ } else {
+ for _, s := range pathDeviceFirstPrefer32Properties {
+ if m, t := SrcIsModuleWithTag(s); m != "" {
+ ctx.AddVariationDependencies(targets[0].Variations(), sourceOrOutputDepTag(m, t), m)
+ }
+ }
+ }
+ }
+ // properties tagged "path_device_common" get the device common variant
+ for _, s := range pathDeviceCommonProperties {
+ if m, t := SrcIsModuleWithTag(s); m != "" {
+ ctx.AddVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), sourceOrOutputDepTag(m, t), m)
+ }
+ }
+ // properties tagged "path_common_os" get the CommonOs variant
+ for _, s := range pathCommonOsProperties {
+ if m, t := SrcIsModuleWithTag(s); m != "" {
+ ctx.AddVariationDependencies([]blueprint.Variation{
+ {Mutator: "os", Variation: "common_os"},
+ {Mutator: "arch", Variation: ""},
+ }, sourceOrOutputDepTag(m, t), m)
+ }
+ }
}
-// pathPropertiesForPropertyStruct uses the indexes of properties that are tagged with
-// android:"path" to extract all their values from a property struct, returning them as a single
+// taggedPropertiesForPropertyStruct uses the indexes of properties that are tagged with
+// android:"tagValue" to extract all their values from a property struct, returning them as a single
// slice of strings.
-func pathPropertiesForPropertyStruct(ctx BottomUpMutatorContext, ps interface{}) []string {
+func taggedPropertiesForPropertyStruct(ctx BottomUpMutatorContext, ps interface{}, tagValue string) []string {
v := reflect.ValueOf(ps)
if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
panic(fmt.Errorf("type %s is not a pointer to a struct", v.Type()))
@@ -79,7 +137,7 @@
v = v.Elem()
// Get or create the list of indexes of properties that are tagged with `android:"path"`.
- pathPropertyIndexes := pathPropertyIndexesForPropertyStruct(ps)
+ pathPropertyIndexes := taggedPropertyIndexesForPropertyStruct(ps, tagValue)
var ret []string
@@ -172,12 +230,20 @@
var pathPropertyIndexesCache OncePer
-// pathPropertyIndexesForPropertyStruct returns a list of all of the indexes of properties in
-// property struct type that are tagged with `android:"path"`. Each index is a []int suitable for
-// passing to reflect.Value.FieldByIndex. The value is cached in a global cache by type.
-func pathPropertyIndexesForPropertyStruct(ps interface{}) [][]int {
- key := NewCustomOnceKey(reflect.TypeOf(ps))
+// taggedPropertyIndexesForPropertyStruct returns a list of all of the indexes of properties in
+// property struct type that are tagged with `android:"tagValue"`. Each index is a []int suitable
+// for passing to reflect.Value.FieldByIndex. The value is cached in a global cache by type and
+// tagValue.
+func taggedPropertyIndexesForPropertyStruct(ps interface{}, tagValue string) [][]int {
+ type pathPropertyIndexesOnceKey struct {
+ propStructType reflect.Type
+ tagValue string
+ }
+ key := NewCustomOnceKey(pathPropertyIndexesOnceKey{
+ propStructType: reflect.TypeOf(ps),
+ tagValue: tagValue,
+ })
return pathPropertyIndexesCache.Once(key, func() interface{} {
- return proptools.PropertyIndexesWithTag(ps, "android", "path")
+ return proptools.PropertyIndexesWithTag(ps, "android", tagValue)
}).([][]int)
}
diff --git a/android/path_properties_test.go b/android/path_properties_test.go
index 07b4869..6f44f28 100644
--- a/android/path_properties_test.go
+++ b/android/path_properties_test.go
@@ -64,7 +64,7 @@
if p.props.Foo != "" {
// Make sure there is only one dependency on a module listed in a property present in multiple property structs
m := SrcIsModule(p.props.Foo)
- if GetModuleFromPathDep(ctx, m, "") == nil {
+ if GetModuleProxyFromPathDep(ctx, m, "") == nil {
ctx.ModuleErrorf("GetDirectDepWithTag failed")
}
}
diff --git a/android/paths.go b/android/paths.go
index d20b84a..1c0321c 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -15,9 +15,6 @@
package android
import (
- "bytes"
- "encoding/gob"
- "errors"
"fmt"
"os"
"path/filepath"
@@ -27,7 +24,7 @@
"strings"
"github.com/google/blueprint"
- "github.com/google/blueprint/bootstrap"
+ "github.com/google/blueprint/gobtools"
"github.com/google/blueprint/pathtools"
)
@@ -92,8 +89,12 @@
// the Path methods that rely on module dependencies having been resolved.
type ModuleWithDepsPathContext interface {
EarlyModulePathContext
- VisitDirectDepsBlueprint(visit func(blueprint.Module))
+ OtherModuleProviderContext
+ VisitDirectDeps(visit func(Module))
+ VisitDirectDepsProxy(visit func(ModuleProxy))
+ VisitDirectDepsProxyWithTag(tag blueprint.DependencyTag, visit func(ModuleProxy))
OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
+ HasMutatorFinished(mutatorName string) bool
}
// ModuleMissingDepsPathContext is a subset of *ModuleContext methods required by
@@ -118,6 +119,9 @@
InstallInOdm() bool
InstallInProduct() bool
InstallInVendor() bool
+ InstallInSystemDlkm() bool
+ InstallInVendorDlkm() bool
+ InstallInOdmDlkm() bool
InstallForceOS() (*OsType, *ArchType)
}
@@ -171,6 +175,18 @@
return ctx.Module().InstallInVendor()
}
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallInSystemDlkm() bool {
+ return ctx.Module().InstallInSystemDlkm()
+}
+
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallInVendorDlkm() bool {
+ return ctx.Module().InstallInVendorDlkm()
+}
+
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallInOdmDlkm() bool {
+ return ctx.Module().InstallInOdmDlkm()
+}
+
func (ctx *baseModuleContextToModuleInstallPathContext) InstallForceOS() (*OsType, *ArchType) {
return ctx.Module().InstallForceOS()
}
@@ -341,6 +357,11 @@
invalidReason string // Not applicable if path != nil. "" if the reason is unknown.
}
+type optionalPathGob struct {
+ Path Path
+ InvalidReason string
+}
+
// OptionalPathForPath returns an OptionalPath containing the path.
func OptionalPathForPath(path Path) OptionalPath {
return OptionalPath{path: path}
@@ -352,6 +373,26 @@
return OptionalPath{invalidReason: reason}
}
+func (p *OptionalPath) ToGob() *optionalPathGob {
+ return &optionalPathGob{
+ Path: p.path,
+ InvalidReason: p.invalidReason,
+ }
+}
+
+func (p *OptionalPath) FromGob(data *optionalPathGob) {
+ p.path = data.Path
+ p.invalidReason = data.InvalidReason
+}
+
+func (p OptionalPath) GobEncode() ([]byte, error) {
+ return gobtools.CustomGobEncode[optionalPathGob](&p)
+}
+
+func (p *OptionalPath) GobDecode(data []byte) error {
+ return gobtools.CustomGobDecode[optionalPathGob](data, p)
+}
+
// Valid returns whether there is a valid path
func (p OptionalPath) Valid() bool {
return p.path != nil
@@ -527,6 +568,78 @@
return ret
}
+type directoryPath struct {
+ basePath
+}
+
+func (d *directoryPath) String() string {
+ return d.basePath.String()
+}
+
+func (d *directoryPath) base() basePath {
+ return d.basePath
+}
+
+// DirectoryPath represents a source path for directories. Incompatible with Path by design.
+type DirectoryPath interface {
+ String() string
+ base() basePath
+}
+
+var _ DirectoryPath = (*directoryPath)(nil)
+
+type DirectoryPaths []DirectoryPath
+
+// DirectoryPathsForModuleSrcExcludes returns a Paths{} containing the resolved references in
+// directory paths. Elements of paths are resolved as:
+// - filepath, relative to local module directory, resolves as a filepath relative to the local
+// source directory
+// - other modules using the ":name" syntax. These modules must implement DirProvider.
+func DirectoryPathsForModuleSrc(ctx ModuleMissingDepsPathContext, paths []string) DirectoryPaths {
+ var ret DirectoryPaths
+
+ for _, path := range paths {
+ if m, t := SrcIsModuleWithTag(path); m != "" {
+ module := GetModuleProxyFromPathDep(ctx, m, t)
+ if module == nil {
+ ctx.ModuleErrorf(`missing dependency on %q, is the property annotated with android:"path"?`, m)
+ continue
+ }
+ if t != "" {
+ ctx.ModuleErrorf("DirProvider dependency %q does not support the tag %q", module, t)
+ continue
+ }
+ mctx, ok := ctx.(OtherModuleProviderContext)
+ if !ok {
+ panic(fmt.Errorf("%s is not an OtherModuleProviderContext", ctx))
+ }
+ if dirProvider, ok := OtherModuleProvider(mctx, *module, DirProvider); ok {
+ ret = append(ret, dirProvider.Dirs...)
+ } else {
+ ReportPathErrorf(ctx, "module %q does not implement DirProvider", module)
+ }
+ } else {
+ p := pathForModuleSrc(ctx, path)
+ if isDir, err := ctx.Config().fs.IsDir(p.String()); err != nil {
+ ReportPathErrorf(ctx, "%s: %s", p, err.Error())
+ } else if !isDir {
+ ReportPathErrorf(ctx, "module directory path %q is not a directory", p)
+ } else {
+ ret = append(ret, &directoryPath{basePath{path: p.path, rel: p.rel}})
+ }
+ }
+ }
+
+ seen := make(map[DirectoryPath]bool, len(ret))
+ for _, path := range ret {
+ if seen[path] {
+ ReportPathErrorf(ctx, "duplicated path %q", path)
+ }
+ seen[path] = true
+ }
+ return ret
+}
+
// OutputPaths is a slice of OutputPath objects, with helpers to operate on the collection.
type OutputPaths []OutputPath
@@ -554,29 +667,19 @@
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.
func getPathsFromModuleDep(ctx ModuleWithDepsPathContext, path, moduleName, tag string) (Paths, error) {
- module := GetModuleFromPathDep(ctx, moduleName, tag)
+ module := GetModuleProxyFromPathDep(ctx, moduleName, tag)
if module == nil {
return nil, missingDependencyError{[]string{moduleName}}
}
- if aModule, ok := module.(Module); ok && !aModule.Enabled(ctx) {
+ if !OtherModuleProviderOrDefault(ctx, *module, CommonModuleInfoKey).Enabled {
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)
+
+ outputFiles, err := outputFilesForModule(ctx, *module, tag)
if outputFiles != nil && err == nil {
return outputFiles, nil
} else {
@@ -584,7 +687,7 @@
}
}
-// GetModuleFromPathDep will return the module that was added as a dependency automatically for
+// GetModuleProxyFromPathDep will return the module that was added as a dependency automatically for
// properties tagged with `android:"path"` or manually using ExtractSourceDeps or
// ExtractSourcesDeps.
//
@@ -594,6 +697,27 @@
//
// If tag is "" then the returned module will be the dependency that was added for ":moduleName".
// Otherwise, it is the dependency that was added for ":moduleName{tag}".
+func GetModuleProxyFromPathDep(ctx ModuleWithDepsPathContext, moduleName, tag string) *ModuleProxy {
+ var found *ModuleProxy
+ // The sourceOrOutputDepTag uniquely identifies the module dependency as it contains both the
+ // module name and the tag. Dependencies added automatically for properties tagged with
+ // `android:"path"` are deduped so are guaranteed to be unique. It is possible for duplicate
+ // dependencies to be added manually using ExtractSourcesDeps or ExtractSourceDeps but even then
+ // it will always be the case that the dependencies will be identical, i.e. the same tag and same
+ // moduleName referring to the same dependency module.
+ //
+ // It does not matter whether the moduleName is a fully qualified name or if the module
+ // dependency is a prebuilt module. All that matters is the same information is supplied to
+ // create the tag here as was supplied to create the tag when the dependency was added so that
+ // this finds the matching dependency module.
+ expectedTag := sourceOrOutputDepTag(moduleName, tag)
+ ctx.VisitDirectDepsProxyWithTag(expectedTag, func(module ModuleProxy) {
+ found = &module
+ })
+ return found
+}
+
+// Deprecated: use GetModuleProxyFromPathDep
func GetModuleFromPathDep(ctx ModuleWithDepsPathContext, moduleName, tag string) blueprint.Module {
var found blueprint.Module
// The sourceOrOutputDepTag uniquely identifies the module dependency as it contains both the
@@ -608,7 +732,7 @@
// create the tag here as was supplied to create the tag when the dependency was added so that
// this finds the matching dependency module.
expectedTag := sourceOrOutputDepTag(moduleName, tag)
- ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
+ ctx.VisitDirectDeps(func(module Module) {
depTag := ctx.OtherModuleDependencyTag(module)
if depTag == expectedTag {
found = module
@@ -1075,26 +1199,29 @@
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
- }
+type basePathGob struct {
+ Path string
+ Rel string
+}
- return w.Bytes(), nil
+func (p *basePath) ToGob() *basePathGob {
+ return &basePathGob{
+ Path: p.path,
+ Rel: p.rel,
+ }
+}
+
+func (p *basePath) FromGob(data *basePathGob) {
+ p.path = data.Path
+ p.rel = data.Rel
+}
+
+func (p basePath) GobEncode() ([]byte, error) {
+ return gobtools.CustomGobEncode[basePathGob](&p)
}
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
+ return gobtools.CustomGobDecode[basePathGob](data, p)
}
func (p basePath) Ext() string {
@@ -1226,7 +1353,7 @@
// 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 {
+func PathForArbitraryOutput(ctx PathContext, pathComponents ...string) WritablePath {
path, err := validatePath(pathComponents...)
if err != nil {
reportPathError(ctx, err)
@@ -1310,33 +1437,6 @@
return p.withRel(path)
}
-// OverlayPath returns the overlay for `path' if it exists. This assumes that the
-// SourcePath is the path to a resource overlay directory.
-func (p SourcePath) OverlayPath(ctx ModuleMissingDepsPathContext, path Path) OptionalPath {
- var relDir string
- if srcPath, ok := path.(SourcePath); ok {
- relDir = srcPath.path
- } else {
- ReportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path)
- // No need to put the error message into the returned path since it has been reported already.
- return OptionalPath{}
- }
- dir := filepath.Join(p.path, relDir)
- // Use Glob so that we are run again if the directory is added.
- if pathtools.IsGlob(dir) {
- ReportPathErrorf(ctx, "Path may not contain a glob: %s", dir)
- }
- paths, err := ctx.GlobWithDeps(dir, nil)
- if err != nil {
- ReportPathErrorf(ctx, "glob: %s", err.Error())
- return OptionalPath{}
- }
- if len(paths) == 0 {
- return InvalidOptionalPath(dir + " does not exist")
- }
- return OptionalPathForPath(PathForSource(ctx, paths[0]))
-}
-
// OutputPath is a Path representing an intermediates file path rooted from the build directory
type OutputPath struct {
basePath
@@ -1347,26 +1447,32 @@
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
- }
+type outputPathGob struct {
+ BasePath basePath
+ OutDir string
+ FullPath string
+}
- return w.Bytes(), nil
+func (p *OutputPath) ToGob() *outputPathGob {
+ return &outputPathGob{
+ BasePath: p.basePath,
+ OutDir: p.outDir,
+ FullPath: p.fullPath,
+ }
+}
+
+func (p *OutputPath) FromGob(data *outputPathGob) {
+ p.basePath = data.BasePath
+ p.outDir = data.OutDir
+ p.fullPath = data.FullPath
+}
+
+func (p OutputPath) GobEncode() ([]byte, error) {
+ return gobtools.CustomGobEncode[outputPathGob](&p)
}
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
+ return gobtools.CustomGobDecode[outputPathGob](data, p)
}
func (p OutputPath) withRel(rel string) OutputPath {
@@ -1766,6 +1872,43 @@
fullPath string
}
+type installPathGob struct {
+ BasePath basePath
+ SoongOutDir string
+ PartitionDir string
+ Partition string
+ MakePath bool
+ FullPath string
+}
+
+func (p *InstallPath) ToGob() *installPathGob {
+ return &installPathGob{
+ BasePath: p.basePath,
+ SoongOutDir: p.soongOutDir,
+ PartitionDir: p.partitionDir,
+ Partition: p.partition,
+ MakePath: p.makePath,
+ FullPath: p.fullPath,
+ }
+}
+
+func (p *InstallPath) FromGob(data *installPathGob) {
+ p.basePath = data.BasePath
+ p.soongOutDir = data.SoongOutDir
+ p.partitionDir = data.PartitionDir
+ p.partition = data.Partition
+ p.makePath = data.MakePath
+ p.fullPath = data.FullPath
+}
+
+func (p InstallPath) GobEncode() ([]byte, error) {
+ return gobtools.CustomGobEncode[installPathGob](&p)
+}
+
+func (p *InstallPath) GobDecode(data []byte) error {
+ return gobtools.CustomGobDecode[installPathGob](data, p)
+}
+
// Will panic if called from outside a test environment.
func ensureTestOnly() {
if PrefixInList(os.Args, "-test.") {
@@ -1933,7 +2076,7 @@
reportPathError(ctx, err)
}
- base := pathForPartitionInstallDir(ctx, partition, partitionPath, ctx.Config().KatiEnabled())
+ base := pathForPartitionInstallDir(ctx, partition, partitionPath, true)
return base.Join(ctx, pathComponents...)
}
@@ -1946,6 +2089,10 @@
return base.Join(ctx, paths...)
}
+func PathForSuiteInstall(ctx PathContext, suite string, pathComponents ...string) InstallPath {
+ return pathForPartitionInstallDir(ctx, "test_suites", "test_suites", false).Join(ctx, suite).Join(ctx, pathComponents...)
+}
+
func InstallPathToOnDevicePath(ctx PathContext, path InstallPath) string {
rel := Rel(ctx, strings.TrimSuffix(path.PartitionDir(), path.partition), path.String())
return "/" + rel
@@ -2000,6 +2147,12 @@
partition = ctx.DeviceConfig().SystemExtPath()
} else if ctx.InstallInRoot() {
partition = "root"
+ } else if ctx.InstallInSystemDlkm() {
+ partition = ctx.DeviceConfig().SystemDlkmPath()
+ } else if ctx.InstallInVendorDlkm() {
+ partition = ctx.DeviceConfig().VendorDlkmPath()
+ } else if ctx.InstallInOdmDlkm() {
+ partition = ctx.DeviceConfig().OdmDlkmPath()
} else {
partition = "system"
}
@@ -2203,6 +2356,9 @@
inOdm bool
inProduct bool
inVendor bool
+ inSystemDlkm bool
+ inVendorDlkm bool
+ inOdmDlkm bool
forceOS *OsType
forceArch *ArchType
}
@@ -2257,6 +2413,18 @@
return m.inVendor
}
+func (m testModuleInstallPathContext) InstallInSystemDlkm() bool {
+ return m.inSystemDlkm
+}
+
+func (m testModuleInstallPathContext) InstallInVendorDlkm() bool {
+ return m.inVendorDlkm
+}
+
+func (m testModuleInstallPathContext) InstallInOdmDlkm() bool {
+ return m.inOdmDlkm
+}
+
func (m testModuleInstallPathContext) InstallForceOS() (*OsType, *ArchType) {
return m.forceOS, m.forceArch
}
@@ -2418,3 +2586,19 @@
}
return false
}
+
+// ToRelativeSourcePath converts absolute source path to the path relative to the source root.
+// This throws an error if the input path is outside of the source root and cannot be converted
+// to the relative path.
+// This should be rarely used given that the source path is relative in Soong.
+func ToRelativeSourcePath(ctx PathContext, path string) string {
+ ret := path
+ if filepath.IsAbs(path) {
+ relPath, err := filepath.Rel(absSrcDir, path)
+ if err != nil || strings.HasPrefix(relPath, "..") {
+ ReportPathErrorf(ctx, "%s is outside of the source root", path)
+ }
+ ret = relPath
+ }
+ return ret
+}
diff --git a/android/paths_test.go b/android/paths_test.go
index 941f0ca..20beecc 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -1561,7 +1561,7 @@
t.Run("install for soong", func(t *testing.T) {
p := PathForModuleInstall(ctx, "install/path")
- AssertPathRelativeToTopEquals(t, "install path for soong", "out/soong/target/product/test_device/system/install/path", p)
+ AssertPathRelativeToTopEquals(t, "install path for soong", "out/target/product/test_device/system/install/path", p)
})
t.Run("install for make", func(t *testing.T) {
p := PathForModuleInstall(ctx, "install/path")
@@ -1584,7 +1584,7 @@
}
expected := []string{
- "out/soong/target/product/test_device/system/install/path",
+ "out/target/product/test_device/system/install/path",
"out/soong/output/path",
"source/path",
}
@@ -1592,6 +1592,12 @@
})
}
+func TestDirectoryPathIsIncompatibleWithPath(t *testing.T) {
+ d := (DirectoryPath)(&directoryPath{})
+ _, ok := d.(Path)
+ AssertBoolEquals(t, "directoryPath shouldn't implement Path", ok, false)
+}
+
func ExampleOutputPath_ReplaceExtension() {
ctx := &configErrorWrapper{
config: TestConfig("out", nil, "", nil),
diff --git a/android/phony.go b/android/phony.go
index f8db88d..7bdd9d3 100644
--- a/android/phony.go
+++ b/android/phony.go
@@ -15,6 +15,7 @@
package android
import (
+ "strings"
"sync"
"github.com/google/blueprint"
@@ -68,13 +69,25 @@
}
if !ctx.Config().KatiEnabled() {
+ // In soong-only builds, the phonies can conflict with dist targets that will
+ // be generated in the packaging step. Instead of emitting a blueprint/ninja phony directly,
+ // create a makefile that defines the phonies that will be included in the packaging step.
+ // Make will dedup the phonies there.
+ var buildPhonyFileContents strings.Builder
for _, phony := range p.phonyList {
- ctx.Build(pctx, BuildParams{
- Rule: blueprint.Phony,
- Outputs: []WritablePath{PathForPhony(ctx, phony)},
- Implicits: p.phonyMap[phony],
- })
+ buildPhonyFileContents.WriteString(".PHONY: ")
+ buildPhonyFileContents.WriteString(phony)
+ buildPhonyFileContents.WriteString("\n")
+ buildPhonyFileContents.WriteString(phony)
+ buildPhonyFileContents.WriteString(":")
+ for _, dep := range p.phonyMap[phony] {
+ buildPhonyFileContents.WriteString(" ")
+ buildPhonyFileContents.WriteString(dep.String())
+ }
+ buildPhonyFileContents.WriteString("\n")
}
+ buildPhonyFile := PathForOutput(ctx, "soong_phony_targets.mk")
+ writeValueIfChanged(ctx, absolutePath(buildPhonyFile.String()), buildPhonyFileContents.String())
}
}
diff --git a/android/prebuilt.go b/android/prebuilt.go
index fd5a6ea..bf27178 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -272,6 +272,25 @@
InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
}
+// InitConfigurablePrebuiltModuleString is the same as InitPrebuiltModule, but uses a
+// Configurable string property instead of a regular list of strings. It only produces a single
+// source file.
+func InitConfigurablePrebuiltModuleString(module PrebuiltInterface, srcs *proptools.Configurable[string], propertyName string) {
+ if srcs == nil {
+ panic(fmt.Errorf("%s must not be nil", propertyName))
+ }
+
+ srcsSupplier := func(ctx BaseModuleContext, _ Module) []string {
+ src := srcs.GetOrDefault(ctx, "")
+ if src == "" {
+ return nil
+ }
+ return []string{src}
+ }
+
+ InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, propertyName)
+}
+
func InitSingleSourcePrebuiltModule(module PrebuiltInterface, srcProps interface{}, srcField string) {
srcPropsValue := reflect.ValueOf(srcProps).Elem()
srcStructField, _ := srcPropsValue.Type().FieldByName(srcField)
@@ -359,13 +378,13 @@
//
// This function is for use on dependencies after PrebuiltPostDepsMutator has
// run - any dependency that is registered before that will already reference
-// the right module. This function is only safe to call after all mutators that
-// may call CreateVariations, e.g. in GenerateAndroidBuildActions.
+// the right module. This function is only safe to call after all TransitionMutators
+// have run, e.g. in GenerateAndroidBuildActions.
func PrebuiltGetPreferred(ctx BaseModuleContext, module Module) Module {
- if !module.IsReplacedByPrebuilt() {
+ if !OtherModuleProviderOrDefault(ctx, module, CommonModuleInfoKey).ReplacedByPrebuilt {
return module
}
- if IsModulePrebuilt(module) {
+ if _, ok := OtherModuleProvider(ctx, module, PrebuiltModuleInfoProvider); ok {
// If we're given a prebuilt then assume there's no source module around.
return module
}
@@ -373,11 +392,11 @@
sourceModDepFound := false
var prebuiltMod Module
- ctx.WalkDeps(func(child, parent Module) bool {
+ ctx.WalkDepsProxy(func(child, parent ModuleProxy) bool {
if prebuiltMod != nil {
return false
}
- if parent == ctx.Module() {
+ if ctx.EqualModules(parent, ctx.Module()) {
// First level: Only recurse if the module is found as a direct dependency.
sourceModDepFound = child == module
return sourceModDepFound
@@ -400,13 +419,13 @@
}
func RegisterPrebuiltsPreArchMutators(ctx RegisterMutatorsContext) {
- ctx.BottomUp("prebuilt_rename", PrebuiltRenameMutator).Parallel()
+ ctx.BottomUp("prebuilt_rename", PrebuiltRenameMutator).UsesRename()
}
func RegisterPrebuiltsPostDepsMutators(ctx RegisterMutatorsContext) {
- ctx.BottomUp("prebuilt_source", PrebuiltSourceDepsMutator).Parallel()
- ctx.BottomUp("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
- ctx.BottomUp("prebuilt_postdeps", PrebuiltPostDepsMutator).Parallel()
+ ctx.BottomUp("prebuilt_source", PrebuiltSourceDepsMutator).UsesReverseDependencies()
+ ctx.BottomUp("prebuilt_select", PrebuiltSelectModuleMutator)
+ ctx.BottomUp("prebuilt_postdeps", PrebuiltPostDepsMutator).UsesReplaceDependencies()
}
// Returns the name of the source module corresponding to a prebuilt module
@@ -550,6 +569,7 @@
for _, moduleInFamily := range allModulesInFamily {
if moduleInFamily.Name() != selectedModuleInFamily.Name() {
moduleInFamily.HideFromMake()
+ moduleInFamily.SkipInstall()
// If this is a prebuilt module, unset properties.UsePrebuilt
// properties.UsePrebuilt might evaluate to true via soong config var fallback mechanism
// Set it to false explicitly so that the following mutator does not replace rdeps to this unselected prebuilt
@@ -620,6 +640,7 @@
}
} else {
m.HideFromMake()
+ m.SkipInstall()
}
}
}
@@ -677,7 +698,7 @@
//
// Even though this is a cc_prebuilt_library_shared, we create both the variants today
// https://source.corp.google.com/h/googleplex-android/platform/build/soong/+/e08e32b45a18a77bc3c3e751f730539b1b374f1b:cc/library.go;l=2113-2116;drc=2c4a9779cd1921d0397a12b3d3521f4c9b30d747;bpv=1;bpt=0
-func (p *Prebuilt) variantIsDisabled(ctx BaseMutatorContext, prebuilt Module) bool {
+func (p *Prebuilt) variantIsDisabled(ctx BaseModuleContext, prebuilt Module) bool {
return p.srcsSupplier != nil && len(p.srcsSupplier(ctx, prebuilt)) == 0
}
@@ -687,7 +708,7 @@
// usePrebuilt returns true if a prebuilt should be used instead of the source module. The prebuilt
// will be used if it is marked "prefer" or if the source module is disabled.
-func (p *Prebuilt) usePrebuilt(ctx BaseMutatorContext, source Module, prebuilt Module) bool {
+func (p *Prebuilt) usePrebuilt(ctx BaseModuleContext, source Module, prebuilt Module) bool {
isMainlinePrebuilt := func(prebuilt Module) bool {
apex, ok := prebuilt.(apexVariationName)
if !ok {
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index 5e4af0b..b90ef3b 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -508,11 +508,10 @@
}
func (p *prebuiltModule) GenerateAndroidBuildActions(ctx ModuleContext) {
- var src Path
if len(p.properties.Srcs) >= 1 {
- src = p.prebuilt.SingleSourcePath(ctx)
+ src := p.prebuilt.SingleSourcePath(ctx)
+ ctx.SetOutputFiles(Paths{src}, "")
}
- ctx.SetOutputFiles(Paths{src}, "")
}
func (p *prebuiltModule) Prebuilt() *Prebuilt {
diff --git a/android/product_config.go b/android/product_config.go
index 20b29a7..850f003 100644
--- a/android/product_config.go
+++ b/android/product_config.go
@@ -14,7 +14,9 @@
package android
-import "github.com/google/blueprint/proptools"
+import (
+ "github.com/google/blueprint/proptools"
+)
func init() {
ctx := InitRegistrationContext
@@ -30,15 +32,17 @@
ctx.ModuleErrorf("There can only be one product_config module in build/soong")
return
}
- outputFilePath := PathForModuleOut(ctx, p.Name()+".json").OutputPath
+ outputFilePath := PathForModuleOut(ctx, p.Name()+".json")
// DeviceProduct can be null so calling ctx.Config().DeviceProduct() may cause null dereference
targetProduct := proptools.String(ctx.Config().config.productVariables.DeviceProduct)
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").
diff --git a/android/product_packages_file.go b/android/product_packages_file.go
new file mode 100644
index 0000000..c7c18a2
--- /dev/null
+++ b/android/product_packages_file.go
@@ -0,0 +1,39 @@
+// 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"
+)
+
+func init() {
+ RegisterParallelSingletonType("product_packages_file_singleton", productPackagesFileSingletonFactory)
+}
+
+func productPackagesFileSingletonFactory() Singleton {
+ return &productPackagesFileSingleton{}
+}
+
+type productPackagesFileSingleton struct{}
+
+func (s *productPackagesFileSingleton) GenerateBuildActions(ctx SingletonContext) {
+ // There's no HasDeviceName() function, but the device name and device product should always
+ // both be present or not.
+ if ctx.Config().HasDeviceProduct() {
+ productPackages := ctx.Config().productVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductPackages
+ output := PathForArbitraryOutput(ctx, "target", "product", ctx.Config().DeviceName(), "product_packages.txt")
+ WriteFileRule(ctx, output, strings.Join(productPackages, "\n"))
+ }
+}
diff --git a/android/proto.go b/android/proto.go
index 0d8e097..91d6732 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -74,14 +74,14 @@
flags = append(flags, JoinWithPrefix(rootProtoIncludeDirs.Strings(), "-I"))
}
- ctx.VisitDirectDepsWithTag(ProtoPluginDepTag, func(dep Module) {
- if hostTool, ok := dep.(HostToolProvider); !ok || !hostTool.HostToolPath().Valid() {
+ ctx.VisitDirectDepsProxyWithTag(ProtoPluginDepTag, func(dep ModuleProxy) {
+ if h, ok := OtherModuleProvider(ctx, dep, HostToolProviderInfoProvider); !ok || !h.HostToolPath.Valid() {
ctx.PropertyErrorf("proto.plugin", "module %q is not a host tool provider",
ctx.OtherModuleName(dep))
} else {
plugin := String(p.Proto.Plugin)
- deps = append(deps, hostTool.HostToolPath().Path())
- flags = append(flags, "--plugin=protoc-gen-"+plugin+"="+hostTool.HostToolPath().String())
+ deps = append(deps, h.HostToolPath.Path())
+ flags = append(flags, "--plugin=protoc-gen-"+plugin+"="+h.HostToolPath.String())
}
})
diff --git a/android/provider.go b/android/provider.go
index 5ded4cc..81d17a1 100644
--- a/android/provider.go
+++ b/android/provider.go
@@ -24,7 +24,7 @@
// OtherModuleProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or
// TopDownMutatorContext.
func OtherModuleProvider[K any](ctx OtherModuleProviderContext, module blueprint.Module, provider blueprint.ProviderKey[K]) (K, bool) {
- value, ok := ctx.otherModuleProvider(module, provider)
+ value, ok := ctx.otherModuleProvider(getWrappedModule(module), provider)
if !ok {
var k K
return k, false
diff --git a/android/raw_files.go b/android/raw_files.go
index 9d7f5e8..fd37196 100644
--- a/android/raw_files.go
+++ b/android/raw_files.go
@@ -18,7 +18,6 @@
"crypto/sha1"
"encoding/hex"
"fmt"
- "github.com/google/blueprint"
"io"
"io/fs"
"os"
@@ -26,25 +25,27 @@
"strings"
"testing"
+ "github.com/google/blueprint"
+
"github.com/google/blueprint/proptools"
)
// WriteFileRule creates a ninja rule to write contents to a file by immediately writing the
// contents, plus a trailing newline, to a file in out/soong/raw-${TARGET_PRODUCT}, and then creating
// a ninja rule to copy the file into place.
-func WriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
- writeFileRule(ctx, outputFile, content, true, false)
+func WriteFileRule(ctx BuilderContext, outputFile WritablePath, content string, validations ...Path) {
+ writeFileRule(ctx, outputFile, content, true, false, validations)
}
// WriteFileRuleVerbatim creates a ninja rule to write contents to a file by immediately writing the
// contents to a file in out/soong/raw-${TARGET_PRODUCT}, and then creating a ninja rule to copy the file into place.
-func WriteFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) {
- writeFileRule(ctx, outputFile, content, false, false)
+func WriteFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string, validations ...Path) {
+ writeFileRule(ctx, outputFile, content, false, false, validations)
}
// WriteExecutableFileRuleVerbatim is the same as WriteFileRuleVerbatim, but runs chmod +x on the result
-func WriteExecutableFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) {
- writeFileRule(ctx, outputFile, content, false, true)
+func WriteExecutableFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string, validations ...Path) {
+ writeFileRule(ctx, outputFile, content, false, true, validations)
}
// tempFile provides a testable wrapper around a file in out/soong/.temp. It writes to a temporary file when
@@ -124,7 +125,7 @@
return tempFile, hex.EncodeToString(hash.Sum(nil))
}
-func writeFileRule(ctx BuilderContext, outputFile WritablePath, content string, newline bool, executable bool) {
+func writeFileRule(ctx BuilderContext, outputFile WritablePath, content string, newline bool, executable bool, validations Paths) {
// Write the contents to a temporary file while computing its hash.
tempFile, hash := writeContentToTempFileAndHash(ctx, content, newline)
@@ -186,6 +187,7 @@
Input: rawPath,
Output: outputFile,
Description: "raw " + outputFile.Base(),
+ Validations: validations,
})
}
diff --git a/android/recovery_build_prop.go b/android/recovery_build_prop.go
new file mode 100644
index 0000000..ac7d2ec
--- /dev/null
+++ b/android/recovery_build_prop.go
@@ -0,0 +1,113 @@
+// 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 "github.com/google/blueprint/proptools"
+
+func init() {
+ RegisterModuleType("recovery_build_prop", RecoveryBuildPropModuleFactory)
+}
+
+type recoveryBuildPropProperties struct {
+ // Path to the system build.prop file
+ System_build_prop *string `android:"path"`
+
+ // Path to the vendor build.prop file
+ Vendor_build_prop *string `android:"path"`
+
+ // Path to the odm build.prop file
+ Odm_build_prop *string `android:"path"`
+
+ // Path to the product build.prop file
+ Product_build_prop *string `android:"path"`
+
+ // Path to the system_ext build.prop file
+ System_ext_build_prop *string `android:"path"`
+}
+
+type recoveryBuildPropModule struct {
+ ModuleBase
+ properties recoveryBuildPropProperties
+
+ outputFilePath ModuleOutPath
+
+ installPath InstallPath
+}
+
+func RecoveryBuildPropModuleFactory() Module {
+ module := &recoveryBuildPropModule{}
+ module.AddProperties(&module.properties)
+ InitAndroidArchModule(module, DeviceSupported, MultilibCommon)
+ return module
+}
+
+// Overrides ctx.Module().InstallInRoot().
+// recovery_build_prop module always installs in root so that the prop.default
+// file is installed in recovery/root instead of recovery/root/system
+func (r *recoveryBuildPropModule) InstallInRoot() bool {
+ return true
+}
+
+func (r *recoveryBuildPropModule) appendRecoveryUIProperties(ctx ModuleContext, rule *RuleBuilder) {
+ rule.Command().Text("echo '#' >>").Output(r.outputFilePath)
+ rule.Command().Text("echo '# RECOVERY UI BUILD PROPERTIES' >>").Output(r.outputFilePath)
+ rule.Command().Text("echo '#' >>").Output(r.outputFilePath)
+
+ for propName, val := range ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.PrivateRecoveryUiProperties {
+ if len(val) > 0 {
+ rule.Command().
+ Textf("echo ro.recovery.ui.%s=%s >>", propName, val).
+ Output(r.outputFilePath)
+ }
+ }
+}
+
+func (r *recoveryBuildPropModule) getBuildProps(ctx ModuleContext) Paths {
+ var buildProps Paths
+ for _, buildProp := range []*string{
+ r.properties.System_build_prop,
+ r.properties.Vendor_build_prop,
+ r.properties.Odm_build_prop,
+ r.properties.Product_build_prop,
+ r.properties.System_ext_build_prop,
+ } {
+ if buildProp != nil {
+ if buildPropPath := PathForModuleSrc(ctx, proptools.String(buildProp)); buildPropPath != nil {
+ buildProps = append(buildProps, buildPropPath)
+ }
+ }
+ }
+ return buildProps
+}
+
+func (r *recoveryBuildPropModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ if !r.InstallInRecovery() {
+ ctx.ModuleErrorf("recovery_build_prop module must set `recovery` property to true")
+ }
+ r.outputFilePath = PathForModuleOut(ctx, ctx.ModuleName(), "prop.default")
+
+ // Replicates the logic in https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=2733;drc=0585bb1bcf4c89065adaf709f48acc8b869fd3ce
+ rule := NewRuleBuilder(pctx, ctx)
+ rule.Command().Text("rm").FlagWithOutput("-f ", r.outputFilePath)
+ rule.Command().Text("cat").
+ Inputs(r.getBuildProps(ctx)).
+ Text(">>").
+ Output(r.outputFilePath)
+ r.appendRecoveryUIProperties(ctx, rule)
+
+ rule.Build(ctx.ModuleName(), "generating recovery prop.default")
+ r.installPath = PathForModuleInstall(ctx)
+ ctx.InstallFile(r.installPath, "prop.default", r.outputFilePath)
+}
diff --git a/android/register.go b/android/register.go
index eb6a35e..8d2f19e 100644
--- a/android/register.go
+++ b/android/register.go
@@ -91,7 +91,14 @@
bottomUpMutator blueprint.BottomUpMutator
topDownMutator blueprint.TopDownMutator
transitionMutator blueprint.TransitionMutator
- parallel bool
+
+ usesRename bool
+ usesReverseDependencies bool
+ usesReplaceDependencies bool
+ usesCreateModule bool
+ mutatesDependencies bool
+ mutatesGlobalState bool
+ neverFar bool
}
var _ sortableComponent = &mutator{}
@@ -235,6 +242,7 @@
PreDepsMutators(f RegisterMutatorFunc)
PostDepsMutators(f RegisterMutatorFunc)
+ PostApexMutators(f RegisterMutatorFunc)
FinalDepsMutators(f RegisterMutatorFunc)
}
@@ -326,6 +334,10 @@
PostDepsMutators(f)
}
+func (ctx *initRegistrationContext) PostApexMutators(f RegisterMutatorFunc) {
+ PostApexMutators(f)
+}
+
func (ctx *initRegistrationContext) FinalDepsMutators(f RegisterMutatorFunc) {
FinalDepsMutators(f)
}
diff --git a/android/removed_package.go b/android/removed_package.go
new file mode 100644
index 0000000..aa54c2a
--- /dev/null
+++ b/android/removed_package.go
@@ -0,0 +1,60 @@
+package android
+
+import (
+ "fmt"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+func init() {
+ InitRegistrationContext.RegisterModuleType("removed_package", removedPackageModuleFactory)
+}
+
+type removedPackageModuleProps struct {
+ // The error message to display when this module is built. This is optional, there is a
+ // reasonable default message.
+ Message *string
+}
+
+type removedPackageModule struct {
+ ModuleBase
+ properties removedPackageModuleProps
+}
+
+// removed_package will cause a build failure when it's included in PRODUCT_PACKAGES. It's needed
+// because currently you can add non-existent packages to PRODUCT_PACKAGES, and the build will
+// not notice/complain, unless you opt-into enforcement via $(call enforce-product-packages-exist).
+// Opting into the enforcement is difficult in some cases, because a package exists on some source
+// trees but not on others. removed_package is an intermediate solution that allows you to remove
+// a package and still get an error if it remains in PRODUCT_PACKAGES somewhere.
+func removedPackageModuleFactory() Module {
+ m := &removedPackageModule{}
+ InitAndroidModule(m)
+ m.AddProperties(&m.properties)
+ return m
+}
+
+var removedPackageRule = pctx.AndroidStaticRule("removed_package", blueprint.RuleParams{
+ Command: "echo $message && false",
+}, "message")
+
+func (m *removedPackageModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ // Unchecked module so that checkbuild doesn't fail
+ ctx.UncheckedModule()
+
+ out := PathForModuleOut(ctx, "out.txt")
+ message := fmt.Sprintf("%s has been removed, and can no longer be used.", ctx.ModuleName())
+ if m.properties.Message != nil {
+ message = *m.properties.Message
+ }
+ ctx.Build(pctx, BuildParams{
+ Rule: removedPackageRule,
+ Output: out,
+ Args: map[string]string{
+ "message": proptools.ShellEscape(message),
+ },
+ })
+
+ ctx.InstallFile(PathForModuleInstall(ctx, "removed_module"), ctx.ModuleName(), out)
+}
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 464aca4..db56c3f 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -38,6 +38,9 @@
const sboxToolsSubDir = "tools"
const sboxOutDir = sboxSandboxBaseDir + "/" + sboxOutSubDir
+const nsjailToolsSubDir = "tools"
+const nsjailOutDir = "out"
+
// RuleBuilder provides an alternative to ModuleContext.Rule and ModuleContext.Build to add a command line to the build
// graph.
type RuleBuilder struct {
@@ -59,6 +62,10 @@
sboxManifestPath WritablePath
missingDeps []string
args map[string]string
+ nsjail bool
+ nsjailKeepGendir bool
+ nsjailBasePath WritablePath
+ nsjailImplicits Paths
}
// NewRuleBuilder returns a newly created RuleBuilder.
@@ -165,12 +172,55 @@
if len(r.commands) > 0 {
panic("Sbox() may not be called after Command()")
}
+ if r.nsjail {
+ panic("Sbox() may not be called after Nsjail()")
+ }
r.sbox = true
r.outDir = outputDir
r.sboxManifestPath = manifestPath
return r
}
+// Nsjail marks the rule as needing to be wrapped by nsjail. The outputDir should point to the
+// output directory that nsjail will mount to out/. It should not be written to by any other rule.
+// baseDir should point to a location where nsjail will mount to /nsjail_build_sandbox, which will
+// be the working directory of the command.
+func (r *RuleBuilder) Nsjail(outputDir WritablePath, baseDir WritablePath) *RuleBuilder {
+ if len(r.commands) > 0 {
+ panic("Nsjail() may not be called after Command()")
+ }
+ if r.sbox {
+ panic("Nsjail() may not be called after Sbox()")
+ }
+ r.nsjail = true
+ r.outDir = outputDir
+ r.nsjailBasePath = baseDir
+ return r
+}
+
+// NsjailImplicits adds implicit inputs that are not directly mounted. This is useful when
+// the rule mounts directories, as files within those directories can be globbed and
+// tracked as dependencies with NsjailImplicits().
+func (r *RuleBuilder) NsjailImplicits(inputs Paths) *RuleBuilder {
+ if !r.nsjail {
+ panic("NsjailImplicits() must be called after Nsjail()")
+ }
+ r.nsjailImplicits = append(r.nsjailImplicits, inputs...)
+ return r
+}
+
+// By default, nsjail rules truncate outputDir and baseDir before running commands, similar to Sbox
+// rules which always run commands in a fresh sandbox. Calling NsjailKeepGendir keeps outputDir and
+// baseDir as-is, leaving previous artifacts. This is useful when the rules support incremental
+// builds.
+func (r *RuleBuilder) NsjailKeepGendir() *RuleBuilder {
+ if !r.nsjail {
+ panic("NsjailKeepGendir() must be called after Nsjail()")
+ }
+ r.nsjailKeepGendir = true
+ return r
+}
+
// SandboxTools enables tool sandboxing for the rule by copying any referenced tools into the
// sandbox.
func (r *RuleBuilder) SandboxTools() *RuleBuilder {
@@ -451,19 +501,15 @@
Inputs(depFiles.Paths())
}
-// BuildWithNinjaVars adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
-// Outputs. This function will not escape Ninja variables, so it may be used to write sandbox manifests using Ninja variables.
-func (r *RuleBuilder) BuildWithUnescapedNinjaVars(name string, desc string) {
- r.build(name, desc, false)
-}
-
// Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
// Outputs.
func (r *RuleBuilder) Build(name string, desc string) {
- r.build(name, desc, true)
+ r.build(name, desc)
}
-func (r *RuleBuilder) build(name string, desc string, ninjaEscapeCommandString bool) {
+var sandboxEnvOnceKey = NewOnceKey("sandbox_environment_variables")
+
+func (r *RuleBuilder) build(name string, desc string) {
name = ninjaNameEscape(name)
if len(r.missingDeps) > 0 {
@@ -512,7 +558,86 @@
commandString := strings.Join(commands, " && ")
- if r.sbox {
+ if !r.sbox {
+ // If not using sbox the rule will run the command directly, put the hash of the
+ // list of input files in a comment at the end of the command line to ensure ninja
+ // reruns the rule when the list of input files changes.
+ commandString += " # hash of input list: " + hashSrcFiles(inputs)
+ }
+
+ if r.nsjail {
+ var nsjailCmd strings.Builder
+ nsjailPath := r.ctx.Config().PrebuiltBuildTool(r.ctx, "nsjail")
+ if !r.nsjailKeepGendir {
+ nsjailCmd.WriteString("rm -rf ")
+ nsjailCmd.WriteString(r.nsjailBasePath.String())
+ nsjailCmd.WriteRune(' ')
+ nsjailCmd.WriteString(r.outDir.String())
+ nsjailCmd.WriteString(" && ")
+ }
+ nsjailCmd.WriteString("mkdir -p ")
+ nsjailCmd.WriteString(r.nsjailBasePath.String())
+ nsjailCmd.WriteRune(' ')
+ nsjailCmd.WriteString(r.outDir.String())
+ nsjailCmd.WriteString(" && ")
+ nsjailCmd.WriteString(nsjailPath.String())
+ nsjailCmd.WriteRune(' ')
+ nsjailCmd.WriteString("-B $PWD/")
+ nsjailCmd.WriteString(r.nsjailBasePath.String())
+ nsjailCmd.WriteString(":nsjail_build_sandbox")
+
+ // out is mounted to $(genDir).
+ nsjailCmd.WriteString(" -B $PWD/")
+ nsjailCmd.WriteString(r.outDir.String())
+ nsjailCmd.WriteString(":nsjail_build_sandbox/out")
+
+ addBindMount := func(src, dst string) {
+ nsjailCmd.WriteString(" -R $PWD/")
+ nsjailCmd.WriteString(src)
+ nsjailCmd.WriteString(":nsjail_build_sandbox/")
+ nsjailCmd.WriteString(dst)
+ }
+
+ for _, input := range inputs {
+ addBindMount(input.String(), r.nsjailPathForInputRel(input))
+ }
+ for _, tool := range tools {
+ addBindMount(tool.String(), nsjailPathForToolRel(r.ctx, tool))
+ }
+ inputs = append(inputs, tools...)
+ for _, c := range r.commands {
+ for _, directory := range c.implicitDirectories {
+ addBindMount(directory.String(), directory.String())
+ // TODO(b/375551969): Add implicitDirectories to BuildParams, rather than relying on implicits
+ inputs = append(inputs, SourcePath{basePath: directory.base()})
+ }
+ for _, tool := range c.packagedTools {
+ addBindMount(tool.srcPath.String(), nsjailPathForPackagedToolRel(tool))
+ inputs = append(inputs, tool.srcPath)
+ }
+ }
+
+ // These five directories are necessary to run native host tools like /bin/bash and py3-cmd.
+ nsjailCmd.WriteString(" -R /bin")
+ nsjailCmd.WriteString(" -R /lib")
+ nsjailCmd.WriteString(" -R /lib64")
+ nsjailCmd.WriteString(" -R /dev")
+ nsjailCmd.WriteString(" -R /usr")
+
+ nsjailCmd.WriteString(" -m none:/tmp:tmpfs:size=1073741824") // 1GB, should be enough
+ nsjailCmd.WriteString(" -D nsjail_build_sandbox")
+ nsjailCmd.WriteString(" --disable_rlimits")
+ nsjailCmd.WriteString(" --skip_setsid") // ABFS relies on process-groups to track file operations
+ nsjailCmd.WriteString(" -q")
+ nsjailCmd.WriteString(" -- ")
+ nsjailCmd.WriteString("/bin/bash -c ")
+ nsjailCmd.WriteString(proptools.ShellEscape(commandString))
+
+ commandString = nsjailCmd.String()
+
+ inputs = append(inputs, nsjailPath)
+ inputs = append(inputs, r.nsjailImplicits...)
+ } else if r.sbox {
// If running the command inside sbox, write the rule data out to an sbox
// manifest.textproto.
manifest := sbox_proto.Manifest{}
@@ -580,6 +705,44 @@
})
}
+ // 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)
}
@@ -618,30 +781,7 @@
if err != nil {
ReportPathErrorf(r.ctx, "sbox manifest failed to marshal: %q", err)
}
- if ninjaEscapeCommandString {
- WriteFileRule(r.ctx, r.sboxManifestPath, string(pbText))
- } else {
- // We need to have a rule to write files that is
- // defined on the RuleBuilder's pctx in order to
- // write Ninja variables in the string.
- // The WriteFileRule function above rule can only write
- // raw strings because it is defined on the android
- // package's pctx, and it can't access variables defined
- // in another context.
- r.ctx.Build(r.pctx, BuildParams{
- Rule: r.ctx.Rule(r.pctx, "unescapedWriteFile", blueprint.RuleParams{
- Command: `rm -rf ${out} && cat ${out}.rsp > ${out}`,
- Rspfile: "${out}.rsp",
- RspfileContent: "${content}",
- Description: "write file",
- }, "content"),
- Output: r.sboxManifestPath,
- Description: "write sbox manifest " + r.sboxManifestPath.Base(),
- Args: map[string]string{
- "content": string(pbText),
- },
- })
- }
+ WriteFileRule(r.ctx, r.sboxManifestPath, string(pbText))
// Generate a new string to use as the command line of the sbox rule. This uses
// a RuleBuilderCommand as a convenience method of building the command line, then
@@ -694,11 +834,6 @@
rewrapperCommand := r.rbeParams.NoVarTemplate(r.ctx.Config().RBEWrapper())
commandString = rewrapperCommand + " bash -c '" + strings.ReplaceAll(commandString, `'`, `'\''`) + "'"
}
- } else {
- // If not using sbox the rule will run the command directly, put the hash of the
- // list of input files in a comment at the end of the command line to ensure ninja
- // reruns the rule when the list of input files changes.
- commandString += " # hash of input list: " + hashSrcFiles(inputs)
}
// Ninja doesn't like multiple outputs when depfiles are enabled, move all but the first output to
@@ -740,10 +875,20 @@
pool = localPool
}
- if ninjaEscapeCommandString {
- commandString = proptools.NinjaEscape(commandString)
+ // If the command length is getting close to linux's maximum, dump it to a file, which allows
+ // for longer commands.
+ if len(commandString) > 100000 {
+ hasher := sha256.New()
+ hasher.Write([]byte(output.String()))
+ script := PathForOutput(r.ctx, "rule_builder_scripts", fmt.Sprintf("%x.sh", hasher.Sum(nil)))
+ commandString = "set -eu\n\n" + commandString + "\n"
+ WriteExecutableFileRuleVerbatim(r.ctx, script, commandString)
+ inputs = append(inputs, script)
+ commandString = script.String()
}
+ commandString = proptools.NinjaEscape(commandString)
+
args_vars := make([]string, len(r.args))
i := 0
for k, _ := range r.args {
@@ -779,16 +924,17 @@
type RuleBuilderCommand struct {
rule *RuleBuilder
- buf strings.Builder
- inputs Paths
- implicits Paths
- orderOnlys Paths
- validations Paths
- outputs WritablePaths
- depFiles WritablePaths
- tools Paths
- packagedTools []PackagingSpec
- rspFiles []rspFileAndPaths
+ buf strings.Builder
+ inputs Paths
+ implicits Paths
+ orderOnlys Paths
+ validations Paths
+ outputs WritablePaths
+ depFiles WritablePaths
+ tools Paths
+ packagedTools []PackagingSpec
+ rspFiles []rspFileAndPaths
+ implicitDirectories DirectoryPaths
}
type rspFileAndPaths struct {
@@ -813,6 +959,10 @@
c.implicits = append(c.implicits, path)
}
+func (c *RuleBuilderCommand) addImplicitDirectory(path DirectoryPath) {
+ c.implicitDirectories = append(c.implicitDirectories, path)
+}
+
func (c *RuleBuilderCommand) addOrderOnly(path Path) {
checkPathNotNil(path)
c.orderOnlys = append(c.orderOnlys, path)
@@ -829,6 +979,8 @@
rel = filepath.Join(sboxSandboxBaseDir, rel)
}
return rel
+ } else if c.rule.nsjail {
+ return c.rule.nsjailPathForInputRel(path)
}
return path.String()
}
@@ -854,6 +1006,10 @@
// Errors will be handled in RuleBuilder.Build where we have a context to report them
rel, _, _ := maybeRelErr(c.rule.outDir.String(), path.String())
return filepath.Join(sboxOutDir, rel)
+ } else if c.rule.nsjail {
+ // Errors will be handled in RuleBuilder.Build where we have a context to report them
+ rel, _, _ := maybeRelErr(c.rule.outDir.String(), path.String())
+ return filepath.Join(nsjailOutDir, rel)
}
return path.String()
}
@@ -905,15 +1061,49 @@
return filepath.Join(sboxToolsSubDir, "out", spec.relPathInPackage)
}
+func nsjailPathForToolRel(ctx BuilderContext, path Path) string {
+ // Errors will be handled in RuleBuilder.Build where we have a context to report them
+ toolDir := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "")
+ relOutSoong, isRelOutSoong, _ := maybeRelErr(toolDir.String(), path.String())
+ if isRelOutSoong {
+ // The tool is in the Soong output directory, it will be copied to __SBOX_OUT_DIR__/tools/out
+ return filepath.Join(nsjailToolsSubDir, "out", relOutSoong)
+ }
+ // The tool is in the source directory, it will be copied to __SBOX_OUT_DIR__/tools/src
+ return filepath.Join(nsjailToolsSubDir, "src", path.String())
+}
+
+func (r *RuleBuilder) nsjailPathForInputRel(path Path) string {
+ rel, isRelSboxOut, _ := maybeRelErr(r.outDir.String(), path.String())
+ if isRelSboxOut {
+ return filepath.Join(nsjailOutDir, rel)
+ }
+ return path.String()
+}
+
+func (r *RuleBuilder) nsjailPathsForInputsRel(paths Paths) []string {
+ ret := make([]string, len(paths))
+ for i, path := range paths {
+ ret[i] = r.nsjailPathForInputRel(path)
+ }
+ return ret
+}
+
+func nsjailPathForPackagedToolRel(spec PackagingSpec) string {
+ return filepath.Join(nsjailToolsSubDir, "out", spec.relPathInPackage)
+}
+
// PathForPackagedTool takes a PackageSpec for a tool and returns the corresponding path for the
// tool after copying it into the sandbox. This can be used on the RuleBuilder command line to
// reference the tool.
func (c *RuleBuilderCommand) PathForPackagedTool(spec PackagingSpec) string {
- if !c.rule.sboxTools {
- panic("PathForPackagedTool() requires SandboxTools()")
+ if c.rule.sboxTools {
+ return filepath.Join(sboxSandboxBaseDir, sboxPathForPackagedToolRel(spec))
+ } else if c.rule.nsjail {
+ return nsjailPathForPackagedToolRel(spec)
+ } else {
+ panic("PathForPackagedTool() requires SandboxTools() or Nsjail()")
}
-
- return filepath.Join(sboxSandboxBaseDir, sboxPathForPackagedToolRel(spec))
}
// PathForTool takes a path to a tool, which may be an output file or a source file, and returns
@@ -922,6 +1112,8 @@
func (c *RuleBuilderCommand) PathForTool(path Path) string {
if c.rule.sbox && c.rule.sboxTools {
return filepath.Join(sboxSandboxBaseDir, sboxPathForToolRel(c.rule.ctx, path))
+ } else if c.rule.nsjail {
+ return nsjailPathForToolRel(c.rule.ctx, path)
}
return path.String()
}
@@ -936,6 +1128,12 @@
ret = append(ret, filepath.Join(sboxSandboxBaseDir, sboxPathForToolRel(c.rule.ctx, path)))
}
return ret
+ } else if c.rule.nsjail {
+ var ret []string
+ for _, path := range paths {
+ ret = append(ret, nsjailPathForToolRel(c.rule.ctx, path))
+ }
+ return ret
}
return paths.Strings()
}
@@ -943,20 +1141,22 @@
// PackagedTool adds the specified tool path to the command line. It can only be used with tool
// sandboxing enabled by SandboxTools(), and will copy the tool into the sandbox.
func (c *RuleBuilderCommand) PackagedTool(spec PackagingSpec) *RuleBuilderCommand {
- if !c.rule.sboxTools {
- panic("PackagedTool() requires SandboxTools()")
- }
-
c.packagedTools = append(c.packagedTools, spec)
- c.Text(sboxPathForPackagedToolRel(spec))
+ if c.rule.sboxTools {
+ c.Text(sboxPathForPackagedToolRel(spec))
+ } else if c.rule.nsjail {
+ c.Text(nsjailPathForPackagedToolRel(spec))
+ } else {
+ panic("PackagedTool() requires SandboxTools() or Nsjail()")
+ }
return c
}
// ImplicitPackagedTool copies the specified tool into the sandbox without modifying the command
// line. It can only be used with tool sandboxing enabled by SandboxTools().
func (c *RuleBuilderCommand) ImplicitPackagedTool(spec PackagingSpec) *RuleBuilderCommand {
- if !c.rule.sboxTools {
- panic("ImplicitPackagedTool() requires SandboxTools()")
+ if !c.rule.sboxTools && !c.rule.nsjail {
+ panic("ImplicitPackagedTool() requires SandboxTools() or Nsjail()")
}
c.packagedTools = append(c.packagedTools, spec)
@@ -966,8 +1166,8 @@
// ImplicitPackagedTools copies the specified tools into the sandbox without modifying the command
// line. It can only be used with tool sandboxing enabled by SandboxTools().
func (c *RuleBuilderCommand) ImplicitPackagedTools(specs []PackagingSpec) *RuleBuilderCommand {
- if !c.rule.sboxTools {
- panic("ImplicitPackagedTools() requires SandboxTools()")
+ if !c.rule.sboxTools && !c.rule.nsjail {
+ panic("ImplicitPackagedTools() requires SandboxTools() or Nsjail()")
}
c.packagedTools = append(c.packagedTools, specs...)
@@ -1125,6 +1325,16 @@
return c
}
+// ImplicitDirectory adds the specified input directory to the dependencies without modifying the
+// command line. Added directories will be bind-mounted for the nsjail.
+func (c *RuleBuilderCommand) ImplicitDirectory(path DirectoryPath) *RuleBuilderCommand {
+ if !c.rule.nsjail {
+ panic("ImplicitDirectory() must be called after Nsjail()")
+ }
+ c.addImplicitDirectory(path)
+ return c
+}
+
// GetImplicits returns the command's implicit inputs.
func (c *RuleBuilderCommand) GetImplicits() Paths {
return c.implicits
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index 6a8a964..566bafa 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -358,7 +358,7 @@
"command3 input3 out_local/soong/module/output2 out_local/soong/module/output3 input3 out_local/soong/module/output2",
}
- wantDepMergerCommand := "out_local/soong/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer " +
+ wantDepMergerCommand := "out_local/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer " +
"out_local/soong/module/DepFile out_local/soong/module/depfile out_local/soong/module/ImplicitDepFile out_local/soong/module/depfile2"
AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
@@ -388,7 +388,7 @@
"command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3 input3 __SBOX_SANDBOX_DIR__/out/output2",
}
- wantDepMergerCommand := "out_local/soong/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer __SBOX_SANDBOX_DIR__/out/DepFile __SBOX_SANDBOX_DIR__/out/depfile __SBOX_SANDBOX_DIR__/out/ImplicitDepFile __SBOX_SANDBOX_DIR__/out/depfile2"
+ wantDepMergerCommand := "out_local/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer __SBOX_SANDBOX_DIR__/out/DepFile __SBOX_SANDBOX_DIR__/out/depfile __SBOX_SANDBOX_DIR__/out/ImplicitDepFile __SBOX_SANDBOX_DIR__/out/depfile2"
AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
@@ -475,10 +475,9 @@
Srcs []string
Flags []string
- Restat bool
- Sbox bool
- Sbox_inputs bool
- Unescape_ninja_vars bool
+ Restat bool
+ Sbox bool
+ Sbox_inputs bool
}
}
@@ -498,7 +497,7 @@
testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, t.properties.Flags,
out, outDep, outDir,
- manifestPath, t.properties.Restat, t.properties.Sbox, t.properties.Sbox_inputs, t.properties.Unescape_ninja_vars,
+ manifestPath, t.properties.Restat, t.properties.Sbox, t.properties.Sbox_inputs,
rspFile, rspFileContents, rspFile2, rspFileContents2)
}
@@ -523,14 +522,14 @@
manifestPath := PathForOutput(ctx, "singleton/sbox.textproto")
testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, nil, out, outDep, outDir,
- manifestPath, true, false, false, false,
+ manifestPath, true, false, false,
rspFile, rspFileContents, rspFile2, rspFileContents2)
}
func testRuleBuilder_Build(ctx BuilderContext, in Paths, implicit, orderOnly, validation Path,
flags []string,
out, outDep, outDir, manifestPath WritablePath,
- restat, sbox, sboxInputs, unescapeNinjaVars bool,
+ restat, sbox, sboxInputs bool,
rspFile WritablePath, rspFileContents Paths, rspFile2 WritablePath, rspFileContents2 Paths) {
rule := NewRuleBuilder(pctx_ruleBuilderTest, ctx)
@@ -558,11 +557,7 @@
rule.Restat()
}
- if unescapeNinjaVars {
- rule.BuildWithUnescapedNinjaVars("rule", "desc")
- } else {
- rule.Build("rule", "desc")
- }
+ rule.Build("rule", "desc")
}
var prepareForRuleBuilderTest = FixtureRegisterWithContext(func(ctx RegistrationContext) {
@@ -669,7 +664,7 @@
rspFile := filepath.Join(outDir, "rsp")
rspFile2 := filepath.Join(outDir, "rsp2")
manifest := filepath.Join(outDir, "sbox.textproto")
- sbox := filepath.Join("out", "soong", "host", result.Config.PrebuiltOS(), "bin/sbox")
+ sbox := filepath.Join("out", "host", result.Config.PrebuiltOS(), "bin/sbox")
sandboxPath := shared.TempDirForOutDir("out/soong")
cmd := sbox + ` --sandbox-path ` + sandboxPath + ` --output-dir ` + sboxOutDir + ` --manifest ` + manifest
@@ -685,7 +680,7 @@
rspFile := filepath.Join(outDir, "rsp")
rspFile2 := filepath.Join(outDir, "rsp2")
manifest := filepath.Join(outDir, "sbox.textproto")
- sbox := filepath.Join("out", "soong", "host", result.Config.PrebuiltOS(), "bin/sbox")
+ sbox := filepath.Join("out", "host", result.Config.PrebuiltOS(), "bin/sbox")
sandboxPath := shared.TempDirForOutDir("out/soong")
cmd := sbox + ` --sandbox-path ` + sandboxPath + ` --output-dir ` + sboxOutDir + ` --manifest ` + manifest
@@ -777,48 +772,3 @@
})
}
}
-
-func TestRuleBuilderWithNinjaVarEscaping(t *testing.T) {
- bp := `
- rule_builder_test {
- name: "foo_sbox_escaped",
- flags: ["${cmdFlags}"],
- sbox: true,
- sbox_inputs: true,
- }
- rule_builder_test {
- name: "foo_sbox_unescaped",
- flags: ["${cmdFlags}"],
- sbox: true,
- sbox_inputs: true,
- unescape_ninja_vars: true,
- }
- `
- result := GroupFixturePreparers(
- prepareForRuleBuilderTest,
- FixtureWithRootAndroidBp(bp),
- ).RunTest(t)
-
- escapedNinjaMod := result.ModuleForTests("foo_sbox_escaped", "").Output("sbox.textproto")
- AssertStringEquals(t, "expected rule", "android/soong/android.rawFileCopy", escapedNinjaMod.Rule.String())
- AssertStringDoesContain(
- t,
- "",
- ContentFromFileRuleForTests(t, result.TestContext, escapedNinjaMod),
- "${cmdFlags}",
- )
-
- unescapedNinjaMod := result.ModuleForTests("foo_sbox_unescaped", "").Rule("unescapedWriteFile")
- AssertStringDoesContain(
- t,
- "",
- unescapedNinjaMod.BuildParams.Args["content"],
- "${cmdFlags}",
- )
- AssertStringDoesNotContain(
- t,
- "",
- unescapedNinjaMod.BuildParams.Args["content"],
- "$${cmdFlags}",
- )
-}
diff --git a/android/sbom.go b/android/sbom.go
index 2a5499e..f2b9c0f 100644
--- a/android/sbom.go
+++ b/android/sbom.go
@@ -15,9 +15,7 @@
package android
import (
- "io"
"path/filepath"
- "strings"
"github.com/google/blueprint"
)
@@ -55,21 +53,7 @@
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))
- }
+ implicits := []Path{}
prodVars := ctx.Config().productVariables
buildFingerprintFile := PathForArbitraryOutput(ctx, "target", "product", String(prodVars.DeviceName), "build_fingerprint.txt")
implicits = append(implicits, buildFingerprintFile)
diff --git a/android/sdk.go b/android/sdk.go
index d3f04a4..ab9a91c 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -813,8 +813,6 @@
// 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.
//
diff --git a/android/sdk_version.go b/android/sdk_version.go
index 01b55d0..a9b88fb 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -93,6 +93,15 @@
}
}
+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:
diff --git a/android/selects_test.go b/android/selects_test.go
index fc020a4..1397ed8 100644
--- a/android/selects_test.go
+++ b/android/selects_test.go
@@ -1009,6 +1009,76 @@
},
expectedError: `variable already set in inherited scope, previous assignment:`,
},
+ {
+ name: "Basic string list postprocessor",
+ bp: `
+my_defaults {
+ name: "defaults_a",
+ my_string_list: ["a", "b", "c"],
+ string_list_postprocessor_add_to_elements: "1",
+}
+my_defaults {
+ name: "defaults_b",
+ my_string_list: ["d", "e", "f"],
+ string_list_postprocessor_add_to_elements: "2",
+}
+my_module_type {
+ name: "foo",
+ defaults: ["defaults_a", "defaults_b"],
+}
+`,
+ provider: selectsTestProvider{
+ my_string_list: &[]string{"d2", "e2", "f2", "a1", "b1", "c1"},
+ },
+ },
+ {
+ name: "string list variables",
+ bp: `
+my_module_type {
+ name: "foo",
+ my_string_list: ["a"] + select(soong_config_variable("my_namespace", "my_var"), {
+ any @ my_var: my_var,
+ default: [],
+ }),
+}
+`,
+ vendorVars: map[string]map[string]string{
+ "my_namespace": {
+ "my_var": "b c",
+ },
+ },
+ vendorVarTypes: map[string]map[string]string{
+ "my_namespace": {
+ "my_var": "string_list",
+ },
+ },
+ provider: selectsTestProvider{
+ my_string_list: &[]string{"a", "b", "c"},
+ },
+ },
+ {
+ name: "string list variables don't match string matchers",
+ bp: `
+my_module_type {
+ name: "foo",
+ my_string_list: ["a"] + select(soong_config_variable("my_namespace", "my_var"), {
+ "foo": ["b"],
+ default: [],
+ }),
+}
+`,
+ vendorVars: map[string]map[string]string{
+ "my_namespace": {
+ "my_var": "b c",
+ },
+ },
+ vendorVarTypes: map[string]map[string]string{
+ "my_namespace": {
+ "my_var": "string_list",
+ },
+ },
+ expectedError: `Expected all branches of a select on condition soong_config_variable\("my_namespace", "my_var"\) to have type string_list, found string`,
+ },
}
for _, tc := range testCases {
@@ -1161,9 +1231,15 @@
return m
}
+type selectsMockDefaultsProperties struct {
+ String_list_postprocessor_add_to_elements string
+}
+
type selectsMockModuleDefaults struct {
ModuleBase
DefaultsModuleBase
+ myProperties selectsMockModuleProperties
+ defaultsProperties selectsMockDefaultsProperties
}
func (d *selectsMockModuleDefaults) GenerateAndroidBuildActions(ctx ModuleContext) {
@@ -1173,10 +1249,22 @@
module := &selectsMockModuleDefaults{}
module.AddProperties(
- &selectsMockModuleProperties{},
+ &module.myProperties,
+ &module.defaultsProperties,
)
InitDefaultsModule(module)
+ AddLoadHook(module, func(lhc LoadHookContext) {
+ if module.defaultsProperties.String_list_postprocessor_add_to_elements != "" {
+ module.myProperties.My_string_list.AddPostProcessor(func(x []string) []string {
+ for i := range x {
+ x[i] = x[i] + module.defaultsProperties.String_list_postprocessor_add_to_elements
+ }
+ return x
+ })
+ }
+ })
+
return module
}
diff --git a/android/singleton.go b/android/singleton.go
index 8542bd9..0754b0c 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -64,6 +64,7 @@
VisitAllModulesBlueprint(visit func(blueprint.Module))
VisitAllModules(visit func(Module))
+ VisitAllModuleProxies(visit func(proxy ModuleProxy))
VisitAllModulesIf(pred func(Module) bool, visit func(Module))
VisitDirectDeps(module Module, visit func(Module))
@@ -77,8 +78,10 @@
VisitAllModuleVariants(module Module, visit func(Module))
+ VisitAllModuleVariantProxies(module Module, visit func(proxy ModuleProxy))
+
PrimaryModule(module Module) Module
- FinalModule(module Module) Module
+ IsFinalModule(module Module) bool
AddNinjaFileDeps(deps ...string)
@@ -90,6 +93,10 @@
// 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 {
@@ -189,7 +196,7 @@
}
// visitAdaptor wraps a visit function that takes an android.Module parameter into
-// a function that takes an blueprint.Module parameter and only calls the visit function if the
+// a function that takes a blueprint.Module parameter and only calls the visit function if the
// blueprint.Module is an android.Module.
func visitAdaptor(visit func(Module)) func(blueprint.Module) {
return func(module blueprint.Module) {
@@ -199,6 +206,16 @@
}
}
+// visitProxyAdaptor wraps a visit function that takes an android.ModuleProxy parameter into
+// a function that takes a blueprint.ModuleProxy parameter.
+func visitProxyAdaptor(visit func(proxy ModuleProxy)) func(proxy blueprint.ModuleProxy) {
+ return func(module blueprint.ModuleProxy) {
+ visit(ModuleProxy{
+ module: module,
+ })
+ }
+}
+
// predAdaptor wraps a pred function that takes an android.Module parameter
// into a function that takes an blueprint.Module parameter and only calls the visit function if the
// blueprint.Module is an android.Module, otherwise returns false.
@@ -220,6 +237,10 @@
s.SingletonContext.VisitAllModules(visitAdaptor(visit))
}
+func (s *singletonContextAdaptor) VisitAllModuleProxies(visit func(proxy ModuleProxy)) {
+ s.SingletonContext.VisitAllModuleProxies(visitProxyAdaptor(visit))
+}
+
func (s *singletonContextAdaptor) VisitAllModulesIf(pred func(Module) bool, visit func(Module)) {
s.SingletonContext.VisitAllModulesIf(predAdaptor(pred), visitAdaptor(visit))
}
@@ -244,12 +265,16 @@
s.SingletonContext.VisitAllModuleVariants(module, visitAdaptor(visit))
}
+func (s *singletonContextAdaptor) VisitAllModuleVariantProxies(module Module, visit func(proxy ModuleProxy)) {
+ s.SingletonContext.VisitAllModuleVariantProxies(module, visitProxyAdaptor(visit))
+}
+
func (s *singletonContextAdaptor) PrimaryModule(module Module) Module {
return s.SingletonContext.PrimaryModule(module).(Module)
}
-func (s *singletonContextAdaptor) FinalModule(module Module) Module {
- return s.SingletonContext.FinalModule(module).(Module)
+func (s *singletonContextAdaptor) IsFinalModule(module Module) bool {
+ return s.SingletonContext.IsFinalModule(module)
}
func (s *singletonContextAdaptor) ModuleVariantsFromName(referer Module, name string) []Module {
@@ -286,3 +311,7 @@
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)
+}
diff --git a/android/singleton_module.go b/android/singleton_module.go
index 2351738..43028e8 100644
--- a/android/singleton_module.go
+++ b/android/singleton_module.go
@@ -68,7 +68,7 @@
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()
diff --git a/android/singleton_module_test.go b/android/singleton_module_test.go
index 3b1bf39..3b8c6b2 100644
--- a/android/singleton_module_test.go
+++ b/android/singleton_module_test.go
@@ -96,12 +96,6 @@
}
}
-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 @@
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"}
+ },
+ })
})
}),
).
diff --git a/android/team_proto/Android.bp b/android/team_proto/Android.bp
index 7e2a4c1..5faaaf1 100644
--- a/android/team_proto/Android.bp
+++ b/android/team_proto/Android.bp
@@ -40,4 +40,8 @@
proto: {
canonical_path_from_root: false,
},
+ visibility: [
+ "//build/soong:__subpackages__",
+ "//tools/asuite/team_build_scripts",
+ ],
}
diff --git a/android/test_asserts.go b/android/test_asserts.go
index c33ade5..22472c5 100644
--- a/android/test_asserts.go
+++ b/android/test_asserts.go
@@ -33,6 +33,23 @@
}
}
+// AssertSame checks if the expected and actual values are equal and if they are not then
+// it reports an error prefixed with the supplied message and including a reason for why it failed.
+func AssertSameArray[T comparable](t *testing.T, message string, expected []T, actual []T) {
+ t.Helper()
+ if len(actual) != len(expected) {
+ t.Errorf("%s: expected %d (%v), actual (%d) %v", message, len(expected), expected, len(actual), actual)
+ return
+ }
+ for i := range actual {
+ if actual[i] != expected[i] {
+ t.Errorf("%s: expected %d-th, %v (%v), actual %v (%v)",
+ message, i, expected[i], expected, actual[i], actual)
+ return
+ }
+ }
+}
+
// AssertBoolEquals checks if the expected and actual values are equal and if they are not then it
// reports an error prefixed with the supplied message and including a reason for why it failed.
func AssertBoolEquals(t *testing.T, message string, expected bool, actual bool) {
diff --git a/android/test_config.go b/android/test_config.go
index f251038..3609e6b 100644
--- a/android/test_config.go
+++ b/android/test_config.go
@@ -45,6 +45,7 @@
Platform_version_active_codenames: []string{"S", "Tiramisu"},
DeviceSystemSdkVersions: []string{"29", "30", "S"},
Platform_systemsdk_versions: []string{"29", "30", "S", "Tiramisu"},
+ VendorApiLevel: stringPtr("202404"),
AAPTConfig: []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
AAPTPreferredConfig: stringPtr("xhdpi"),
AAPTCharacteristics: stringPtr("nosdcard"),
diff --git a/android/testing.go b/android/testing.go
index 816707d..6c4f4f8 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -19,6 +19,7 @@
"fmt"
"path/filepath"
"regexp"
+ "runtime"
"sort"
"strings"
"sync"
@@ -189,6 +190,26 @@
})
}
+// PrepareForNativeBridgeEnabled sets configuration with targets including:
+// - X86_64 (primary)
+// - X86 (secondary)
+// - Arm64 on X86_64 (native bridge)
+// - Arm on X86 (native bridge)
+var PrepareForNativeBridgeEnabled = FixtureModifyConfig(
+ func(config Config) {
+ config.Targets[Android] = []Target{
+ {Os: Android, Arch: Arch{ArchType: X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}},
+ NativeBridge: NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+ {Os: Android, Arch: Arch{ArchType: X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}},
+ NativeBridge: NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+ {Os: Android, Arch: Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}},
+ NativeBridge: NativeBridgeEnabled, NativeBridgeHostArchName: "x86_64", NativeBridgeRelativePath: "arm64"},
+ {Os: Android, Arch: Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}},
+ NativeBridge: NativeBridgeEnabled, NativeBridgeHostArchName: "x86", NativeBridgeRelativePath: "arm"},
+ }
+ },
+)
+
func NewTestArchContext(config Config) *TestContext {
ctx := NewTestContext(config)
ctx.preDeps = append(ctx.preDeps, registerArchMutator)
@@ -197,8 +218,8 @@
type TestContext struct {
*Context
- preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc
- NameResolver *NameResolver
+ preArch, preDeps, postDeps, postApex, finalDeps []RegisterMutatorFunc
+ NameResolver *NameResolver
// The list of singletons registered for the test.
singletons sortableComponents
@@ -229,6 +250,10 @@
ctx.postDeps = append(ctx.postDeps, f)
}
+func (ctx *TestContext) PostApexMutators(f RegisterMutatorFunc) {
+ ctx.postApex = append(ctx.postApex, f)
+}
+
func (ctx *TestContext) FinalDepsMutators(f RegisterMutatorFunc) {
ctx.finalDeps = append(ctx.finalDeps, f)
}
@@ -449,7 +474,7 @@
func (ctx *TestContext) Register() {
globalOrder := globallyRegisteredComponentsOrder()
- mutators := collateRegisteredMutators(ctx.preArch, ctx.preDeps, ctx.postDeps, ctx.finalDeps)
+ mutators := collateRegisteredMutators(ctx.preArch, ctx.preDeps, ctx.postDeps, ctx.postApex, ctx.finalDeps)
// Ensure that the mutators used in the test are in the same order as they are used at runtime.
globalOrder.mutatorOrder.enforceOrdering(mutators)
mutators.registerAll(ctx.Context)
@@ -1127,17 +1152,12 @@
config.katiEnabled = true
}
-func SetTrimmedApexEnabledForTests(config Config) {
- config.productVariables.TrimmedApex = new(bool)
- *config.productVariables.TrimmedApex = true
-}
-
func AndroidMkEntriesForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) []AndroidMkEntries {
t.Helper()
var p AndroidMkEntriesProvider
var ok bool
if p, ok = mod.(AndroidMkEntriesProvider); !ok {
- t.Errorf("module does not implement AndroidMkEntriesProvider: " + mod.Name())
+ t.Error("module does not implement AndroidMkEntriesProvider: " + mod.Name())
}
entriesList := p.AndroidMkEntries()
@@ -1148,12 +1168,36 @@
return entriesList
}
+func AndroidMkInfoForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) *AndroidMkProviderInfo {
+ if runtime.GOOS == "darwin" && mod.(Module).base().Os() != Darwin {
+ // The AndroidMkInfo provider is not set in this case.
+ t.Skip("AndroidMkInfo provider is not set on darwin")
+ }
+
+ t.Helper()
+ var ok bool
+ if _, ok = mod.(AndroidMkProviderInfoProducer); !ok {
+ t.Error("module does not implement AndroidMkProviderInfoProducer: " + mod.Name())
+ }
+
+ info := OtherModuleProviderOrDefault(ctx, mod, AndroidMkInfoProvider)
+ aconfigUpdateAndroidMkInfos(ctx, mod.(Module), info)
+ info.PrimaryInfo.fillInEntries(ctx, mod)
+ if len(info.ExtraInfo) > 0 {
+ for _, ei := range info.ExtraInfo {
+ ei.fillInEntries(ctx, mod)
+ }
+ }
+
+ return info
+}
+
func AndroidMkDataForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) AndroidMkData {
t.Helper()
var p AndroidMkDataProvider
var ok bool
if p, ok = mod.(AndroidMkDataProvider); !ok {
- t.Fatalf("module does not implement AndroidMkDataProvider: " + mod.Name())
+ t.Fatal("module does not implement AndroidMkDataProvider: " + mod.Name())
}
data := p.AndroidMk()
data.fillInData(ctx, mod)
@@ -1326,7 +1370,15 @@
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,
}
diff --git a/android/transition.go b/android/transition.go
new file mode 100644
index 0000000..a9346bb
--- /dev/null
+++ b/android/transition.go
@@ -0,0 +1,283 @@
+// 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 "github.com/google/blueprint"
+
+// TransitionMutator implements a top-down mechanism where a module tells its
+// direct dependencies what variation they should be built in but the dependency
+// has the final say.
+//
+// When implementing a transition mutator, one needs to implement four methods:
+// - Split() that tells what variations a module has by itself
+// - OutgoingTransition() where a module tells what it wants from its
+// dependency
+// - IncomingTransition() where a module has the final say about its own
+// variation
+// - Mutate() that changes the state of a module depending on its variation
+//
+// That the effective variation of module B when depended on by module A is the
+// composition the outgoing transition of module A and the incoming transition
+// of module B.
+//
+// the outgoing transition should not take the properties of the dependency into
+// account, only those of the module that depends on it. For this reason, the
+// dependency is not even passed into it as an argument. Likewise, the incoming
+// transition should not take the properties of the depending module into
+// account and is thus not informed about it. This makes for a nice
+// decomposition of the decision logic.
+//
+// A given transition mutator only affects its own variation; other variations
+// stay unchanged along the dependency edges.
+//
+// Soong makes sure that all modules are created in the desired variations and
+// that dependency edges are set up correctly. This ensures that "missing
+// variation" errors do not happen and allows for more flexible changes in the
+// value of the variation among dependency edges (as oppposed to bottom-up
+// mutators where if module A in variation X depends on module B and module B
+// has that variation X, A must depend on variation X of B)
+//
+// The limited power of the context objects passed to individual mutators
+// methods also makes it more difficult to shoot oneself in the foot. Complete
+// safety is not guaranteed because no one prevents individual transition
+// mutators from mutating modules in illegal ways and for e.g. Split() or
+// Mutate() to run their own visitations of the transitive dependency of the
+// module and both of these are bad ideas, but it's better than no guardrails at
+// all.
+//
+// This model is pretty close to Bazel's configuration transitions. The mapping
+// between concepts in Soong and Bazel is as follows:
+// - Module == configured target
+// - Variant == configuration
+// - Variation name == configuration flag
+// - Variation == configuration flag value
+// - Outgoing transition == attribute transition
+// - Incoming transition == rule transition
+//
+// The Split() method does not have a Bazel equivalent and Bazel split
+// transitions do not have a Soong equivalent.
+//
+// Mutate() does not make sense in Bazel due to the different models of the
+// two systems: when creating new variations, Soong clones the old module and
+// thus some way is needed to change it state whereas Bazel creates each
+// configuration of a given configured target anew.
+type TransitionMutator interface {
+ // Split returns the set of variations that should be created for a module no
+ // matter who depends on it. Used when Make depends on a particular variation
+ // or when the module knows its variations just based on information given to
+ // it in the Blueprint file. This method should not mutate the module it is
+ // called on.
+ Split(ctx BaseModuleContext) []string
+
+ // OutgoingTransition is called on a module to determine which variation it wants
+ // from its direct dependencies. The dependency itself can override this decision.
+ // This method should not mutate the module itself.
+ OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string
+
+ // IncomingTransition is called on a module to determine which variation it should
+ // be in based on the variation modules that depend on it want. This gives the module
+ // a final say about its own variations. This method should not mutate the module
+ // itself.
+ IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string
+
+ // Mutate is called after a module was split into multiple variations on each variation.
+ // It should not split the module any further but adding new dependencies is
+ // fine. Unlike all the other methods on TransitionMutator, this method is
+ // allowed to mutate the module.
+ Mutate(ctx BottomUpMutatorContext, variation string)
+}
+
+type IncomingTransitionContext interface {
+ ArchModuleContext
+ ModuleProviderContext
+ ModuleErrorContext
+
+ // Module returns the target of the dependency edge for which the transition
+ // is being computed
+ Module() Module
+
+ // ModuleName returns the name of the module. This is generally the value that was returned by Module.Name() when
+ // the module was created, but may have been modified by calls to BottomUpMutatorContext.Rename.
+ ModuleName() string
+
+ // DepTag() Returns the dependency tag through which this dependency is
+ // reached
+ DepTag() blueprint.DependencyTag
+
+ // Config returns the configuration for the build.
+ 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 {
+ ArchModuleContext
+ ModuleProviderContext
+
+ // Module returns the target of the dependency edge for which the transition
+ // is being computed
+ Module() Module
+
+ // ModuleName returns the name of the module. This is generally the value that was returned by Module.Name() when
+ // the module was created, but may have been modified by calls to BottomUpMutatorContext.Rename.
+ ModuleName() string
+
+ // DepTag() Returns the dependency tag through which this dependency is
+ // reached
+ DepTag() blueprint.DependencyTag
+
+ // Config returns the configuration for the build.
+ Config() Config
+
+ DeviceConfig() DeviceConfig
+}
+
+type androidTransitionMutator struct {
+ finalPhase bool
+ mutator TransitionMutator
+ name string
+}
+
+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)
+ } else {
+ return []string{""}
+ }
+}
+
+func (a *androidTransitionMutator) OutgoingTransition(bpctx blueprint.OutgoingTransitionContext, sourceVariation string) string {
+ if m, ok := bpctx.Module().(Module); ok {
+ ctx := outgoingTransitionContextPool.Get().(*outgoingTransitionContextImpl)
+ defer outgoingTransitionContextPool.Put(ctx)
+ *ctx = outgoingTransitionContextImpl{
+ archModuleContext: m.base().archModuleContextFactory(bpctx),
+ bp: bpctx,
+ }
+ return a.mutator.OutgoingTransition(ctx, sourceVariation)
+ } else {
+ return ""
+ }
+}
+
+func (a *androidTransitionMutator) IncomingTransition(bpctx blueprint.IncomingTransitionContext, incomingVariation string) string {
+ if m, ok := bpctx.Module().(Module); ok {
+ ctx := incomingTransitionContextPool.Get().(*incomingTransitionContextImpl)
+ defer incomingTransitionContextPool.Put(ctx)
+ *ctx = incomingTransitionContextImpl{
+ archModuleContext: m.base().archModuleContextFactory(bpctx),
+ bp: bpctx,
+ }
+ return a.mutator.IncomingTransition(ctx, incomingVariation)
+ } else {
+ return ""
+ }
+}
+
+func (a *androidTransitionMutator) Mutate(ctx blueprint.BottomUpMutatorContext, variation string) {
+ if am, ok := ctx.Module().(Module); ok {
+ if variation != "" {
+ // TODO: this should really be checking whether the TransitionMutator affected this module, not
+ // the empty variant, but TransitionMutator has no concept of skipping a module.
+ base := am.base()
+ base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, a.name)
+ base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variation)
+ }
+
+ mctx := bottomUpMutatorContextFactory(ctx, am, a.finalPhase)
+ defer bottomUpMutatorContextPool.Put(mctx)
+ a.mutator.Mutate(mctx, variation)
+ }
+}
+
+type incomingTransitionContextImpl struct {
+ archModuleContext
+ bp blueprint.IncomingTransitionContext
+}
+
+func (c *incomingTransitionContextImpl) Module() Module {
+ return c.bp.Module().(Module)
+}
+
+func (c *incomingTransitionContextImpl) ModuleName() string {
+ return c.bp.ModuleName()
+}
+
+func (c *incomingTransitionContextImpl) DepTag() blueprint.DependencyTag {
+ return c.bp.DepTag()
+}
+
+func (c *incomingTransitionContextImpl) Config() Config {
+ return c.bp.Config().(Config)
+}
+
+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)
+}
+
+func (c *incomingTransitionContextImpl) ModuleErrorf(fmt string, args ...interface{}) {
+ c.bp.ModuleErrorf(fmt, args)
+}
+
+func (c *incomingTransitionContextImpl) PropertyErrorf(property, fmt string, args ...interface{}) {
+ c.bp.PropertyErrorf(property, fmt, args)
+}
+
+type outgoingTransitionContextImpl struct {
+ archModuleContext
+ bp blueprint.OutgoingTransitionContext
+}
+
+func (c *outgoingTransitionContextImpl) Module() Module {
+ return c.bp.Module().(Module)
+}
+
+func (c *outgoingTransitionContextImpl) ModuleName() string {
+ return c.bp.ModuleName()
+}
+
+func (c *outgoingTransitionContextImpl) DepTag() blueprint.DependencyTag {
+ return c.bp.DepTag()
+}
+
+func (c *outgoingTransitionContextImpl) Config() Config {
+ return c.bp.Config().(Config)
+}
+
+func (c *outgoingTransitionContextImpl) DeviceConfig() DeviceConfig {
+ return DeviceConfig{c.bp.Config().(Config).deviceConfig}
+}
+
+func (c *outgoingTransitionContextImpl) provider(provider blueprint.AnyProviderKey) (any, bool) {
+ return c.bp.Provider(provider)
+}
diff --git a/android/transition_test.go b/android/transition_test.go
new file mode 100644
index 0000000..f7618f3
--- /dev/null
+++ b/android/transition_test.go
@@ -0,0 +1,162 @@
+// 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 "testing"
+
+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 {
+ name: "foo",
+ }
+ `
+
+ var moduleStrings []string
+
+ GroupFixturePreparers(
+ FixtureRegisterWithContext(func(ctx RegistrationContext) {
+
+ ctx.PreArchMutators(func(ctx RegisterMutatorsContext) {
+ ctx.Transition("pre_arch", &testTransitionMutator{
+ split: func(ctx BaseModuleContext) []string {
+ moduleStrings = append(moduleStrings, ctx.Module().String())
+ return []string{"a", "b"}
+ },
+ })
+ })
+
+ ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
+ 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.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())
+ ctx.Rename(ctx.Module().base().Name() + "_renamed1")
+ }).UsesRename()
+ ctx.BottomUp("final", func(ctx BottomUpMutatorContext) {
+ moduleStrings = append(moduleStrings, ctx.Module().String())
+ })
+ })
+
+ ctx.RegisterModuleType("test", mutatorTestModuleFactory)
+ }),
+ FixtureWithRootAndroidBp(bp),
+ ).RunTest(t)
+
+ want := []string{
+ // Initial name.
+ "foo{}",
+
+ // After pre_arch (reversed because rename_top_down is TopDown so it visits in reverse order).
+ "foo{pre_arch:b}",
+ "foo{pre_arch:a}",
+
+ // After pre_deps (reversed because post_deps TransitionMutator.Split is TopDown).
+ "foo{pre_arch:b,pre_deps:d}",
+ "foo{pre_arch:b,pre_deps:c}",
+ "foo{pre_arch:a,pre_deps:d}",
+ "foo{pre_arch:a,pre_deps:c}",
+
+ // After post_deps.
+ "foo{pre_arch:a,pre_deps:c,post_deps:e}",
+ "foo{pre_arch:a,pre_deps:c,post_deps:f}",
+ "foo{pre_arch:a,pre_deps:d,post_deps:e}",
+ "foo{pre_arch:a,pre_deps:d,post_deps:f}",
+ "foo{pre_arch:b,pre_deps:c,post_deps:e}",
+ "foo{pre_arch:b,pre_deps:c,post_deps:f}",
+ "foo{pre_arch:b,pre_deps:d,post_deps:e}",
+ "foo{pre_arch:b,pre_deps:d,post_deps:f}",
+
+ // After rename_bottom_up.
+ "foo_renamed1{pre_arch:a,pre_deps:c,post_deps:e}",
+ "foo_renamed1{pre_arch:a,pre_deps:c,post_deps:f}",
+ "foo_renamed1{pre_arch:a,pre_deps:d,post_deps:e}",
+ "foo_renamed1{pre_arch:a,pre_deps:d,post_deps:f}",
+ "foo_renamed1{pre_arch:b,pre_deps:c,post_deps:e}",
+ "foo_renamed1{pre_arch:b,pre_deps:c,post_deps:f}",
+ "foo_renamed1{pre_arch:b,pre_deps:d,post_deps:e}",
+ "foo_renamed1{pre_arch:b,pre_deps:d,post_deps:f}",
+ }
+
+ AssertDeepEquals(t, "module String() values", want, moduleStrings)
+}
+
+func TestTransitionMutatorInFinalDeps(t *testing.T) {
+ GroupFixturePreparers(
+ FixtureRegisterWithContext(func(ctx RegistrationContext) {
+ ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) {
+ ctx.Transition("vars", &testTransitionMutator{
+ split: func(ctx BaseModuleContext) []string {
+ return []string{"a", "b"}
+ },
+ })
+ })
+
+ ctx.RegisterModuleType("test", mutatorTestModuleFactory)
+ }),
+ FixtureWithRootAndroidBp(`test {name: "foo"}`),
+ ).
+ ExtendWithErrorHandler(FixtureExpectsOneErrorPattern("not allowed in FinalDepsMutators")).
+ RunTest(t)
+}
diff --git a/android/updatable_modules.go b/android/updatable_modules.go
deleted file mode 100644
index dd7dc2c..0000000
--- a/android/updatable_modules.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (C) 2022 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package android
-
-// This file contains branch specific constants. They are stored in a separate
-// file to minimise the potential of merge conflicts between branches when
-// the code from the package is changed.
-
-// The default manifest version for all the modules on this branch.
-// This version code will be used only if there is no version field in the
-// module's apex_manifest.json. Release branches have their version injected
-// into apex_manifest.json by the tooling and will not use the version set
-// here. Developers can also set the version field locally in the
-// apex_manifest.json to build a module with a specific version.
-//
-// The value follows the schema from go/mainline-version-codes, and is chosen
-// based on the branch such that the builds from testing and development
-// branches will have a version higher than the prebuilts.
-// Versions per branch:
-// * x-dev - xx0090000 (where xx is the branch SDK level)
-// * AOSP - xx9990000
-// * x-mainline-prod - xx9990000
-// * master - 990090000
-const DefaultUpdatableModuleVersion = "350090000"
diff --git a/android/util.go b/android/util.go
index 3c0af2f..30d8ec6 100644
--- a/android/util.go
+++ b/android/util.go
@@ -177,6 +177,41 @@
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.
@@ -273,6 +308,20 @@
return
}
+// FilterListByPrefixes performs the same splitting as FilterList does, but treats the passed
+// filters as prefixes
+func FilterListByPrefix(list []string, filter []string) (remainder []string, filtered []string) {
+ for _, l := range list {
+ if HasAnyPrefix(l, filter) {
+ filtered = append(filtered, l)
+ } else {
+ remainder = append(remainder, l)
+ }
+ }
+
+ return
+}
+
// FilterListPred returns the elements of the given list for which the predicate
// returns true. Order is kept.
func FilterListPred(list []string, pred func(s string) bool) (filtered []string) {
@@ -625,3 +674,13 @@
v, loaded := m.Map.LoadOrStore(key, value)
return v.(V), loaded
}
+
+// AppendIfNotZero append the given value to the slice if it is not the zero value
+// for its type.
+func AppendIfNotZero[T comparable](slice []T, value T) []T {
+ var zeroValue T // Get the zero value of the type T
+ if value != zeroValue {
+ return append(slice, value)
+ }
+ return slice
+}
diff --git a/android/util_test.go b/android/util_test.go
index 6537d69..b76ffcf 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -867,3 +867,51 @@
})
}
}
+
+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)
+ }
+ })
+ }
+}
diff --git a/android/variable.go b/android/variable.go
index c8744ed..3e637fe 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -29,7 +29,7 @@
func registerVariableBuildComponents(ctx RegistrationContext) {
ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
- ctx.BottomUp("variable", VariableMutator).Parallel()
+ ctx.BottomUp("variable", VariableMutator)
})
}
@@ -121,6 +121,7 @@
// 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
@@ -161,6 +162,7 @@
Optimize struct {
Enabled *bool
}
+ Aaptflags []string
}
Uml struct {
@@ -192,6 +194,9 @@
Required []string
Vintf_fragment_modules []string
}
+ SelinuxIgnoreNeverallows struct {
+ Required []string
+ }
} `android:"arch_variant"`
}
@@ -237,7 +242,8 @@
DeviceMaxPageSizeSupported *string `json:",omitempty"`
DeviceNoBionicPageSizeMacro *bool `json:",omitempty"`
- VendorApiLevel *string `json:",omitempty"`
+ VendorApiLevel *string `json:",omitempty"`
+ VendorApiLevelPropOverride *string `json:",omitempty"`
DeviceSecondaryArch *string `json:",omitempty"`
DeviceSecondaryArchVariant *string `json:",omitempty"`
@@ -333,10 +339,21 @@
HWASanIncludePaths []string `json:",omitempty"`
HWASanExcludePaths []string `json:",omitempty"`
- VendorPath *string `json:",omitempty"`
- OdmPath *string `json:",omitempty"`
- ProductPath *string `json:",omitempty"`
- SystemExtPath *string `json:",omitempty"`
+ VendorPath *string `json:",omitempty"`
+ VendorDlkmPath *string `json:",omitempty"`
+ BuildingVendorImage *bool `json:",omitempty"`
+ OdmPath *string `json:",omitempty"`
+ BuildingOdmImage *bool `json:",omitempty"`
+ OdmDlkmPath *string `json:",omitempty"`
+ ProductPath *string `json:",omitempty"`
+ BuildingProductImage *bool `json:",omitempty"`
+ SystemExtPath *string `json:",omitempty"`
+ SystemDlkmPath *string `json:",omitempty"`
+ OemPath *string `json:",omitempty"`
+ UserdataPath *string `json:",omitempty"`
+ BuildingUserdataImage *bool `json:",omitempty"`
+ RecoveryPath *string `json:",omitempty"`
+ BuildingRecoveryImage *bool `json:",omitempty"`
ClangTidy *bool `json:",omitempty"`
TidyChecks *string `json:",omitempty"`
@@ -394,10 +411,10 @@
Ndk_abis *bool `json:",omitempty"`
- TrimmedApex *bool `json:",omitempty"`
- ForceApexSymlinkOptimization *bool `json:",omitempty"`
- CompressedApex *bool `json:",omitempty"`
- Aml_abis *bool `json:",omitempty"`
+ ForceApexSymlinkOptimization *bool `json:",omitempty"`
+ CompressedApex *bool `json:",omitempty"`
+ DefaultApexPayloadType *string `json:",omitempty"`
+ Aml_abis *bool `json:",omitempty"`
DexpreoptGlobalConfig *string `json:",omitempty"`
@@ -422,10 +439,10 @@
TargetFSConfigGen []string `json:",omitempty"`
- EnforceProductPartitionInterface *bool `json:",omitempty"`
+ UseSoongSystemImage *bool `json:",omitempty"`
+ ProductSoongDefinedSystemImage *string `json:",omitempty"`
- EnforceInterPartitionJavaSdkLibrary *bool `json:",omitempty"`
- InterPartitionJavaLibraryAllowList []string `json:",omitempty"`
+ EnforceProductPartitionInterface *bool `json:",omitempty"`
BoardUsesRecoveryAsBoot *bool `json:",omitempty"`
@@ -445,7 +462,6 @@
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"`
@@ -475,6 +491,8 @@
ProductManufacturer string `json:",omitempty"`
ProductBrand string `json:",omitempty"`
+ ProductDevice string `json:",omitempty"`
+ ProductModel string `json:",omitempty"`
ReleaseVersion string `json:",omitempty"`
ReleaseAconfigValueSets []string `json:",omitempty"`
@@ -512,17 +530,32 @@
SystemPropFiles []string `json:",omitempty"`
SystemExtPropFiles []string `json:",omitempty"`
ProductPropFiles []string `json:",omitempty"`
+ OdmPropFiles []string `json:",omitempty"`
+ VendorPropFiles []string `json:",omitempty"`
- EnableUffdGc *string `json:",omitempty"`
+ EnableUffdGc *string `json:",omitempty"`
+ BoardKernelVersion *string `json:",omitempty"`
BoardAvbEnable *bool `json:",omitempty"`
BoardAvbSystemAddHashtreeFooterArgs []string `json:",omitempty"`
DeviceFrameworkCompatibilityMatrixFile []string `json:",omitempty"`
DeviceProductCompatibilityMatrixFile []string `json:",omitempty"`
+
+ PartitionVarsForSoongMigrationOnlyDoNotUse PartitionVariables
+
+ AdbKeys *string `json:",omitempty"`
+
+ DeviceMatrixFile []string `json:",omitempty"`
+ ProductManifestFiles []string `json:",omitempty"`
+ SystemManifestFile []string `json:",omitempty"`
+ SystemExtManifestFiles []string `json:",omitempty"`
+ DeviceManifestFiles []string `json:",omitempty"`
+ OdmManifestFiles []string `json:",omitempty"`
}
type PartitionQualifiedVariablesType struct {
BuildingImage bool `json:",omitempty"`
+ PrebuiltImage bool `json:",omitempty"`
BoardErofsCompressor string `json:",omitempty"`
BoardErofsCompressHints string `json:",omitempty"`
BoardErofsPclusterSize string `json:",omitempty"`
@@ -549,6 +582,19 @@
BoardAvbRollbackIndexLocation string `json:",omitempty"`
}
+type BoardSuperPartitionGroupProps struct {
+ GroupSize string `json:",omitempty"`
+ PartitionList []string `json:",omitempty"`
+}
+
+type ChainedAvbPartitionProps struct {
+ Partitions []string `json:",omitempty"`
+ Key string `json:",omitempty"`
+ Algorithm string `json:",omitempty"`
+ RollbackIndex string `json:",omitempty"`
+ RollbackIndexLocation string `json:",omitempty"`
+}
+
type PartitionVariables struct {
ProductDirectory string `json:",omitempty"`
PartitionQualifiedVariables map[string]PartitionQualifiedVariablesType
@@ -569,13 +615,99 @@
BoardExt4ShareDupBlocks string `json:",omitempty"`
BoardFlashLogicalBlockSize string `json:",omitempty"`
BoardFlashEraseBlockSize string `json:",omitempty"`
- BoardUsesRecoveryAsBoot bool `json:",omitempty"`
ProductUseDynamicPartitionSize bool `json:",omitempty"`
CopyImagesForTargetFilesZip bool `json:",omitempty"`
- BoardAvbEnable bool `json:",omitempty"`
+ VendorSecurityPatch string `json:",omitempty"`
+ OdmSecurityPatch string `json:",omitempty"`
+ SystemDlkmSecurityPatch string `json:",omitempty"`
+ VendorDlkmSecurityPatch string `json:",omitempty"`
+ OdmDlkmSecurityPatch string `json:",omitempty"`
- ProductPackages []string `json:",omitempty"`
+ BuildingSystemOtherImage bool `json:",omitempty"`
+
+ // Boot image stuff
+ BuildingRamdiskImage bool `json:",omitempty"`
+ ProductBuildBootImage bool `json:",omitempty"`
+ ProductBuildVendorBootImage string `json:",omitempty"`
+ ProductBuildInitBootImage bool `json:",omitempty"`
+ BoardUsesRecoveryAsBoot bool `json:",omitempty"`
+ BoardPrebuiltBootimage string `json:",omitempty"`
+ BoardPrebuiltInitBootimage string `json:",omitempty"`
+ BoardBootimagePartitionSize string `json:",omitempty"`
+ BoardVendorBootimagePartitionSize string `json:",omitempty"`
+ BoardInitBootimagePartitionSize string `json:",omitempty"`
+ BoardBootHeaderVersion string `json:",omitempty"`
+ TargetKernelPath string `json:",omitempty"`
+ BoardUsesGenericKernelImage bool `json:",omitempty"`
+ BootSecurityPatch string `json:",omitempty"`
+ InitBootSecurityPatch string `json:",omitempty"`
+ BoardIncludeDtbInBootimg bool `json:",omitempty"`
+ InternalKernelCmdline []string `json:",omitempty"`
+ InternalBootconfig []string `json:",omitempty"`
+ InternalBootconfigFile string `json:",omitempty"`
+
+ // Super image stuff
+ ProductUseDynamicPartitions bool `json:",omitempty"`
+ ProductRetrofitDynamicPartitions bool `json:",omitempty"`
+ ProductBuildSuperPartition bool `json:",omitempty"`
+ BoardSuperPartitionSize string `json:",omitempty"`
+ BoardSuperPartitionMetadataDevice string `json:",omitempty"`
+ BoardSuperPartitionBlockDevices []string `json:",omitempty"`
+ BoardSuperPartitionGroups map[string]BoardSuperPartitionGroupProps `json:",omitempty"`
+ ProductVirtualAbOta bool `json:",omitempty"`
+ ProductVirtualAbOtaRetrofit bool `json:",omitempty"`
+ ProductVirtualAbCompression bool `json:",omitempty"`
+ ProductVirtualAbCompressionMethod string `json:",omitempty"`
+ ProductVirtualAbCompressionFactor string `json:",omitempty"`
+ ProductVirtualAbCowVersion string `json:",omitempty"`
+ AbOtaUpdater bool `json:",omitempty"`
+
+ // Avb (android verified boot) stuff
+ BoardAvbEnable bool `json:",omitempty"`
+ BoardAvbAlgorithm string `json:",omitempty"`
+ BoardAvbKeyPath string `json:",omitempty"`
+ BoardAvbRollbackIndex string `json:",omitempty"`
+ BuildingVbmetaImage bool `json:",omitempty"`
+ ChainedVbmetaPartitions map[string]ChainedAvbPartitionProps `json:",omitempty"`
+
+ ProductPackages []string `json:",omitempty"`
+ ProductPackagesDebug []string `json:",omitempty"`
+ VendorLinkerConfigSrcs []string `json:",omitempty"`
+ ProductLinkerConfigSrcs []string `json:",omitempty"`
+
+ BoardInfoFiles []string `json:",omitempty"`
+ BootLoaderBoardName string `json:",omitempty"`
+
+ ProductCopyFiles []string `json:",omitempty"`
+
+ BuildingSystemDlkmImage bool `json:",omitempty"`
+ SystemKernelModules []string `json:",omitempty"`
+ SystemKernelBlocklistFile string `json:",omitempty"`
+ SystemKernelLoadModules []string `json:",omitempty"`
+ BuildingVendorDlkmImage bool `json:",omitempty"`
+ VendorKernelModules []string `json:",omitempty"`
+ VendorKernelBlocklistFile string `json:",omitempty"`
+ BuildingOdmDlkmImage bool `json:",omitempty"`
+ OdmKernelModules []string `json:",omitempty"`
+ OdmKernelBlocklistFile string `json:",omitempty"`
+
+ VendorRamdiskKernelModules []string `json:",omitempty"`
+ VendorRamdiskKernelBlocklistFile string `json:",omitempty"`
+ VendorRamdiskKernelLoadModules []string `json:",omitempty"`
+ VendorRamdiskKernelOptionsFile string `json:",omitempty"`
+
+ ProductFsverityGenerateMetadata bool `json:",omitempty"`
+
+ TargetScreenDensity string `json:",omitempty"`
+
+ PrivateRecoveryUiProperties map[string]string `json:",omitempty"`
+
+ PrebuiltBootloader string `json:",omitempty"`
+
+ ProductFsCasefold string `json:",omitempty"`
+ ProductQuotaProjid string `json:",omitempty"`
+ ProductFsCompression string `json:",omitempty"`
}
func boolPtr(v bool) *bool {
@@ -626,7 +758,6 @@
Malloc_zero_contents: boolPtr(true),
Malloc_pattern_fill_contents: boolPtr(false),
Safestack: boolPtr(false),
- TrimmedApex: boolPtr(false),
Build_from_text_stub: boolPtr(false),
BootJars: ConfiguredJarList{apexes: []string{}, jars: []string{}},
diff --git a/android/vendor_api_levels.go b/android/vendor_api_levels.go
new file mode 100644
index 0000000..d32bc56
--- /dev/null
+++ b/android/vendor_api_levels.go
@@ -0,0 +1,51 @@
+// 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"
+ "strconv"
+)
+
+func getSdkVersionOfVendorApiLevel(apiLevel int) (int, bool) {
+ ok := true
+ sdkVersion := -1
+ switch apiLevel {
+ case 202404:
+ sdkVersion = 35
+ case 202504:
+ sdkVersion = 36
+ case 202604:
+ sdkVersion = 37
+ default:
+ ok = false
+ }
+ return sdkVersion, ok
+}
+
+func GetSdkVersionForVendorApiLevel(vendorApiLevel string) (ApiLevel, error) {
+ vendorApiLevelInt, err := strconv.Atoi(vendorApiLevel)
+ if err != nil {
+ return NoneApiLevel, fmt.Errorf("The vendor API level %q must be able to be parsed as an integer", vendorApiLevel)
+ }
+ if vendorApiLevelInt < 35 {
+ return uncheckedFinalApiLevel(vendorApiLevelInt), nil
+ }
+
+ if sdkInt, ok := getSdkVersionOfVendorApiLevel(vendorApiLevelInt); ok {
+ return uncheckedFinalApiLevel(sdkInt), nil
+ }
+ return NoneApiLevel, fmt.Errorf("Unknown vendor API level %q. Requires updating the map in vendor_api_level.go?", vendorApiLevel)
+}
diff --git a/android/vintf_data.go b/android/vintf_data.go
new file mode 100644
index 0000000..2909817
--- /dev/null
+++ b/android/vintf_data.go
@@ -0,0 +1,172 @@
+// 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"
+ "strings"
+
+ "github.com/google/blueprint/proptools"
+)
+
+const (
+ deviceCmType = "device_cm"
+ systemManifestType = "system_manifest"
+ productManifestType = "product_manifest"
+ systemExtManifestType = "system_ext_manifest"
+ vendorManifestType = "vendor_manifest"
+ odmManifestType = "odm_manifest"
+
+ defaultDcm = "system/libhidl/vintfdata/device_compatibility_matrix.default.xml"
+ defaultSystemManifest = "system/libhidl/vintfdata/manifest.xml"
+ defaultSystemExtManifest = "system/libhidl/vintfdata/system_ext_manifest.default.xml"
+)
+
+type vintfDataProperties struct {
+ // Optional name for the installed file. If unspecified it will be manifest.xml by default.
+ Filename *string
+
+ // Type of the vintf data type, the allowed type are device_compatibility_matrix, system_manifest,
+ // product_manifest, and system_ext_manifest.
+ Type *string
+}
+
+type vintfDataRule struct {
+ ModuleBase
+
+ properties vintfDataProperties
+
+ installDirPath InstallPath
+ outputFilePath Path
+ noAction bool
+}
+
+func init() {
+ registerVintfDataComponents(InitRegistrationContext)
+}
+
+func registerVintfDataComponents(ctx RegistrationContext) {
+ ctx.RegisterModuleType("vintf_data", vintfDataFactory)
+}
+
+// vintf_fragment module processes vintf fragment file and installs under etc/vintf/manifest.
+func vintfDataFactory() Module {
+ m := &vintfDataRule{}
+ m.AddProperties(
+ &m.properties,
+ )
+ InitAndroidArchModule(m, DeviceSupported, MultilibFirst)
+
+ return m
+}
+
+func (m *vintfDataRule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ builder := NewRuleBuilder(pctx, ctx)
+ gensrc := PathForModuleOut(ctx, "manifest.xml")
+ assembleVintfEnvs := []string{}
+ inputPaths := make(Paths, 0)
+
+ switch proptools.String(m.properties.Type) {
+ case deviceCmType:
+ assembleVintfEnvs = append(assembleVintfEnvs, fmt.Sprintf("BOARD_SYSTEMSDK_VERSIONS=\"%s\"", strings.Join(ctx.DeviceConfig().SystemSdkVersions(), " ")))
+
+ deviceMatrixs := PathsForSource(ctx, ctx.Config().DeviceMatrixFile())
+ if len(deviceMatrixs) > 0 {
+ inputPaths = append(inputPaths, deviceMatrixs...)
+ } else {
+ inputPaths = append(inputPaths, PathForSource(ctx, defaultDcm))
+ }
+ case systemManifestType:
+ assembleVintfEnvs = append(assembleVintfEnvs, fmt.Sprintf("PLATFORM_SYSTEMSDK_VERSIONS=\"%s\"", strings.Join(ctx.DeviceConfig().PlatformSystemSdkVersions(), " ")))
+
+ inputPaths = append(inputPaths, PathForSource(ctx, defaultSystemManifest))
+ systemManifestFiles := PathsForSource(ctx, ctx.Config().SystemManifestFile())
+ if len(systemManifestFiles) > 0 {
+ inputPaths = append(inputPaths, systemManifestFiles...)
+ }
+ case productManifestType:
+ productManifestFiles := PathsForSource(ctx, ctx.Config().ProductManifestFiles())
+ // Only need to generate the manifest if PRODUCT_MANIFEST_FILES not defined.
+ if len(productManifestFiles) == 0 {
+ m.noAction = true
+ return
+ }
+
+ inputPaths = append(inputPaths, productManifestFiles...)
+ case systemExtManifestType:
+ assembleVintfEnvs = append(assembleVintfEnvs, fmt.Sprintf("PROVIDED_VNDK_VERSIONS=\"%s\"", strings.Join(ctx.DeviceConfig().ExtraVndkVersions(), " ")))
+
+ inputPaths = append(inputPaths, PathForSource(ctx, defaultSystemExtManifest))
+ systemExtManifestFiles := PathsForSource(ctx, ctx.Config().SystemExtManifestFiles())
+ if len(systemExtManifestFiles) > 0 {
+ inputPaths = append(inputPaths, systemExtManifestFiles...)
+ }
+ case vendorManifestType:
+ assembleVintfEnvs = append(assembleVintfEnvs, fmt.Sprintf("BOARD_SEPOLICY_VERS=\"%s\"", ctx.DeviceConfig().BoardSepolicyVers()))
+ assembleVintfEnvs = append(assembleVintfEnvs, fmt.Sprintf("PRODUCT_ENFORCE_VINTF_MANIFEST=%t", *ctx.Config().productVariables.Enforce_vintf_manifest))
+ deviceManifestFiles := PathsForSource(ctx, ctx.Config().DeviceManifestFiles())
+ // Only need to generate the manifest if DEVICE_MANIFEST_FILE is defined.
+ if len(deviceManifestFiles) == 0 {
+ m.noAction = true
+ return
+ }
+
+ inputPaths = append(inputPaths, deviceManifestFiles...)
+ case odmManifestType:
+ assembleVintfEnvs = append(assembleVintfEnvs, "VINTF_IGNORE_TARGET_FCM_VERSION=true")
+ odmManifestFiles := PathsForSource(ctx, ctx.Config().OdmManifestFiles())
+ // Only need to generate the manifest if ODM_MANIFEST_FILES is defined.
+ if len(odmManifestFiles) == 0 {
+ m.noAction = true
+ return
+ }
+
+ inputPaths = append(inputPaths, odmManifestFiles...)
+ default:
+ panic(fmt.Errorf("For %s: The attribute 'type' value only allowed device_cm, system_manifest, product_manifest, system_ext_manifest!", ctx.Module().Name()))
+ }
+
+ // Process vintf fragment source file with assemble_vintf tool
+ builder.Command().
+ Implicits(inputPaths).
+ Flags(assembleVintfEnvs).
+ BuiltTool("assemble_vintf").
+ FlagWithArg("-i ", strings.Join(inputPaths.Strings(), ":")).
+ FlagWithOutput("-o ", gensrc)
+
+ builder.Build("assemble_vintf", "Process vintf data "+gensrc.String())
+
+ m.installDirPath = PathForModuleInstall(ctx, "etc", "vintf")
+ m.outputFilePath = gensrc
+
+ installFileName := "manifest.xml"
+ if filename := proptools.String(m.properties.Filename); filename != "" {
+ installFileName = filename
+ }
+
+ ctx.InstallFile(m.installDirPath, installFileName, gensrc)
+}
+
+// Make this module visible to AndroidMK so it can be referenced from modules defined from Android.mk files
+func (m *vintfDataRule) AndroidMkEntries() []AndroidMkEntries {
+ if m.noAction {
+ return []AndroidMkEntries{}
+ }
+
+ return []AndroidMkEntries{{
+ Class: "ETC",
+ OutputFile: OptionalPathForPath(m.outputFilePath),
+ }}
+}
diff --git a/android/vintf_fragment.go b/android/vintf_fragment.go
index 329eac9..a3343fd 100644
--- a/android/vintf_fragment.go
+++ b/android/vintf_fragment.go
@@ -25,7 +25,7 @@
properties vintfFragmentProperties
installDirPath InstallPath
- outputFilePath OutputPath
+ outputFilePath Path
}
func init() {
@@ -44,7 +44,7 @@
m.AddProperties(
&m.properties,
)
- InitAndroidArchModule(m, DeviceSupported, MultilibFirst)
+ InitAndroidArchModule(m, DeviceSupported, MultilibCommon)
return m
}
@@ -64,7 +64,7 @@
builder.Build("assemble_vintf", "Process vintf fragment "+processedVintfFragment.String())
m.installDirPath = PathForModuleInstall(ctx, "etc", "vintf", "manifest")
- m.outputFilePath = processedVintfFragment.OutputPath
+ m.outputFilePath = processedVintfFragment
ctx.InstallFile(m.installDirPath, processedVintfFragment.Base(), processedVintfFragment)
}
diff --git a/android/vintf_fragment_test.go b/android/vintf_fragment_test.go
index 8be534c..cb038f5 100644
--- a/android/vintf_fragment_test.go
+++ b/android/vintf_fragment_test.go
@@ -29,8 +29,8 @@
testResult := PrepareForTestWithAndroidBuildComponents.RunTestWithBp(t, bp)
- vintfFragmentBuild := testResult.TestContext.ModuleForTests("test_vintf_fragment", "android_arm64_armv8-a").Rule("assemble_vintf")
+ vintfFragmentBuild := testResult.TestContext.ModuleForTests("test_vintf_fragment", "android_common").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)
+ t.Error("Vintf_manifest build command does not process with assemble_vintf : " + vintfFragmentBuild.RuleParams.Command)
}
}
diff --git a/android/visibility.go b/android/visibility.go
index 89c0adc..cee465e 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -268,7 +268,7 @@
// The rule checker needs to be registered before defaults expansion to correctly check that
// //visibility:xxx isn't combined with other packages in the same list in any one module.
func RegisterVisibilityRuleChecker(ctx RegisterMutatorsContext) {
- ctx.BottomUp("visibilityRuleChecker", visibilityRuleChecker).Parallel()
+ ctx.BottomUp("visibilityRuleChecker", visibilityRuleChecker)
}
// Registers the function that gathers the visibility rules for each module.
@@ -278,12 +278,12 @@
// the complete visibility lists from flat lists and after the package info is gathered to ensure
// that default_visibility is available.
func RegisterVisibilityRuleGatherer(ctx RegisterMutatorsContext) {
- ctx.BottomUp("visibilityRuleGatherer", visibilityRuleGatherer).Parallel()
+ ctx.BottomUp("visibilityRuleGatherer", visibilityRuleGatherer)
}
// This must be registered after the deps have been resolved.
func RegisterVisibilityRuleEnforcer(ctx RegisterMutatorsContext) {
- ctx.TopDown("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel()
+ ctx.BottomUp("visibilityRuleEnforcer", visibilityRuleEnforcer)
}
// Checks the per-module visibility rule lists before defaults expansion.
@@ -507,7 +507,7 @@
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.
diff --git a/android/visibility_test.go b/android/visibility_test.go
index 1a2eeca..277be0f 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -2098,8 +2098,9 @@
}
type mockFilesystemModuleProperties struct {
- Partition_type *string
- Deps []string
+ Partition_type *string
+ Deps []string
+ Is_auto_generated *bool
}
type mockFilesystemModule struct {
diff --git a/androidmk/parser/ast.go b/androidmk/parser/ast.go
index d5d1354..c3d198f 100644
--- a/androidmk/parser/ast.go
+++ b/androidmk/parser/ast.go
@@ -84,6 +84,7 @@
Prerequisites *MakeString
RecipePos Pos
Recipe string
+ RecipeEndPos Pos
}
func (x *Rule) Dump() string {
@@ -95,7 +96,7 @@
}
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
diff --git a/androidmk/parser/parser.go b/androidmk/parser/parser.go
index 8a20bb0..f2477db 100644
--- a/androidmk/parser/parser.go
+++ b/androidmk/parser/parser.go
@@ -448,6 +448,7 @@
Prerequisites: prerequisites,
Recipe: recipe,
RecipePos: recipePos,
+ RecipeEndPos: p.pos(),
})
}
}
diff --git a/androidmk/parser/parser_test.go b/androidmk/parser/parser_test.go
index fb03c23..21baf6b 100644
--- a/androidmk/parser/parser_test.go
+++ b/androidmk/parser/parser_test.go
@@ -124,3 +124,25 @@
})
}
}
+
+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())
+ }
+}
diff --git a/apex/Android.bp b/apex/Android.bp
index 17fdfc3..870ca7e 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -7,6 +7,7 @@
pkgPath: "android/soong/apex",
deps: [
"blueprint",
+ "blueprint-bpmodify",
"soong",
"soong-aconfig",
"soong-aconfig-codegen",
@@ -15,7 +16,6 @@
"soong-cc",
"soong-filesystem",
"soong-java",
- "soong-multitree",
"soong-provenance",
"soong-python",
"soong-rust",
@@ -34,6 +34,7 @@
"vndk.go",
],
testSrcs: [
+ "aconfig_test.go",
"apex_test.go",
"bootclasspath_fragment_test.go",
"classpath_element_test.go",
@@ -43,4 +44,6 @@
"systemserver_classpath_fragment_test.go",
],
pluginFor: ["soong_build"],
+ // Used by plugins
+ visibility: ["//visibility:public"],
}
diff --git a/apex/aconfig_test.go b/apex/aconfig_test.go
index 14c0b63..0eb8ef4 100644
--- a/apex/aconfig_test.go
+++ b/apex/aconfig_test.go
@@ -33,6 +33,7 @@
})
func TestValidationAcrossContainersExportedPass(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
bp string
@@ -59,6 +60,7 @@
apex_available: [
"myapex",
],
+ compile_dex: true,
}
aconfig_declarations {
name: "my_aconfig_declarations_foo",
@@ -74,6 +76,8 @@
apex_available: [
"myapex",
],
+ sdk_version: "none",
+ system_modules: "none",
}`,
},
{
@@ -122,6 +126,8 @@
apex_available: [
"myapex",
],
+ sdk_version: "none",
+ system_modules: "none",
}`,
},
{
@@ -290,6 +296,7 @@
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
java.PrepareForTestWithJavaDefaultModules,
cc.PrepareForTestWithCcBuildComponents,
@@ -305,6 +312,7 @@
}
func TestValidationAcrossContainersNotExportedFail(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
expectedError string
@@ -332,6 +340,7 @@
apex_available: [
"myapex",
],
+ compile_dex: true,
}
aconfig_declarations {
name: "my_aconfig_declarations_foo",
@@ -345,6 +354,8 @@
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 +403,8 @@
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`,
},
@@ -671,7 +684,7 @@
}
filegroup {
name: "my_filegroup_foo_srcjars",
- srcs: [
+ device_common_srcs: [
":my_aconfig_declarations_group_foo{.srcjars}",
],
}
@@ -693,12 +706,15 @@
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`,
},
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
errorHandler := android.FixtureExpectsNoErrors
if test.expectedError != "" {
errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(test.expectedError)
@@ -720,6 +736,7 @@
}
func TestValidationNotPropagateAcrossShared(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
bp string
@@ -746,6 +763,7 @@
apex_available: [
"myapex",
],
+ compile_dex: true,
}
java_library {
name: "my_java_library_foo",
@@ -769,11 +787,14 @@
apex_available: [
"myapex",
],
+ sdk_version: "none",
+ system_modules: "none",
}`,
},
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
java.PrepareForTestWithJavaDefaultModules,
cc.PrepareForTestWithCcBuildComponents,
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 4112108..ec5ca15 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -136,6 +136,11 @@
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
@@ -292,7 +297,7 @@
fmt.Fprintf(w, "$(call declare-0p-target,%s)\n", a.installedFilesFile.String())
}
for _, dist := range data.Entries.GetDistForGoals(a) {
- fmt.Fprintf(w, dist)
+ fmt.Fprintln(w, dist)
}
distCoverageFiles(w, "ndk_apis_usedby_apex", a.nativeApisUsedByModuleFile.String())
diff --git a/apex/apex.go b/apex/apex.go
index ec71c18..d98cfae 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -20,19 +20,21 @@
"fmt"
"path/filepath"
"regexp"
+ "slices"
"sort"
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/depset"
"github.com/google/blueprint/proptools"
"android/soong/android"
"android/soong/bpf"
"android/soong/cc"
+ "android/soong/dexpreopt"
prebuilt_etc "android/soong/etc"
"android/soong/filesystem"
"android/soong/java"
- "android/soong/multitree"
"android/soong/rust"
"android/soong/sh"
)
@@ -50,33 +52,21 @@
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()
+ ctx.BottomUp("apex_vndk_deps", apexVndkDepsMutator).UsesReverseDependencies()
}
func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
- ctx.TopDown("apex_info", apexInfoMutator).Parallel()
- ctx.BottomUp("apex_unique", apexUniqueVariationsMutator).Parallel()
- ctx.BottomUp("apex_test_for_deps", apexTestForDepsMutator).Parallel()
- ctx.BottomUp("apex_test_for", apexTestForMutator).Parallel()
+ ctx.TopDown("apex_info", apexInfoMutator)
+ ctx.BottomUp("apex_unique", apexUniqueVariationsMutator)
// Run mark_platform_availability before the apexMutator as the apexMutator needs to know whether
// it should create a platform variant.
- ctx.BottomUp("mark_platform_availability", markPlatformAvailability).Parallel()
+ ctx.BottomUp("mark_platform_availability", markPlatformAvailability)
ctx.Transition("apex", &apexTransitionMutator{})
- ctx.BottomUp("apex_directly_in_any", apexDirectlyInAnyMutator).Parallel()
- ctx.BottomUp("apex_dcla_deps", apexDCLADepsMutator).Parallel()
- // Register after apex_info mutator so that it can use ApexVariationName
- ctx.TopDown("apex_strict_updatability_lint", apexStrictUpdatibilityLintMutator).Parallel()
}
type apexBundleProperties struct {
@@ -114,11 +104,10 @@
Rros []string
// List of bootclasspath fragments that are embedded inside this APEX bundle.
- Bootclasspath_fragments []string
+ Bootclasspath_fragments proptools.Configurable[[]string]
// List of systemserverclasspath fragments that are embedded inside this APEX bundle.
- Systemserverclasspath_fragments proptools.Configurable[[]string]
- ResolvedSystemserverclasspathFragments []string `blueprint:"mutated"`
+ Systemserverclasspath_fragments proptools.Configurable[[]string]
// List of java libraries that are embedded inside this APEX bundle.
Java_libs []string
@@ -158,9 +147,6 @@
// Default: true.
Installable *bool
- // Deprecated. Do not use. TODO(b/350644693) remove this after removing all usage
- Use_vndk_as_stable *bool
-
// The type of filesystem to use. Either 'ext4', 'f2fs' or 'erofs'. Default 'ext4'.
Payload_fs_type *string
@@ -168,10 +154,6 @@
// 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
@@ -216,7 +198,7 @@
Native_shared_libs proptools.Configurable[[]string]
// List of JNI libraries that are embedded inside this APEX.
- Jni_libs []string
+ Jni_libs proptools.Configurable[[]string]
// List of rust dyn libraries that are embedded inside this APEX.
Rust_dyn_libs []string
@@ -300,9 +282,9 @@
}
// Merge combines another ApexNativeDependencies into this one
-func (a *ResolvedApexNativeDependencies) Merge(ctx android.BaseMutatorContext, b ApexNativeDependencies) {
+func (a *ResolvedApexNativeDependencies) Merge(ctx android.BaseModuleContext, 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.Jni_libs = append(a.Jni_libs, b.Jni_libs.GetOrDefault(ctx, nil)...)
a.Rust_dyn_libs = append(a.Rust_dyn_libs, b.Rust_dyn_libs...)
a.Binaries = append(a.Binaries, b.Binaries.GetOrDefault(ctx, nil)...)
a.Tests = append(a.Tests, b.Tests...)
@@ -404,7 +386,7 @@
// Apex Container package name. Override value for attribute package:name in
// AndroidManifest.xml
- Package_name string
+ Package_name proptools.Configurable[string]
// A txt file containing list of files that are allowed to be included in this APEX.
Allowed_files *string `android:"path"`
@@ -438,7 +420,6 @@
android.ModuleBase
android.DefaultableModuleBase
android.OverridableModuleBase
- multitree.ExportableModuleBase
// Properties
properties apexBundleProperties
@@ -446,6 +427,7 @@
archProperties apexArchBundleProperties
overridableProperties overridableProperties
vndkProperties apexVndkProperties // only for apex_vndk modules
+ testProperties apexTestProperties // only for apex_test modules
///////////////////////////////////////////////////////////////////////////////////////////
// Inputs
@@ -473,6 +455,12 @@
// GenerateAndroidBuildActions.
filesInfo []apexFile
+ // List of files that were excluded by the unwanted_transitive_deps property.
+ unwantedTransitiveFilesInfo []apexFile
+
+ // List of files that were excluded due to conflicts with other variants of the same module.
+ duplicateTransitiveFilesInfo []apexFile
+
// List of other module names that should be installed when this APEX gets installed (LOCAL_REQUIRED_MODULES).
makeModulesToInstall []string
@@ -516,7 +504,7 @@
// Text file having the list of individual files that are included in this APEX. Used for
// debugging purpose.
- installedFilesFile android.WritablePath
+ installedFilesFile android.Path
// List of module names that this APEX is including (to be shown via *-deps-info target).
// Used for debugging purpose.
@@ -577,6 +565,8 @@
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>]
@@ -589,7 +579,7 @@
dataPaths []android.DataPath // becomes LOCAL_TEST_DATA
jacocoReportClassesFile android.Path // only for javalibs and apps
- lintDepSets java.LintDepSets // only for javalibs and apps
+ lintInfo *java.LintInfo // only for javalibs and apps
certificate java.Certificate // only for apps
overriddenPackageName string // only for apps
@@ -612,11 +602,11 @@
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)
- ret.targetRequiredModuleNames = module.TargetRequiredModuleNames()
- ret.hostRequiredModuleNames = module.HostRequiredModuleNames()
ret.multilib = module.Target().Arch.ArchType.Multilib
}
return ret
@@ -699,6 +689,8 @@
// 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 {
@@ -717,18 +709,22 @@
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"}
+ 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}
@@ -736,7 +732,6 @@
prebuiltTag = &dependencyTag{name: "prebuilt", payload: true}
rroTag = &dependencyTag{name: "rro", payload: true}
sharedLibTag = &dependencyTag{name: "sharedLib", payload: true}
- testForTag = &dependencyTag{name: "test for"}
testTag = &dependencyTag{name: "test", payload: true}
shBinaryTag = &dependencyTag{name: "shBinary", payload: true}
)
@@ -830,6 +825,7 @@
deps.Merge(ctx, a.properties.Multilib.Both)
deps.Merge(ctx, ApexNativeDependencies{
Native_shared_libs: a.properties.Native_shared_libs,
+ Rust_dyn_libs: a.properties.Rust_dyn_libs,
Tests: a.properties.Tests,
Jni_libs: a.properties.Jni_libs,
})
@@ -842,7 +838,7 @@
deps.Merge(ctx, ApexNativeDependencies{
Native_shared_libs: proptools.NewConfigurable[[]string](nil, nil),
Tests: nil,
- Jni_libs: nil,
+ Jni_libs: proptools.NewConfigurable[[]string](nil, nil),
Binaries: a.properties.Binaries,
})
}
@@ -884,18 +880,28 @@
}
}
- a.properties.ResolvedSystemserverclasspathFragments = a.properties.Systemserverclasspath_fragments.GetOrDefault(ctx, nil)
-
// Common-arch dependencies come next
commonVariation := ctx.Config().AndroidCommonTarget.Variations()
ctx.AddFarVariationDependencies(commonVariation, rroTag, a.properties.Rros...)
- ctx.AddFarVariationDependencies(commonVariation, bcpfTag, a.properties.Bootclasspath_fragments...)
- ctx.AddFarVariationDependencies(commonVariation, sscpfTag, a.properties.ResolvedSystemserverclasspathFragments...)
+ ctx.AddFarVariationDependencies(commonVariation, bcpfTag, a.properties.Bootclasspath_fragments.GetOrDefault(ctx, nil)...)
+ ctx.AddFarVariationDependencies(commonVariation, sscpfTag, a.properties.Systemserverclasspath_fragments.GetOrDefault(ctx, nil)...)
ctx.AddFarVariationDependencies(commonVariation, javaLibTag, a.properties.Java_libs...)
ctx.AddFarVariationDependencies(commonVariation, fsTag, a.properties.Filesystems...)
ctx.AddFarVariationDependencies(commonVariation, compatConfigTag, a.properties.Compat_configs...)
+
+ // Add a reverse dependency to all_apex_certs singleton module.
+ // all_apex_certs will use this dependency to collect the certificate of this apex.
+ ctx.AddReverseDependency(ctx.Module(), allApexCertsDepTag, "all_apex_certs")
}
+type allApexCertsDependencyTag struct {
+ blueprint.DependencyTag
+}
+
+func (_ allApexCertsDependencyTag) ExcludeFromVisibilityEnforcement() {}
+
+var allApexCertsDepTag = allApexCertsDependencyTag{}
+
// DepsMutator for the overridden properties.
func (a *apexBundle) OverridablePropertiesDepsMutator(ctx android.BottomUpMutatorContext) {
if a.overridableProperties.Allowed_files != nil {
@@ -940,33 +946,6 @@
}
}
-func apexDCLADepsMutator(mctx android.BottomUpMutatorContext) {
- if !mctx.Config().ApexTrimEnabled() {
- return
- }
- if a, ok := mctx.Module().(*apexBundle); ok && a.overridableProperties.Trim_against != nil {
- commonVariation := mctx.Config().AndroidCommonTarget.Variations()
- mctx.AddFarVariationDependencies(commonVariation, dclaTag, String(a.overridableProperties.Trim_against))
- } else if o, ok := mctx.Module().(*OverrideApex); ok {
- for _, p := range o.GetProperties() {
- properties, ok := p.(*overridableProperties)
- if !ok {
- continue
- }
- if properties.Trim_against != nil {
- commonVariation := mctx.Config().AndroidCommonTarget.Variations()
- mctx.AddFarVariationDependencies(commonVariation, dclaTag, String(properties.Trim_against))
- }
- }
- }
-}
-
-type DCLAInfo struct {
- ProvidedLibs []string
-}
-
-var DCLAInfoProvider = blueprint.NewMutatorProvider[DCLAInfo]("apex_info")
-
var _ ApexInfoMutator = (*apexBundle)(nil)
func (a *apexBundle) ApexVariationName() string {
@@ -999,42 +978,11 @@
if !ok || !am.CanHaveApexVariants() {
return false
}
- depTag := mctx.OtherModuleDependencyTag(child)
- // Check to see if the tag always requires that the child module has an apex variant for every
- // apex variant of the parent module. If it does not then it is still possible for something
- // else, e.g. the DepIsInSameApex(...) method to decide that a variant is required.
- if required, ok := depTag.(android.AlwaysRequireApexVariantTag); ok && required.AlwaysRequireApexVariant() {
- return true
- }
- if !android.IsDepInSameApex(mctx, parent, child) {
- return false
- }
-
- // By default, all the transitive dependencies are collected, unless filtered out
- // above.
- return true
+ return android.IsDepInSameApex(mctx, parent, child)
}
- // Records whether a certain module is included in this apexBundle via direct dependency or
- // inndirect dependency.
- contents := make(map[string]android.ApexMembership)
- mctx.WalkDeps(func(child, parent android.Module) bool {
- if !continueApexDepsWalk(child, parent) {
- return false
- }
- // If the parent is apexBundle, this child is directly depended.
- _, directDep := parent.(*apexBundle)
- depName := mctx.OtherModuleName(child)
- contents[depName] = contents[depName].Add(directDep)
- return true
- })
-
- // The membership information is saved for later access
- apexContents := android.NewApexContents(contents)
- android.SetProvider(mctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{
- Contents: apexContents,
- })
+ android.SetProvider(mctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{})
minSdkVersion := a.minSdkVersion(mctx)
// When min_sdk_version is not set, the apex is built against FutureApiLevel.
@@ -1052,20 +1000,14 @@
}
a.properties.ApexVariationName = apexVariationName
- testApexes := []string{}
- if a.testApex {
- testApexes = []string{apexVariationName}
- }
apexInfo := android.ApexInfo{
ApexVariationName: apexVariationName,
MinSdkVersion: minSdkVersion,
Updatable: a.Updatable(),
UsePlatformApis: a.UsePlatformApis(),
InApexVariants: []string{apexVariationName},
- 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) {
@@ -1074,12 +1016,6 @@
child.(android.ApexModule).BuildForApex(apexInfo) // leave a mark!
return true
})
-
- if a.dynamic_common_lib_apex() {
- android.SetProvider(mctx, DCLAInfoProvider, DCLAInfo{
- ProvidedLibs: a.properties.Native_shared_libs.GetOrDefault(mctx, nil),
- })
- }
}
type ApexInfoMutator interface {
@@ -1107,51 +1043,6 @@
if am, ok := mctx.Module().(android.ApexModule); ok {
android.ApexInfoMutator(mctx, am)
}
- enforceAppUpdatability(mctx)
-}
-
-// apexStrictUpdatibilityLintMutator propagates strict_updatability_linting to transitive deps of a mainline module
-// This check is enforced for updatable modules
-func apexStrictUpdatibilityLintMutator(mctx android.TopDownMutatorContext) {
- if !mctx.Module().Enabled(mctx) {
- return
- }
- if apex, ok := mctx.Module().(*apexBundle); ok && apex.checkStrictUpdatabilityLinting(mctx) {
- mctx.WalkDeps(func(child, parent android.Module) bool {
- // b/208656169 Do not propagate strict updatability linting to libcore/
- // These libs are available on the classpath during compilation
- // These libs are transitive deps of the sdk. See java/sdk.go:decodeSdkDep
- // Only skip libraries defined in libcore root, not subdirectories
- if mctx.OtherModuleDir(child) == "libcore" {
- // Do not traverse transitive deps of libcore/ libs
- return false
- }
- if android.InList(child.Name(), skipLintJavalibAllowlist) {
- return false
- }
- if lintable, ok := child.(java.LintDepSetsIntf); ok {
- lintable.SetStrictUpdatabilityLinting(true)
- }
- // visit transitive deps
- return true
- })
- }
-}
-
-// enforceAppUpdatability propagates updatable=true to apps of updatable apexes
-func enforceAppUpdatability(mctx android.TopDownMutatorContext) {
- if !mctx.Module().Enabled(mctx) {
- return
- }
- if apex, ok := mctx.Module().(*apexBundle); ok && apex.Updatable() {
- // checking direct deps is sufficient since apex->apk is a direct edge, even when inherited via apex_defaults
- mctx.VisitDirectDeps(func(module android.Module) {
- // ignore android_test_app
- if app, ok := module.(*java.AndroidApp); ok {
- app.SetUpdatable(true)
- }
- })
- }
}
// TODO: b/215736885 Whittle the denylist
@@ -1165,7 +1056,7 @@
"com.android.appsearch",
"com.android.art",
"com.android.art.debug",
- "com.android.btservices",
+ "com.android.bt",
"com.android.cellbroadcast",
"com.android.configinfrastructure",
"com.android.conscrypt",
@@ -1198,20 +1089,9 @@
"test_jitzygote_com.android.art",
// go/keep-sorted end
}
-
- // TODO: b/215736885 Remove this list
- skipLintJavalibAllowlist = []string{
- "conscrypt.module.platform.api.stubs",
- "conscrypt.module.public.api.stubs",
- "conscrypt.module.public.api.stubs.system",
- "conscrypt.module.public.api.stubs.module_lib",
- "framework-media.stubs",
- "framework-media.stubs.system",
- "framework-media.stubs.module_lib",
- }
)
-func (a *apexBundle) checkStrictUpdatabilityLinting(mctx android.TopDownMutatorContext) bool {
+func (a *apexBundle) checkStrictUpdatabilityLinting(mctx android.ModuleContext) bool {
// The allowlist contains the base apex name, so use that instead of the ApexVariationName
return a.Updatable() && !android.InList(mctx.ModuleName(), skipStrictUpdatabilityLintAllowlist)
}
@@ -1228,40 +1108,6 @@
}
}
-// apexTestForDepsMutator checks if this module is a test for an apex. If so, add a dependency on
-// the apex in order to retrieve its contents later.
-// TODO(jiyong): move this to android/apex.go?
-func apexTestForDepsMutator(mctx android.BottomUpMutatorContext) {
- if !mctx.Module().Enabled(mctx) {
- return
- }
- if am, ok := mctx.Module().(android.ApexModule); ok {
- if testFor := am.TestFor(); len(testFor) > 0 {
- mctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "os", Variation: am.Target().OsVariation()},
- {"arch", "common"},
- }, testForTag, testFor...)
- }
- }
-}
-
-// TODO(jiyong): move this to android/apex.go?
-func apexTestForMutator(mctx android.BottomUpMutatorContext) {
- if !mctx.Module().Enabled(mctx) {
- return
- }
- if _, ok := mctx.Module().(android.ApexModule); ok {
- var contents []*android.ApexContents
- for _, testFor := range mctx.GetDirectDepsWithTag(testForTag) {
- abInfo, _ := android.OtherModuleProvider(mctx, testFor, android.ApexBundleInfoProvider)
- contents = append(contents, abInfo.Contents)
- }
- android.SetProvider(mctx, android.ApexTestForInfoProvider, android.ApexTestForInfo{
- ApexContents: contents,
- })
- }
-}
-
// markPlatformAvailability marks whether or not a module can be available to platform. A module
// cannot be available to platform if 1) it is explicitly marked as not available (i.e.
// "//apex_available:platform" is absent) or 2) it depends on another module that isn't (or can't
@@ -1360,17 +1206,6 @@
return true
}
-// See android.UpdateDirectlyInAnyApex
-// TODO(jiyong): move this to android/apex.go?
-func apexDirectlyInAnyMutator(mctx android.BottomUpMutatorContext) {
- if !mctx.Module().Enabled(mctx) {
- return
- }
- if am, ok := mctx.Module().(android.ApexModule); ok {
- android.UpdateDirectlyInAnyApex(mctx, am)
- }
-}
-
const (
// File extensions of an APEX for different packaging methods
imageApexSuffix = ".apex"
@@ -1387,13 +1222,17 @@
var _ android.DepIsInSameApex = (*apexBundle)(nil)
// Implements android.DepInInSameApex
-func (a *apexBundle) DepIsInSameApex(_ android.BaseModuleContext, _ android.Module) bool {
+func (a *apexBundle) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
// direct deps of an APEX bundle are all part of the APEX bundle
// TODO(jiyong): shouldn't we look into the payload field of the dependencyTag?
return true
}
-var _ multitree.Exportable = (*apexBundle)(nil)
+func (a *apexBundle) IncomingDepIsInSameApex(tag blueprint.DependencyTag) bool {
+ // direct deps of an APEX bundle are all part of the APEX bundle
+ // TODO(jiyong): shouldn't we look into the payload field of the dependencyTag?
+ return true
+}
func (a *apexBundle) Exportable() bool {
return true
@@ -1448,6 +1287,23 @@
return proptools.BoolDefault(a.properties.Platform_apis, false)
}
+type apexValidationType int
+
+const (
+ hostApexVerifier apexValidationType = iota
+ apexSepolicyTests
+)
+
+func (a *apexBundle) skipValidation(validationType apexValidationType) bool {
+ switch validationType {
+ case hostApexVerifier:
+ return proptools.Bool(a.testProperties.Skip_validations.Host_apex_verifier)
+ case apexSepolicyTests:
+ return proptools.Bool(a.testProperties.Skip_validations.Apex_sepolicy_tests)
+ }
+ panic("Unknown validation type")
+}
+
// getCertString returns the name of the cert that should be used to sign this APEX. This is
// basically from the "certificate" property, but could be overridden by the device config.
func (a *apexBundle) getCertString(ctx android.BaseModuleContext) string {
@@ -1470,11 +1326,6 @@
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)
@@ -1490,19 +1341,6 @@
return proptools.BoolDefault(a.properties.Dynamic_common_lib_apex, false)
}
-// See the list of libs to trim
-func (a *apexBundle) libs_to_trim(ctx android.ModuleContext) []string {
- dclaModules := ctx.GetDirectDepsWithTag(dclaTag)
- if len(dclaModules) > 1 {
- panic(fmt.Errorf("expected exactly at most one dcla dependency, got %d", len(dclaModules)))
- }
- if len(dclaModules) > 0 {
- DCLAInfo, _ := android.OtherModuleProvider(ctx, dclaModules[0], DCLAInfoProvider)
- return DCLAInfo.ProvidedLibs
- }
- return []string{}
-}
-
// These functions are interfacing with cc/sanitizer.go. The entire APEX (along with all of its
// members) can be sanitized, either forcibly, or by the global configuration. For some of the
// sanitizers, extra dependencies can be forcibly added as well.
@@ -1548,12 +1386,12 @@
// apexFileFor<Type> functions below create an apexFile struct for a given Soong module. The
// returned apexFile saves information about the Soong module that will be used for creating the
// build rules.
-func apexFileForNativeLibrary(ctx android.BaseModuleContext, ccMod *cc.Module, handleSpecialLibs bool) apexFile {
+func apexFileForNativeLibrary(ctx android.BaseModuleContext, ccMod cc.VersionedLinkableInterface, handleSpecialLibs bool) apexFile {
// Decide the APEX-local directory by the multilib of the library In the future, we may
// query this to the module.
// TODO(jiyong): use the new PackagingSpec
var dirInApex string
- switch ccMod.Arch().ArchType.Multilib {
+ switch ccMod.Multilib() {
case "lib32":
dirInApex = "lib"
case "lib64":
@@ -1580,7 +1418,7 @@
dirInApex = filepath.Join(dirInApex, ccMod.RelativeInstallPath())
fileToCopy := android.OutputFileForModule(ctx, ccMod, "")
- androidMkModuleName := ccMod.BaseModuleName() + ccMod.Properties.SubName
+ androidMkModuleName := ccMod.BaseModuleName() + ccMod.SubName()
return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, ccMod)
}
@@ -1610,25 +1448,6 @@
return af
}
-func apexFileForRustLibrary(ctx android.BaseModuleContext, rustm *rust.Module) apexFile {
- // Decide the APEX-local directory by the multilib of the library
- // In the future, we may query this to the module.
- var dirInApex string
- switch rustm.Arch().ArchType.Multilib {
- case "lib32":
- dirInApex = "lib"
- case "lib64":
- dirInApex = "lib64"
- }
- if rustm.Target().NativeBridge == android.NativeBridgeEnabled {
- dirInApex = filepath.Join(dirInApex, rustm.Target().NativeBridgeRelativePath)
- }
- dirInApex = filepath.Join(dirInApex, rustm.RelativeInstallPath())
- fileToCopy := android.OutputFileForModule(ctx, rustm, "")
- androidMkModuleName := rustm.BaseModuleName() + rustm.Properties.SubName
- return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, rustm)
-}
-
func apexFileForShBinary(ctx android.BaseModuleContext, sh *sh.ShBinary) apexFile {
dirInApex := filepath.Join("bin", sh.SubDir())
if sh.Target().NativeBridge == android.NativeBridgeEnabled {
@@ -1659,7 +1478,6 @@
BaseModuleName() string
DexJarBuildPath(ctx android.ModuleErrorfContext) java.OptionalDexJarPath
JacocoReportClassesFile() android.Path
- LintDepSets() java.LintDepSets
Stem() string
}
@@ -1679,19 +1497,19 @@
dirInApex := "javalib"
af := newApexFile(ctx, dexImplementationJar, module.BaseModuleName(), dirInApex, javaSharedLib, module)
af.jacocoReportClassesFile = module.JacocoReportClassesFile()
- af.lintDepSets = module.LintDepSets()
+ if lintInfo, ok := android.OtherModuleProvider(ctx, module, java.LintProvider); ok {
+ af.lintInfo = lintInfo
+ }
af.customStem = module.Stem() + ".jar"
// TODO: b/338641779 - Remove special casing of sdkLibrary once bcpf and sscpf depends
// on the implementation library
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
@@ -1719,7 +1537,6 @@
JacocoReportClassesFile() android.Path
Certificate() java.Certificate
BaseModuleName() string
- LintDepSets() java.LintDepSets
PrivAppAllowlist() android.OptionalPath
}
@@ -1755,7 +1572,9 @@
af := newApexFile(ctx, fileToCopy, aapp.BaseModuleName(), dirInApex, app, aapp)
af.jacocoReportClassesFile = aapp.JacocoReportClassesFile()
- af.lintDepSets = aapp.LintDepSets()
+ if lintInfo, ok := android.OtherModuleProvider(ctx, aapp, java.LintProvider); ok {
+ af.lintInfo = lintInfo
+ }
af.certificate = aapp.Certificate()
if app, ok := aapp.(interface {
@@ -1806,7 +1625,7 @@
// visited module, the `do` callback is executed. Returning true in the callback continues the visit
// to the child modules. Returning false makes the visit to continue in the sibling or the parent
// modules. This is used in check* functions below.
-func (a *apexBundle) WalkPayloadDeps(ctx android.ModuleContext, do android.PayloadDepsCallback) {
+func (a *apexBundle) WalkPayloadDeps(ctx android.BaseModuleContext, do android.PayloadDepsCallback) {
ctx.WalkDeps(func(child, parent android.Module) bool {
am, ok := child.(android.ApexModule)
if !ok || !am.CanHaveApexVariants() {
@@ -1833,6 +1652,32 @@
})
}
+func (a *apexBundle) WalkPayloadDepsProxy(ctx android.BaseModuleContext,
+ do func(ctx android.BaseModuleContext, from, to android.ModuleProxy, externalDep bool) bool) {
+ ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool {
+ if !android.OtherModuleProviderOrDefault(ctx, child, android.CommonModuleInfoKey).CanHaveApexVariants {
+ return false
+ }
+ // Filter-out unwanted depedendencies
+ depTag := ctx.OtherModuleDependencyTag(child)
+ if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
+ return false
+ }
+ if dt, ok := depTag.(*dependencyTag); ok && !dt.payload {
+ return false
+ }
+ if depTag == android.RequiredDepTag {
+ return false
+ }
+
+ ai, _ := android.OtherModuleProvider(ctx, child, android.ApexInfoProvider)
+ externalDep := !android.InList(ctx.ModuleName(), ai.InApexVariants)
+
+ // Visit actually
+ return do(ctx, parent, child, externalDep)
+ })
+}
+
// filesystem type of the apex_payload.img inside the APEX. Currently, ext4 and f2fs are supported.
type fsType int
@@ -1888,7 +1733,8 @@
}
func (a *apexBundle) setPayloadFsType(ctx android.ModuleContext) {
- switch proptools.StringDefault(a.properties.Payload_fs_type, ext4FsType) {
+ defaultFsType := ctx.Config().DefaultApexPayloadType()
+ switch proptools.StringDefault(a.properties.Payload_fs_type, defaultFsType) {
case ext4FsType:
a.payloadFsType = ext4
case f2fsFsType:
@@ -1901,7 +1747,13 @@
}
func (a *apexBundle) isCompressable() bool {
- return proptools.BoolDefault(a.overridableProperties.Compressible, false) && !a.testApex
+ if a.testApex {
+ return false
+ }
+ if a.payloadFsType == erofs {
+ return false
+ }
+ return proptools.Bool(a.overridableProperties.Compressible)
}
func (a *apexBundle) commonBuildActions(ctx android.ModuleContext) bool {
@@ -1910,6 +1762,7 @@
a.CheckMinSdkVersion(ctx)
a.checkStaticLinkingToStubLibraries(ctx)
a.checkStaticExecutables(ctx)
+ a.enforceAppUpdatability(ctx)
if len(a.properties.Tests) > 0 && !a.testApex {
ctx.PropertyErrorf("tests", "property allowed only in apex_test module type")
return false
@@ -1933,7 +1786,13 @@
// visitor skips these from this list of module names
unwantedTransitiveDeps []string
- aconfigFiles []android.Path
+ // unwantedTransitiveFilesInfo contains files that would have been in the apex
+ // except that they were listed in unwantedTransitiveDeps.
+ unwantedTransitiveFilesInfo []apexFile
+
+ // duplicateTransitiveFilesInfo contains files that would ahve been in the apex
+ // except that another variant of the same module was already in the apex.
+ duplicateTransitiveFilesInfo []apexFile
}
func (vctx *visitorContext) normalizeFileInfo(mctx android.ModuleContext) {
@@ -1944,6 +1803,7 @@
// Needs additional verification for the resulting APEX to ensure that skipped artifacts don't make problems.
// For example, DT_NEEDED modules should be found within the APEX unless they are marked in `requiredNativeLibs`.
if f.transitiveDep && f.module != nil && android.InList(mctx.OtherModuleName(f.module), vctx.unwantedTransitiveDeps) {
+ vctx.unwantedTransitiveFilesInfo = append(vctx.unwantedTransitiveFilesInfo, f)
continue
}
dest := filepath.Join(f.installDir, f.builtFile.Base())
@@ -1954,6 +1814,8 @@
mctx.ModuleErrorf("apex file %v is provided by two different files %v and %v",
dest, e.builtFile, f.builtFile)
return
+ } else {
+ vctx.duplicateTransitiveFilesInfo = append(vctx.duplicateTransitiveFilesInfo, f)
}
// If a module is directly included and also transitively depended on
// consider it as directly included.
@@ -1968,6 +1830,7 @@
for _, v := range encountered {
vctx.filesInfo = append(vctx.filesInfo, v)
}
+
sort.Slice(vctx.filesInfo, func(i, j int) bool {
// Sort by destination path so as to ensure consistent ordering even if the source of the files
// changes.
@@ -1975,12 +1838,38 @@
})
}
-func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, child, parent blueprint.Module) bool {
+// enforcePartitionTagOnApexSystemServerJar checks that the partition tags of an apex system server jar matches
+// the partition tags of the top-level apex.
+// e.g. if the top-level apex sets system_ext_specific to true, the javalib must set this property to true as well.
+// This check ensures that the dexpreopt artifacts of the apex system server jar is installed in the same partition
+// as the apex.
+func (a *apexBundle) enforcePartitionTagOnApexSystemServerJar(ctx android.ModuleContext) {
+ global := dexpreopt.GetGlobalConfig(ctx)
+ ctx.VisitDirectDepsProxyWithTag(sscpfTag, func(child android.ModuleProxy) {
+ info, ok := android.OtherModuleProvider(ctx, child, java.LibraryNameToPartitionInfoProvider)
+ if !ok {
+ ctx.ModuleErrorf("Could not find partition info of apex system server jars.")
+ }
+ apexPartition := ctx.Module().PartitionTag(ctx.DeviceConfig())
+ for javalib, javalibPartition := range info.LibraryNameToPartition {
+ if !global.AllApexSystemServerJars(ctx).ContainsJar(javalib) {
+ continue // not an apex system server jar
+ }
+ if apexPartition != javalibPartition {
+ ctx.ModuleErrorf(`
+%s is an apex systemserver jar, but its partition does not match the partition of its containing apex. Expected %s, Got %s`,
+ javalib, apexPartition, javalibPartition)
+ }
+ }
+ })
+}
+
+func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, child, parent android.Module) bool {
depTag := ctx.OtherModuleDependencyTag(child)
if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
return false
}
- if mod, ok := child.(android.Module); ok && !mod.Enabled(ctx) {
+ if !child.Enabled(ctx) {
return false
}
depName := ctx.OtherModuleName(child)
@@ -1992,15 +1881,14 @@
if isJniLib {
propertyName = "jni_libs"
}
- switch ch := child.(type) {
- case *cc.Module:
+
+ if ch, ok := child.(cc.VersionedLinkableInterface); ok {
if ch.IsStubs() {
ctx.PropertyErrorf(propertyName, "%q is a stub. Remove it from the list.", depName)
}
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
@@ -2008,24 +1896,18 @@
vctx.provideNativeLibs = append(vctx.provideNativeLibs, fi.stem())
}
return true // track transitive dependencies
- case *rust.Module:
- 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)
+ } else {
+ ctx.PropertyErrorf(propertyName,
+ "%q is not a VersionLinkableInterface (e.g. cc_library or rust_ffi module)", depName)
}
+
case executableTag:
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",
@@ -2065,7 +1947,6 @@
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))
@@ -2074,14 +1955,11 @@
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() {
@@ -2095,7 +1973,6 @@
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)
}
@@ -2127,7 +2004,6 @@
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)
}
@@ -2142,7 +2018,6 @@
af := apexFileForExecutable(ctx, ccTest)
af.class = nativeTest
vctx.filesInfo = append(vctx.filesInfo, af)
- addAconfigFiles(vctx, ctx, child)
return true // track transitive dependencies
} else {
ctx.PropertyErrorf("tests", "%q is not a cc module", depName)
@@ -2177,12 +2052,11 @@
// We cannot use a switch statement on `depTag` here as the checked
// tags used below are private (e.g. `cc.sharedDepTag`).
if cc.IsSharedDepTag(depTag) || cc.IsRuntimeDepTag(depTag) {
- if ch, ok := child.(*cc.Module); ok {
+ if ch, ok := child.(cc.VersionedLinkableInterface); ok {
af := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs)
af.transitiveDep = true
- abInfo, _ := android.ModuleProvider(ctx, android.ApexBundleInfoProvider)
- if !abInfo.Contents.DirectlyInApex(depName) && (ch.IsStubs() || ch.HasStubsVariants()) {
+ if ch.IsStubs() || ch.HasStubsVariants() {
// If the dependency is a stubs lib, don't include it in this APEX,
// but make sure that the lib is installed on the device.
// In case no APEX is having the lib, the lib is installed to the system
@@ -2193,9 +2067,10 @@
//
// Skip the dependency in unbundled builds where the device image is not
// being built.
- if ch.IsStubsImplementationRequired() && !am.DirectlyInAnyApex() && !ctx.Config().UnbundledBuild() {
+ if ch.VersionedInterface().IsStubsImplementationRequired() &&
+ !am.NotInPlatform() && !ctx.Config().UnbundledBuild() {
// we need a module name for Make
- name := ch.ImplementationModuleNameForMake(ctx) + ch.Properties.SubName
+ name := ch.ImplementationModuleNameForMake(ctx) + ch.SubName()
if !android.InList(name, a.makeModulesToInstall) {
a.makeModulesToInstall = append(a.makeModulesToInstall, name)
}
@@ -2214,21 +2089,11 @@
// like to record requiredNativeLibs even when
// DepIsInSameAPex is false. We also shouldn't do
// this for host.
- //
- // TODO(jiyong): explain why the same module is passed in twice.
- // Switching the first am to parent breaks lots of tests.
- if !android.IsDepInSameApex(ctx, am, am) {
+ if !android.IsDepInSameApex(ctx, parent, am) {
return false
}
vctx.filesInfo = append(vctx.filesInfo, af)
- addAconfigFiles(vctx, ctx, child)
- return true // track transitive dependencies
- } else if rm, ok := child.(*rust.Module); ok {
- af := apexFileForRustLibrary(ctx, rm)
- af.transitiveDep = true
- vctx.filesInfo = append(vctx.filesInfo, af)
- addAconfigFiles(vctx, ctx, child)
return true // track transitive dependencies
}
} else if cc.IsHeaderDepTag(depTag) {
@@ -2244,10 +2109,13 @@
}
} else if rust.IsDylibDepTag(depTag) {
if rustm, ok := child.(*rust.Module); ok && rustm.IsInstallableToApex() {
- af := apexFileForRustLibrary(ctx, rustm)
+ if !android.IsDepInSameApex(ctx, am, am) {
+ return false
+ }
+
+ af := apexFileForNativeLibrary(ctx, child.(cc.VersionedLinkableInterface), vctx.handleSpecialLibs)
af.transitiveDep = true
vctx.filesInfo = append(vctx.filesInfo, af)
- addAconfigFiles(vctx, ctx, child)
return true // track transitive dependencies
}
} else if rust.IsRlibDepTag(depTag) {
@@ -2266,7 +2134,6 @@
return false
}
vctx.filesInfo = append(vctx.filesInfo, af)
- addAconfigFiles(vctx, ctx, child)
return true // track transitive dependencies
default:
ctx.PropertyErrorf("bootclasspath_fragments",
@@ -2281,14 +2148,11 @@
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",
"systemserverclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
}
- } else if _, ok := depTag.(android.CopyDirectlyInAnyApexTag); ok {
- // nothing
} else if depTag == android.DarwinUniversalVariantTag {
// nothing
} else if depTag == android.RequiredDepTag {
@@ -2299,19 +2163,6 @@
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 {
@@ -2345,7 +2196,7 @@
checkDuplicate: a.shouldCheckDuplicate(ctx),
unwantedTransitiveDeps: a.properties.Unwanted_transitive_deps,
}
- ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool { return a.depVisitor(&vctx, ctx, child, parent) })
+ ctx.WalkDeps(func(child, parent android.Module) bool { return a.depVisitor(&vctx, ctx, child, parent) })
vctx.normalizeFileInfo(ctx)
if a.privateKeyFile == nil {
if ctx.Config().AllowMissingDependencies() {
@@ -2393,13 +2244,18 @@
// 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.unwantedTransitiveFilesInfo = vctx.unwantedTransitiveFilesInfo
+ a.duplicateTransitiveFilesInfo = vctx.duplicateTransitiveFilesInfo
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)
a.buildApex(ctx)
@@ -2415,6 +2271,9 @@
a.required = append(a.required, a.VintfFragmentModuleNames(ctx)...)
a.setOutputFiles(ctx)
+ a.enforcePartitionTagOnApexSystemServerJar(ctx)
+
+ a.verifyNativeImplementationLibs(ctx)
}
// Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file
@@ -2431,7 +2290,7 @@
// Apexes built from source retrieve this information by visiting `bootclasspath_fragments`
// Used by dex_bootjars to generate the boot image
func (a *apexBundle) provideApexExportsInfo(ctx android.ModuleContext) {
- ctx.VisitDirectDepsWithTag(bcpfTag, func(child android.Module) {
+ ctx.VisitDirectDepsProxyWithTag(bcpfTag, func(child android.ModuleProxy) {
if info, ok := android.OtherModuleProvider(ctx, child, java.BootclasspathFragmentApexContentInfoProvider); ok {
exports := android.ApexExportsInfo{
ApexName: a.ApexVariationName(),
@@ -2455,6 +2314,24 @@
}
}
+// enforceAppUpdatability propagates updatable=true to apps of updatable apexes
+func (a *apexBundle) enforceAppUpdatability(mctx android.ModuleContext) {
+ if !a.Enabled(mctx) {
+ return
+ }
+ if a.Updatable() {
+ // checking direct deps is sufficient since apex->apk is a direct edge, even when inherited via apex_defaults
+ mctx.VisitDirectDepsProxy(func(module android.ModuleProxy) {
+ if appInfo, ok := android.OtherModuleProvider(mctx, module, java.AppInfoProvider); ok {
+ // ignore android_test_app
+ if !appInfo.TestHelperApp && !appInfo.Updatable {
+ mctx.ModuleErrorf("app dependency %s must have updatable: true", mctx.OtherModuleName(module))
+ }
+ }
+ })
+ }
+}
+
// 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 {
@@ -2549,14 +2426,17 @@
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
android.InitOverridableModule(module, &module.overridableProperties.Overrides)
- multitree.InitExportableModule(module)
return module
}
-func ApexBundleFactory(testApex bool) android.Module {
- bundle := newApexBundle()
- bundle.testApex = testApex
- return bundle
+type apexTestProperties struct {
+ // Boolean flags for validation checks. Test APEXes can turn on/off individual checks.
+ Skip_validations struct {
+ // Skips `Apex_sepolicy_tests` check if true
+ Apex_sepolicy_tests *bool
+ // Skips `Host_apex_verifier` check if true
+ Host_apex_verifier *bool
+ }
}
// apex_test is an APEX for testing. The difference from the ordinary apex module type is that
@@ -2564,6 +2444,7 @@
func TestApexBundleFactory() android.Module {
bundle := newApexBundle()
bundle.testApex = true
+ bundle.AddProperties(&bundle.testProperties)
return bundle
}
@@ -2671,24 +2552,25 @@
return
}
- abInfo, _ := android.ModuleProvider(ctx, android.ApexBundleInfoProvider)
+ librariesDirectlyInApex := make(map[string]bool)
+ ctx.VisitDirectDepsProxyWithTag(sharedLibTag, func(dep android.ModuleProxy) {
+ librariesDirectlyInApex[ctx.OtherModuleName(dep)] = true
+ })
- a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
- if ccm, ok := to.(*cc.Module); ok {
- apexName := ctx.ModuleName()
- fromName := ctx.OtherModuleName(from)
- toName := ctx.OtherModuleName(to)
-
+ a.WalkPayloadDepsProxy(ctx, func(ctx android.BaseModuleContext, from, to android.ModuleProxy, externalDep bool) bool {
+ if info, ok := android.OtherModuleProvider(ctx, to, cc.LinkableInfoProvider); ok {
// If `to` is not actually in the same APEX as `from` then it does not need
// apex_available and neither do any of its dependencies.
- //
- // It is ok to call DepIsInSameApex() directly from within WalkPayloadDeps().
- if am, ok := from.(android.DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
+ if externalDep {
// As soon as the dependency graph crosses the APEX boundary, don't go further.
return false
}
- // The dynamic linker and crash_dump tool in the runtime APEX is the only
+ apexName := ctx.ModuleName()
+ fromName := ctx.OtherModuleName(from)
+ toName := ctx.OtherModuleName(to)
+
+ // The dynamic linker and crash_dump tool in the runtime APEX is an
// exception to this rule. It can't make the static dependencies dynamic
// because it can't do the dynamic linking for itself.
// Same rule should be applied to linkerconfig, because it should be executed
@@ -2697,12 +2579,20 @@
return false
}
- isStubLibraryFromOtherApex := ccm.HasStubsVariants() && !abInfo.Contents.DirectlyInApex(toName)
+ // b/389067742 adds libz as an exception to this check. Although libz is
+ // a part of NDK and thus provides a stable interface, it never was the
+ // intention because the upstream zlib provides neither ABI- nor behavior-
+ // stability. Therefore, we want to allow portable components like APEXes to
+ // bundle libz by statically linking to it.
+ if toName == "libz" {
+ return false
+ }
+
+ isStubLibraryFromOtherApex := info.HasStubsVariants && !librariesDirectlyInApex[toName]
if isStubLibraryFromOtherApex && !externalDep {
ctx.ModuleErrorf("%q required by %q is a native library providing stub. "+
"It shouldn't be included in this APEX via static linking. Dependency path: %s", to.String(), fromName, ctx.GetPathString(false))
}
-
}
return true
})
@@ -2730,7 +2620,7 @@
// checkClasspathFragments enforces that all classpath fragments in deps generate classpaths.proto config.
func (a *apexBundle) checkClasspathFragments(ctx android.ModuleContext) {
- ctx.VisitDirectDeps(func(module android.Module) {
+ ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) {
if tag := ctx.OtherModuleDependencyTag(module); tag == bcpfTag || tag == sscpfTag {
info, _ := android.OtherModuleProvider(ctx, module, java.ClasspathFragmentProtoContentInfoProvider)
if !info.ClasspathFragmentProtoGenerated {
@@ -2744,16 +2634,12 @@
func (a *apexBundle) checkJavaStableSdkVersion(ctx android.ModuleContext) {
// Visit direct deps only. As long as we guarantee top-level deps are using stable SDKs,
// java's checkLinkType guarantees correct usage for transitive deps
- ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
+ ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) {
tag := ctx.OtherModuleDependencyTag(module)
switch tag {
case javaLibTag, androidAppTag:
- if m, ok := module.(interface {
- CheckStableSdkVersion(ctx android.BaseModuleContext) error
- }); ok {
- if err := m.CheckStableSdkVersion(ctx); err != nil {
- ctx.ModuleErrorf("cannot depend on \"%v\": %v", ctx.OtherModuleName(module), err)
- }
+ if err := java.CheckStableSdkVersion(ctx, module); err != nil {
+ ctx.ModuleErrorf("cannot depend on \"%v\": %v", ctx.OtherModuleName(module), err)
}
}
})
@@ -2772,6 +2658,12 @@
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.
@@ -2779,7 +2671,7 @@
return
}
- a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ a.WalkPayloadDepsProxy(ctx, func(ctx android.BaseModuleContext, from, to android.ModuleProxy, externalDep bool) bool {
// As soon as the dependency graph crosses the APEX boundary, don't go further.
if externalDep {
return false
@@ -2796,17 +2688,8 @@
fromName := ctx.OtherModuleName(from)
toName := ctx.OtherModuleName(to)
- // If `to` is not actually in the same APEX as `from` then it does not need
- // apex_available and neither do any of its dependencies.
- //
- // It is ok to call DepIsInSameApex() directly from within WalkPayloadDeps().
- if am, ok := from.(android.DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
- // As soon as the dependency graph crosses the APEX boundary, don't go
- // further.
- return false
- }
-
- if to.AvailableFor(apexName) || baselineApexAvailable(apexName, toName) {
+ if android.CheckAvailableForApex(apexName,
+ android.OtherModuleProviderOrDefault(ctx, to, android.ApexInfoProvider).ApexAvailableFor) {
return true
}
@@ -2831,12 +2714,12 @@
// checkStaticExecutable ensures that executables in an APEX are not static.
func (a *apexBundle) checkStaticExecutables(ctx android.ModuleContext) {
- ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
+ ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) {
if ctx.OtherModuleDependencyTag(module) != executableTag {
return
}
- if l, ok := module.(cc.LinkableInterface); ok && l.StaticExecutable() {
+ if android.OtherModuleProviderOrDefault(ctx, module, cc.LinkableInfoProvider).StaticExecutable {
apex := a.ApexVariationName()
exec := ctx.OtherModuleName(module)
if isStaticExecutableAllowed(apex, exec) {
@@ -2860,78 +2743,10 @@
}
// 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
+ dpInfo.Deps = append(dpInfo.Deps, a.properties.Bootclasspath_fragments.GetOrDefault(ctx, nil)...)
+ dpInfo.Deps = append(dpInfo.Deps, a.properties.Systemserverclasspath_fragments.GetOrDefault(ctx, nil)...)
}
func init() {
@@ -3010,6 +2825,104 @@
}
}
-func (a *apexBundle) IsTestApex() bool {
- return a.testApex
+// verifyNativeImplementationLibs compares the list of transitive implementation libraries used to link native
+// libraries in the apex against the list of implementation libraries in the apex, ensuring that none of the
+// libraries in the apex have references to private APIs from outside the apex.
+func (a *apexBundle) verifyNativeImplementationLibs(ctx android.ModuleContext) {
+ var directImplementationLibs android.Paths
+ var transitiveImplementationLibs []depset.DepSet[android.Path]
+
+ if a.properties.IsCoverageVariant {
+ return
+ }
+
+ if a.testApex {
+ return
+ }
+
+ if a.UsePlatformApis() {
+ return
+ }
+
+ checkApexTag := func(tag blueprint.DependencyTag) bool {
+ switch tag {
+ case sharedLibTag, jniLibTag, executableTag, androidAppTag:
+ return true
+ default:
+ return false
+ }
+ }
+
+ checkTransitiveTag := func(tag blueprint.DependencyTag) bool {
+ switch {
+ case cc.IsSharedDepTag(tag), java.IsJniDepTag(tag), rust.IsRlibDepTag(tag), rust.IsDylibDepTag(tag), checkApexTag(tag):
+ return true
+ default:
+ return false
+ }
+ }
+
+ var appEmbeddedJNILibs android.Paths
+ ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) {
+ tag := ctx.OtherModuleDependencyTag(dep)
+ if !checkApexTag(tag) {
+ return
+ }
+ if tag == sharedLibTag || tag == jniLibTag {
+ outputFile := android.OutputFileForModule(ctx, dep, "")
+ directImplementationLibs = append(directImplementationLibs, outputFile)
+ }
+ if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok {
+ transitiveImplementationLibs = append(transitiveImplementationLibs, info.ImplementationDeps)
+ }
+ if info, ok := android.OtherModuleProvider(ctx, dep, java.AppInfoProvider); ok {
+ appEmbeddedJNILibs = append(appEmbeddedJNILibs, info.EmbeddedJNILibs...)
+ }
+ })
+
+ depSet := depset.New(depset.PREORDER, directImplementationLibs, transitiveImplementationLibs)
+ allImplementationLibs := depSet.ToList()
+
+ allFileInfos := slices.Concat(a.filesInfo, a.unwantedTransitiveFilesInfo, a.duplicateTransitiveFilesInfo)
+
+ for _, lib := range allImplementationLibs {
+ inApex := slices.ContainsFunc(allFileInfos, func(fi apexFile) bool {
+ return fi.builtFile == lib
+ })
+ inApkInApex := slices.Contains(appEmbeddedJNILibs, lib)
+
+ if !inApex && !inApkInApex {
+ ctx.ModuleErrorf("library in apex transitively linked against implementation library %q not in apex", lib)
+ var depPath []android.Module
+ ctx.WalkDeps(func(child, parent android.Module) bool {
+ if depPath != nil {
+ return false
+ }
+
+ tag := ctx.OtherModuleDependencyTag(child)
+
+ if parent == ctx.Module() {
+ if !checkApexTag(tag) {
+ return false
+ }
+ }
+
+ if checkTransitiveTag(tag) {
+ if android.OutputFileForModule(ctx, child, "") == lib {
+ depPath = ctx.GetWalkPath()
+ }
+ return true
+ }
+
+ return false
+ })
+ if depPath != nil {
+ ctx.ModuleErrorf("dependency path:")
+ for _, m := range depPath {
+ ctx.ModuleErrorf(" %s", ctx.OtherModuleName(m))
+ }
+ return
+ }
+ }
+ }
}
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index f405cb2..263e0a5 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -18,6 +18,7 @@
import (
"encoding/json"
+ "strings"
"github.com/google/blueprint"
@@ -63,12 +64,14 @@
if grep -v '^#' ${allowed_deps} | diff -B - ${new_allowed_deps}; then
touch ${out};
else
- echo -e "\n******************************";
+ echo;
+ echo "******************************";
echo "ERROR: go/apex-allowed-deps-error contains more information";
echo "******************************";
echo "Detected changes to allowed dependencies in updatable modules.";
echo "To fix and update packages/modules/common/build/allowed_deps.txt, please run:";
- echo -e "$$ (croot && packages/modules/common/build/update-apex-allowed-deps.sh)\n";
+ echo "$$ (croot && packages/modules/common/build/update-apex-allowed-deps.sh)";
+ echo;
echo "When submitting the generated CL, you must include the following information";
echo "in the commit message if you are adding a new dependency:";
echo "Apex-Size-Increase: Expected binary size increase for affected APEXes (or the size of the .jar / .so file of the new library)";
@@ -77,7 +80,8 @@
echo "Test-Info: What’s the testing strategy for the new dependency? Does it have its own tests, and are you adding integration tests? How/when are the tests run?";
echo "You do not need OWNERS approval to submit the change, but mainline-modularization@";
echo "will periodically review additions and may require changes.";
- echo -e "******************************\n";
+ echo "******************************";
+ echo;
exit 1;
fi;
`,
@@ -91,7 +95,9 @@
apexInfo, _ := android.OtherModuleProvider(ctx, module, android.ApexInfoProvider)
if path := binaryInfo.FlatListPath(); path != nil {
if binaryInfo.Updatable() || apexInfo.Updatable {
- updatableFlatLists = append(updatableFlatLists, path)
+ if strings.HasPrefix(module.String(), "com.android.") {
+ updatableFlatLists = append(updatableFlatLists, path)
+ }
}
}
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 6b9944d..a5b66c1 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -20,6 +20,7 @@
"path/filepath"
"reflect"
"regexp"
+ "slices"
"sort"
"strconv"
"strings"
@@ -28,6 +29,7 @@
"android/soong/aconfig/codegen"
"github.com/google/blueprint"
+ "github.com/google/blueprint/bpmodify"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -82,34 +84,6 @@
return files.AddToFixture()
}
-func withTargets(targets map[android.OsType][]android.Target) android.FixturePreparer {
- return android.FixtureModifyConfig(func(config android.Config) {
- for k, v := range targets {
- config.Targets[k] = v
- }
- })
-}
-
-// withNativeBridgeTargets sets configuration with targets including:
-// - X86_64 (primary)
-// - X86 (secondary)
-// - Arm64 on X86_64 (native bridge)
-// - Arm on X86 (native bridge)
-var withNativeBridgeEnabled = android.FixtureModifyConfig(
- func(config android.Config) {
- config.Targets[android.Android] = []android.Target{
- {Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}},
- NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
- {Os: android.Android, Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}},
- NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
- {Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}},
- NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86_64", NativeBridgeRelativePath: "arm64"},
- {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}},
- NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86", NativeBridgeRelativePath: "arm"},
- }
- },
-)
-
func withManifestPackageNameOverrides(specs []string) android.FixturePreparer {
return android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.ManifestPackageNameOverrides = specs
@@ -233,6 +207,10 @@
"system/sepolicy/apex/myapex-file_contexts": nil,
})
+var prepareForTestWithOtherapex = android.FixtureMergeMockFs(android.MockFS{
+ "system/sepolicy/apex/otherapex-file_contexts": nil,
+})
+
// ensure that 'result' equals 'expected'
func ensureEquals(t *testing.T, result string, expected string) {
t.Helper()
@@ -267,6 +245,7 @@
}
func ensureMatches(t *testing.T, result string, expectedRex string) {
+ t.Helper()
ok, err := regexp.MatchString(expectedRex, result)
if err != nil {
t.Fatalf("regexp failure trying to match %s against `%s` expression: %s", result, expectedRex, err)
@@ -277,6 +256,14 @@
}
}
+func ensureListContainsMatch(t *testing.T, result []string, expectedRex string) {
+ t.Helper()
+ p := regexp.MustCompile(expectedRex)
+ if android.IndexListPred(func(s string) bool { return p.MatchString(s) }, result) == -1 {
+ t.Errorf("%q is not found in %v", expectedRex, result)
+ }
+}
+
func ensureListContains(t *testing.T, result []string, expected string) {
t.Helper()
if !android.InList(expected, result) {
@@ -307,6 +294,7 @@
// Minimal test
func TestBasicApex(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex_defaults {
name: "myapex-defaults",
@@ -391,7 +379,7 @@
name: "foo.rust",
srcs: ["foo.rs"],
rlibs: ["libfoo.rlib.rust"],
- rustlibs: ["libfoo.dylib.rust"],
+ rustlibs: ["libfoo.transitive.dylib.rust"],
apex_available: ["myapex"],
}
@@ -418,6 +406,13 @@
apex_available: ["myapex"],
}
+ rust_library_dylib {
+ name: "libfoo.transitive.dylib.rust",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ apex_available: ["myapex"],
+ }
+
rust_ffi_shared {
name: "libfoo.ffi",
srcs: ["foo.rs"],
@@ -453,7 +448,7 @@
"//apex_available:platform",
"myapex",
],
- }
+ }
cc_library_static {
name: "libstatic",
@@ -480,6 +475,7 @@
"//apex_available:platform",
"myapex",
],
+ compile_dex: true,
}
dex_import {
@@ -545,6 +541,7 @@
ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common_apex10000")
ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.rlib.rust"), "android_arm64_armv8-a_rlib_dylib-std_apex10000")
ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.dylib.rust"), "android_arm64_armv8-a_dylib_apex10000")
+ ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.transitive.dylib.rust"), "android_arm64_armv8-a_dylib_apex10000")
ensureListContains(t, ctx.ModuleVariantsForTests("libbar.ffi"), "android_arm64_armv8-a_shared_apex10000")
ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.shared_from_rust"), "android_arm64_armv8-a_shared_apex10000")
@@ -554,6 +551,7 @@
ensureContains(t, copyCmds, "image.apex/javalib/myjar_stem.jar")
ensureContains(t, copyCmds, "image.apex/javalib/myjar_dex.jar")
ensureContains(t, copyCmds, "image.apex/lib64/libfoo.dylib.rust.dylib.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libfoo.transitive.dylib.rust.dylib.so")
ensureContains(t, copyCmds, "image.apex/lib64/libfoo.ffi.so")
ensureContains(t, copyCmds, "image.apex/lib64/libbar.ffi.so")
ensureContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so")
@@ -604,6 +602,7 @@
}
func TestDefaults(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex_defaults {
name: "myapex-defaults",
@@ -646,6 +645,7 @@
sdk_version: "none",
system_modules: "none",
apex_available: [ "myapex" ],
+ compile_dex: true,
}
android_app {
@@ -686,6 +686,7 @@
}
func TestApexManifest(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -708,6 +709,7 @@
}
func TestApexManifestMinSdkVersion(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex_defaults {
name: "my_defaults",
@@ -781,6 +783,7 @@
}
func TestApexWithDessertSha(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex_defaults {
name: "my_defaults",
@@ -854,6 +857,7 @@
}
func TestFileContexts(t *testing.T) {
+ t.Parallel()
for _, vendor := range []bool{true, false} {
prop := ""
if vendor {
@@ -888,11 +892,16 @@
}
func TestApexWithStubs(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
- native_shared_libs: ["mylib", "mylib3"],
+ native_shared_libs: [
+ "mylib",
+ "mylib3",
+ "libmylib3_rs",
+ ],
binaries: ["foo.rust"],
updatable: false,
}
@@ -906,7 +915,14 @@
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
- shared_libs: ["mylib2", "mylib3"],
+ shared_libs: [
+ "mylib2",
+ "mylib3#impl",
+ "libmylib2_rs",
+ "libmylib3_rs#impl",
+ "my_prebuilt_platform_lib",
+ "my_prebuilt_platform_stub_only_lib",
+ ],
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex" ],
@@ -919,6 +935,17 @@
system_shared_libs: [],
stl: "none",
stubs: {
+ symbol_file: "mylib2.map.txt",
+ versions: ["1", "2", "3"],
+ },
+ }
+
+ rust_ffi {
+ name: "libmylib2_rs",
+ crate_name: "mylib2",
+ srcs: ["mylib.rs"],
+ stubs: {
+ symbol_file: "mylib2.map.txt",
versions: ["1", "2", "3"],
},
}
@@ -930,6 +957,19 @@
system_shared_libs: [],
stl: "none",
stubs: {
+ symbol_file: "mylib3.map.txt",
+ versions: ["10", "11", "12"],
+ },
+ apex_available: [ "myapex" ],
+ }
+
+ rust_ffi {
+ name: "libmylib3_rs",
+ crate_name: "mylib3",
+ srcs: ["mylib.rs"],
+ shared_libs: ["mylib4.from_rust"],
+ stubs: {
+ symbol_file: "mylib3.map.txt",
versions: ["10", "11", "12"],
},
apex_available: [ "myapex" ],
@@ -943,10 +983,39 @@
apex_available: [ "myapex" ],
}
+ cc_library {
+ name: "mylib4.from_rust",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+
+ cc_prebuilt_library_shared {
+ name: "my_prebuilt_platform_lib",
+ stubs: {
+ symbol_file: "my_prebuilt_platform_lib.map.txt",
+ versions: ["1", "2", "3"],
+ },
+ srcs: ["foo.so"],
+ }
+
+ // Similar to my_prebuilt_platform_lib, but this library only provides stubs, i.e. srcs is empty
+ cc_prebuilt_library_shared {
+ name: "my_prebuilt_platform_stub_only_lib",
+ stubs: {
+ symbol_file: "my_prebuilt_platform_stub_only_lib.map.txt",
+ versions: ["1", "2", "3"],
+ }
+ }
+
rust_binary {
name: "foo.rust",
srcs: ["foo.rs"],
- shared_libs: ["libfoo.shared_from_rust"],
+ shared_libs: [
+ "libfoo.shared_from_rust",
+ "libfoo_rs.shared_from_rust",
+ ],
prefer_rlib: true,
apex_available: ["myapex"],
}
@@ -961,6 +1030,15 @@
},
}
+ rust_ffi {
+ name: "libfoo_rs.shared_from_rust",
+ crate_name: "foo_rs",
+ srcs: ["mylib.rs"],
+ stubs: {
+ versions: ["10", "11", "12"],
+ },
+ }
+
`)
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
@@ -971,21 +1049,27 @@
// Ensure that indirect stubs dep is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libmylib2_rs.so")
// Ensure that direct stubs dep is included
ensureContains(t, copyCmds, "image.apex/lib64/mylib3.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libmylib3_rs.so")
mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
// Ensure that mylib is linking with the latest version of stubs for mylib2
ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so")
+ ensureContains(t, mylibLdFlags, "libmylib2_rs/android_arm64_armv8-a_shared_current/unstripped/libmylib2_rs.so")
// ... and not linking to the non-stub (impl) variant of mylib2
ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so")
+ ensureNotContains(t, mylibLdFlags, "libmylib2_rs/android_arm64_armv8-a_shared/unstripped/libmylib2_rs.so")
- // Ensure that mylib is linking with the non-stub (impl) of mylib3 (because mylib3 is in the same apex)
+ // Ensure that mylib is linking with the non-stub (impl) of mylib3 (because the dependency is added with mylib3#impl)
ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_apex10000/mylib3.so")
+ ensureContains(t, mylibLdFlags, "libmylib3_rs/android_arm64_armv8-a_shared_apex10000/unstripped/libmylib3_rs.so")
// .. and not linking to the stubs variant of mylib3
ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12/mylib3.so")
+ ensureNotContains(t, mylibLdFlags, "libmylib3_rs/android_arm64_armv8-a_shared_12/unstripped/mylib3.so")
// Comment out this test. Now it fails after the optimization of sharing "cflags" in cc/cc.go
// is replaced by sharing of "cFlags" in cc/builder.go.
@@ -1001,30 +1085,53 @@
// Ensure that genstub for platform-provided lib is invoked with --systemapi
ensureContains(t, ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi")
+ ensureContains(t, ctx.ModuleForTests("libmylib2_rs", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi")
// Ensure that genstub for apex-provided lib is invoked with --apex
ensureContains(t, ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_shared_12").Rule("genStubSrc").Args["flags"], "--apex")
+ ensureContains(t, ctx.ModuleForTests("libmylib3_rs", "android_arm64_armv8-a_shared_12").Rule("genStubSrc").Args["flags"], "--apex")
ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
"lib64/mylib.so",
"lib64/mylib3.so",
+ "lib64/libmylib3_rs.so",
"lib64/mylib4.so",
+ "lib64/mylib4.from_rust.so",
"bin/foo.rust",
- "lib64/libc++.so", // by the implicit dependency from foo.rust
- "lib64/liblog.so", // by the implicit dependency from foo.rust
+
+ "lib64/libstd.dylib.so", // implicit rust ffi dep
})
// Ensure that stub dependency from a rust module is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo_rs.shared_from_rust.so")
// The rust module is linked to the stub cc library
rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"]
ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so")
+ ensureContains(t, rustDeps, "libfoo_rs.shared_from_rust/android_arm64_armv8-a_shared_current/unstripped/libfoo_rs.shared_from_rust.so")
ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
+ ensureNotContains(t, rustDeps, "libfoo_rs.shared_from_rust/android_arm64_armv8-a_shared/unstripped/libfoo_rs.shared_from_rust.so")
apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.shared_from_rust.so")
+ ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo_rs.shared_from_rust.so")
+
+ // Ensure that mylib is linking with the latest version of stubs for my_prebuilt_platform_lib
+ ensureContains(t, mylibLdFlags, "my_prebuilt_platform_lib/android_arm64_armv8-a_shared_current/my_prebuilt_platform_lib.so")
+ // ... and not linking to the non-stub (impl) variant of my_prebuilt_platform_lib
+ ensureNotContains(t, mylibLdFlags, "my_prebuilt_platform_lib/android_arm64_armv8-a_shared/my_prebuilt_platform_lib.so")
+ // Ensure that genstub for platform-provided lib is invoked with --systemapi
+ ensureContains(t, ctx.ModuleForTests("my_prebuilt_platform_lib", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi")
+
+ // Ensure that mylib is linking with the latest version of stubs for my_prebuilt_platform_lib
+ ensureContains(t, mylibLdFlags, "my_prebuilt_platform_stub_only_lib/android_arm64_armv8-a_shared_current/my_prebuilt_platform_stub_only_lib.so")
+ // ... and not linking to the non-stub (impl) variant of my_prebuilt_platform_lib
+ ensureNotContains(t, mylibLdFlags, "my_prebuilt_platform_stub_only_lib/android_arm64_armv8-a_shared/my_prebuilt_platform_stub_only_lib.so")
+ // Ensure that genstub for platform-provided lib is invoked with --systemapi
+ ensureContains(t, ctx.ModuleForTests("my_prebuilt_platform_stub_only_lib", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi")
}
func TestApexShouldNotEmbedStubVariant(t *testing.T) {
+ t.Parallel()
testApexError(t, `module "myapex" .*: native_shared_libs: "libbar" is a stub`, `
apex {
name: "myapex",
@@ -1051,6 +1158,7 @@
}
func TestApexCanUsePrivateApis(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -1070,7 +1178,10 @@
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
- shared_libs: ["mylib2"],
+ shared_libs: [
+ "mylib2",
+ "libmylib2_rust"
+ ],
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex" ],
@@ -1087,10 +1198,22 @@
},
}
+ rust_ffi {
+ name: "libmylib2_rust",
+ crate_name: "mylib2_rust",
+ srcs: ["mylib.rs"],
+ stubs: {
+ versions: ["1", "2", "3"],
+ },
+ }
+
rust_binary {
name: "foo.rust",
srcs: ["foo.rs"],
- shared_libs: ["libfoo.shared_from_rust"],
+ shared_libs: [
+ "libfoo.shared_from_rust",
+ "libmylib_rust.shared_from_rust"
+ ],
prefer_rlib: true,
apex_available: ["myapex"],
}
@@ -1104,6 +1227,15 @@
versions: ["10", "11", "12"],
},
}
+ rust_ffi {
+ name: "libmylib_rust.shared_from_rust",
+ crate_name: "mylib_rust",
+ srcs: ["mylib.rs"],
+ stubs: {
+ versions: ["1", "2", "3"],
+ },
+ }
+
`)
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
@@ -1111,6 +1243,8 @@
// Ensure that indirect stubs dep is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libmylib_rust.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libmylib_rust.shared_from_rust.so")
ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so")
// Ensure that we are using non-stub variants of mylib2 and libfoo.shared_from_rust (because
@@ -1118,9 +1252,13 @@
mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so")
ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so")
+ ensureNotContains(t, mylibLdFlags, "libmylib2_rust/android_arm64_armv8-a_shared_current/unstripped/libmylib2_rust.so")
+ ensureContains(t, mylibLdFlags, "libmylib2_rust/android_arm64_armv8-a_shared/unstripped/libmylib2_rust.so")
rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"]
ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so")
ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
+ ensureNotContains(t, rustDeps, "libmylib_rust.shared_from_rust/android_arm64_armv8-a_shared_current/unstripped/libmylib_rust.shared_from_rust.so")
+ ensureContains(t, rustDeps, "libmylib_rust.shared_from_rust/android_arm64_armv8-a_shared/unstripped/libmylib_rust.shared_from_rust.so")
}
func TestApexWithStubsWithMinSdkVersion(t *testing.T) {
@@ -1129,7 +1267,11 @@
apex {
name: "myapex",
key: "myapex.key",
- native_shared_libs: ["mylib", "mylib3"],
+ native_shared_libs: [
+ "mylib",
+ "mylib3",
+ "libmylib3_rust",
+ ],
min_sdk_version: "29",
}
@@ -1142,7 +1284,12 @@
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
- shared_libs: ["mylib2", "mylib3"],
+ shared_libs: [
+ "mylib2",
+ "mylib3#impl",
+ "libmylib2_rust",
+ "libmylib3_rust#impl",
+ ],
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex" ],
@@ -1156,6 +1303,18 @@
system_shared_libs: [],
stl: "none",
stubs: {
+ symbol_file: "mylib2.map.txt",
+ versions: ["28", "29", "30", "current"],
+ },
+ min_sdk_version: "28",
+ }
+
+ rust_ffi {
+ name: "libmylib2_rust",
+ crate_name: "mylib2_rust",
+ srcs: ["mylib.rs"],
+ stubs: {
+ symbol_file: "mylib2.map.txt",
versions: ["28", "29", "30", "current"],
},
min_sdk_version: "28",
@@ -1168,6 +1327,20 @@
system_shared_libs: [],
stl: "none",
stubs: {
+ symbol_file: "mylib3.map.txt",
+ versions: ["28", "29", "30", "current"],
+ },
+ apex_available: [ "myapex" ],
+ min_sdk_version: "28",
+ }
+
+ rust_ffi {
+ name: "libmylib3_rust",
+ crate_name: "mylib3_rust",
+ srcs: ["mylib.rs"],
+ shared_libs: ["libmylib4.from_rust"],
+ stubs: {
+ symbol_file: "mylib3.map.txt",
versions: ["28", "29", "30", "current"],
},
apex_available: [ "myapex" ],
@@ -1182,6 +1355,14 @@
apex_available: [ "myapex" ],
min_sdk_version: "28",
}
+
+ rust_ffi {
+ name: "libmylib4.from_rust",
+ crate_name: "mylib4",
+ srcs: ["mylib.rs"],
+ apex_available: [ "myapex" ],
+ min_sdk_version: "28",
+ }
`)
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
@@ -1189,9 +1370,12 @@
// Ensure that direct non-stubs dep is always included
ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/mylib3.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libmylib3_rust.so")
// Ensure that indirect stubs dep is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libmylib2_rust.so")
// Ensure that direct stubs dep is included
ensureContains(t, copyCmds, "image.apex/lib64/mylib3.so")
@@ -1200,13 +1384,17 @@
// Ensure that mylib is linking with the latest version of stub for mylib2
ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so")
+ ensureContains(t, mylibLdFlags, "libmylib2_rust/android_arm64_armv8-a_shared_current/unstripped/libmylib2_rust.so")
// ... and not linking to the non-stub (impl) variant of mylib2
ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so")
+ ensureNotContains(t, mylibLdFlags, "libmylib2_rust/android_arm64_armv8-a_shared/unstripped/libmylib2_rust.so")
- // Ensure that mylib is linking with the non-stub (impl) of mylib3 (because mylib3 is in the same apex)
+ // Ensure that mylib is linking with the non-stub (impl) of mylib3 (because the dependency is added with mylib3#impl)
ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_apex29/mylib3.so")
+ ensureContains(t, mylibLdFlags, "libmylib3_rust/android_arm64_armv8-a_shared_apex29/unstripped/libmylib3_rust.so")
// .. and not linking to the stubs variant of mylib3
ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_29/mylib3.so")
+ ensureNotContains(t, mylibLdFlags, "libmylib3_rust/android_arm64_armv8-a_shared_29/unstripped/libmylib3_rust.so")
// Ensure that stubs libs are built without -include flags
mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("cc").Args["cFlags"]
@@ -1214,11 +1402,16 @@
// Ensure that genstub is invoked with --systemapi
ensureContains(t, ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("genStubSrc").Args["flags"], "--systemapi")
+ ensureContains(t, ctx.ModuleForTests("libmylib2_rust", "android_arm64_armv8-a_shared_29").Rule("cc.genStubSrc").Args["flags"], "--systemapi")
ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
"lib64/mylib.so",
"lib64/mylib3.so",
+ "lib64/libmylib3_rust.so",
"lib64/mylib4.so",
+ "lib64/libmylib4.from_rust.so",
+
+ "lib64/libstd.dylib.so", // by the implicit dependency from foo.rust
})
}
@@ -1243,7 +1436,10 @@
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
- shared_libs: ["libstub"],
+ shared_libs: [
+ "libstub",
+ "libstub_rust",
+ ],
apex_available: ["myapex"],
min_sdk_version: "Z",
}
@@ -1257,7 +1453,10 @@
apex {
name: "otherapex",
key: "myapex.key",
- native_shared_libs: ["libstub"],
+ native_shared_libs: [
+ "libstub",
+ "libstub_rust",
+ ],
min_sdk_version: "29",
}
@@ -1271,11 +1470,25 @@
min_sdk_version: "29",
}
+ rust_ffi {
+ name: "libstub_rust",
+ crate_name: "stub_rust",
+ srcs: ["mylib.rs"],
+ stubs: {
+ versions: ["29", "Z", "current"],
+ },
+ apex_available: ["otherapex"],
+ min_sdk_version: "29",
+ }
+
// platform module depending on libstub from otherapex should use the latest stub("current")
cc_library {
name: "libplatform",
srcs: ["mylib.cpp"],
- shared_libs: ["libstub"],
+ shared_libs: [
+ "libstub",
+ "libstub_rust",
+ ],
}
`,
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
@@ -1288,17 +1501,24 @@
// Ensure that mylib from myapex is built against the latest stub (current)
mylibCflags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"]
ensureContains(t, mylibCflags, "-D__LIBSTUB_API__=10000 ")
+ // rust stubs do not emit -D__LIBFOO_API__ flags as this is deprecated behavior for cc stubs
+
mylibLdflags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
ensureContains(t, mylibLdflags, "libstub/android_arm64_armv8-a_shared_current/libstub.so ")
+ ensureContains(t, mylibLdflags, "libstub_rust/android_arm64_armv8-a_shared_current/unstripped/libstub_rust.so ")
// Ensure that libplatform is built against latest stub ("current") of mylib3 from the apex
libplatformCflags := ctx.ModuleForTests("libplatform", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
ensureContains(t, libplatformCflags, "-D__LIBSTUB_API__=10000 ") // "current" maps to 10000
+ // rust stubs do not emit -D__LIBFOO_API__ flags as this is deprecated behavior for cc stubs
+
libplatformLdflags := ctx.ModuleForTests("libplatform", "android_arm64_armv8-a_shared").Rule("ld").Args["libFlags"]
ensureContains(t, libplatformLdflags, "libstub/android_arm64_armv8-a_shared_current/libstub.so ")
+ ensureContains(t, libplatformLdflags, "libstub_rust/android_arm64_armv8-a_shared_current/unstripped/libstub_rust.so ")
}
func TestApexWithExplicitStubsDependency(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex2",
@@ -1316,7 +1536,10 @@
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
- shared_libs: ["libfoo#10"],
+ shared_libs: [
+ "libfoo#10",
+ "libfoo_rust#10"
+ ],
static_libs: ["libbaz"],
system_shared_libs: [],
stl: "none",
@@ -1334,6 +1557,16 @@
},
}
+ rust_ffi {
+ name: "libfoo_rust",
+ crate_name: "foo_rust",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["libbar.from_rust"],
+ stubs: {
+ versions: ["10", "20", "30"],
+ },
+ }
+
cc_library {
name: "libbar",
srcs: ["mylib.cpp"],
@@ -1341,6 +1574,13 @@
stl: "none",
}
+ cc_library {
+ name: "libbar.from_rust",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+
cc_library_static {
name: "libbaz",
srcs: ["mylib.cpp"],
@@ -1359,21 +1599,27 @@
// Ensure that indirect stubs dep is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo_rust.so")
// Ensure that dependency of stubs is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.from_rust.so")
mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
// Ensure that mylib is linking with version 10 of libfoo
ensureContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_shared_10/libfoo.so")
+ ensureContains(t, mylibLdFlags, "libfoo_rust/android_arm64_armv8-a_shared_10/unstripped/libfoo_rust.so")
// ... and not linking to the non-stub (impl) variant of libfoo
ensureNotContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_shared/libfoo.so")
+ ensureNotContains(t, mylibLdFlags, "libfoo_rust/android_arm64_armv8-a_shared/unstripped/libfoo_rust.so")
libFooStubsLdFlags := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared_10").Rule("ld").Args["libFlags"]
+ libFooRustStubsLdFlags := ctx.ModuleForTests("libfoo_rust", "android_arm64_armv8-a_shared_10").Rule("ld").Args["libFlags"]
// Ensure that libfoo stubs is not linking to libbar (since it is a stubs)
ensureNotContains(t, libFooStubsLdFlags, "libbar.so")
+ ensureNotContains(t, libFooRustStubsLdFlags, "libbar.from_rust.so")
fullDepsInfo := strings.Split(android.ContentFromFileRuleForTests(t, ctx,
ctx.ModuleForTests("myapex2", "android_common_myapex2").Output("depsinfo/fulllist.txt")), "\n")
@@ -1385,6 +1631,7 @@
}
func TestApexWithRuntimeLibsDependency(t *testing.T) {
+ t.Parallel()
/*
myapex
|
@@ -1412,7 +1659,11 @@
srcs: ["mylib.cpp"],
static_libs: ["libstatic"],
shared_libs: ["libshared"],
- runtime_libs: ["libfoo", "libbar"],
+ runtime_libs: [
+ "libfoo",
+ "libbar",
+ "libfoo_rs",
+ ],
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex" ],
@@ -1428,6 +1679,15 @@
},
}
+ rust_ffi {
+ name: "libfoo_rs",
+ crate_name: "foo_rs",
+ srcs: ["mylib.rs"],
+ stubs: {
+ versions: ["10", "20", "30"],
+ },
+ }
+
cc_library {
name: "libbar",
srcs: ["mylib.cpp"],
@@ -1479,6 +1739,7 @@
// Ensure that indirect stubs dep is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo_rs.so")
// Ensure that runtime_libs dep in included
ensureContains(t, copyCmds, "image.apex/lib64/libbar.so")
@@ -1490,6 +1751,7 @@
apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.so")
+ ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo_rs.so")
}
var prepareForTestOfRuntimeApexWithHwasan = android.GroupFixturePreparers(
@@ -1513,6 +1775,7 @@
)
func TestRuntimeApexShouldInstallHwasanIfLibcDependsOnIt(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(prepareForTestOfRuntimeApexWithHwasan).RunTestWithBp(t, `
cc_library {
name: "libc",
@@ -1566,6 +1829,7 @@
}
func TestRuntimeApexShouldInstallHwasanIfHwaddressSanitized(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestOfRuntimeApexWithHwasan,
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
@@ -1621,6 +1885,7 @@
}
func TestApexDependsOnLLNDKTransitively(t *testing.T) {
+ t.Parallel()
testcases := []struct {
name string
minSdkVersion string
@@ -1645,6 +1910,7 @@
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -1712,11 +1978,12 @@
}
func TestApexWithSystemLibsStubs(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
- native_shared_libs: ["mylib", "mylib_shared", "libdl", "libm"],
+ native_shared_libs: ["mylib", "mylib_shared", "libdl", "libm", "libmylib_rs"],
updatable: false,
}
@@ -1729,12 +1996,20 @@
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
- system_shared_libs: ["libc", "libm"],
- shared_libs: ["libdl#27"],
+ system_shared_libs: ["libc"],
+ shared_libs: ["libdl#27", "libm#impl"],
stl: "none",
apex_available: [ "myapex" ],
}
+ rust_ffi {
+ name: "libmylib_rs",
+ crate_name: "mylib_rs",
+ shared_libs: ["libvers#27", "libm#impl"],
+ srcs: ["mylib.rs"],
+ apex_available: [ "myapex" ],
+ }
+
cc_library_shared {
name: "mylib_shared",
srcs: ["mylib.cpp"],
@@ -1749,20 +2024,38 @@
stl: "none",
bootstrap: true,
}
+
+ rust_ffi {
+ name: "libbootstrap_rs",
+ srcs: ["mylib.cpp"],
+ crate_name: "bootstrap_rs",
+ bootstrap: true,
+ }
+
+ cc_library {
+ name: "libvers",
+ srcs: ["mylib.cpp"],
+ stl: "none",
+ stubs: { versions: ["27","30"] },
+ }
`)
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
copyCmds := apexRule.Args["copy_commands"]
- // Ensure that mylib, libm, libdl are included.
+ // Ensure that mylib, libmylib_rs, libm, libdl, libstd.dylib.so (from Rust) are included.
ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libmylib_rs.so")
ensureContains(t, copyCmds, "image.apex/lib64/bionic/libm.so")
ensureContains(t, copyCmds, "image.apex/lib64/bionic/libdl.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libstd.dylib.so")
- // Ensure that libc is not included (since it has stubs and not listed in native_shared_libs)
+ // Ensure that libc and liblog (from Rust) is not included (since it has stubs and not listed in native_shared_libs)
ensureNotContains(t, copyCmds, "image.apex/lib64/bionic/libc.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/liblog.so")
mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
+ mylibRsFlags := ctx.ModuleForTests("libmylib_rs", "android_arm64_armv8-a_shared_apex10000").Rule("rustc").Args["linkFlags"]
mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"]
mylibSharedCFlags := ctx.ModuleForTests("mylib_shared", "android_arm64_armv8-a_shared_apex10000").Rule("cc").Args["cFlags"]
@@ -1796,14 +2089,46 @@
ensureContains(t, mylibCFlags, "__LIBDL_API__=27")
ensureContains(t, mylibSharedCFlags, "__LIBDL_API__=27")
+ // Rust checks
+ // For dependency to libc, liblog
+ // Ensure that libmylib_rs is linking with the latest versions of stubs
+ ensureContains(t, mylibRsFlags, "libc/android_arm64_armv8-a_shared_current/libc.so")
+ ensureContains(t, mylibRsFlags, "liblog/android_arm64_armv8-a_shared_current/liblog.so")
+ // ... and not linking to the non-stub (impl) variants
+ ensureNotContains(t, mylibRsFlags, "libc/android_arm64_armv8-a_shared/libc.so")
+ ensureNotContains(t, mylibRsFlags, "liblog/android_arm64_armv8-a_shared/liblog.so")
+
+ // For libm dependency (explicit)
+ // Ensure that mylib is linking with the non-stub (impl) variant
+ ensureContains(t, mylibRsFlags, "libm/android_arm64_armv8-a_shared_apex10000/libm.so")
+ // ... and not linking to the stub variant
+ ensureNotContains(t, mylibRsFlags, "libm/android_arm64_armv8-a_shared_29/libm.so")
+
+ // For dependency to libvers
+ // (We do not use libdl#27 as Rust links the system libs implicitly and does
+ // not currently have a system_shared_libs equivalent to prevent this)
+ // Ensure that mylib is linking with the specified version of stubs
+ ensureContains(t, mylibRsFlags, "libvers/android_arm64_armv8-a_shared_27/libvers.so")
+ // ... and not linking to the other versions of stubs
+ ensureNotContains(t, mylibRsFlags, "libvers/android_arm64_armv8-a_shared_30/libvers.so")
+ // ... and not linking to the non-stub (impl) variant
+ ensureNotContains(t, mylibRsFlags, "libvers/android_arm64_armv8-a_shared_apex10000/libvers.so")
+
// Ensure that libBootstrap is depending on the platform variant of bionic libs
libFlags := ctx.ModuleForTests("libBootstrap", "android_arm64_armv8-a_shared").Rule("ld").Args["libFlags"]
ensureContains(t, libFlags, "libc/android_arm64_armv8-a_shared/libc.so")
ensureContains(t, libFlags, "libm/android_arm64_armv8-a_shared/libm.so")
ensureContains(t, libFlags, "libdl/android_arm64_armv8-a_shared/libdl.so")
+
+ // Ensure that libbootstrap_rs is depending on the platform variant of bionic libs
+ libRsFlags := ctx.ModuleForTests("libbootstrap_rs", "android_arm64_armv8-a_shared").Rule("rustc").Args["linkFlags"]
+ ensureContains(t, libRsFlags, "libc/android_arm64_armv8-a_shared/libc.so")
+ ensureContains(t, libRsFlags, "libm/android_arm64_armv8-a_shared/libm.so")
+ ensureContains(t, libRsFlags, "libdl/android_arm64_armv8-a_shared/libdl.so")
}
func TestApexMinSdkVersion_NativeModulesShouldBeBuiltAgainstStubs(t *testing.T) {
+ t.Parallel()
// there are three links between liba --> libz.
// 1) myapex -> libx -> liba -> libz : this should be #30 link
// 2) otherapex -> liby -> liba -> libz : this should be #30 link
@@ -1849,7 +2174,7 @@
cc_library {
name: "liba",
- shared_libs: ["libz"],
+ shared_libs: ["libz", "libz_rs"],
system_shared_libs: [],
stl: "none",
apex_available: [
@@ -1867,6 +2192,15 @@
versions: ["28", "30"],
},
}
+
+ rust_ffi {
+ name: "libz_rs",
+ crate_name: "z_rs",
+ srcs: ["foo.rs"],
+ stubs: {
+ versions: ["28", "30"],
+ },
+ }
`)
expectLink := func(from, from_variant, to, to_variant string) {
@@ -1879,19 +2213,29 @@
}
// platform liba is linked to non-stub version
expectLink("liba", "shared", "libz", "shared")
+ expectLink("liba", "shared", "unstripped/libz_rs", "shared")
// liba in myapex is linked to current
expectLink("liba", "shared_apex29", "libz", "shared_current")
expectNoLink("liba", "shared_apex29", "libz", "shared_30")
expectNoLink("liba", "shared_apex29", "libz", "shared_28")
expectNoLink("liba", "shared_apex29", "libz", "shared")
+ expectLink("liba", "shared_apex29", "unstripped/libz_rs", "shared_current")
+ expectNoLink("liba", "shared_apex29", "unstripped/libz_rs", "shared_30")
+ expectNoLink("liba", "shared_apex29", "unstripped/libz_rs", "shared_28")
+ expectNoLink("liba", "shared_apex29", "unstripped/libz_rs", "shared")
// liba in otherapex is linked to current
expectLink("liba", "shared_apex30", "libz", "shared_current")
expectNoLink("liba", "shared_apex30", "libz", "shared_30")
expectNoLink("liba", "shared_apex30", "libz", "shared_28")
expectNoLink("liba", "shared_apex30", "libz", "shared")
+ expectLink("liba", "shared_apex30", "unstripped/libz_rs", "shared_current")
+ expectNoLink("liba", "shared_apex30", "unstripped/libz_rs", "shared_30")
+ expectNoLink("liba", "shared_apex30", "unstripped/libz_rs", "shared_28")
+ expectNoLink("liba", "shared_apex30", "unstripped/libz_rs", "shared")
}
func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -1944,6 +2288,7 @@
}
func TestApexMinSdkVersion_SupportsCodeNames_JavaLibs(t *testing.T) {
+ t.Parallel()
testApex(t, `
apex {
name: "myapex",
@@ -1964,6 +2309,7 @@
apex_available: [ "myapex" ],
sdk_version: "current",
min_sdk_version: "S", // should be okay
+ compile_dex: true,
}
`,
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
@@ -1974,6 +2320,7 @@
}
func TestApexMinSdkVersion_DefaultsToLatest(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -2021,6 +2368,7 @@
}
func TestApexMinSdkVersion_InVendorApex(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -2073,7 +2421,88 @@
android.AssertStringDoesContain(t, "cflags", cflags, "-target aarch64-linux-android29")
}
-func TestTrackAllowedDeps(t *testing.T) {
+func TestTrackAllowedDepsForAndroidApex(t *testing.T) {
+ t.Parallel()
+ ctx := testApex(t, `
+ apex {
+ name: "com.android.myapex",
+ key: "myapex.key",
+ updatable: true,
+ native_shared_libs: [
+ "mylib",
+ "yourlib",
+ ],
+ min_sdk_version: "29",
+ }
+
+ apex {
+ name: "myapex2",
+ key: "myapex.key",
+ updatable: false,
+ native_shared_libs: ["yourlib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["libbar", "libbar_rs"],
+ min_sdk_version: "29",
+ apex_available: ["com.android.myapex"],
+ }
+
+ cc_library {
+ name: "libbar",
+ stubs: { versions: ["29", "30"] },
+ }
+
+ rust_ffi {
+ name: "libbar_rs",
+ crate_name: "bar_rs",
+ srcs: ["bar.rs"],
+ stubs: { versions: ["29", "30"] },
+ }
+
+ cc_library {
+ name: "yourlib",
+ srcs: ["mylib.cpp"],
+ min_sdk_version: "29",
+ apex_available: ["com.android.myapex", "myapex2", "//apex_available:platform"],
+ }
+ `, withFiles(android.MockFS{
+ "packages/modules/common/build/allowed_deps.txt": nil,
+ }),
+ android.FixtureMergeMockFs(android.MockFS{
+ "system/sepolicy/apex/com.android.myapex-file_contexts": nil,
+ }))
+
+ depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton")
+ inputs := depsinfo.Rule("generateApexDepsInfoFilesRule").BuildParams.Inputs.Strings()
+ android.AssertStringListContains(t, "updatable com.android.myapex should generate depsinfo file", inputs,
+ "out/soong/.intermediates/com.android.myapex/android_common_com.android.myapex/depsinfo/flatlist.txt")
+ android.AssertStringListDoesNotContain(t, "non-updatable myapex2 should not generate depsinfo file", inputs,
+ "out/soong/.intermediates/myapex2/android_common_myapex2/depsinfo/flatlist.txt")
+
+ myapex := ctx.ModuleForTests("com.android.myapex", "android_common_com.android.myapex")
+ flatlist := strings.Split(android.ContentFromFileRuleForTests(t, ctx,
+ myapex.Output("depsinfo/flatlist.txt")), "\n")
+ android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep",
+ flatlist, "libbar(minSdkVersion:(no version)) (external)")
+ android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep",
+ flatlist, "libbar_rs(minSdkVersion:(no version)) (external)")
+ android.AssertStringListDoesNotContain(t, "do not track if not available for platform",
+ flatlist, "mylib:(minSdkVersion:29)")
+ android.AssertStringListContains(t, "track platform-available lib",
+ flatlist, "yourlib(minSdkVersion:29)")
+}
+
+func TestNotTrackAllowedDepsForNonAndroidApex(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -2124,26 +2553,17 @@
depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton")
inputs := depsinfo.Rule("generateApexDepsInfoFilesRule").BuildParams.Inputs.Strings()
- android.AssertStringListContains(t, "updatable myapex should generate depsinfo file", inputs,
+ android.AssertStringListDoesNotContain(t, "updatable myapex should generate depsinfo file", inputs,
"out/soong/.intermediates/myapex/android_common_myapex/depsinfo/flatlist.txt")
android.AssertStringListDoesNotContain(t, "non-updatable myapex2 should not generate depsinfo file", inputs,
"out/soong/.intermediates/myapex2/android_common_myapex2/depsinfo/flatlist.txt")
-
- myapex := ctx.ModuleForTests("myapex", "android_common_myapex")
- flatlist := strings.Split(android.ContentFromFileRuleForTests(t, ctx,
- myapex.Output("depsinfo/flatlist.txt")), "\n")
- android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep",
- flatlist, "libbar(minSdkVersion:(no version)) (external)")
- android.AssertStringListDoesNotContain(t, "do not track if not available for platform",
- flatlist, "mylib:(minSdkVersion:29)")
- android.AssertStringListContains(t, "track platform-available lib",
- flatlist, "yourlib(minSdkVersion:29)")
}
func TestTrackAllowedDeps_SkipWithoutAllowedDepsTxt(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
- name: "myapex",
+ name: "com.android.myapex",
key: "myapex.key",
updatable: true,
min_sdk_version: "29",
@@ -2154,7 +2574,10 @@
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
}
- `)
+ `,
+ android.FixtureMergeMockFs(android.MockFS{
+ "system/sepolicy/apex/com.android.myapex-file_contexts": nil,
+ }))
depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton")
if nil != depsinfo.MaybeRule("generateApexDepsInfoFilesRule").Output {
t.Error("apex_depsinfo_singleton shouldn't run when allowed_deps.txt doesn't exist")
@@ -2162,11 +2585,12 @@
}
func TestPlatformUsesLatestStubsFromApexes(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
- native_shared_libs: ["libx"],
+ native_shared_libs: ["libx", "libx_rs"],
updatable: false,
}
@@ -2186,9 +2610,19 @@
},
}
+ rust_ffi {
+ name: "libx_rs",
+ crate_name: "x_rs",
+ srcs: ["x.rs"],
+ apex_available: [ "myapex" ],
+ stubs: {
+ versions: ["1", "2"],
+ },
+ }
+
cc_library {
name: "libz",
- shared_libs: ["libx"],
+ shared_libs: ["libx", "libx_rs",],
system_shared_libs: [],
stl: "none",
}
@@ -2206,6 +2640,8 @@
}
expectLink("libz", "shared", "libx", "shared_current")
expectNoLink("libz", "shared", "libx", "shared_2")
+ expectLink("libz", "shared", "unstripped/libx_rs", "shared_current")
+ expectNoLink("libz", "shared", "unstripped/libx_rs", "shared_2")
expectNoLink("libz", "shared", "libz", "shared_1")
expectNoLink("libz", "shared", "libz", "shared")
}
@@ -2217,6 +2653,7 @@
)
func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -2233,11 +2670,18 @@
cc_library {
name: "libx",
- shared_libs: ["libbar"],
+ shared_libs: ["libbar", "libbar_rs"],
apex_available: [ "myapex" ],
min_sdk_version: "29",
}
+ rust_ffi {
+ name: "libbar_rs",
+ crate_name: "bar_rs",
+ srcs: ["bar.rs"],
+ stubs: { versions: ["29", "30"] },
+ }
+
cc_library {
name: "libbar",
stubs: {
@@ -2253,9 +2697,11 @@
ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
}
expectLink("libx", "shared_hwasan_apex29", "libbar", "shared_current")
+ expectLink("libx", "shared_hwasan_apex29", "unstripped/libbar_rs", "shared_current")
}
func TestQTargetApexUsesStaticUnwinder(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -2286,6 +2732,7 @@
}
func TestApexMinSdkVersion_ErrorIfIncompatibleVersion(t *testing.T) {
+ t.Parallel()
testApexError(t, `module "mylib".*: should support min_sdk_version\(29\)`, `
apex {
name: "myapex",
@@ -2358,6 +2805,7 @@
"myapex",
],
min_sdk_version: "30",
+ compile_dex: true,
}
`)
@@ -2385,12 +2833,14 @@
// Compile against core API surface
sdk_version: "core_current",
min_sdk_version: "30",
+ compile_dex: true,
}
`)
}
func TestApexMinSdkVersion_Okay(t *testing.T) {
+ t.Parallel()
testApex(t, `
apex {
name: "myapex",
@@ -2431,6 +2881,7 @@
],
apex_available: ["myapex"],
min_sdk_version: "29",
+ compile_dex: true,
}
java_library {
@@ -2451,6 +2902,7 @@
}
func TestApexMinSdkVersion_MinApiForArch(t *testing.T) {
+ t.Parallel()
// Tests that an apex dependency with min_sdk_version higher than the
// min_sdk_version of the apex is allowed as long as the dependency's
// min_sdk_version is less than or equal to the api level that the
@@ -2483,6 +2935,7 @@
}
func TestJavaStableSdkVersion(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
expectedError string
@@ -2508,6 +2961,7 @@
srcs: ["foo/bar/MyClass.java"],
sdk_version: "test_current",
apex_available: ["myapex"],
+ compile_dex: true,
}
`,
},
@@ -2532,6 +2986,7 @@
sdk_version: "current",
apex_available: ["myapex"],
min_sdk_version: "29",
+ compile_dex: true,
}
`,
},
@@ -2555,6 +3010,7 @@
srcs: ["foo/bar/MyClass.java"],
sdk_version: "test_current",
apex_available: ["myapex"],
+ compile_dex: true,
}
`,
},
@@ -2578,6 +3034,7 @@
srcs: ["foo/bar/MyClass.java"],
sdk_version: "core_platform",
apex_available: ["myapex"],
+ compile_dex: true,
}
`,
preparer: java.FixtureUseLegacyCorePlatformApi("myjar-uses-legacy"),
@@ -2606,6 +3063,7 @@
sdk_version: "current",
apex_available: ["myapex"],
static_libs: ["transitive-jar"],
+ compile_dex: true,
}
java_library {
name: "transitive-jar",
@@ -2622,6 +3080,7 @@
continue
}
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
errorHandler := android.FixtureExpectsNoErrors
if test.expectedError != "" {
errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(test.expectedError)
@@ -2680,6 +3139,7 @@
}
func TestApexMinSdkVersion_ErrorIfDepIsNewer_Java(t *testing.T) {
+ t.Parallel()
testApexError(t, `module "bar".*: should support min_sdk_version\(29\) for "myapex"`, `
apex {
name: "myapex",
@@ -2716,6 +3176,7 @@
}
func TestApexMinSdkVersion_OkayEvenWhenDepIsNewer_IfItSatisfiesApexMinSdkVersion(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -2730,8 +3191,7 @@
private_key: "testkey.pem",
}
- // mylib in myapex will link to mylib2#current
- // mylib in otherapex will link to mylib2(non-stub) in otherapex as well
+ // mylib will link to mylib2#current
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
@@ -2765,10 +3225,11 @@
ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
}
expectLink("mylib", "shared_apex29", "mylib2", "shared_current")
- expectLink("mylib", "shared_apex30", "mylib2", "shared_apex30")
+ expectLink("mylib", "shared_apex30", "mylib2", "shared_current")
}
func TestApexMinSdkVersion_WorksWithSdkCodename(t *testing.T) {
+ t.Parallel()
withSAsActiveCodeNames := android.FixtureModifyProductVariables(
func(variables android.FixtureProductVariables) {
variables.Platform_sdk_codename = proptools.StringPtr("S")
@@ -2801,6 +3262,7 @@
}
func TestApexMinSdkVersion_WorksWithActiveCodenames(t *testing.T) {
+ t.Parallel()
withSAsActiveCodeNames := android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.Platform_sdk_codename = proptools.StringPtr("S")
variables.Platform_version_active_codenames = []string{"S", "T"}
@@ -2839,6 +3301,7 @@
}
func TestFilesInSubDir(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -2908,6 +3371,7 @@
}
func TestFilesInSubDirWhenNativeBridgeEnabled(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -2952,7 +3416,7 @@
},
},
}
- `, withNativeBridgeEnabled)
+ `, android.PrepareForNativeBridgeEnabled)
ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
"bin/foo/bar/mybin",
"bin/foo/bar/mybin64",
@@ -2966,6 +3430,7 @@
}
func TestVendorApex(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForApexTest,
android.FixtureModifyConfig(android.SetKatiEnabledForTests),
@@ -3016,6 +3481,7 @@
}
func TestProductVariant(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -3048,6 +3514,7 @@
}
func TestApex_withPrebuiltFirmware(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
additionalProp string
@@ -3057,6 +3524,7 @@
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -3085,6 +3553,7 @@
}
func TestAndroidMk_VendorApexRequired(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -3147,6 +3616,7 @@
}
func TestStaticLinking(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -3172,10 +3642,20 @@
apex_available: ["myapex"],
}
+ rust_ffi {
+ name: "libmylib_rs",
+ crate_name: "mylib_rs",
+ srcs: ["mylib.rs"],
+ stubs: {
+ versions: ["1", "2", "3"],
+ },
+ apex_available: ["myapex"],
+ }
+
cc_binary {
name: "not_in_apex",
srcs: ["mylib.cpp"],
- static_libs: ["mylib"],
+ static_libs: ["mylib", "libmylib_rs"],
static_executable: true,
system_shared_libs: [],
stl: "none",
@@ -3186,9 +3666,11 @@
// Ensure that not_in_apex is linking with the static variant of mylib
ensureContains(t, ldFlags, "mylib/android_arm64_armv8-a_static/mylib.a")
+ ensureContains(t, ldFlags, "generated_rust_staticlib/librustlibs.a")
}
func TestKeys(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex_keytest",
@@ -3246,7 +3728,9 @@
}
func TestCertificate(t *testing.T) {
+ t.Parallel()
t.Run("if unspecified, it defaults to DefaultAppCertificate", func(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -3265,6 +3749,7 @@
}
})
t.Run("override when unspecified", func(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex_keytest",
@@ -3288,6 +3773,7 @@
}
})
t.Run("if specified as :module, it respects the prop", func(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -3311,6 +3797,7 @@
}
})
t.Run("override when specifiec as <:module>", func(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex_keytest",
@@ -3335,6 +3822,7 @@
}
})
t.Run("if specified as name, finds it from DefaultDevKeyDir", func(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -3346,7 +3834,11 @@
name: "myapex.key",
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
- }`)
+ }`,
+ android.MockFS{
+ "vendor/foo/devkeys/testkey.x509.pem": nil,
+ }.AddToFixture(),
+ )
rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk")
expected := "vendor/foo/devkeys/testkey.x509.pem vendor/foo/devkeys/testkey.pk8"
if actual := rule.Args["certificates"]; actual != expected {
@@ -3354,6 +3846,7 @@
}
})
t.Run("override when specified as <name>", func(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex_keytest",
@@ -3380,6 +3873,7 @@
}
func TestMacro(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -3473,6 +3967,7 @@
}
func TestHeaderLibsDependency(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -3640,7 +4135,7 @@
}
func ensureExactDeapexedContents(t *testing.T, ctx *android.TestContext, moduleName string, variant string, files []string) {
- deapexer := ctx.ModuleForTests(moduleName+".deapexer", variant).Description("deapex")
+ deapexer := ctx.ModuleForTests(moduleName, variant).Description("deapex")
outputs := make([]string, 0, len(deapexer.ImplicitOutputs)+1)
if deapexer.Output != nil {
outputs = append(outputs, deapexer.Output.String())
@@ -3676,6 +4171,7 @@
}
func TestVndkApexVersion(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex_vndk {
name: "com.android.vndk.v27",
@@ -3745,6 +4241,7 @@
}
func TestVndkApexNameRule(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex_vndk {
name: "com.android.vndk.v29",
@@ -3777,6 +4274,7 @@
}
func TestVndkApexDoesntSupportNativeBridgeSupported(t *testing.T) {
+ t.Parallel()
testApexError(t, `module "com.android.vndk.v30" .*: native_bridge_supported: .* doesn't support native bridge binary`, `
apex_vndk {
name: "com.android.vndk.v30",
@@ -3807,6 +4305,7 @@
}
func TestVndkApexWithBinder32(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex_vndk {
name: "com.android.vndk.v27",
@@ -3861,11 +4360,20 @@
"libvndk27binder32.so": nil,
}),
withBinder32bit,
- withTargets(map[android.OsType][]android.Target{
- android.Android: {
- {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}},
- NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
- },
+ android.FixtureModifyConfig(func(config android.Config) {
+ target := android.Target{
+ Os: android.Android,
+ Arch: android.Arch{
+ ArchType: android.Arm,
+ ArchVariant: "armv7-a-neon",
+ Abi: []string{"armeabi-v7a"},
+ },
+ NativeBridge: android.NativeBridgeDisabled,
+ NativeBridgeHostArchName: "",
+ NativeBridgeRelativePath: "",
+ }
+ config.Targets[android.Android] = []android.Target{target}
+ config.AndroidFirstDeviceTarget = target
}),
)
@@ -3876,6 +4384,7 @@
}
func TestDependenciesInApexManifest(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex_nodep",
@@ -4009,6 +4518,7 @@
}
func TestOverrideApexManifestDefaultVersion(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -4043,6 +4553,7 @@
}
func TestCompileMultilibProp(t *testing.T) {
+ t.Parallel()
testCases := []struct {
compileMultiLibProp string
containedLibs []string
@@ -4113,6 +4624,7 @@
}
func TestNonTestApex(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -4166,6 +4678,7 @@
}
func TestTestApex(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex_test {
name: "myapex",
@@ -4215,6 +4728,7 @@
}
func TestLibzVendorIsntStable(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -4281,6 +4795,7 @@
}
func TestApexWithTarget(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -4372,6 +4887,7 @@
}
func TestApexWithArch(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -4447,6 +4963,7 @@
}
func TestApexWithShBinary(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -4477,6 +4994,7 @@
}
func TestApexInVariousPartition(t *testing.T) {
+ t.Parallel()
testcases := []struct {
propName, partition string
}{
@@ -4489,6 +5007,7 @@
}
for _, tc := range testcases {
t.Run(tc.propName+":"+tc.partition, func(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -4505,7 +5024,7 @@
`)
apex := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
- expected := "out/soong/target/product/test_device/" + tc.partition + "/apex"
+ expected := "out/target/product/test_device/" + tc.partition + "/apex"
actual := apex.installDir.RelativeToTop().String()
if actual != expected {
t.Errorf("wrong install path. expected %q. actual %q", expected, actual)
@@ -4515,6 +5034,7 @@
}
func TestFileContexts_FindInDefaultLocationIfNotSet(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -4534,6 +5054,7 @@
}
func TestFileContexts_ShouldBeUnderSystemSepolicyForSystemApexes(t *testing.T) {
+ t.Parallel()
testApexError(t, `"myapex" .*: file_contexts: should be under system/sepolicy`, `
apex {
name: "myapex",
@@ -4553,6 +5074,7 @@
}
func TestFileContexts_ProductSpecificApexes(t *testing.T) {
+ t.Parallel()
testApexError(t, `"myapex" .*: file_contexts: cannot find`, `
apex {
name: "myapex",
@@ -4592,6 +5114,7 @@
}
func TestFileContexts_SetViaFileGroup(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -4620,6 +5143,7 @@
}
func TestApexKeyFromOtherModule(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex_key {
name: "myapex.key",
@@ -4653,6 +5177,7 @@
}
func TestPrebuilt(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
prebuilt_apex {
name: "myapex",
@@ -4687,6 +5212,7 @@
}
func TestPrebuiltMissingSrc(t *testing.T) {
+ t.Parallel()
testApexError(t, `module "myapex" variant "android_common_myapex".*: prebuilt_apex does not support "arm64_armv8-a"`, `
prebuilt_apex {
name: "myapex",
@@ -4695,6 +5221,7 @@
}
func TestPrebuiltFilenameOverride(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
prebuilt_apex {
name: "myapex",
@@ -4718,6 +5245,7 @@
}
func TestApexSetFilenameOverride(t *testing.T) {
+ t.Parallel()
testApex(t, `
apex_set {
name: "com.company.android.myapex",
@@ -4747,6 +5275,7 @@
}
func TestPrebuiltOverrides(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
prebuilt_apex {
name: "myapex.prebuilt",
@@ -4773,6 +5302,7 @@
}
func TestPrebuiltApexName(t *testing.T) {
+ t.Parallel()
testApex(t, `
prebuilt_apex {
name: "com.company.android.myapex",
@@ -4791,6 +5321,7 @@
}
func TestPrebuiltApexNameWithPlatformBootclasspath(t *testing.T) {
+ t.Parallel()
_ = android.GroupFixturePreparers(
java.PrepareForTestWithJavaDefaultModules,
PrepareForTestWithApexBuildComponents,
@@ -4840,201 +5371,8 @@
func (ctx moduleErrorfTestCtx) ModuleErrorf(format string, args ...interface{}) {
}
-// These tests verify that the prebuilt_apex/deapexer to java_import wiring allows for the
-// propagation of paths to dex implementation jars from the former to the latter.
-func TestPrebuiltExportDexImplementationJars(t *testing.T) {
- transform := android.NullFixturePreparer
-
- checkDexJarBuildPath := func(t *testing.T, ctx *android.TestContext, name string) {
- t.Helper()
- // Make sure the import has been given the correct path to the dex jar.
- p := ctx.ModuleForTests(name, "android_common_myapex").Module().(java.UsesLibraryDependency)
- dexJarBuildPath := p.DexJarBuildPath(moduleErrorfTestCtx{}).PathOrNil()
- stem := android.RemoveOptionalPrebuiltPrefix(name)
- android.AssertStringEquals(t, "DexJarBuildPath should be apex-related path.",
- ".intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/"+stem+".jar",
- android.NormalizePathForTesting(dexJarBuildPath))
- }
-
- checkDexJarInstallPath := func(t *testing.T, ctx *android.TestContext, name string) {
- t.Helper()
- // Make sure the import has been given the correct path to the dex jar.
- p := ctx.ModuleForTests(name, "android_common_myapex").Module().(java.UsesLibraryDependency)
- dexJarBuildPath := p.DexJarInstallPath()
- stem := android.RemoveOptionalPrebuiltPrefix(name)
- android.AssertStringEquals(t, "DexJarInstallPath should be apex-related path.",
- "target/product/test_device/apex/myapex/javalib/"+stem+".jar",
- android.NormalizePathForTesting(dexJarBuildPath))
- }
-
- ensureNoSourceVariant := func(t *testing.T, ctx *android.TestContext, name string) {
- t.Helper()
- // Make sure that an apex variant is not created for the source module.
- android.AssertArrayString(t, "Check if there is no source variant",
- []string{"android_common"},
- ctx.ModuleVariantsForTests(name))
- }
-
- t.Run("prebuilt only", func(t *testing.T) {
- bp := `
- prebuilt_apex {
- name: "myapex",
- arch: {
- arm64: {
- src: "myapex-arm64.apex",
- },
- arm: {
- src: "myapex-arm.apex",
- },
- },
- exported_java_libs: ["libfoo", "libbar"],
- }
-
- java_import {
- name: "libfoo",
- jars: ["libfoo.jar"],
- }
-
- java_sdk_library_import {
- name: "libbar",
- public: {
- jars: ["libbar.jar"],
- },
- }
- `
-
- // Make sure that dexpreopt can access dex implementation files from the prebuilt.
- ctx := testDexpreoptWithApexes(t, bp, "", transform)
-
- deapexerName := deapexerModuleName("prebuilt_myapex")
- android.AssertStringEquals(t, "APEX module name from deapexer name", "prebuilt_myapex", apexModuleName(deapexerName))
-
- // Make sure that the deapexer has the correct input APEX.
- deapexer := ctx.ModuleForTests(deapexerName, "android_common")
- rule := deapexer.Rule("deapexer")
- if expected, actual := []string{"myapex-arm64.apex"}, android.NormalizePathsForTesting(rule.Implicits); !reflect.DeepEqual(expected, actual) {
- t.Errorf("expected: %q, found: %q", expected, actual)
- }
-
- // Make sure that the prebuilt_apex has the correct input APEX.
- prebuiltApex := ctx.ModuleForTests("myapex", "android_common_myapex")
- rule = prebuiltApex.Rule("android/soong/android.Cp")
- if expected, actual := "myapex-arm64.apex", android.NormalizePathForTesting(rule.Input); !reflect.DeepEqual(expected, actual) {
- t.Errorf("expected: %q, found: %q", expected, actual)
- }
-
- checkDexJarBuildPath(t, ctx, "libfoo")
- checkDexJarInstallPath(t, ctx, "libfoo")
-
- checkDexJarBuildPath(t, ctx, "libbar")
- checkDexJarInstallPath(t, ctx, "libbar")
- })
-
- t.Run("prebuilt with source preferred", func(t *testing.T) {
-
- bp := `
- prebuilt_apex {
- name: "myapex",
- arch: {
- arm64: {
- src: "myapex-arm64.apex",
- },
- arm: {
- src: "myapex-arm.apex",
- },
- },
- exported_java_libs: ["libfoo", "libbar"],
- }
-
- java_import {
- name: "libfoo",
- jars: ["libfoo.jar"],
- }
-
- java_library {
- name: "libfoo",
- }
-
- java_sdk_library_import {
- name: "libbar",
- public: {
- jars: ["libbar.jar"],
- },
- }
-
- java_sdk_library {
- name: "libbar",
- srcs: ["foo/bar/MyClass.java"],
- unsafe_ignore_missing_latest_api: true,
- }
- `
-
- // Make sure that dexpreopt can access dex implementation files from the prebuilt.
- ctx := testDexpreoptWithApexes(t, bp, "", transform)
-
- checkDexJarBuildPath(t, ctx, "prebuilt_libfoo")
- checkDexJarInstallPath(t, ctx, "prebuilt_libfoo")
- ensureNoSourceVariant(t, ctx, "libfoo")
-
- checkDexJarBuildPath(t, ctx, "prebuilt_libbar")
- checkDexJarInstallPath(t, ctx, "prebuilt_libbar")
- ensureNoSourceVariant(t, ctx, "libbar")
- })
-
- t.Run("prebuilt preferred with source", func(t *testing.T) {
- bp := `
- prebuilt_apex {
- name: "myapex",
- arch: {
- arm64: {
- src: "myapex-arm64.apex",
- },
- arm: {
- src: "myapex-arm.apex",
- },
- },
- exported_java_libs: ["libfoo", "libbar"],
- }
-
- java_import {
- name: "libfoo",
- prefer: true,
- jars: ["libfoo.jar"],
- }
-
- java_library {
- name: "libfoo",
- }
-
- java_sdk_library_import {
- name: "libbar",
- prefer: true,
- public: {
- jars: ["libbar.jar"],
- },
- }
-
- java_sdk_library {
- name: "libbar",
- srcs: ["foo/bar/MyClass.java"],
- unsafe_ignore_missing_latest_api: true,
- }
- `
-
- // Make sure that dexpreopt can access dex implementation files from the prebuilt.
- ctx := testDexpreoptWithApexes(t, bp, "", transform)
-
- checkDexJarBuildPath(t, ctx, "prebuilt_libfoo")
- checkDexJarInstallPath(t, ctx, "prebuilt_libfoo")
- ensureNoSourceVariant(t, ctx, "libfoo")
-
- checkDexJarBuildPath(t, ctx, "prebuilt_libbar")
- checkDexJarInstallPath(t, ctx, "prebuilt_libbar")
- ensureNoSourceVariant(t, ctx, "libbar")
- })
-}
-
func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
+ t.Parallel()
preparer := android.GroupFixturePreparers(
java.FixtureConfigureApexBootJars("myapex:libfoo", "myapex:libbar"),
// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
@@ -5056,23 +5394,6 @@
}),
)
- checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, stem string, bootDexJarPath string) {
- t.Helper()
- s := ctx.ModuleForTests("dex_bootjars", "android_common")
- foundLibfooJar := false
- base := stem + ".jar"
- for _, output := range s.AllOutputs() {
- if filepath.Base(output) == base {
- foundLibfooJar = true
- buildRule := s.Output(output)
- android.AssertStringEquals(t, "boot dex jar path", bootDexJarPath, buildRule.Input.String())
- }
- }
- if !foundLibfooJar {
- t.Errorf("Rule for libfoo.jar missing in dex_bootjars singleton outputs %q", android.StringPathsRelativeToTop(ctx.Config().SoongOutDir(), s.AllOutputs()))
- }
- }
-
checkHiddenAPIIndexFromClassesInputs := func(t *testing.T, ctx *android.TestContext, expectedIntermediateInputs string) {
t.Helper()
platformBootclasspath := ctx.ModuleForTests("platform-bootclasspath", "android_common")
@@ -5097,6 +5418,7 @@
}
t.Run("prebuilt only", func(t *testing.T) {
+ t.Parallel()
bp := `
prebuilt_apex {
name: "myapex",
@@ -5125,10 +5447,13 @@
},
}
- java_import {
+ java_sdk_library_import {
name: "libfoo",
- jars: ["libfoo.jar"],
+ public: {
+ jars: ["libfoo.jar"],
+ },
apex_available: ["myapex"],
+ shared_library: false,
permitted_packages: ["foo"],
}
@@ -5144,8 +5469,6 @@
`
ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
- checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
- checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
// Verify the correct module jars contribute to the hiddenapi index file.
checkHiddenAPIIndexFromClassesInputs(t, ctx, `out/soong/.intermediates/platform/foo/android_common/javac/foo.jar`)
@@ -5157,22 +5480,15 @@
})
t.Run("apex_set only", func(t *testing.T) {
+ t.Parallel()
bp := `
apex_set {
name: "myapex",
set: "myapex.apks",
- exported_java_libs: ["myjavalib"],
exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
exported_systemserverclasspath_fragments: ["my-systemserverclasspath-fragment"],
}
- java_import {
- name: "myjavalib",
- jars: ["myjavalib.jar"],
- apex_available: ["myapex"],
- permitted_packages: ["javalib"],
- }
-
prebuilt_bootclasspath_fragment {
name: "my-bootclasspath-fragment",
contents: ["libfoo", "libbar"],
@@ -5193,13 +5509,17 @@
apex_available: ["myapex"],
}
- java_import {
+ java_sdk_library_import {
name: "libfoo",
- jars: ["libfoo.jar"],
+ public: {
+ jars: ["libfoo.jar"],
+ },
apex_available: ["myapex"],
- permitted_packages: ["foo"],
+ shared_library: false,
+ permitted_packages: ["libfoo"],
}
+
java_sdk_library_import {
name: "libbar",
public: {
@@ -5222,8 +5542,6 @@
`
ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
- checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
- checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
// Verify the correct module jars contribute to the hiddenapi index file.
checkHiddenAPIIndexFromClassesInputs(t, ctx, `out/soong/.intermediates/platform/foo/android_common/javac/foo.jar`)
@@ -5253,6 +5571,7 @@
})
t.Run("prebuilt with source library preferred", func(t *testing.T) {
+ t.Parallel()
bp := `
prebuilt_apex {
name: "myapex",
@@ -5284,12 +5603,14 @@
name: "libfoo",
jars: ["libfoo.jar"],
apex_available: ["myapex"],
+ sdk_version: "core_current",
}
java_library {
name: "libfoo",
srcs: ["foo/bar/MyClass.java"],
apex_available: ["myapex"],
+ sdk_version: "core_current",
}
java_sdk_library_import {
@@ -5324,6 +5645,7 @@
})
t.Run("prebuilt library preferred with source", func(t *testing.T) {
+ t.Parallel()
bp := `
apex {
name: "myapex",
@@ -5375,12 +5697,15 @@
},
}
- java_import {
+ java_sdk_library_import {
name: "libfoo",
prefer: true,
- jars: ["libfoo.jar"],
+ public: {
+ jars: ["libfoo.jar"],
+ },
apex_available: ["myapex"],
- permitted_packages: ["foo"],
+ shared_library: false,
+ permitted_packages: ["libfoo"],
}
java_library {
@@ -5388,6 +5713,7 @@
srcs: ["foo/bar/MyClass.java"],
apex_available: ["myapex"],
installable: true,
+ sdk_version: "core_current",
}
java_sdk_library_import {
@@ -5411,8 +5737,6 @@
`
ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
- checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
- checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
// Verify the correct module jars contribute to the hiddenapi index file.
checkHiddenAPIIndexFromClassesInputs(t, ctx, `out/soong/.intermediates/platform/foo/android_common/javac/foo.jar`)
@@ -5424,6 +5748,7 @@
})
t.Run("prebuilt with source apex preferred", func(t *testing.T) {
+ t.Parallel()
bp := `
apex {
name: "myapex",
@@ -5478,6 +5803,7 @@
name: "libfoo",
jars: ["libfoo.jar"],
apex_available: ["myapex"],
+ sdk_version: "core_current",
}
java_library {
@@ -5486,6 +5812,7 @@
apex_available: ["myapex"],
permitted_packages: ["foo"],
installable: true,
+ sdk_version: "core_current",
}
java_sdk_library_import {
@@ -5504,12 +5831,11 @@
apex_available: ["myapex"],
permitted_packages: ["bar"],
compile_dex: true,
+ sdk_version: "core_current",
}
`
ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
- checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/my-bootclasspath-fragment/android_common_myapex/hiddenapi-modular/encoded/libfoo.jar")
- checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/my-bootclasspath-fragment/android_common_myapex/hiddenapi-modular/encoded/libbar.jar")
// Verify the correct module jars contribute to the hiddenapi index file.
checkHiddenAPIIndexFromClassesInputs(t, ctx, `out/soong/.intermediates/platform/foo/android_common/javac/foo.jar`)
@@ -5521,6 +5847,7 @@
})
t.Run("prebuilt preferred with source apex disabled", func(t *testing.T) {
+ t.Parallel()
bp := `
apex {
name: "myapex",
@@ -5595,11 +5922,11 @@
apex_available: ["myapex"],
shared_library: false,
permitted_packages: ["bar"],
+ prefer: true,
}
java_sdk_library {
name: "libbar",
- enabled: false,
srcs: ["foo/bar/MyClass.java"],
unsafe_ignore_missing_latest_api: true,
apex_available: ["myapex"],
@@ -5616,13 +5943,11 @@
android.PrepareForTestWithAllowMissingDependencies,
android.FixtureMergeMockFs(map[string][]byte{
"build/soong/scripts/check_boot_jars/package_allowed_list.txt": nil,
- "frameworks/base/config/boot-profile.txt": nil,
+ "frameworks/base/boot/boot-profile.txt": nil,
}),
)
ctx := testDexpreoptWithApexes(t, bp, "", preparer2, fragment)
- checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
- checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
// Verify the correct module jars contribute to the hiddenapi index file.
checkHiddenAPIIndexFromClassesInputs(t, ctx, `out/soong/.intermediates/platform/foo/android_common/javac/foo.jar`)
@@ -5634,6 +5959,7 @@
})
t.Run("Co-existing unflagged apexes should create a duplicate module error", func(t *testing.T) {
+ t.Parallel()
bp := `
// Source
apex {
@@ -5713,6 +6039,7 @@
}
func TestApexWithTests(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex_test {
name: "myapex",
@@ -5744,7 +6071,6 @@
relative_install_path: "test",
shared_libs: ["mylib"],
system_shared_libs: [],
- static_executable: true,
stl: "none",
data: [":fg"],
}
@@ -5788,6 +6114,7 @@
}
func TestErrorsIfDepsAreNotEnabled(t *testing.T) {
+ t.Parallel()
testApexError(t, `module "myapex" .* depends on disabled module "libfoo"`, `
apex {
name: "myapex",
@@ -5829,6 +6156,7 @@
system_modules: "none",
enabled: false,
apex_available: ["myapex"],
+ compile_dex: true,
}
`)
}
@@ -5863,6 +6191,7 @@
}
func TestApexWithApps(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -5957,6 +6286,7 @@
}
func TestApexWithAppImportBuildId(t *testing.T) {
+ t.Parallel()
invalidBuildIds := []string{"../", "a b", "a/b", "a/b/../c", "/a"}
for _, id := range invalidBuildIds {
message := fmt.Sprintf("Unable to use build id %s as filename suffix", id)
@@ -5987,6 +6317,7 @@
}
func TestApexWithAppImports(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -6036,6 +6367,7 @@
}
func TestApexWithAppImportsPrefer(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -6078,6 +6410,7 @@
}
func TestApexWithTestHelperApp(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -6098,6 +6431,7 @@
name: "TesterHelpAppFoo",
srcs: ["foo/bar/MyClass.java"],
apex_available: [ "myapex" ],
+ sdk_version: "test_current",
}
`)
@@ -6110,6 +6444,7 @@
}
func TestApexPropertiesShouldBeDefaultable(t *testing.T) {
+ t.Parallel()
// libfoo's apex_available comes from cc_defaults
testApexError(t, `requires "libfoo" that doesn't list the APEX under 'apex_available'.`, `
apex {
@@ -6146,6 +6481,7 @@
}
func TestApexAvailable_DirectDep(t *testing.T) {
+ t.Parallel()
// libfoo is not available to myapex, but only to otherapex
testApexError(t, "requires \"libfoo\" that doesn't list the APEX under 'apex_available'.", `
apex {
@@ -6180,17 +6516,105 @@
system_shared_libs: [],
apex_available: ["otherapex"],
}`)
+
+ // 'apex_available' check is bypassed for /product apex with a specific prefix.
+ // TODO: b/352818241 - Remove below two cases after APEX availability is enforced for /product APEXes.
+ testApex(t, `
+ apex {
+ name: "com.sdv.myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo"],
+ updatable: false,
+ product_specific: true,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ apex {
+ name: "com.any.otherapex",
+ key: "otherapex.key",
+ native_shared_libs: ["libfoo"],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "otherapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libfoo",
+ stl: "none",
+ system_shared_libs: [],
+ apex_available: ["com.any.otherapex"],
+ product_specific: true,
+ }`,
+ android.FixtureMergeMockFs(android.MockFS{
+ "system/sepolicy/apex/com.sdv.myapex-file_contexts": nil,
+ "system/sepolicy/apex/com.any.otherapex-file_contexts": nil,
+ }))
+
+ // 'apex_available' check is not bypassed for non-product apex with a specific prefix.
+ testApexError(t, "requires \"libfoo\" that doesn't list the APEX under 'apex_available'.", `
+ apex {
+ name: "com.sdv.myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo"],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ apex {
+ name: "com.any.otherapex",
+ key: "otherapex.key",
+ native_shared_libs: ["libfoo"],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "otherapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libfoo",
+ stl: "none",
+ system_shared_libs: [],
+ apex_available: ["com.any.otherapex"],
+ }`,
+ android.FixtureMergeMockFs(android.MockFS{
+ "system/sepolicy/apex/com.sdv.myapex-file_contexts": nil,
+ "system/sepolicy/apex/com.any.otherapex-file_contexts": nil,
+ }))
}
func TestApexAvailable_IndirectDep(t *testing.T) {
+ t.Parallel()
// libbbaz is an indirect dep
testApexError(t, `requires "libbaz" that doesn't list the APEX under 'apex_available'.\n\nDependency path:
.*via tag apex\.dependencyTag\{"sharedLib"\}
.*-> libfoo.*link:shared.*
+.*via tag cc\.dependencyTag.*
+.*-> libfoo.*link:static.*
.*via tag cc\.libraryDependencyTag.*Kind:sharedLibraryDependency.*
.*-> libbar.*link:shared.*
+.*via tag cc\.dependencyTag.*
+.*-> libbar.*link:static.*
.*via tag cc\.libraryDependencyTag.*Kind:sharedLibraryDependency.*
-.*-> libbaz.*link:shared.*`, `
+.*-> libbaz.*link:shared.*
+.*via tag cc\.dependencyTag.*
+.*-> libbaz.*link:static.*`, `
apex {
name: "myapex",
key: "myapex.key",
@@ -6225,9 +6649,95 @@
stl: "none",
system_shared_libs: [],
}`)
+
+ // 'apex_available' check is bypassed for /product apex with a specific prefix.
+ // TODO: b/352818241 - Remove below two cases after APEX availability is enforced for /product APEXes.
+ testApex(t, `
+ apex {
+ name: "com.sdv.myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo"],
+ updatable: false,
+ product_specific: true,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libfoo",
+ stl: "none",
+ shared_libs: ["libbar"],
+ system_shared_libs: [],
+ apex_available: ["com.sdv.myapex"],
+ product_specific: true,
+ }
+
+ cc_library {
+ name: "libbar",
+ stl: "none",
+ shared_libs: ["libbaz"],
+ system_shared_libs: [],
+ apex_available: ["com.sdv.myapex"],
+ product_specific: true,
+ }
+
+ cc_library {
+ name: "libbaz",
+ stl: "none",
+ system_shared_libs: [],
+ product_specific: true,
+ }`,
+ android.FixtureMergeMockFs(android.MockFS{
+ "system/sepolicy/apex/com.sdv.myapex-file_contexts": nil,
+ }))
+
+ // 'apex_available' check is not bypassed for non-product apex with a specific prefix.
+ testApexError(t, `requires "libbaz" that doesn't list the APEX under 'apex_available'.`, `
+ apex {
+ name: "com.sdv.myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo"],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libfoo",
+ stl: "none",
+ shared_libs: ["libbar"],
+ system_shared_libs: [],
+ apex_available: ["com.sdv.myapex"],
+ }
+
+ cc_library {
+ name: "libbar",
+ stl: "none",
+ shared_libs: ["libbaz"],
+ system_shared_libs: [],
+ apex_available: ["com.sdv.myapex"],
+ }
+
+ cc_library {
+ name: "libbaz",
+ stl: "none",
+ system_shared_libs: [],
+ }`,
+ android.FixtureMergeMockFs(android.MockFS{
+ "system/sepolicy/apex/com.sdv.myapex-file_contexts": nil,
+ }))
}
func TestApexAvailable_IndirectStaticDep(t *testing.T) {
+ t.Parallel()
testApex(t, `
apex {
name: "myapex",
@@ -6294,6 +6804,7 @@
}
func TestApexAvailable_InvalidApexName(t *testing.T) {
+ t.Parallel()
testApexError(t, "\"otherapex\" is not a valid module name", `
apex {
name: "myapex",
@@ -6355,7 +6866,9 @@
}
func TestApexAvailable_ApexAvailableNameWithVersionCodeError(t *testing.T) {
+ t.Parallel()
t.Run("negative variant_version produces error", func(t *testing.T) {
+ t.Parallel()
testApexError(t, "expected an integer between 0-9; got -1", `
apex {
name: "myapex",
@@ -6373,6 +6886,7 @@
})
t.Run("variant_version greater than 9 produces error", func(t *testing.T) {
+ t.Parallel()
testApexError(t, "expected an integer between 0-9; got 10", `
apex {
name: "myapex",
@@ -6391,6 +6905,7 @@
}
func TestApexAvailable_ApexAvailableNameWithVersionCode(t *testing.T) {
+ t.Parallel()
context := android.GroupFixturePreparers(
android.PrepareForIntegrationTestWithAndroid,
PrepareForTestWithApexBuildComponents,
@@ -6426,14 +6941,14 @@
`)
fooManifestRule := result.ModuleForTests("foo", "android_common_foo").Rule("apexManifestRule")
- fooExpectedDefaultVersion := android.DefaultUpdatableModuleVersion
+ fooExpectedDefaultVersion := testDefaultUpdatableModuleVersion
fooActualDefaultVersion := fooManifestRule.Args["default_version"]
if fooActualDefaultVersion != fooExpectedDefaultVersion {
t.Errorf("expected to find defaultVersion %q; got %q", fooExpectedDefaultVersion, fooActualDefaultVersion)
}
barManifestRule := result.ModuleForTests("bar", "android_common_bar").Rule("apexManifestRule")
- defaultVersionInt, _ := strconv.Atoi(android.DefaultUpdatableModuleVersion)
+ defaultVersionInt, _ := strconv.Atoi(testDefaultUpdatableModuleVersion)
barExpectedDefaultVersion := fmt.Sprint(defaultVersionInt + 3)
barActualDefaultVersion := barManifestRule.Args["default_version"]
if barActualDefaultVersion != barExpectedDefaultVersion {
@@ -6448,7 +6963,9 @@
}
func TestApexAvailable_ApexAvailableName(t *testing.T) {
+ t.Parallel()
t.Run("using name of apex that sets apex_available_name is not allowed", func(t *testing.T) {
+ t.Parallel()
testApexError(t, "Consider adding \"myapex\" to 'apex_available' property of \"AppFoo\"", `
apex {
name: "myapex_sminus",
@@ -6482,6 +6999,7 @@
})
t.Run("apex_available_name allows module to be used in two different apexes", func(t *testing.T) {
+ t.Parallel()
testApex(t, `
apex {
name: "myapex_sminus",
@@ -6515,6 +7033,7 @@
})
t.Run("override_apexes work with apex_available_name", func(t *testing.T) {
+ t.Parallel()
testApex(t, `
override_apex {
name: "myoverrideapex_sminus",
@@ -6568,6 +7087,7 @@
}
func TestApexAvailable_ApexAvailableNameWithOverrides(t *testing.T) {
+ t.Parallel()
context := android.GroupFixturePreparers(
android.PrepareForIntegrationTestWithAndroid,
PrepareForTestWithApexBuildComponents,
@@ -6625,6 +7145,7 @@
}
func TestApexAvailable_CheckForPlatform(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -6688,6 +7209,7 @@
}
func TestApexAvailable_CreatedForApex(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -6723,6 +7245,7 @@
}
func TestApexAvailable_PrefixMatch(t *testing.T) {
+ t.Parallel()
for _, tc := range []struct {
name string
@@ -6760,6 +7283,7 @@
},
} {
t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
errorHandler := android.FixtureExpectsNoErrors
if tc.expectedError != "" {
errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(tc.expectedError)
@@ -6815,7 +7339,81 @@
`)
}
+func TestApexValidation_UsesProperPartitionTag(t *testing.T) {
+ t.Parallel()
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ updatable: false,
+ vendor: true,
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ // vendor path should not affect "partition tag"
+ variables.VendorPath = proptools.StringPtr("system/vendor")
+ }))
+
+ module := ctx.ModuleForTests("myapex", "android_common_myapex")
+ android.AssertStringEquals(t, "partition tag for host_apex_verifier",
+ "vendor",
+ module.Output("host_apex_verifier.timestamp").Args["partition_tag"])
+ android.AssertStringEquals(t, "partition tag for apex_sepolicy_tests",
+ "vendor",
+ module.Output("apex_sepolicy_tests.timestamp").Args["partition_tag"])
+}
+
+func TestApexValidation_TestApexCanSkipInitRcCheck(t *testing.T) {
+ t.Parallel()
+ ctx := testApex(t, `
+ apex_test {
+ name: "myapex",
+ key: "myapex.key",
+ skip_validations: {
+ host_apex_verifier: true,
+ },
+ updatable: false,
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `)
+
+ validations := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk").Validations.Strings()
+ if android.SuffixInList(validations, "host_apex_verifier.timestamp") {
+ t.Error("should not run host_apex_verifier")
+ }
+}
+
+func TestApexValidation_TestApexCheckInitRc(t *testing.T) {
+ t.Parallel()
+ ctx := testApex(t, `
+ apex_test {
+ name: "myapex",
+ key: "myapex.key",
+ updatable: false,
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `)
+
+ validations := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk").Validations.Strings()
+ if !android.SuffixInList(validations, "host_apex_verifier.timestamp") {
+ t.Error("should run host_apex_verifier")
+ }
+}
+
func TestOverrideApex(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -6966,6 +7564,7 @@
}
func TestMinSdkVersionOverride(t *testing.T) {
+ t.Parallel()
// Override from 29 to 31
minSdkOverride31 := "31"
ctx := testApex(t, `
@@ -7025,6 +7624,7 @@
}
func TestMinSdkVersionOverrideToLowerVersionNoOp(t *testing.T) {
+ t.Parallel()
// Attempt to override from 31 to 29, should be a NOOP
minSdkOverride29 := "29"
ctx := testApex(t, `
@@ -7084,6 +7684,7 @@
}
func TestLegacyAndroid10Support(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -7111,7 +7712,6 @@
module := ctx.ModuleForTests("myapex", "android_common_myapex")
args := module.Rule("apexRule").Args
ensureContains(t, args["opt_flags"], "--manifest_json "+module.Output("apex_manifest.json").Output.String())
- ensureNotContains(t, args["opt_flags"], "--no_hashtree")
// The copies of the libraries in the apex should have one more dependency than
// the ones outside the apex, namely the unwinder. Ideally we should check
@@ -7144,6 +7744,7 @@
}
func TestJavaSDKLibrary(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -7183,6 +7784,7 @@
}
func TestJavaSDKLibraryOverrideApexes(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
override_apex {
name: "mycompanyapex",
@@ -7223,6 +7825,7 @@
}
func TestJavaSDKLibrary_WithinApex(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -7244,15 +7847,17 @@
apex_available: ["myapex"],
sdk_version: "none",
system_modules: "none",
+ compile_dex: true,
}
java_library {
name: "bar",
srcs: ["a.java"],
- libs: ["foo"],
+ libs: ["foo.impl"],
apex_available: ["myapex"],
sdk_version: "none",
system_modules: "none",
+ compile_dex: true,
}
prebuilt_apis {
@@ -7276,6 +7881,7 @@
}
func TestJavaSDKLibrary_CrossBoundary(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -7302,7 +7908,7 @@
java_library {
name: "bar",
srcs: ["a.java"],
- libs: ["foo"],
+ libs: ["foo.stubs"],
sdk_version: "none",
system_modules: "none",
}
@@ -7327,6 +7933,7 @@
}
func TestJavaSDKLibrary_ImportPreferred(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
prebuilt_apis {
name: "sdk",
@@ -7356,10 +7963,11 @@
java_library {
name: "bar",
srcs: ["a.java"],
- libs: ["foo"],
+ libs: ["foo.impl"],
apex_available: ["myapex"],
sdk_version: "none",
system_modules: "none",
+ compile_dex: true,
}
`),
"source/a.java": nil,
@@ -7381,6 +7989,7 @@
public: {
enabled: true,
},
+ compile_dex: true,
}
`),
"prebuilt/a.jar": nil,
@@ -7397,6 +8006,7 @@
public: {
jars: ["a.jar"],
},
+ compile_dex: true,
}
`),
}), withFiles(filesForSdkLibrary),
@@ -7417,6 +8027,7 @@
}
func TestJavaSDKLibrary_ImportOnly(t *testing.T) {
+ t.Parallel()
testApexError(t, `java_libs: "foo" is not configured to be compiled into dex`, `
apex {
name: "myapex",
@@ -7444,6 +8055,7 @@
}
func TestCompatConfig(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForApexTest,
java.PrepareForTestWithPlatformCompatConfig,
@@ -7473,6 +8085,7 @@
sdk_version: "none",
system_modules: "none",
apex_available: [ "myapex" ],
+ compile_dex: true,
}
// Make sure that a preferred prebuilt does not affect the apex contents.
@@ -7490,6 +8103,7 @@
}
func TestNoDupeApexFiles(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
android.PrepareForTestWithAndroidBuildComponents,
PrepareForTestWithApexBuildComponents,
@@ -7526,6 +8140,7 @@
}
func TestApexUnwantedTransitiveDeps(t *testing.T) {
+ t.Parallel()
bp := `
apex {
name: "myapex",
@@ -7562,6 +8177,7 @@
}
func TestRejectNonInstallableJavaLibrary(t *testing.T) {
+ t.Parallel()
testApexError(t, `"myjar" is not configured to be compiled into dex`, `
apex {
name: "myapex",
@@ -7587,46 +8203,8 @@
`)
}
-func TestCarryRequiredModuleNames(t *testing.T) {
- ctx := testApex(t, `
- apex {
- name: "myapex",
- key: "myapex.key",
- native_shared_libs: ["mylib"],
- updatable: false,
- }
-
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
- cc_library {
- name: "mylib",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- required: ["a", "b"],
- host_required: ["c", "d"],
- target_required: ["e", "f"],
- apex_available: [ "myapex" ],
- }
- `)
-
- apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
- data := android.AndroidMkDataForTest(t, ctx, apexBundle)
- name := apexBundle.BaseModuleName()
- prefix := "TARGET_"
- var builder strings.Builder
- data.Custom(&builder, name, prefix, "", data)
- androidMk := builder.String()
- ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := mylib.myapex:64 a b\n")
- ensureContains(t, androidMk, "LOCAL_HOST_REQUIRED_MODULES := c d\n")
- ensureContains(t, androidMk, "LOCAL_TARGET_REQUIRED_MODULES := e f\n")
-}
-
func TestSymlinksFromApexToSystem(t *testing.T) {
+ t.Parallel()
bp := `
apex {
name: "myapex",
@@ -7700,13 +8278,14 @@
srcs: ["foo/bar/MyClass.java"],
sdk_version: "none",
system_modules: "none",
- libs: ["myotherjar"],
+ static_libs: ["myotherjar"],
apex_available: [
"myapex",
"myapex.updatable",
"//apex_available:platform",
],
min_sdk_version: "33",
+ compile_dex: true,
}
java_library {
@@ -7781,6 +8360,7 @@
}
func TestSymlinksFromApexToSystemRequiredModuleNames(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -7833,6 +8413,7 @@
}
func TestApexWithJniLibs(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -7913,8 +8494,6 @@
"lib64/mylib2.so",
"lib64/mylib3.so",
"lib64/libfoo.rust.so",
- "lib64/libc++.so", // auto-added to libfoo.rust by Soong
- "lib64/liblog.so", // auto-added to libfoo.rust by Soong
})
// b/220397949
@@ -7922,6 +8501,7 @@
}
func TestApexMutatorsDontRunIfDisabled(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -7946,6 +8526,7 @@
}
func TestAppBundle(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -7977,6 +8558,7 @@
}
func TestAppSetBundle(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -8029,9 +8611,9 @@
ctx := testApex(t, bp, prepareForTestWithSantitizeHwaddress)
// Check that the extractor produces the correct output file from the correct input file.
- extractorOutput := "out/soong/.intermediates/prebuilt_myapex.apex.extractor/android_common/extracted/myapex.hwasan.apks"
+ extractorOutput := "out/soong/.intermediates/myapex/android_common_myapex/extracted/myapex.hwasan.apks"
- m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common")
+ m := ctx.ModuleForTests("myapex", "android_common_myapex")
extractedApex := m.Output(extractorOutput)
android.AssertArrayString(t, "extractor input", []string{"myapex.hwasan.apks"}, extractedApex.Inputs.Strings())
@@ -8044,6 +8626,7 @@
}
func TestApexSetApksModuleAssignment(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex_set {
name: "myapex",
@@ -8056,10 +8639,10 @@
}
`)
- m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common")
+ m := ctx.ModuleForTests("myapex", "android_common_myapex")
// Check that the extractor produces the correct apks file from the input module
- extractorOutput := "out/soong/.intermediates/prebuilt_myapex.apex.extractor/android_common/extracted/myapex.apks"
+ extractorOutput := "out/soong/.intermediates/myapex/android_common_myapex/extracted/myapex.apks"
extractedApex := m.Output(extractorOutput)
android.AssertArrayString(t, "extractor input", []string{"myapex.apks"}, extractedApex.Inputs.Strings())
@@ -8121,190 +8704,8 @@
return result.TestContext
}
-func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) {
- preparers := android.GroupFixturePreparers(
- java.PrepareForTestWithJavaDefaultModules,
- prepareForTestWithBootclasspathFragment,
- dexpreopt.FixtureSetTestOnlyArtBootImageJars("com.android.art:libfoo"),
- PrepareForTestWithApexBuildComponents,
- ).
- ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
- "Multiple installable prebuilt APEXes provide ambiguous deapexers: prebuilt_com.android.art and prebuilt_com.mycompany.android.art"))
-
- bpBase := `
- apex_set {
- name: "com.android.art",
- installable: true,
- exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
- set: "myapex.apks",
- }
-
- apex_set {
- name: "com.mycompany.android.art",
- apex_name: "com.android.art",
- installable: true,
- exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
- set: "company-myapex.apks",
- }
-
- prebuilt_bootclasspath_fragment {
- name: "art-bootclasspath-fragment",
- apex_available: ["com.android.art"],
- hidden_api: {
- annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
- metadata: "my-bootclasspath-fragment/metadata.csv",
- index: "my-bootclasspath-fragment/index.csv",
- stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
- all_flags: "my-bootclasspath-fragment/all-flags.csv",
- },
- %s
- }
- `
-
- t.Run("java_import", func(t *testing.T) {
- _ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+`
- java_import {
- name: "libfoo",
- jars: ["libfoo.jar"],
- apex_available: ["com.android.art"],
- }
- `)
- })
-
- t.Run("java_sdk_library_import", func(t *testing.T) {
- _ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+`
- java_sdk_library_import {
- name: "libfoo",
- public: {
- jars: ["libbar.jar"],
- },
- shared_library: false,
- apex_available: ["com.android.art"],
- }
- `)
- })
-
- t.Run("prebuilt_bootclasspath_fragment", func(t *testing.T) {
- _ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `
- image_name: "art",
- contents: ["libfoo"],
- `)+`
- java_sdk_library_import {
- name: "libfoo",
- public: {
- jars: ["libbar.jar"],
- },
- shared_library: false,
- apex_available: ["com.android.art"],
- }
- `)
- })
-}
-
-func TestDuplicateButEquivalentDeapexersFromPrebuiltApexes(t *testing.T) {
- preparers := android.GroupFixturePreparers(
- java.PrepareForTestWithJavaDefaultModules,
- PrepareForTestWithApexBuildComponents,
- )
-
- errCtx := moduleErrorfTestCtx{}
-
- bpBase := `
- apex_set {
- name: "com.android.myapex",
- installable: true,
- exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
- set: "myapex.apks",
- }
-
- apex_set {
- name: "com.android.myapex_compressed",
- apex_name: "com.android.myapex",
- installable: true,
- exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
- set: "myapex_compressed.apks",
- }
-
- prebuilt_bootclasspath_fragment {
- name: "my-bootclasspath-fragment",
- apex_available: [
- "com.android.myapex",
- "com.android.myapex_compressed",
- ],
- hidden_api: {
- annotation_flags: "annotation-flags.csv",
- metadata: "metadata.csv",
- index: "index.csv",
- signature_patterns: "signature_patterns.csv",
- },
- %s
- }
- `
-
- t.Run("java_import", func(t *testing.T) {
- result := preparers.RunTestWithBp(t,
- fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+`
- java_import {
- name: "libfoo",
- jars: ["libfoo.jar"],
- apex_available: [
- "com.android.myapex",
- "com.android.myapex_compressed",
- ],
- }
- `)
-
- module := result.Module("libfoo", "android_common_com.android.myapex")
- usesLibraryDep := module.(java.UsesLibraryDependency)
- android.AssertPathRelativeToTopEquals(t, "dex jar path",
- "out/soong/.intermediates/prebuilt_com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
- usesLibraryDep.DexJarBuildPath(errCtx).Path())
- })
-
- t.Run("java_sdk_library_import", func(t *testing.T) {
- result := preparers.RunTestWithBp(t,
- fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+`
- java_sdk_library_import {
- name: "libfoo",
- public: {
- jars: ["libbar.jar"],
- },
- apex_available: [
- "com.android.myapex",
- "com.android.myapex_compressed",
- ],
- compile_dex: true,
- }
- `)
-
- module := result.Module("libfoo", "android_common_com.android.myapex")
- usesLibraryDep := module.(java.UsesLibraryDependency)
- android.AssertPathRelativeToTopEquals(t, "dex jar path",
- "out/soong/.intermediates/prebuilt_com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
- usesLibraryDep.DexJarBuildPath(errCtx).Path())
- })
-
- t.Run("prebuilt_bootclasspath_fragment", func(t *testing.T) {
- _ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `
- image_name: "art",
- contents: ["libfoo"],
- `)+`
- java_sdk_library_import {
- name: "libfoo",
- public: {
- jars: ["libbar.jar"],
- },
- apex_available: [
- "com.android.myapex",
- "com.android.myapex_compressed",
- ],
- compile_dex: true,
- }
- `)
- })
-}
-
func TestUpdatable_should_set_min_sdk_version(t *testing.T) {
+ t.Parallel()
testApexError(t, `"myapex" .*: updatable: updatable APEXes should set min_sdk_version`, `
apex {
name: "myapex",
@@ -8321,6 +8722,7 @@
}
func TestUpdatableDefault_should_set_min_sdk_version(t *testing.T) {
+ t.Parallel()
testApexError(t, `"myapex" .*: updatable: updatable APEXes should set min_sdk_version`, `
apex {
name: "myapex",
@@ -8336,6 +8738,7 @@
}
func TestUpdatable_should_not_set_generate_classpaths_proto(t *testing.T) {
+ t.Parallel()
testApexError(t, `"mysystemserverclasspathfragment" .* it must not set generate_classpaths_proto to false`, `
apex {
name: "myapex",
@@ -8361,6 +8764,7 @@
apex_available: [
"myapex",
],
+ sdk_version: "current",
}
systemserverclasspath_fragment {
@@ -8379,8 +8783,10 @@
}
func TestDexpreoptAccessDexFilesFromPrebuiltApex(t *testing.T) {
+ t.Parallel()
preparer := java.FixtureConfigureApexBootJars("myapex:libfoo")
t.Run("prebuilt no source", func(t *testing.T) {
+ t.Parallel()
fragment := java.ApexVariantReference{
Apex: proptools.StringPtr("myapex"),
Module: proptools.StringPtr("my-bootclasspath-fragment"),
@@ -8414,12 +8820,16 @@
},
}
- java_import {
- name: "libfoo",
+ java_sdk_library_import {
+ name: "libfoo",
+ prefer: true,
+ public: {
jars: ["libfoo.jar"],
- apex_available: ["myapex"],
- permitted_packages: ["libfoo"],
- }
+ },
+ apex_available: ["myapex"],
+ shared_library: false,
+ permitted_packages: ["libfoo"],
+ }
`, "", preparer, fragment)
})
}
@@ -8462,6 +8872,7 @@
}
func TestApexPermittedPackagesRules(t *testing.T) {
+ t.Parallel()
testcases := []struct {
name string
expectedError string
@@ -8481,6 +8892,7 @@
apex_available: ["myapex"],
sdk_version: "none",
system_modules: "none",
+ compile_dex: true,
}
java_library {
name: "nonbcp_lib2",
@@ -8489,6 +8901,7 @@
permitted_packages: ["a.b"],
sdk_version: "none",
system_modules: "none",
+ compile_dex: true,
}
apex {
name: "myapex",
@@ -8514,6 +8927,7 @@
permitted_packages: ["foo.bar"],
sdk_version: "none",
system_modules: "none",
+ compile_dex: true,
}
java_library {
name: "bcp_lib2",
@@ -8522,6 +8936,7 @@
permitted_packages: ["foo.bar", "bar.baz"],
sdk_version: "none",
system_modules: "none",
+ compile_dex: true,
}
apex {
name: "myapex",
@@ -8552,6 +8967,7 @@
sdk_version: "none",
min_sdk_version: "29",
system_modules: "none",
+ compile_dex: true,
}
java_library {
name: "bcp_lib_unrestricted",
@@ -8561,6 +8977,7 @@
sdk_version: "none",
min_sdk_version: "29",
system_modules: "none",
+ compile_dex: true,
}
apex {
name: "myapex",
@@ -8581,205 +8998,20 @@
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
rules := createBcpPermittedPackagesRules(tc.bcpPermittedPackages)
testBootJarPermittedPackagesRules(t, tc.expectedError, tc.bp, tc.bootJars, rules)
})
}
}
-func TestTestFor(t *testing.T) {
- ctx := testApex(t, `
- apex {
- name: "myapex",
- key: "myapex.key",
- native_shared_libs: ["mylib", "myprivlib"],
- updatable: false,
- }
-
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
- cc_library {
- name: "mylib",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- stubs: {
- versions: ["1"],
- },
- apex_available: ["myapex"],
- }
-
- cc_library {
- name: "myprivlib",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- apex_available: ["myapex"],
- }
-
-
- cc_test {
- name: "mytest",
- gtest: false,
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- shared_libs: ["mylib", "myprivlib", "mytestlib"],
- test_for: ["myapex"]
- }
-
- cc_library {
- name: "mytestlib",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- shared_libs: ["mylib", "myprivlib"],
- stl: "none",
- test_for: ["myapex"],
- }
-
- cc_benchmark {
- name: "mybench",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- shared_libs: ["mylib", "myprivlib"],
- stl: "none",
- test_for: ["myapex"],
- }
- `)
-
- ensureLinkedLibIs := func(mod, variant, linkedLib, expectedVariant string) {
- ldFlags := strings.Split(ctx.ModuleForTests(mod, variant).Rule("ld").Args["libFlags"], " ")
- mylibLdFlags := android.FilterListPred(ldFlags, func(s string) bool { return strings.HasPrefix(s, linkedLib) })
- android.AssertArrayString(t, "unexpected "+linkedLib+" link library for "+mod, []string{linkedLib + expectedVariant}, mylibLdFlags)
- }
-
- // These modules are tests for the apex, therefore are linked to the
- // actual implementation of mylib instead of its stub.
- ensureLinkedLibIs("mytest", "android_arm64_armv8-a", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
- ensureLinkedLibIs("mytestlib", "android_arm64_armv8-a_shared", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
- ensureLinkedLibIs("mybench", "android_arm64_armv8-a", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
-}
-
-func TestIndirectTestFor(t *testing.T) {
- ctx := testApex(t, `
- apex {
- name: "myapex",
- key: "myapex.key",
- native_shared_libs: ["mylib", "myprivlib"],
- updatable: false,
- }
-
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
- cc_library {
- name: "mylib",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- stubs: {
- versions: ["1"],
- },
- apex_available: ["myapex"],
- }
-
- cc_library {
- name: "myprivlib",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- shared_libs: ["mylib"],
- apex_available: ["myapex"],
- }
-
- cc_library {
- name: "mytestlib",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- shared_libs: ["myprivlib"],
- stl: "none",
- test_for: ["myapex"],
- }
- `)
-
- ensureLinkedLibIs := func(mod, variant, linkedLib, expectedVariant string) {
- ldFlags := strings.Split(ctx.ModuleForTests(mod, variant).Rule("ld").Args["libFlags"], " ")
- mylibLdFlags := android.FilterListPred(ldFlags, func(s string) bool { return strings.HasPrefix(s, linkedLib) })
- android.AssertArrayString(t, "unexpected "+linkedLib+" link library for "+mod, []string{linkedLib + expectedVariant}, mylibLdFlags)
- }
-
- // The platform variant of mytestlib links to the platform variant of the
- // internal myprivlib.
- ensureLinkedLibIs("mytestlib", "android_arm64_armv8-a_shared", "out/soong/.intermediates/myprivlib/", "android_arm64_armv8-a_shared/myprivlib.so")
-
- // The platform variant of myprivlib links to the platform variant of mylib
- // and bypasses its stubs.
- ensureLinkedLibIs("myprivlib", "android_arm64_armv8-a_shared", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
-}
-
-func TestTestForForLibInOtherApex(t *testing.T) {
- // This case is only allowed for known overlapping APEXes, i.e. the ART APEXes.
- _ = testApex(t, `
- apex {
- name: "com.android.art",
- key: "myapex.key",
- native_shared_libs: ["libnativebridge"],
- updatable: false,
- }
-
- apex {
- name: "com.android.art.debug",
- key: "myapex.key",
- native_shared_libs: ["libnativebridge", "libnativebrdige_test"],
- updatable: false,
- }
-
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
- cc_library {
- name: "libnativebridge",
- srcs: ["libnativebridge.cpp"],
- system_shared_libs: [],
- stl: "none",
- stubs: {
- versions: ["1"],
- },
- apex_available: ["com.android.art", "com.android.art.debug"],
- }
-
- cc_library {
- name: "libnativebrdige_test",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- shared_libs: ["libnativebridge"],
- stl: "none",
- apex_available: ["com.android.art.debug"],
- test_for: ["com.android.art"],
- }
- `,
- android.MockFS{
- "system/sepolicy/apex/com.android.art-file_contexts": nil,
- "system/sepolicy/apex/com.android.art.debug-file_contexts": nil,
- }.AddToFixture())
-}
-
// TODO(jungjw): Move this to proptools
func intPtr(i int) *int {
return &i
}
func TestApexSet(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex_set {
name: "myapex",
@@ -8799,7 +9031,7 @@
}),
)
- m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common")
+ m := ctx.ModuleForTests("myapex", "android_common_myapex")
// Check extract_apks tool parameters.
extractedApex := m.Output("extracted/myapex.apks")
@@ -8824,6 +9056,7 @@
}
func TestApexSet_NativeBridge(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex_set {
name: "myapex",
@@ -8840,7 +9073,7 @@
}),
)
- m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common")
+ m := ctx.ModuleForTests("myapex", "android_common_myapex")
// Check extract_apks tool parameters. No native bridge arch expected
extractedApex := m.Output("extracted/myapex.apks")
@@ -8848,6 +9081,7 @@
}
func TestNoStaticLinkingToStubsLib(t *testing.T) {
+ t.Parallel()
testApexError(t, `.*required by "mylib" is a native library providing stub.*`, `
apex {
name: "myapex",
@@ -8885,6 +9119,7 @@
}
func TestApexKeysTxt(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -8906,6 +9141,7 @@
}
func TestApexKeysTxtOverrides(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -8950,6 +9186,7 @@
}
func TestAllowedFiles(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -9006,6 +9243,7 @@
}
func TestNonPreferredPrebuiltDependency(t *testing.T) {
+ t.Parallel()
testApex(t, `
apex {
name: "myapex",
@@ -9042,6 +9280,7 @@
}
func TestCompressedApex(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -9078,9 +9317,38 @@
ensureContains(t, androidMk, "LOCAL_MODULE_STEM := myapex.capex\n")
}
+func TestCompressedApexIsDisabledWhenUsingErofs(t *testing.T) {
+ t.Parallel()
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ compressible: true,
+ updatable: false,
+ payload_fs_type: "erofs",
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.CompressedApex = proptools.BoolPtr(true)
+ }),
+ )
+
+ compressRule := ctx.ModuleForTests("myapex", "android_common_myapex").MaybeRule("compressRule")
+ if compressRule.Rule != nil {
+ t.Error("erofs apex should not be compressed")
+ }
+}
+
func TestApexSet_ShouldRespectCompressedApexFlag(t *testing.T) {
+ t.Parallel()
for _, compressionEnabled := range []bool{true, false} {
t.Run(fmt.Sprintf("compressionEnabled=%v", compressionEnabled), func(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex_set {
name: "com.company.android.myapex",
@@ -9103,6 +9371,7 @@
}
func TestPreferredPrebuiltSharedLibDep(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -9155,6 +9424,7 @@
}
func TestExcludeDependency(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -9205,6 +9475,7 @@
}
func TestPrebuiltStubLibDep(t *testing.T) {
+ t.Parallel()
bpBase := `
apex {
name: "myapex",
@@ -9297,13 +9568,15 @@
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
for _, otherApexEnabled := range test.otherApexEnabled {
t.Run("otherapex_enabled_"+otherApexEnabled, func(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, fmt.Sprintf(bpBase, otherApexEnabled)+test.stublibBp)
type modAndMkEntries struct {
mod *cc.Module
- mkEntries android.AndroidMkEntries
+ mkEntries android.AndroidMkInfo
}
entries := []*modAndMkEntries{}
@@ -9317,7 +9590,10 @@
if !mod.Enabled(android.PanickingConfigAndErrorContext(ctx)) || mod.IsHideFromMake() {
continue
}
- for _, ent := range android.AndroidMkEntriesForTest(t, ctx, mod) {
+ info := android.AndroidMkInfoForTest(t, ctx, mod)
+ ents := []android.AndroidMkInfo{info.PrimaryInfo}
+ ents = append(ents, info.ExtraInfo...)
+ for _, ent := range ents {
if ent.Disabled {
continue
}
@@ -9366,6 +9642,7 @@
}
func TestApexJavaCoverage(t *testing.T) {
+ t.Parallel()
bp := `
apex {
name: "myapex",
@@ -9403,6 +9680,7 @@
srcs: ["mybootclasspathlib.java"],
apex_available: ["myapex"],
compile_dex: true,
+ sdk_version: "current",
}
systemserverclasspath_fragment {
@@ -9443,6 +9721,7 @@
}
func TestProhibitStaticExecutable(t *testing.T) {
+ t.Parallel()
testApexError(t, `executable mybin is static`, `
apex {
name: "myapex",
@@ -9494,6 +9773,7 @@
}
func TestAndroidMk_DexpreoptBuiltInstalledForApex(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -9526,43 +9806,8 @@
ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := foo.myapex foo-dexpreopt-arm64-apex@myapex@javalib@foo.jar@classes.odex foo-dexpreopt-arm64-apex@myapex@javalib@foo.jar@classes.vdex\n")
}
-func TestAndroidMk_DexpreoptBuiltInstalledForApex_Prebuilt(t *testing.T) {
- ctx := testApex(t, `
- prebuilt_apex {
- name: "myapex",
- arch: {
- arm64: {
- src: "myapex-arm64.apex",
- },
- arm: {
- src: "myapex-arm.apex",
- },
- },
- exported_java_libs: ["foo"],
- }
-
- java_import {
- name: "foo",
- jars: ["foo.jar"],
- apex_available: ["myapex"],
- }
- `,
- dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"),
- )
-
- prebuilt := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*Prebuilt)
- entriesList := android.AndroidMkEntriesForTest(t, ctx, prebuilt)
- mainModuleEntries := entriesList[0]
- android.AssertArrayString(t,
- "LOCAL_REQUIRED_MODULES",
- mainModuleEntries.EntryMap["LOCAL_REQUIRED_MODULES"],
- []string{
- "foo-dexpreopt-arm64-apex@myapex@javalib@foo.jar@classes.odex",
- "foo-dexpreopt-arm64-apex@myapex@javalib@foo.jar@classes.vdex",
- })
-}
-
func TestAndroidMk_RequiredModules(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -9602,6 +9847,7 @@
}
func TestAndroidMk_RequiredDeps(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -9626,6 +9872,7 @@
}
func TestApexOutputFileProducer(t *testing.T) {
+ t.Parallel()
for _, tc := range []struct {
name string
ref string
@@ -9643,6 +9890,7 @@
},
} {
t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -9674,6 +9922,7 @@
}
func TestSdkLibraryCanHaveHigherMinSdkVersion(t *testing.T) {
+ t.Parallel()
preparer := android.GroupFixturePreparers(
PrepareForTestWithApexBuildComponents,
prepareForTestWithMyapex,
@@ -9686,6 +9935,7 @@
// Test java_sdk_library in bootclasspath_fragment may define higher min_sdk_version than the apex
t.Run("bootclasspath_fragment jar has higher min_sdk_version than apex", func(t *testing.T) {
+ t.Parallel()
preparer.RunTestWithBp(t, `
apex {
name: "myapex",
@@ -9718,6 +9968,7 @@
unsafe_ignore_missing_latest_api: true,
min_sdk_version: "31",
static_libs: ["util"],
+ sdk_version: "core_current",
}
java_library {
@@ -9726,6 +9977,7 @@
apex_available: ["myapex"],
min_sdk_version: "31",
static_libs: ["another_util"],
+ sdk_version: "core_current",
}
java_library {
@@ -9733,12 +9985,14 @@
srcs: ["a.java"],
min_sdk_version: "31",
apex_available: ["myapex"],
+ sdk_version: "core_current",
}
`)
})
// Test java_sdk_library in systemserverclasspath_fragment may define higher min_sdk_version than the apex
t.Run("systemserverclasspath_fragment jar has higher min_sdk_version than apex", func(t *testing.T) {
+ t.Parallel()
preparer.RunTestWithBp(t, `
apex {
name: "myapex",
@@ -9788,7 +10042,8 @@
})
t.Run("bootclasspath_fragment jar must set min_sdk_version", func(t *testing.T) {
- preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "mybootclasspathlib".*must set min_sdk_version`)).
+ t.Parallel()
+ preparer.
RunTestWithBp(t, `
apex {
name: "myapex",
@@ -9819,11 +10074,14 @@
apex_available: ["myapex"],
compile_dex: true,
unsafe_ignore_missing_latest_api: true,
+ sdk_version: "current",
+ min_sdk_version: "30",
}
`)
})
t.Run("systemserverclasspath_fragment jar must set min_sdk_version", func(t *testing.T) {
+ t.Parallel()
preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "mysystemserverclasspathlib".*must set min_sdk_version`)).
RunTestWithBp(t, `
apex {
@@ -9874,6 +10132,7 @@
}
func TestApexStrictUpdtabilityLint(t *testing.T) {
+ t.Parallel()
bpTemplate := `
apex {
name: "myapex",
@@ -9895,6 +10154,7 @@
},
sdk_version: "current",
min_sdk_version: "29",
+ compile_dex: true,
}
`
fs := android.MockFS{
@@ -9902,125 +10162,91 @@
}
testCases := []struct {
- testCaseName string
- apexUpdatable bool
- javaStrictUpdtabilityLint bool
- lintFileExists bool
- disallowedFlagExpected bool
+ testCaseName string
+ apexUpdatable bool
+ javaStrictUpdtabilityLint bool
+ lintFileExists bool
+ disallowedFlagExpectedOnApex bool
+ disallowedFlagExpectedOnJavalib bool
}{
{
- testCaseName: "lint-baseline.xml does not exist, no disallowed flag necessary in lint cmd",
- apexUpdatable: true,
- javaStrictUpdtabilityLint: true,
- lintFileExists: false,
- disallowedFlagExpected: false,
+ testCaseName: "lint-baseline.xml does not exist, no disallowed flag necessary in lint cmd",
+ apexUpdatable: true,
+ javaStrictUpdtabilityLint: true,
+ lintFileExists: false,
+ disallowedFlagExpectedOnApex: false,
+ disallowedFlagExpectedOnJavalib: false,
},
{
- testCaseName: "non-updatable apex respects strict_updatability of javalib",
- apexUpdatable: false,
- javaStrictUpdtabilityLint: false,
- lintFileExists: true,
- disallowedFlagExpected: false,
+ testCaseName: "non-updatable apex respects strict_updatability of javalib",
+ apexUpdatable: false,
+ javaStrictUpdtabilityLint: false,
+ lintFileExists: true,
+ disallowedFlagExpectedOnApex: false,
+ disallowedFlagExpectedOnJavalib: false,
},
{
- testCaseName: "non-updatable apex respects strict updatability of javalib",
- apexUpdatable: false,
- javaStrictUpdtabilityLint: true,
- lintFileExists: true,
- disallowedFlagExpected: true,
+ testCaseName: "non-updatable apex respects strict updatability of javalib",
+ apexUpdatable: false,
+ javaStrictUpdtabilityLint: true,
+ lintFileExists: true,
+ disallowedFlagExpectedOnApex: false,
+ disallowedFlagExpectedOnJavalib: true,
},
{
- testCaseName: "updatable apex sets strict updatability of javalib to true",
- apexUpdatable: true,
- javaStrictUpdtabilityLint: false, // will be set to true by mutator
- lintFileExists: true,
- disallowedFlagExpected: true,
+ testCaseName: "updatable apex checks strict updatability of javalib",
+ apexUpdatable: true,
+ javaStrictUpdtabilityLint: false,
+ lintFileExists: true,
+ disallowedFlagExpectedOnApex: true,
+ disallowedFlagExpectedOnJavalib: false,
},
}
for _, testCase := range testCases {
- fixtures := []android.FixturePreparer{}
- baselineProperty := ""
- if testCase.lintFileExists {
- fixtures = append(fixtures, fs.AddToFixture())
- baselineProperty = "baseline_filename: \"lint-baseline.xml\""
- }
- bp := fmt.Sprintf(bpTemplate, testCase.apexUpdatable, testCase.javaStrictUpdtabilityLint, baselineProperty)
-
- result := testApex(t, bp, fixtures...)
- myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
- sboxProto := android.RuleBuilderSboxProtoForTests(t, result, myjavalib.Output("lint.sbox.textproto"))
- disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi")
-
- if disallowedFlagActual != testCase.disallowedFlagExpected {
- t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command)
- }
- }
-}
-
-func TestUpdatabilityLintSkipLibcore(t *testing.T) {
- bp := `
- apex {
- name: "myapex",
- key: "myapex.key",
- java_libs: ["myjavalib"],
- updatable: true,
- min_sdk_version: "29",
- }
- apex_key {
- name: "myapex.key",
- }
- java_library {
- name: "myjavalib",
- srcs: ["MyClass.java"],
- apex_available: [ "myapex" ],
- sdk_version: "current",
- min_sdk_version: "29",
- lint: {
- baseline_filename: "lint-baseline.xml",
+ t.Run(testCase.testCaseName, func(t *testing.T) {
+ t.Parallel()
+ fixtures := []android.FixturePreparer{}
+ baselineProperty := ""
+ if testCase.lintFileExists {
+ fixtures = append(fixtures, fs.AddToFixture())
+ baselineProperty = "baseline_filename: \"lint-baseline.xml\""
}
- }
- `
+ bp := fmt.Sprintf(bpTemplate, testCase.apexUpdatable, testCase.javaStrictUpdtabilityLint, baselineProperty)
- testCases := []struct {
- testCaseName string
- moduleDirectory string
- disallowedFlagExpected bool
- }{
- {
- testCaseName: "lintable module defined outside libcore",
- moduleDirectory: "",
- disallowedFlagExpected: true,
- },
- {
- testCaseName: "lintable module defined in libcore root directory",
- moduleDirectory: "libcore/",
- disallowedFlagExpected: false,
- },
- {
- testCaseName: "lintable module defined in libcore child directory",
- moduleDirectory: "libcore/childdir/",
- disallowedFlagExpected: true,
- },
- }
+ result := testApex(t, bp, fixtures...)
- for _, testCase := range testCases {
- lintFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"lint-baseline.xml", "")
- bpFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"Android.bp", bp)
- result := testApex(t, "", lintFileCreator, bpFileCreator)
- myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
- sboxProto := android.RuleBuilderSboxProtoForTests(t, result, myjavalib.Output("lint.sbox.textproto"))
- cmdFlags := fmt.Sprintf("--baseline %vlint-baseline.xml --disallowed_issues NewApi", testCase.moduleDirectory)
- disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, cmdFlags)
+ checkModule := func(m android.TestingBuildParams, name string, expectStrictUpdatability bool) {
+ if expectStrictUpdatability {
+ if m.Rule == nil {
+ t.Errorf("expected strict updatability check rule on %s", name)
+ } else {
+ android.AssertStringDoesContain(t, fmt.Sprintf("strict updatability check rule for %s", name),
+ m.RuleParams.Command, "--disallowed_issues NewApi")
+ android.AssertStringListContains(t, fmt.Sprintf("strict updatability check baselines for %s", name),
+ m.Inputs.Strings(), "lint-baseline.xml")
+ }
+ } else {
+ if m.Rule != nil {
+ t.Errorf("expected no strict updatability check rule on %s", name)
+ }
+ }
+ }
- if disallowedFlagActual != testCase.disallowedFlagExpected {
- t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command)
- }
+ myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
+ apex := result.ModuleForTests("myapex", "android_common_myapex")
+ apexStrictUpdatabilityCheck := apex.MaybeOutput("lint_strict_updatability_check.stamp")
+ javalibStrictUpdatabilityCheck := myjavalib.MaybeOutput("lint_strict_updatability_check.stamp")
+
+ checkModule(apexStrictUpdatabilityCheck, "myapex", testCase.disallowedFlagExpectedOnApex)
+ checkModule(javalibStrictUpdatabilityCheck, "myjavalib", testCase.disallowedFlagExpectedOnJavalib)
+ })
}
}
// checks transtive deps of an apex coming from bootclasspath_fragment
func TestApexStrictUpdtabilityLintBcpFragmentDeps(t *testing.T) {
+ t.Parallel()
bp := `
apex {
name: "myapex",
@@ -10057,20 +10283,25 @@
}
result := testApex(t, bp, dexpreopt.FixtureSetApexBootJars("myapex:myjavalib"), fs.AddToFixture())
- myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
- sboxProto := android.RuleBuilderSboxProtoForTests(t, result, myjavalib.Output("lint.sbox.textproto"))
- if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi") {
- t.Errorf("Strict updabality lint missing in myjavalib coming from bootclasspath_fragment mybootclasspath-fragment\nActual lint cmd: %v", *sboxProto.Commands[0].Command)
- }
+ apex := result.ModuleForTests("myapex", "android_common_myapex")
+ apexStrictUpdatabilityCheck := apex.Output("lint_strict_updatability_check.stamp")
+ android.AssertStringDoesContain(t, "strict updatability check rule for myapex",
+ apexStrictUpdatabilityCheck.RuleParams.Command, "--disallowed_issues NewApi")
+ android.AssertStringListContains(t, "strict updatability check baselines for myapex",
+ apexStrictUpdatabilityCheck.Inputs.Strings(), "lint-baseline.xml")
}
func TestApexLintBcpFragmentSdkLibDeps(t *testing.T) {
+ t.Parallel()
bp := `
apex {
name: "myapex",
key: "myapex.key",
bootclasspath_fragments: ["mybootclasspathfragment"],
min_sdk_version: "29",
+ java_libs: [
+ "jacocoagent",
+ ],
}
apex_key {
name: "myapex.key",
@@ -10113,11 +10344,12 @@
// updatable apexes should propagate updatable=true to its apps
func TestUpdatableApexEnforcesAppUpdatability(t *testing.T) {
+ t.Parallel()
bp := `
apex {
name: "myapex",
key: "myapex.key",
- updatable: %v,
+ updatable: true,
apps: [
"myapp",
],
@@ -10128,7 +10360,6 @@
}
android_app {
name: "myapp",
- updatable: %v,
apex_available: [
"myapex",
],
@@ -10136,316 +10367,14 @@
min_sdk_version: "30",
}
`
- testCases := []struct {
- name string
- apex_is_updatable_bp bool
- app_is_updatable_bp bool
- app_is_updatable_expected bool
- }{
- {
- name: "Non-updatable apex respects updatable property of non-updatable app",
- apex_is_updatable_bp: false,
- app_is_updatable_bp: false,
- app_is_updatable_expected: false,
- },
- {
- name: "Non-updatable apex respects updatable property of updatable app",
- apex_is_updatable_bp: false,
- app_is_updatable_bp: true,
- app_is_updatable_expected: true,
- },
- {
- name: "Updatable apex respects updatable property of updatable app",
- apex_is_updatable_bp: true,
- app_is_updatable_bp: true,
- app_is_updatable_expected: true,
- },
- {
- name: "Updatable apex sets updatable=true on non-updatable app",
- apex_is_updatable_bp: true,
- app_is_updatable_bp: false,
- app_is_updatable_expected: true,
- },
- }
- for _, testCase := range testCases {
- result := testApex(t, fmt.Sprintf(bp, testCase.apex_is_updatable_bp, testCase.app_is_updatable_bp))
- myapp := result.ModuleForTests("myapp", "android_common").Module().(*java.AndroidApp)
- android.AssertBoolEquals(t, testCase.name, testCase.app_is_updatable_expected, myapp.Updatable())
- }
-}
-
-func TestApexBuildsAgainstApiSurfaceStubLibraries(t *testing.T) {
- bp := `
- apex {
- name: "myapex",
- key: "myapex.key",
- native_shared_libs: ["libbaz"],
- binaries: ["binfoo"],
- min_sdk_version: "29",
- }
- apex_key {
- name: "myapex.key",
- }
- cc_binary {
- name: "binfoo",
- shared_libs: ["libbar", "libbaz", "libqux",],
- apex_available: ["myapex"],
- min_sdk_version: "29",
- recovery_available: false,
- }
- cc_library {
- name: "libbar",
- srcs: ["libbar.cc"],
- stubs: {
- symbol_file: "libbar.map.txt",
- versions: [
- "29",
- ],
- },
- }
- cc_library {
- name: "libbaz",
- srcs: ["libbaz.cc"],
- apex_available: ["myapex"],
- min_sdk_version: "29",
- stubs: {
- symbol_file: "libbaz.map.txt",
- versions: [
- "29",
- ],
- },
- }
- cc_api_library {
- name: "libbar",
- src: "libbar_stub.so",
- min_sdk_version: "29",
- variants: ["apex.29"],
- }
- cc_api_variant {
- name: "libbar",
- variant: "apex",
- version: "29",
- src: "libbar_apex_29.so",
- }
- cc_api_library {
- name: "libbaz",
- src: "libbaz_stub.so",
- min_sdk_version: "29",
- variants: ["apex.29"],
- }
- cc_api_variant {
- name: "libbaz",
- variant: "apex",
- version: "29",
- src: "libbaz_apex_29.so",
- }
- cc_api_library {
- name: "libqux",
- src: "libqux_stub.so",
- min_sdk_version: "29",
- variants: ["apex.29"],
- }
- cc_api_variant {
- name: "libqux",
- variant: "apex",
- version: "29",
- src: "libqux_apex_29.so",
- }
- api_imports {
- name: "api_imports",
- apex_shared_libs: [
- "libbar",
- "libbaz",
- "libqux",
- ],
- }
- `
- result := testApex(t, bp)
-
- hasDep := func(m android.Module, wantDep android.Module) bool {
- t.Helper()
- var found bool
- result.VisitDirectDeps(m, func(dep blueprint.Module) {
- if dep == wantDep {
- found = true
- }
- })
- return found
- }
-
- // Library defines stubs and cc_api_library should be used with cc_api_library
- binfooApexVariant := result.ModuleForTests("binfoo", "android_arm64_armv8-a_apex29").Module()
- libbarCoreVariant := result.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
- libbarApiImportCoreVariant := result.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
-
- android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries", true, hasDep(binfooApexVariant, libbarApiImportCoreVariant))
- android.AssertBoolEquals(t, "apex variant should link against original library if exists", true, hasDep(binfooApexVariant, libbarCoreVariant))
-
- binFooCFlags := result.ModuleForTests("binfoo", "android_arm64_armv8-a_apex29").Rule("ld").Args["libFlags"]
- android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libbar.apex.29.apiimport.so")
- android.AssertStringDoesNotContain(t, "binfoo should not link against cc_api_library itself", binFooCFlags, "libbar.apiimport.so")
- android.AssertStringDoesNotContain(t, "binfoo should not link against original definition", binFooCFlags, "libbar.so")
-
- // Library defined in the same APEX should be linked with original definition instead of cc_api_library
- libbazApexVariant := result.ModuleForTests("libbaz", "android_arm64_armv8-a_shared_apex29").Module()
- libbazApiImportCoreVariant := result.ModuleForTests("libbaz.apiimport", "android_arm64_armv8-a_shared").Module()
- android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries even from same APEX", true, hasDep(binfooApexVariant, libbazApiImportCoreVariant))
- android.AssertBoolEquals(t, "apex variant should link against original library if exists", true, hasDep(binfooApexVariant, libbazApexVariant))
-
- android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libbaz.so")
- android.AssertStringDoesNotContain(t, "binfoo should not link against cc_api_library itself", binFooCFlags, "libbaz.apiimport.so")
- android.AssertStringDoesNotContain(t, "binfoo should not link against original definition", binFooCFlags, "libbaz.apex.29.apiimport.so")
-
- // cc_api_library defined without original library should be linked with cc_api_library
- libquxApiImportApexVariant := result.ModuleForTests("libqux.apiimport", "android_arm64_armv8-a_shared").Module()
- android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries even original library definition does not exist", true, hasDep(binfooApexVariant, libquxApiImportApexVariant))
- android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libqux.apex.29.apiimport.so")
-}
-
-func TestPlatformBinaryBuildsAgainstApiSurfaceStubLibraries(t *testing.T) {
- bp := `
- apex {
- name: "myapex",
- key: "myapex.key",
- native_shared_libs: ["libbar"],
- min_sdk_version: "29",
- }
- apex_key {
- name: "myapex.key",
- }
- cc_binary {
- name: "binfoo",
- shared_libs: ["libbar"],
- recovery_available: false,
- }
- cc_library {
- name: "libbar",
- srcs: ["libbar.cc"],
- apex_available: ["myapex"],
- min_sdk_version: "29",
- stubs: {
- symbol_file: "libbar.map.txt",
- versions: [
- "29",
- ],
- },
- }
- cc_api_library {
- name: "libbar",
- src: "libbar_stub.so",
- variants: ["apex.29"],
- }
- cc_api_variant {
- name: "libbar",
- variant: "apex",
- version: "29",
- src: "libbar_apex_29.so",
- }
- api_imports {
- name: "api_imports",
- apex_shared_libs: [
- "libbar",
- ],
- }
- `
-
- result := testApex(t, bp)
-
- hasDep := func(m android.Module, wantDep android.Module) bool {
- t.Helper()
- var found bool
- result.VisitDirectDeps(m, func(dep blueprint.Module) {
- if dep == wantDep {
- found = true
- }
- })
- return found
- }
-
- // Library defines stubs and cc_api_library should be used with cc_api_library
- binfooApexVariant := result.ModuleForTests("binfoo", "android_arm64_armv8-a").Module()
- libbarCoreVariant := result.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
- libbarApiImportCoreVariant := result.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
-
- android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries", true, hasDep(binfooApexVariant, libbarApiImportCoreVariant))
- android.AssertBoolEquals(t, "apex variant should link against original library if exists", true, hasDep(binfooApexVariant, libbarCoreVariant))
-
- binFooCFlags := result.ModuleForTests("binfoo", "android_arm64_armv8-a").Rule("ld").Args["libFlags"]
- android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libbar.apex.29.apiimport.so")
- android.AssertStringDoesNotContain(t, "binfoo should not link against cc_api_library itself", binFooCFlags, "libbar.apiimport.so")
- android.AssertStringDoesNotContain(t, "binfoo should not link against original definition", binFooCFlags, "libbar.so")
-}
-
-func TestTrimmedApex(t *testing.T) {
- bp := `
- apex {
- name: "myapex",
- key: "myapex.key",
- native_shared_libs: ["libfoo","libbaz"],
- min_sdk_version: "29",
- trim_against: "mydcla",
- }
- apex {
- name: "mydcla",
- key: "myapex.key",
- native_shared_libs: ["libfoo","libbar"],
- min_sdk_version: "29",
- file_contexts: ":myapex-file_contexts",
- dynamic_common_lib_apex: true,
- }
- apex_key {
- name: "myapex.key",
- }
- cc_library {
- name: "libfoo",
- shared_libs: ["libc"],
- apex_available: ["myapex","mydcla"],
- min_sdk_version: "29",
- }
- cc_library {
- name: "libbar",
- shared_libs: ["libc"],
- apex_available: ["myapex","mydcla"],
- min_sdk_version: "29",
- }
- cc_library {
- name: "libbaz",
- shared_libs: ["libc"],
- apex_available: ["myapex","mydcla"],
- min_sdk_version: "29",
- }
- cc_api_library {
- name: "libc",
- src: "libc.so",
- min_sdk_version: "29",
- recovery_available: true,
- vendor_available: true,
- product_available: true,
- }
- api_imports {
- name: "api_imports",
- shared_libs: [
- "libc",
- ],
- header_libs: [],
- }
- `
- ctx := testApex(t, bp)
- module := ctx.ModuleForTests("myapex", "android_common_myapex")
- apexRule := module.MaybeRule("apexRule")
- if apexRule.Rule == nil {
- t.Errorf("Expecting regular apex rule but a non regular apex rule found")
- }
-
- ctx = testApex(t, bp, android.FixtureModifyConfig(android.SetTrimmedApexEnabledForTests))
- trimmedApexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("TrimmedApexRule")
- libs_to_trim := trimmedApexRule.Args["libs_to_trim"]
- android.AssertStringDoesContain(t, "missing lib to trim", libs_to_trim, "libfoo")
- android.AssertStringDoesContain(t, "missing lib to trim", libs_to_trim, "libbar")
- android.AssertStringDoesNotContain(t, "unexpected libs in the libs to trim", libs_to_trim, "libbaz")
+ _ = android.GroupFixturePreparers(
+ prepareForApexTest,
+ ).ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("app dependency myapp must have updatable: true")).
+ RunTestWithBp(t, bp)
}
func TestCannedFsConfig(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -10466,6 +10395,7 @@
}
func TestCannedFsConfig_HasCustomConfig(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -10488,6 +10418,7 @@
}
func TestStubLibrariesMultipleApexViolation(t *testing.T) {
+ t.Parallel()
testCases := []struct {
desc string
hasStubs bool
@@ -10512,9 +10443,9 @@
expectedError: "Stub libraries should have a single apex_available.*myapex.*otherapex",
},
{
- desc: "stub library can be available to a core apex and a test apex",
+ desc: "stub library can be available to a core apex and a test apex using apex_available_name",
hasStubs: true,
- apexAvailable: `["myapex", "test_myapex"]`,
+ apexAvailable: `["myapex"]`,
},
}
bpTemplate := `
@@ -10539,29 +10470,33 @@
key: "apex.key",
updatable: false,
native_shared_libs: ["libfoo"],
+ apex_available_name: "myapex",
}
apex_key {
name: "apex.key",
}
`
for _, tc := range testCases {
- stubs := ""
- if tc.hasStubs {
- stubs = `stubs: {symbol_file: "libfoo.map.txt"},`
- }
- bp := fmt.Sprintf(bpTemplate, stubs, tc.apexAvailable)
- mockFsFixturePreparer := android.FixtureModifyMockFS(func(fs android.MockFS) {
- fs["system/sepolicy/apex/test_myapex-file_contexts"] = nil
+ t.Run(tc.desc, func(t *testing.T) {
+ stubs := ""
+ if tc.hasStubs {
+ stubs = `stubs: {symbol_file: "libfoo.map.txt"},`
+ }
+ bp := fmt.Sprintf(bpTemplate, stubs, tc.apexAvailable)
+ mockFsFixturePreparer := android.FixtureModifyMockFS(func(fs android.MockFS) {
+ fs["system/sepolicy/apex/test_myapex-file_contexts"] = nil
+ })
+ if tc.expectedError == "" {
+ testApex(t, bp, mockFsFixturePreparer)
+ } else {
+ testApexError(t, tc.expectedError, bp, mockFsFixturePreparer)
+ }
})
- if tc.expectedError == "" {
- testApex(t, bp, mockFsFixturePreparer)
- } else {
- testApexError(t, tc.expectedError, bp, mockFsFixturePreparer)
- }
}
}
func TestFileSystemShouldSkipApexLibraries(t *testing.T) {
+ t.Parallel()
context := android.GroupFixturePreparers(
android.PrepareForIntegrationTestWithAndroid,
cc.PrepareForIntegrationTestWithCc,
@@ -10575,7 +10510,10 @@
deps: [
"libfoo",
],
- linker_config_src: "linker.config.json",
+ linker_config: {
+ gen_linker_config: true,
+ linker_config_srcs: ["linker.config.json"],
+ },
}
cc_library {
@@ -10631,6 +10569,7 @@
`
func TestAconfigFilesJavaDeps(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, apex_default_bp+`
apex {
name: "myapex",
@@ -10653,6 +10592,7 @@
apex_available: [
"myapex",
],
+ compile_dex: true,
}
java_library {
@@ -10664,6 +10604,7 @@
apex_available: [
"myapex",
],
+ compile_dex: true,
}
aconfig_declarations {
@@ -10700,14 +10641,15 @@
mod := ctx.ModuleForTests("myapex", "android_common_myapex")
s := mod.Rule("apexRule").Args["copy_commands"]
copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
- if len(copyCmds) != 8 {
- t.Fatalf("Expected 5 commands, got %d in:\n%s", len(copyCmds), s)
+ if len(copyCmds) != 14 {
+ t.Fatalf("Expected 14 commands, got %d in:\n%s", len(copyCmds), s)
}
- ensureMatches(t, copyCmds[4], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$")
- ensureMatches(t, copyCmds[5], "^cp -f .*/package.map .*/image.apex/etc$")
- ensureMatches(t, copyCmds[6], "^cp -f .*/flag.map .*/image.apex/etc$")
- ensureMatches(t, copyCmds[7], "^cp -f .*/flag.val .*/image.apex/etc$")
+ ensureListContainsMatch(t, copyCmds, "^cp -f .*/aconfig_flags.pb .*/image.apex/etc/aconfig_flags.pb")
+ ensureListContainsMatch(t, copyCmds, "^cp -f .*/package.map .*/image.apex/etc/package.map")
+ ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.map .*/image.apex/etc/flag.map")
+ ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.val .*/image.apex/etc/flag.val")
+ ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.info.*/image.apex/etc/flag.info")
inputs := []string{
"my_aconfig_declarations_foo/intermediate.pb",
@@ -10717,9 +10659,11 @@
VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map")
VerifyAconfigRule(t, &mod, "create_aconfig_flag_map_file", inputs, "android_common_myapex/flag.map", "myapex", "flag_map")
VerifyAconfigRule(t, &mod, "create_aconfig_flag_val_file", inputs, "android_common_myapex/flag.val", "myapex", "flag_val")
+ VerifyAconfigRule(t, &mod, "create_aconfig_flag_info_file", inputs, "android_common_myapex/flag.info", "myapex", "flag_info")
}
func TestAconfigFilesJavaAndCcDeps(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, apex_default_bp+`
apex {
name: "myapex",
@@ -10747,6 +10691,7 @@
apex_available: [
"myapex",
],
+ compile_dex: true,
}
cc_library {
@@ -10835,14 +10780,15 @@
mod := ctx.ModuleForTests("myapex", "android_common_myapex")
s := mod.Rule("apexRule").Args["copy_commands"]
copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
- if len(copyCmds) != 12 {
- t.Fatalf("Expected 12 commands, got %d in:\n%s", len(copyCmds), s)
+ if len(copyCmds) != 18 {
+ t.Fatalf("Expected 18 commands, got %d in:\n%s", len(copyCmds), s)
}
- ensureMatches(t, copyCmds[8], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$")
- ensureMatches(t, copyCmds[9], "^cp -f .*/package.map .*/image.apex/etc$")
- ensureMatches(t, copyCmds[10], "^cp -f .*/flag.map .*/image.apex/etc$")
- ensureMatches(t, copyCmds[11], "^cp -f .*/flag.val .*/image.apex/etc$")
+ ensureListContainsMatch(t, copyCmds, "^cp -f .*/aconfig_flags.pb .*/image.apex/etc/aconfig_flags.pb")
+ ensureListContainsMatch(t, copyCmds, "^cp -f .*/package.map .*/image.apex/etc/package.map")
+ ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.map .*/image.apex/etc/flag.map")
+ ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.val .*/image.apex/etc/flag.val")
+ ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.info .*/image.apex/etc/flag.info")
inputs := []string{
"my_aconfig_declarations_foo/intermediate.pb",
@@ -10853,9 +10799,11 @@
VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map")
VerifyAconfigRule(t, &mod, "create_aconfig_flag_map_file", inputs, "android_common_myapex/flag.map", "myapex", "flag_map")
VerifyAconfigRule(t, &mod, "create_aconfig_flag_val_file", inputs, "android_common_myapex/flag.val", "myapex", "flag_val")
+ VerifyAconfigRule(t, &mod, "create_aconfig_flag_info_file", inputs, "android_common_myapex/flag.info", "myapex", "flag_info")
}
func TestAconfigFilesRustDeps(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, apex_default_bp+`
apex {
name: "myapex",
@@ -11003,14 +10951,15 @@
mod := ctx.ModuleForTests("myapex", "android_common_myapex")
s := mod.Rule("apexRule").Args["copy_commands"]
copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
- if len(copyCmds) != 32 {
- t.Fatalf("Expected 28 commands, got %d in:\n%s", len(copyCmds), s)
+ if len(copyCmds) != 34 {
+ t.Fatalf("Expected 34 commands, got %d in:\n%s", len(copyCmds), s)
}
- ensureMatches(t, copyCmds[28], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$")
- ensureMatches(t, copyCmds[29], "^cp -f .*/package.map .*/image.apex/etc$")
- ensureMatches(t, copyCmds[30], "^cp -f .*/flag.map .*/image.apex/etc$")
- ensureMatches(t, copyCmds[31], "^cp -f .*/flag.val .*/image.apex/etc$")
+ ensureListContainsMatch(t, copyCmds, "^cp -f .*/aconfig_flags.pb .*/image.apex/etc/aconfig_flags.pb")
+ ensureListContainsMatch(t, copyCmds, "^cp -f .*/package.map .*/image.apex/etc/package.map")
+ ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.map .*/image.apex/etc/flag.map")
+ ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.val .*/image.apex/etc/flag.val")
+ ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.info .*/image.apex/etc/flag.info")
inputs := []string{
"my_aconfig_declarations_foo/intermediate.pb",
@@ -11022,6 +10971,7 @@
VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map")
VerifyAconfigRule(t, &mod, "create_aconfig_flag_map_file", inputs, "android_common_myapex/flag.map", "myapex", "flag_map")
VerifyAconfigRule(t, &mod, "create_aconfig_flag_val_file", inputs, "android_common_myapex/flag.val", "myapex", "flag_val")
+ VerifyAconfigRule(t, &mod, "create_aconfig_flag_info_file", inputs, "android_common_myapex/flag.info", "myapex", "flag_info")
}
func VerifyAconfigRule(t *testing.T, mod *android.TestingModule, desc string, inputs []string, output string, container string, file_type string) {
@@ -11045,6 +10995,7 @@
}
func TestAconfigFilesOnlyMatchCurrentApex(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, apex_default_bp+`
apex {
name: "myapex",
@@ -11067,6 +11018,7 @@
apex_available: [
"myapex",
],
+ compile_dex: true,
}
java_library {
@@ -11078,6 +11030,7 @@
apex_available: [
"myapex",
],
+ compile_dex: true,
}
aconfig_declarations {
@@ -11129,6 +11082,7 @@
}
func TestAconfigFilesRemoveDuplicates(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, apex_default_bp+`
apex {
name: "myapex",
@@ -11151,6 +11105,7 @@
apex_available: [
"myapex",
],
+ compile_dex: true,
}
java_library {
@@ -11162,6 +11117,7 @@
apex_available: [
"myapex",
],
+ compile_dex: true,
}
aconfig_declarations {
@@ -11208,6 +11164,7 @@
// Test that the boot jars come from the _selected_ apex prebuilt
// RELEASE_APEX_CONTIRBUTIONS_* build flags will be used to select the correct prebuilt for a specific release config
func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) {
+ t.Parallel()
checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, stem string, bootDexJarPath string) {
t.Helper()
s := ctx.ModuleForTests("dex_bootjars", "android_common")
@@ -11350,12 +11307,12 @@
{
desc: "Prebuilt apex prebuilt_com.android.foo is selected, profile should come from .prof deapexed from the prebuilt",
selectedApexContributions: "foo.prebuilt.contributions",
- expectedBootJar: "out/soong/.intermediates/prebuilt_com.android.foo.deapexer/android_common/deapexer/javalib/framework-foo.jar",
+ expectedBootJar: "out/soong/.intermediates/prebuilt_com.android.foo/android_common_com.android.foo/deapexer/javalib/framework-foo.jar",
},
{
desc: "Prebuilt apex prebuilt_com.android.foo.v2 is selected, profile should come from .prof deapexed from the prebuilt",
selectedApexContributions: "foo.prebuilt.v2.contributions",
- expectedBootJar: "out/soong/.intermediates/prebuilt_com.android.foo.v2.deapexer/android_common/deapexer/javalib/framework-foo.jar",
+ expectedBootJar: "out/soong/.intermediates/com.android.foo.v2/android_common_com.android.foo/deapexer/javalib/framework-foo.jar",
},
}
@@ -11396,6 +11353,7 @@
// Test that product packaging installs the selected mainline module (either source or a specific prebuilt)
// RELEASE_APEX_CONTIRBUTIONS_* build flags will be used to select the correct prebuilt for a specific release config
func TestInstallationRulesForMultipleApexPrebuilts(t *testing.T) {
+ t.Parallel()
// for a mainline module family, check that only the flagged soong module is visible to make
checkHideFromMake := func(t *testing.T, ctx *android.TestContext, visibleModuleName string, hiddenModuleNames []string) {
variation := func(moduleName string) string {
@@ -11541,6 +11499,7 @@
// Test that product packaging installs the selected mainline module in workspaces withtout source mainline module
func TestInstallationRulesForMultipleApexPrebuiltsWithoutSource(t *testing.T) {
+ t.Parallel()
// for a mainline module family, check that only the flagged soong module is visible to make
checkHideFromMake := func(t *testing.T, ctx *android.TestContext, visibleModuleNames []string, hiddenModuleNames []string) {
variation := func(moduleName string) string {
@@ -11648,6 +11607,7 @@
}
func TestAconfifDeclarationsValidation(t *testing.T) {
+ t.Parallel()
aconfigDeclarationLibraryString := func(moduleNames []string) (ret string) {
for _, moduleName := range moduleNames {
ret += fmt.Sprintf(`
@@ -11681,7 +11641,7 @@
}
filegroup {
name: "qux-filegroup",
- srcs: [
+ device_common_srcs: [
":qux-lib{.generated_srcjars}",
],
}
@@ -11764,6 +11724,7 @@
}
func TestMultiplePrebuiltsWithSameBase(t *testing.T) {
+ t.Parallel()
ctx := testApex(t, `
apex {
name: "myapex",
@@ -11803,6 +11764,7 @@
}
func TestApexMinSdkVersionOverride(t *testing.T) {
+ t.Parallel()
checkMinSdkVersion := func(t *testing.T, module android.TestingModule, expectedMinSdkVersion string) {
args := module.Rule("apexRule").Args
optFlags := args["opt_flags"]
@@ -11838,6 +11800,7 @@
apex_available: ["com.android.apex30"],
min_sdk_version: "30",
sdk_version: "current",
+ compile_dex: true,
}
override_apex {
@@ -11879,6 +11842,7 @@
}
func TestOverrideApexWithPrebuiltApexPreferred(t *testing.T) {
+ t.Parallel()
context := android.GroupFixturePreparers(
android.PrepareForIntegrationTestWithAndroid,
PrepareForTestWithApexBuildComponents,
@@ -11914,6 +11878,7 @@
}
func TestUpdatableApexMinSdkVersionCurrent(t *testing.T) {
+ t.Parallel()
testApexError(t, `"myapex" .*: updatable: updatable APEXes should not set min_sdk_version to current. Please use a finalized API level or a recognized in-development codename`, `
apex {
name: "myapex",
@@ -11931,6 +11896,7 @@
}
func TestPrebuiltStubNoinstall(t *testing.T) {
+ t.Parallel()
testFunc := func(t *testing.T, expectLibfooOnSystemLib bool, fs android.MockFS) {
result := android.GroupFixturePreparers(
prepareForApexTest,
@@ -11940,7 +11906,7 @@
).RunTest(t)
ldRule := result.ModuleForTests("installedlib", "android_arm64_armv8-a_shared").Rule("ld")
- android.AssertStringDoesContain(t, "", ldRule.Args["libFlags"], "android_arm64_armv8-a_shared/libfoo.so")
+ android.AssertStringDoesContain(t, "", ldRule.Args["libFlags"], "android_arm64_armv8-a_shared_current/libfoo.so")
installRules := result.InstallMakeRulesForTesting(t)
@@ -12010,6 +11976,7 @@
`)
t.Run("prebuilt stub (without source): no install", func(t *testing.T) {
+ t.Parallel()
testFunc(
t,
/*expectLibfooOnSystemLib=*/ false,
@@ -12034,6 +12001,7 @@
`)
t.Run("prebuilt stub (with disabled source): no install", func(t *testing.T) {
+ t.Parallel()
testFunc(
t,
/*expectLibfooOnSystemLib=*/ false,
@@ -12047,3 +12015,591 @@
)
})
}
+
+func TestSdkLibraryTransitiveClassLoaderContext(t *testing.T) {
+ t.Parallel()
+ // This test case tests that listing the impl lib instead of the top level java_sdk_library
+ // in libs of android_app and java_library does not lead to class loader context device/host
+ // path mismatch errors.
+ android.GroupFixturePreparers(
+ prepareForApexTest,
+ android.PrepareForIntegrationTestWithAndroid,
+ PrepareForTestWithApexBuildComponents,
+ android.FixtureModifyEnv(func(env map[string]string) {
+ env["DISABLE_CONTAINER_CHECK"] = "true"
+ }),
+ withFiles(filesForSdkLibrary),
+ android.FixtureMergeMockFs(android.MockFS{
+ "system/sepolicy/apex/com.android.foo30-file_contexts": nil,
+ }),
+ ).RunTestWithBp(t, `
+ apex {
+ name: "com.android.foo30",
+ key: "myapex.key",
+ updatable: true,
+ bootclasspath_fragments: [
+ "foo-bootclasspath-fragment",
+ ],
+ java_libs: [
+ "bar",
+ ],
+ apps: [
+ "bar-app",
+ ],
+ min_sdk_version: "30",
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ bootclasspath_fragment {
+ name: "foo-bootclasspath-fragment",
+ contents: [
+ "framework-foo",
+ ],
+ apex_available: [
+ "com.android.foo30",
+ ],
+ hidden_api: {
+ split_packages: ["*"]
+ },
+ }
+
+ java_sdk_library {
+ name: "framework-foo",
+ srcs: [
+ "A.java"
+ ],
+ unsafe_ignore_missing_latest_api: true,
+ apex_available: [
+ "com.android.foo30",
+ ],
+ compile_dex: true,
+ sdk_version: "core_current",
+ shared_library: false,
+ }
+
+ java_library {
+ name: "bar",
+ srcs: [
+ "A.java"
+ ],
+ libs: [
+ "framework-foo.impl",
+ ],
+ apex_available: [
+ "com.android.foo30",
+ ],
+ sdk_version: "core_current",
+ compile_dex: true,
+ }
+
+ java_library {
+ name: "baz",
+ srcs: [
+ "A.java"
+ ],
+ libs: [
+ "bar",
+ ],
+ sdk_version: "core_current",
+ }
+
+ android_app {
+ name: "bar-app",
+ srcs: [
+ "A.java"
+ ],
+ libs: [
+ "baz",
+ "framework-foo.impl",
+ ],
+ apex_available: [
+ "com.android.foo30",
+ ],
+ sdk_version: "core_current",
+ min_sdk_version: "30",
+ manifest: "AndroidManifest.xml",
+ updatable: true,
+ }
+ `)
+}
+
+// If an apex sets system_ext_specific: true, its systemserverclasspath libraries must set this property as well.
+func TestApexSSCPJarMustBeInSamePartitionAsApex(t *testing.T) {
+ t.Parallel()
+ testApexError(t, `foo is an apex systemserver jar, but its partition does not match the partition of its containing apex`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ systemserverclasspath_fragments: [
+ "mysystemserverclasspathfragment",
+ ],
+ min_sdk_version: "29",
+ updatable: true,
+ system_ext_specific: true,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_library {
+ name: "foo",
+ srcs: ["b.java"],
+ min_sdk_version: "29",
+ installable: true,
+ apex_available: [
+ "myapex",
+ ],
+ sdk_version: "current",
+ }
+
+ systemserverclasspath_fragment {
+ name: "mysystemserverclasspathfragment",
+ contents: [
+ "foo",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ }
+ `,
+ dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"),
+ )
+}
+
+// partitions should not package the artifacts that are included inside the apex.
+func TestFilesystemWithApexDeps(t *testing.T) {
+ t.Parallel()
+ result := testApex(t, `
+ android_filesystem {
+ name: "myfilesystem",
+ deps: ["myapex"],
+ }
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ binaries: ["binfoo"],
+ native_shared_libs: ["libfoo"],
+ apps: ["appfoo"],
+ updatable: false,
+ }
+ apex_key {
+ name: "myapex.key",
+ }
+ cc_binary {
+ name: "binfoo",
+ apex_available: ["myapex"],
+ }
+ cc_library {
+ name: "libfoo",
+ apex_available: ["myapex"],
+ }
+ android_app {
+ name: "appfoo",
+ sdk_version: "current",
+ apex_available: ["myapex"],
+ }
+ `, filesystem.PrepareForTestWithFilesystemBuildComponents)
+
+ partition := result.ModuleForTests("myfilesystem", "android_common")
+ fileList := android.ContentFromFileRuleForTests(t, result, partition.Output("fileList"))
+ android.AssertDeepEquals(t, "filesystem with apex", "apex/myapex.apex\n", fileList)
+}
+
+func TestApexVerifyNativeImplementationLibs(t *testing.T) {
+ t.Parallel()
+
+ extractDepenencyPathFromErrors := func(errs []error) []string {
+ i := slices.IndexFunc(errs, func(err error) bool {
+ return strings.Contains(err.Error(), "dependency path:")
+ })
+ if i < 0 {
+ return nil
+ }
+ var dependencyPath []string
+ for _, err := range errs[i+1:] {
+ s := err.Error()
+ lastSpace := strings.LastIndexByte(s, ' ')
+ if lastSpace >= 0 {
+ dependencyPath = append(dependencyPath, s[lastSpace+1:])
+ }
+ }
+ return dependencyPath
+ }
+
+ checkErrors := func(wantDependencyPath []string) func(t *testing.T, result *android.TestResult) {
+ return func(t *testing.T, result *android.TestResult) {
+ t.Helper()
+ if len(result.Errs) == 0 {
+ t.Fatalf("expected errors")
+ }
+ t.Log("found errors:")
+ for _, err := range result.Errs {
+ t.Log(err)
+ }
+ if g, w := result.Errs[0].Error(), "library in apex transitively linked against implementation library"; !strings.Contains(g, w) {
+ t.Fatalf("expected error %q, got %q", w, g)
+ }
+ dependencyPath := extractDepenencyPathFromErrors(result.Errs)
+ if g, w := dependencyPath, wantDependencyPath; !slices.Equal(g, w) {
+ t.Errorf("expected dependency path %q, got %q", w, g)
+ }
+ }
+ }
+
+ addToSharedLibs := func(module, lib string) func(bp *bpmodify.Blueprint) {
+ return func(bp *bpmodify.Blueprint) {
+ m := bp.ModulesByName(module)
+ props, err := m.GetOrCreateProperty(bpmodify.List, "shared_libs")
+ if err != nil {
+ panic(err)
+ }
+ props.AddStringToList(lib)
+ }
+ }
+
+ bpTemplate := `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ rust_dyn_libs: ["libmyrust"],
+ binaries: ["mybin", "myrustbin"],
+ jni_libs: ["libjni"],
+ apps: ["myapp"],
+ updatable: false,
+ }
+
+ apex {
+ name: "otherapex",
+ key: "myapex.key",
+ native_shared_libs: ["libotherapex"],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["foo.cpp"],
+ apex_available: ["myapex"],
+ }
+
+ cc_binary {
+ name: "mybin",
+ srcs: ["foo.cpp"],
+ apex_available: ["myapex"],
+ }
+
+ rust_library {
+ name: "libmyrust",
+ crate_name: "myrust",
+ srcs: ["src/lib.rs"],
+ rustlibs: ["libmyrust_transitive_dylib"],
+ rlibs: ["libmyrust_transitive_rlib"],
+ apex_available: ["myapex"],
+ }
+
+ rust_library{
+ name: "libmyrust_transitive_dylib",
+ crate_name: "myrust_transitive_dylib",
+ srcs: ["src/lib.rs"],
+ apex_available: ["myapex"],
+ }
+
+ rust_library {
+ name: "libmyrust_transitive_rlib",
+ crate_name: "myrust_transitive_rlib",
+ srcs: ["src/lib.rs"],
+ apex_available: ["myapex"],
+ }
+
+ rust_binary {
+ name: "myrustbin",
+ srcs: ["src/main.rs"],
+ apex_available: ["myapex"],
+ }
+
+ cc_library {
+ name: "libbar",
+ sdk_version: "current",
+ srcs: ["bar.cpp"],
+ apex_available: ["myapex"],
+ stl: "none",
+ }
+
+ android_app {
+ name: "myapp",
+ jni_libs: ["libembeddedjni"],
+ use_embedded_native_libs: true,
+ sdk_version: "current",
+ apex_available: ["myapex"],
+ }
+
+ cc_library {
+ name: "libembeddedjni",
+ sdk_version: "current",
+ srcs: ["bar.cpp"],
+ apex_available: ["myapex"],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "libjni",
+ sdk_version: "current",
+ srcs: ["bar.cpp"],
+ apex_available: ["myapex"],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "libotherapex",
+ sdk_version: "current",
+ srcs: ["otherapex.cpp"],
+ apex_available: ["otherapex"],
+ stubs: {
+ symbol_file: "libotherapex.map.txt",
+ versions: ["1", "2", "3"],
+ },
+ stl: "none",
+ }
+
+ cc_library {
+ name: "libplatform",
+ sdk_version: "current",
+ srcs: ["libplatform.cpp"],
+ stubs: {
+ symbol_file: "libplatform.map.txt",
+ versions: ["1", "2", "3"],
+ },
+ stl: "none",
+ system_shared_libs: [],
+ }
+ `
+
+ testCases := []struct {
+ name string
+ bpModifier func(bp *bpmodify.Blueprint)
+ dependencyPath []string
+ }{
+ {
+ name: "library dependency in other apex",
+ bpModifier: addToSharedLibs("mylib", "libotherapex#impl"),
+ dependencyPath: []string{"myapex", "mylib", "libotherapex"},
+ },
+ {
+ name: "transitive library dependency in other apex",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("mylib", "libbar")(bp)
+ addToSharedLibs("libbar", "libotherapex#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "mylib", "libbar", "libotherapex"},
+ },
+ {
+ name: "library dependency in platform",
+ bpModifier: addToSharedLibs("mylib", "libplatform#impl"),
+ dependencyPath: []string{"myapex", "mylib", "libplatform"},
+ },
+ {
+ name: "jni library dependency in other apex",
+ bpModifier: addToSharedLibs("libjni", "libotherapex#impl"),
+ dependencyPath: []string{"myapex", "libjni", "libotherapex"},
+ },
+ {
+ name: "transitive jni library dependency in other apex",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libjni", "libbar")(bp)
+ addToSharedLibs("libbar", "libotherapex#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "libjni", "libbar", "libotherapex"},
+ },
+ {
+ name: "jni library dependency in platform",
+ bpModifier: addToSharedLibs("libjni", "libplatform#impl"),
+ dependencyPath: []string{"myapex", "libjni", "libplatform"},
+ },
+ {
+ name: "transitive jni library dependency in platform",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libjni", "libbar")(bp)
+ addToSharedLibs("libbar", "libplatform#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "libjni", "libbar", "libplatform"},
+ },
+ {
+ name: "app jni library dependency in other apex",
+ bpModifier: addToSharedLibs("libembeddedjni", "libotherapex#impl"),
+ dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libotherapex"},
+ },
+ {
+ name: "transitive app jni library dependency in other apex",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libembeddedjni", "libbar")(bp)
+ addToSharedLibs("libbar", "libotherapex#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libbar", "libotherapex"},
+ },
+ {
+ name: "app jni library dependency in platform",
+ bpModifier: addToSharedLibs("libembeddedjni", "libplatform#impl"),
+ dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libplatform"},
+ },
+ {
+ name: "transitive app jni library dependency in platform",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libembeddedjni", "libbar")(bp)
+ addToSharedLibs("libbar", "libplatform#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libbar", "libplatform"},
+ },
+ {
+ name: "binary dependency in other apex",
+ bpModifier: addToSharedLibs("mybin", "libotherapex#impl"),
+ dependencyPath: []string{"myapex", "mybin", "libotherapex"},
+ },
+ {
+ name: "transitive binary dependency in other apex",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("mybin", "libbar")(bp)
+ addToSharedLibs("libbar", "libotherapex#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "mybin", "libbar", "libotherapex"},
+ },
+ {
+ name: "binary dependency in platform",
+ bpModifier: addToSharedLibs("mybin", "libplatform#impl"),
+ dependencyPath: []string{"myapex", "mybin", "libplatform"},
+ },
+ {
+ name: "transitive binary dependency in platform",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("mybin", "libbar")(bp)
+ addToSharedLibs("libbar", "libplatform#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "mybin", "libbar", "libplatform"},
+ },
+
+ {
+ name: "rust library dependency in other apex",
+ bpModifier: addToSharedLibs("libmyrust", "libotherapex#impl"),
+ dependencyPath: []string{"myapex", "libmyrust", "libotherapex"},
+ },
+ {
+ name: "transitive rust library dependency in other apex",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libmyrust", "libbar")(bp)
+ addToSharedLibs("libbar", "libotherapex#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "libmyrust", "libbar", "libotherapex"},
+ },
+ {
+ name: "rust library dependency in platform",
+ bpModifier: addToSharedLibs("libmyrust", "libplatform#impl"),
+ dependencyPath: []string{"myapex", "libmyrust", "libplatform"},
+ },
+ {
+ name: "transitive rust library dependency in platform",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libmyrust", "libbar")(bp)
+ addToSharedLibs("libbar", "libplatform#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "libmyrust", "libbar", "libplatform"},
+ },
+ {
+ name: "transitive rust library dylib dependency in other apex",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libmyrust_transitive_dylib", "libotherapex#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "libmyrust", "libmyrust_transitive_dylib", "libotherapex"},
+ },
+ {
+ name: "transitive rust library dylib dependency in platform",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libmyrust_transitive_dylib", "libplatform#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "libmyrust", "libmyrust_transitive_dylib", "libplatform"},
+ },
+ {
+ name: "transitive rust library rlib dependency in other apex",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libmyrust_transitive_rlib", "libotherapex#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "libmyrust", "libmyrust_transitive_rlib", "libotherapex"},
+ },
+ {
+ name: "transitive rust library rlib dependency in platform",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libmyrust_transitive_rlib", "libplatform#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "libmyrust", "libmyrust_transitive_rlib", "libplatform"},
+ },
+ {
+ name: "rust binary dependency in other apex",
+ bpModifier: addToSharedLibs("myrustbin", "libotherapex#impl"),
+ dependencyPath: []string{"myapex", "myrustbin", "libotherapex"},
+ },
+ {
+ name: "transitive rust binary dependency in other apex",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("myrustbin", "libbar")(bp)
+ addToSharedLibs("libbar", "libotherapex#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "myrustbin", "libbar", "libotherapex"},
+ },
+ {
+ name: "rust binary dependency in platform",
+ bpModifier: addToSharedLibs("myrustbin", "libplatform#impl"),
+ dependencyPath: []string{"myapex", "myrustbin", "libplatform"},
+ },
+ {
+ name: "transitive rust binary dependency in platform",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("myrustbin", "libbar")(bp)
+ addToSharedLibs("libbar", "libplatform#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "myrustbin", "libbar", "libplatform"},
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ t.Parallel()
+ bp, err := bpmodify.NewBlueprint("", []byte(bpTemplate))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if testCase.bpModifier != nil {
+ func() {
+ defer func() {
+ if r := recover(); r != nil {
+ t.Fatalf("panic in bpModifier: %v", r)
+ }
+ }()
+ testCase.bpModifier(bp)
+ }()
+ }
+ android.GroupFixturePreparers(
+ android.PrepareForTestWithAndroidBuildComponents,
+ cc.PrepareForTestWithCcBuildComponents,
+ java.PrepareForTestWithDexpreopt,
+ rust.PrepareForTestWithRustDefaultModules,
+ PrepareForTestWithApexBuildComponents,
+ prepareForTestWithMyapex,
+ prepareForTestWithOtherapex,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BuildId = proptools.StringPtr("TEST.BUILD_ID")
+ }),
+ ).ExtendWithErrorHandler(android.FixtureCustomErrorHandler(checkErrors(testCase.dependencyPath))).
+ RunTestWithBp(t, bp.String())
+ })
+ }
+}
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 25131ee..71a8246 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -47,6 +47,7 @@
)
func TestBootclasspathFragments_FragmentDependency(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithBootclasspathFragment,
// Configure some libraries in the art bootclasspath_fragment and platform_bootclasspath.
@@ -104,6 +105,7 @@
test: {
enabled: true,
},
+ sdk_version: "core_current",
}
java_library {
@@ -177,6 +179,7 @@
}
func TestBootclasspathFragmentInArtApex(t *testing.T) {
+ t.Parallel()
commonPreparer := android.GroupFixturePreparers(
prepareForTestWithBootclasspathFragment,
prepareForTestWithArtApex,
@@ -297,6 +300,7 @@
}
t.Run("boot image files from source", func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
commonPreparer,
@@ -328,6 +332,7 @@
})
t.Run("boot image files from source of override apex", func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
commonPreparer,
@@ -348,6 +353,7 @@
})
t.Run("generate boot image profile even if dexpreopt is disabled", func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
commonPreparer,
@@ -368,6 +374,7 @@
})
t.Run("boot image disable generate profile", func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
commonPreparer,
@@ -386,6 +393,7 @@
})
t.Run("boot image files with preferred prebuilt", func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
commonPreparer,
@@ -397,11 +405,20 @@
// 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",
@@ -421,6 +438,7 @@
})
t.Run("source with inconsistency between config and contents", func(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
commonPreparer,
@@ -434,6 +452,7 @@
})
t.Run("prebuilt with inconsistency between config and contents", func(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
commonPreparer,
@@ -447,6 +466,7 @@
})
t.Run("preferred prebuilt with inconsistency between config and contents", func(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
commonPreparer,
@@ -463,6 +483,7 @@
})
t.Run("source preferred and prebuilt with inconsistency between config and contents", func(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
commonPreparer,
@@ -481,6 +502,7 @@
}
func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) {
+ t.Parallel()
preparers := android.GroupFixturePreparers(
prepareForTestWithBootclasspathFragment,
prepareForTestWithArtApex,
@@ -494,6 +516,7 @@
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 := `
@@ -551,36 +574,34 @@
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) {
+ t.Parallel()
result := preparers.RunTestWithBp(t, fmt.Sprintf(bp, "enabled: false,"))
java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
`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
@@ -606,6 +627,7 @@
}
func TestBootclasspathFragmentContentsNoName(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithBootclasspathFragment,
prepareForTestWithMyapex,
@@ -714,6 +736,7 @@
// TestBootclasspathFragment_HiddenAPIList checks to make sure that the correct parameters are
// passed to the hiddenapi list tool.
func TestBootclasspathFragment_HiddenAPIList(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithBootclasspathFragment,
prepareForTestWithArtApex,
@@ -749,6 +772,7 @@
],
srcs: ["b.java"],
compile_dex: true,
+ sdk_version: "core_current",
}
java_sdk_library {
@@ -833,6 +857,7 @@
`)
java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
+ "all_apex_contributions",
"art-bootclasspath-fragment",
"bar",
"dex2oatd",
@@ -867,6 +892,7 @@
// additional_stubs: ["android-non-updatable"] causes the source android-non-updatable modules to be
// added to the hiddenapi list tool.
func TestBootclasspathFragment_AndroidNonUpdatable_FromSource(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithBootclasspathFragment,
prepareForTestWithArtApex,
@@ -922,6 +948,7 @@
],
srcs: ["b.java"],
compile_dex: true,
+ sdk_version: "core_current",
}
java_library {
@@ -1003,6 +1030,7 @@
`)
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",
@@ -1038,6 +1066,7 @@
}
func TestBootclasspathFragment_AndroidNonUpdatable_FromText(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithBootclasspathFragment,
prepareForTestWithArtApex,
@@ -1093,6 +1122,7 @@
],
srcs: ["b.java"],
compile_dex: true,
+ sdk_version: "core_current",
}
java_library {
@@ -1174,6 +1204,7 @@
`)
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",
@@ -1203,6 +1234,7 @@
// setting additional_stubs: ["android-non-updatable"] causes the prebuilt android-non-updatable
// modules to be added to the hiddenapi list tool.
func TestBootclasspathFragment_AndroidNonUpdatable_AlwaysUsePrebuiltSdks(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithBootclasspathFragment,
java.PrepareForTestWithDexpreopt,
@@ -1245,6 +1277,7 @@
],
srcs: ["b.java"],
compile_dex: true,
+ sdk_version: "core_current",
}
java_library {
@@ -1326,6 +1359,7 @@
`)
java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
+ "all_apex_contributions",
"art-bootclasspath-fragment",
"bar",
"dex2oatd",
@@ -1361,6 +1395,7 @@
}
func TestBootclasspathFragmentProtoContainsMinSdkVersion(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithBootclasspathFragment,
prepareForTestWithMyapex,
diff --git a/apex/builder.go b/apex/builder.go
index bfe1692..3f2623e 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -43,7 +43,6 @@
pctx.Import("android/soong/java")
pctx.HostBinToolVariable("apexer", "apexer")
pctx.HostBinToolVariable("apexer_with_DCLA_preprocessing", "apexer_with_DCLA_preprocessing")
- pctx.HostBinToolVariable("apexer_with_trim_preprocessing", "apexer_with_trim_preprocessing")
// ART minimal builds (using the master-art manifest) do not have the "frameworks/base"
// projects, and hence cannot build 'aapt2'. Use the SDK prebuilt instead.
@@ -71,9 +70,10 @@
pctx.HostBinToolVariable("extract_apks", "extract_apks")
pctx.HostBinToolVariable("make_f2fs", "make_f2fs")
pctx.HostBinToolVariable("sload_f2fs", "sload_f2fs")
- pctx.HostBinToolVariable("make_erofs", "make_erofs")
+ pctx.HostBinToolVariable("make_erofs", "mkfs.erofs")
pctx.HostBinToolVariable("apex_compression_tool", "apex_compression_tool")
pctx.HostBinToolVariable("dexdeps", "dexdeps")
+ pctx.HostBinToolVariable("apex_ls", "apex-ls")
pctx.HostBinToolVariable("apex_sepolicy_tests", "apex_sepolicy_tests")
pctx.HostBinToolVariable("deapexer", "deapexer")
pctx.HostBinToolVariable("debugfs_static", "debugfs_static")
@@ -83,6 +83,7 @@
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 {
@@ -95,6 +96,7 @@
{"package.map", "create_aconfig_package_map_file", "package_map"},
{"flag.map", "create_aconfig_flag_map_file", "flag_map"},
{"flag.val", "create_aconfig_flag_val_file", "flag_val"},
+ {"flag.info", "create_aconfig_flag_info_file", "flag_info"},
}
var (
@@ -171,34 +173,6 @@
}, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key",
"opt_flags", "manifest", "is_DCLA")
- TrimmedApexRule = pctx.StaticRule("TrimmedApexRule", blueprint.RuleParams{
- Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
- `(. ${out}.copy_commands) && ` +
- `APEXER_TOOL_PATH=${tool_path} ` +
- `${apexer_with_trim_preprocessing} ` +
- `--apexer ${apexer} ` +
- `--canned_fs_config ${canned_fs_config} ` +
- `--manifest ${manifest} ` +
- `--libs_to_trim ${libs_to_trim} ` +
- `${image_dir} ` +
- `${out} ` +
- `-- ` +
- `--include_build_info ` +
- `--force ` +
- `--payload_type image ` +
- `--key ${key} ` +
- `--file_contexts ${file_contexts} ` +
- `${opt_flags} `,
- CommandDeps: []string{"${apexer_with_trim_preprocessing}", "${apexer}", "${avbtool}", "${e2fsdroid}",
- "${merge_zips}", "${mke2fs}", "${resize2fs}", "${sefcontext_compile}", "${make_f2fs}",
- "${sload_f2fs}", "${make_erofs}", "${soong_zip}", "${zipalign}", "${aapt2}",
- "prebuilts/sdk/current/public/android.jar"},
- Rspfile: "${out}.copy_commands",
- RspfileContent: "${copy_commands}",
- Description: "APEX ${image_dir} => ${out}",
- }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key",
- "opt_flags", "manifest", "libs_to_trim")
-
apexProtoConvertRule = pctx.AndroidStaticRule("apexProtoConvertRule",
blueprint.RuleParams{
Command: `${aapt2} convert --output-format proto $in -o $out`,
@@ -223,7 +197,7 @@
Command: `diff --unchanged-group-format='' \` +
`--changed-group-format='%<' \` +
`${image_content_file} ${allowed_files_file} || (` +
- `echo -e "New unexpected files were added to ${apex_module_name}." ` +
+ `echo "New unexpected files were added to ${apex_module_name}." ` +
` "To fix the build run following command:" && ` +
`echo "system/apex/tools/update_allowed_list.sh ${allowed_files_file} ${image_content_file}" && ` +
`exit 1); touch ${out}`,
@@ -237,11 +211,11 @@
}, "image_dir", "readelf")
apexSepolicyTestsRule = pctx.StaticRule("apexSepolicyTestsRule", blueprint.RuleParams{
- Command: `${deapexer} --debugfs_path ${debugfs_static} list -Z ${in} > ${out}.fc` +
- ` && ${apex_sepolicy_tests} -f ${out}.fc && touch ${out}`,
- CommandDeps: []string{"${apex_sepolicy_tests}", "${deapexer}", "${debugfs_static}"},
+ Command: `${apex_ls} -Z ${in} > ${out}.fc` +
+ ` && ${apex_sepolicy_tests} -f ${out}.fc --partition ${partition_tag} && touch ${out}`,
+ CommandDeps: []string{"${apex_sepolicy_tests}", "${apex_ls}"},
Description: "run apex_sepolicy_tests",
- })
+ }, "partition_tag")
apexLinkerconfigValidationRule = pctx.StaticRule("apexLinkerconfigValidationRule", blueprint.RuleParams{
Command: `${conv_linker_config} validate --type apex ${image_dir} && touch ${out}`,
@@ -249,6 +223,13 @@
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} --partition_tag=${partition_tag} && touch ${out}`,
+ CommandDeps: []string{"${host_apex_verifier}", "${deapexer}", "${debugfs_static}", "${fsck_erofs}"},
+ Description: "run host_apex_verifier",
+ }, "partition_tag")
+
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 +243,65 @@
}, "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))
+
+ // To enable fingerprint, we need to have v2 storage files. The default version is 1.
+ storageFilesVersion := 1
+ if ctx.Config().ReleaseFingerprintAconfigPackages() {
+ storageFilesVersion = 2
+ }
+
+ 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 "),
+ "version": strconv.Itoa(storageFilesVersion),
+ },
+ })
+ 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
@@ -299,14 +339,14 @@
}
manifestJsonFullOut := android.PathForModuleOut(ctx, "apex_manifest_full.json")
- defaultVersion := android.DefaultUpdatableModuleVersion
+ defaultVersion := ctx.Config().ReleaseDefaultUpdatableModuleVersion()
if a.properties.Variant_version != nil {
defaultVersionInt, err := strconv.Atoi(defaultVersion)
if err != nil {
- ctx.ModuleErrorf("expected DefaultUpdatableModuleVersion to be an int, but got %s", defaultVersion)
+ ctx.ModuleErrorf("expected RELEASE_DEFAULT_UPDATABLE_MODULE_VERSION to be an int, but got %s", defaultVersion)
}
- if defaultVersionInt%10 != 0 {
- ctx.ModuleErrorf("expected DefaultUpdatableModuleVersion to end in a zero, but got %s", defaultVersion)
+ if defaultVersionInt%10 != 0 && defaultVersionInt%10 != 9 {
+ ctx.ModuleErrorf("expected RELEASE_DEFAULT_UPDATABLE_MODULE_VERSION to end in a zero or a nine, but got %s", defaultVersion)
}
variantVersion := []rune(*a.properties.Variant_version)
if len(variantVersion) != 1 || variantVersion[0] < '0' || variantVersion[0] > '9' {
@@ -356,7 +396,7 @@
// file for this APEX which is either from /systme/sepolicy/apex/<apexname>-file_contexts or from
// the file_contexts property of this APEX. This is to make sure that the manifest file is correctly
// labeled as system_file or vendor_apex_metadata_file.
-func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.OutputPath {
+func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.Path {
var fileContexts android.Path
var fileContextsDir string
isFileContextsModule := false
@@ -365,8 +405,10 @@
} else {
if m, t := android.SrcIsModuleWithTag(*a.properties.File_contexts); m != "" {
isFileContextsModule = true
- otherModule := android.GetModuleFromPathDep(ctx, m, t)
- fileContextsDir = ctx.OtherModuleDir(otherModule)
+ otherModule := android.GetModuleProxyFromPathDep(ctx, m, t)
+ if otherModule != nil {
+ fileContextsDir = ctx.OtherModuleDir(*otherModule)
+ }
}
fileContexts = android.PathForModuleSrc(ctx, *a.properties.File_contexts)
}
@@ -409,13 +451,13 @@
}
rule.Build("file_contexts."+a.Name(), "Generate file_contexts")
- return output.OutputPath
+ return output
}
// buildInstalledFilesFile creates a build rule for the installed-files.txt file where the list of
// files included in this APEX is shown. The text file is dist'ed so that people can see what's
// included in the APEX without actually downloading and extracting it.
-func (a *apexBundle) buildInstalledFilesFile(ctx android.ModuleContext, builtApex android.Path, imageDir android.Path) android.OutputPath {
+func (a *apexBundle) buildInstalledFilesFile(ctx android.ModuleContext, builtApex android.Path, imageDir android.Path) android.Path {
output := android.PathForModuleOut(ctx, "installed-files.txt")
rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
@@ -425,12 +467,12 @@
Text(" | sort -nr > ").
Output(output)
rule.Build("installed-files."+a.Name(), "Installed files")
- return output.OutputPath
+ return output
}
// buildBundleConfig creates a build rule for the bundle config file that will control the bundle
// creation process.
-func (a *apexBundle) buildBundleConfig(ctx android.ModuleContext) android.OutputPath {
+func (a *apexBundle) buildBundleConfig(ctx android.ModuleContext) android.Path {
output := android.PathForModuleOut(ctx, "bundle_config.json")
type ApkConfig struct {
@@ -475,7 +517,7 @@
android.WriteFileRule(ctx, output, string(j))
- return output.OutputPath
+ return output
}
func markManifestTestOnly(ctx android.ModuleContext, androidManifestFile android.Path) android.Path {
@@ -510,7 +552,7 @@
imageDir := android.PathForModuleOut(ctx, "image"+suffix)
- installSymbolFiles := (!ctx.Config().KatiEnabled() || a.ExportedToMake()) && a.installable()
+ installSymbolFiles := a.ExportedToMake() && a.installable()
// set of dependency module:location mappings
installMapSet := make(map[string]bool)
@@ -560,6 +602,7 @@
}
} else {
if installSymbolFiles {
+ // store installedPath. symlinks might be created if required.
installedPath = ctx.InstallFile(apexDir.Join(ctx, fi.installDir), fi.stem(), fi.builtFile)
}
}
@@ -595,7 +638,7 @@
if len(installMapSet) > 0 {
var installs []string
installs = append(installs, android.SortedKeys(installMapSet)...)
- a.SetLicenseInstallMap(installs)
+ ctx.SetLicenseInstallMap(installs)
}
////////////////////////////////////////////////////////////////////////////////////////////
@@ -644,48 +687,10 @@
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 +772,6 @@
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")
}
@@ -807,24 +800,6 @@
"opt_flags": strings.Join(optFlags, " "),
},
})
- } else if ctx.Config().ApexTrimEnabled() && len(a.libs_to_trim(ctx)) > 0 {
- ctx.Build(pctx, android.BuildParams{
- Rule: TrimmedApexRule,
- Implicits: implicitInputs,
- Output: unsignedOutputFile,
- Description: "apex",
- Args: map[string]string{
- "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
- "image_dir": imageDir.String(),
- "copy_commands": strings.Join(copyCommands, " && "),
- "manifest": a.manifestPbOut.String(),
- "file_contexts": fileContexts.String(),
- "canned_fs_config": cannedFsConfig.String(),
- "key": a.privateKeyFile.String(),
- "opt_flags": strings.Join(optFlags, " "),
- "libs_to_trim": strings.Join(a.libs_to_trim(ctx), ","),
- },
- })
} else {
ctx.Build(pctx, android.BuildParams{
Rule: apexRule,
@@ -943,14 +918,16 @@
args["outCommaList"] = signedOutputFile.String()
}
var validations android.Paths
- validations = append(validations, runApexLinkerconfigValidation(ctx, unsignedOutputFile.OutputPath, imageDir.OutputPath))
- // TODO(b/279688635) deapexer supports [ext4]
- if !a.testApex && suffix == imageApexSuffix && ext4 == a.payloadFsType {
- validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile.OutputPath))
+ validations = append(validations, runApexLinkerconfigValidation(ctx, unsignedOutputFile, imageDir))
+ if !a.skipValidation(apexSepolicyTests) && android.InList(a.payloadFsType, []fsType{ext4, erofs}) {
+ validations = append(validations, runApexSepolicyTests(ctx, a, unsignedOutputFile))
}
if !a.testApex && len(a.properties.Unwanted_transitive_deps) > 0 {
validations = append(validations,
- runApexElfCheckerUnwanted(ctx, unsignedOutputFile.OutputPath, a.properties.Unwanted_transitive_deps))
+ runApexElfCheckerUnwanted(ctx, unsignedOutputFile, a.properties.Unwanted_transitive_deps))
+ }
+ if !a.skipValidation(hostApexVerifier) && android.InList(a.payloadFsType, []fsType{ext4, erofs}) {
+ validations = append(validations, runApexHostVerifier(ctx, a, unsignedOutputFile))
}
ctx.Build(pctx, android.BuildParams{
Rule: rule,
@@ -1048,8 +1025,9 @@
}
return ""
}
- if a.overridableProperties.Package_name != "" {
- return a.overridableProperties.Package_name
+ packageNameFromProp := a.overridableProperties.Package_name.GetOrDefault(ctx, "")
+ if packageNameFromProp != "" {
+ return packageNameFromProp
}
manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName())
if overridden {
@@ -1066,7 +1044,7 @@
}
depInfos := android.DepNameToDepInfoMap{}
- a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ a.WalkPayloadDepsProxy(ctx, func(ctx android.BaseModuleContext, from, to android.ModuleProxy, externalDep bool) bool {
if from.Name() == to.Name() {
// This can happen for cc.reuseObjTag. We are not interested in tracking this.
// As soon as the dependency graph crosses the APEX boundary, don't go further.
@@ -1075,7 +1053,7 @@
// Skip dependencies that are only available to APEXes; they are developed with updatability
// in mind and don't need manual approval.
- if to.(android.ApexModule).NotAvailableForPlatform() {
+ if android.OtherModuleProviderOrDefault(ctx, to, android.CommonModuleInfoKey).NotAvailableForPlatform {
return !externalDep
}
@@ -1093,16 +1071,8 @@
depInfos[to.Name()] = info
} else {
toMinSdkVersion := "(no version)"
- if m, ok := to.(interface {
- MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel
- }); ok {
- if v := m.MinSdkVersion(ctx); !v.IsNone() {
- toMinSdkVersion = v.String()
- }
- } else if m, ok := to.(interface{ MinSdkVersion() string }); ok {
- // TODO(b/175678607) eliminate the use of MinSdkVersion returning
- // string
- if v := m.MinSdkVersion(); v != "" {
+ if info, ok := android.OtherModuleProvider(ctx, to, android.CommonModuleInfoKey); ok {
+ if v := info.MinSdkVersion; v != "" {
toMinSdkVersion = v
}
}
@@ -1133,14 +1103,27 @@
func (a *apexBundle) buildLintReports(ctx android.ModuleContext) {
depSetsBuilder := java.NewLintDepSetBuilder()
for _, fi := range a.filesInfo {
- depSetsBuilder.Transitive(fi.lintDepSets)
+ if fi.lintInfo != nil {
+ depSetsBuilder.Transitive(fi.lintInfo)
+ }
}
- a.lintReports = java.BuildModuleLintReportZips(ctx, depSetsBuilder.Build())
+ depSets := depSetsBuilder.Build()
+ var validations android.Paths
+
+ if a.checkStrictUpdatabilityLinting(ctx) {
+ baselines := depSets.Baseline.ToList()
+ if len(baselines) > 0 {
+ outputFile := java.VerifyStrictUpdatabilityChecks(ctx, baselines)
+ validations = append(validations, outputFile)
+ }
+ }
+
+ a.lintReports = java.BuildModuleLintReportZips(ctx, depSets, validations)
}
-func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext, defaultReadOnlyFiles []string) android.OutputPath {
- var readOnlyPaths = defaultReadOnlyFiles
+func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.Path {
+ 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)
@@ -1203,10 +1186,10 @@
cmd.Text(")").FlagWithOutput("> ", cannedFsConfig)
builder.Build("generateFsConfig", fmt.Sprintf("Generating canned fs config for %s", a.BaseModuleName()))
- return cannedFsConfig.OutputPath
+ return cannedFsConfig
}
-func runApexLinkerconfigValidation(ctx android.ModuleContext, apexFile android.OutputPath, imageDir android.OutputPath) android.Path {
+func runApexLinkerconfigValidation(ctx android.ModuleContext, apexFile android.Path, imageDir android.Path) android.Path {
timestamp := android.PathForModuleOut(ctx, "apex_linkerconfig_validation.timestamp")
ctx.Build(pctx, android.BuildParams{
Rule: apexLinkerconfigValidationRule,
@@ -1219,21 +1202,40 @@
return timestamp
}
+// Can't use PartitionTag() because PartitionTag() returns the partition this module is actually
+// installed (e.g. PartitionTag() may return "system" for vendor apex when vendor is linked to /system/vendor)
+func (a *apexBundle) partition() string {
+ if a.SocSpecific() {
+ return "vendor"
+ } else if a.DeviceSpecific() {
+ return "odm"
+ } else if a.ProductSpecific() {
+ return "product"
+ } else if a.SystemExtSpecific() {
+ return "system_ext"
+ } else {
+ return "system"
+ }
+}
+
// Runs apex_sepolicy_tests
//
-// $ deapexer list -Z {apex_file} > {file_contexts}
+// $ apex-ls -Z {apex_file} > {file_contexts}
// $ apex_sepolicy_tests -f {file_contexts}
-func runApexSepolicyTests(ctx android.ModuleContext, apexFile android.OutputPath) android.Path {
- timestamp := android.PathForModuleOut(ctx, "sepolicy_tests.timestamp")
+func runApexSepolicyTests(ctx android.ModuleContext, a *apexBundle, apexFile android.Path) android.Path {
+ timestamp := android.PathForModuleOut(ctx, "apex_sepolicy_tests.timestamp")
ctx.Build(pctx, android.BuildParams{
Rule: apexSepolicyTestsRule,
Input: apexFile,
Output: timestamp,
+ Args: map[string]string{
+ "partition_tag": a.partition(),
+ },
})
return timestamp
}
-func runApexElfCheckerUnwanted(ctx android.ModuleContext, apexFile android.OutputPath, unwanted []string) android.Path {
+func runApexElfCheckerUnwanted(ctx android.ModuleContext, apexFile android.Path, unwanted []string) android.Path {
timestamp := android.PathForModuleOut(ctx, "apex_elf_unwanted.timestamp")
ctx.Build(pctx, android.BuildParams{
Rule: apexElfCheckerUnwantedRule,
@@ -1246,3 +1248,16 @@
})
return timestamp
}
+
+func runApexHostVerifier(ctx android.ModuleContext, a *apexBundle, apexFile android.Path) android.Path {
+ timestamp := android.PathForModuleOut(ctx, "host_apex_verifier.timestamp")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: apexHostVerifierRule,
+ Input: apexFile,
+ Output: timestamp,
+ Args: map[string]string{
+ "partition_tag": a.partition(),
+ },
+ })
+ return timestamp
+}
diff --git a/apex/classpath_element_test.go b/apex/classpath_element_test.go
index b9a9198..f367174 100644
--- a/apex/classpath_element_test.go
+++ b/apex/classpath_element_test.go
@@ -40,14 +40,12 @@
var _ java.ClasspathElementContext = (*testClasspathElementContext)(nil)
func TestCreateClasspathElements(t *testing.T) {
+ t.Parallel()
preparer := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
prepareForTestWithArtApex,
prepareForTestWithMyapex,
- // For otherapex.
- android.FixtureMergeMockFs(android.MockFS{
- "system/sepolicy/apex/otherapex-file_contexts": nil,
- }),
+ prepareForTestWithOtherapex,
java.PrepareForTestWithJavaSdkLibraryFiles,
java.FixtureWithLastReleaseApis("foo", "othersdklibrary"),
java.FixtureConfigureApexBootJars("myapex:bar"),
@@ -92,6 +90,7 @@
],
srcs: ["b.java"],
installable: true,
+ sdk_version: "core_current",
}
java_library {
@@ -239,6 +238,7 @@
// Verify that CreateClasspathElements works when given valid input.
t.Run("art:baz, art:quuz, my:bar, foo", func(t *testing.T) {
+ t.Parallel()
ctx := newCtx()
elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, artQuuz, myBar, platformFoo}, []android.Module{artFragment, myFragment})
expectedElements := java.ClasspathElements{
@@ -251,6 +251,7 @@
// Verify that CreateClasspathElements detects when an apex has multiple fragments.
t.Run("multiple fragments for same apex", func(t *testing.T) {
+ t.Parallel()
ctx := newCtx()
elements := java.CreateClasspathElements(ctx, []android.Module{}, []android.Module{artFragment, artFragment})
android.FailIfNoMatchingErrors(t, "apex com.android.art has multiple fragments, art-bootclasspath-fragment{.*} and art-bootclasspath-fragment{.*}", ctx.errs)
@@ -260,6 +261,7 @@
// Verify that CreateClasspathElements detects when a library is in multiple fragments.
t.Run("library from multiple fragments", func(t *testing.T) {
+ t.Parallel()
ctx := newCtx()
elements := java.CreateClasspathElements(ctx, []android.Module{other}, []android.Module{artFragment, myFragment})
android.FailIfNoMatchingErrors(t, "library othersdklibrary{.*} is in two separate fragments, art-bootclasspath-fragment{.*} and mybootclasspath-fragment{.*}", ctx.errs)
@@ -270,6 +272,7 @@
// Verify that CreateClasspathElements detects when a fragment's contents are not contiguous and
// are separated by a library from another fragment.
t.Run("discontiguous separated by fragment", func(t *testing.T) {
+ t.Parallel()
ctx := newCtx()
elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, myBar, artQuuz, platformFoo}, []android.Module{artFragment, myFragment})
expectedElements := java.ClasspathElements{
@@ -284,6 +287,7 @@
// Verify that CreateClasspathElements detects when a fragment's contents are not contiguous and
// are separated by a standalone library.
t.Run("discontiguous separated by library", func(t *testing.T) {
+ t.Parallel()
ctx := newCtx()
elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, platformFoo, artQuuz, myBar}, []android.Module{artFragment, myFragment})
expectedElements := java.ClasspathElements{
@@ -299,6 +303,7 @@
// indicates it is from an apex the supplied fragments list does not contain a fragment for that
// apex.
t.Run("no fragment for apex", func(t *testing.T) {
+ t.Parallel()
ctx := newCtx()
elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, otherApexLibrary}, []android.Module{artFragment})
expectedElements := java.ClasspathElements{
diff --git a/apex/container_test.go b/apex/container_test.go
index 3931174..395793f 100644
--- a/apex/container_test.go
+++ b/apex/container_test.go
@@ -15,10 +15,11 @@
package apex
import (
- "android/soong/android"
- "android/soong/java"
"fmt"
"testing"
+
+ "android/soong/android"
+ "android/soong/java"
)
var checkContainerMatch = func(t *testing.T, name string, container string, expected bool, actual bool) {
@@ -27,10 +28,11 @@
}
func TestApexDepsContainers(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForApexTest,
java.PrepareForTestWithJavaSdkLibraryFiles,
- java.FixtureWithLastReleaseApis("mybootclasspathlib"),
+ java.FixtureWithLastReleaseApis("mybootclasspathlib", "bar"),
).RunTestWithBp(t, `
apex {
name: "myapex",
@@ -68,16 +70,17 @@
],
compile_dex: true,
static_libs: [
- "foo",
+ "food",
"baz",
],
libs: [
- "bar",
+ "bar.stubs",
],
min_sdk_version: "30",
+ sdk_version: "current",
}
java_library {
- name: "foo",
+ name: "food",
srcs:[
"A.java",
],
@@ -85,13 +88,15 @@
"myapex",
],
min_sdk_version: "30",
+ sdk_version: "core_current",
}
- java_library {
+ java_sdk_library {
name: "bar",
srcs:[
"A.java",
],
min_sdk_version: "30",
+ sdk_version: "core_current",
}
java_library {
name: "baz",
@@ -103,6 +108,7 @@
"myapex",
],
min_sdk_version: "30",
+ sdk_version: "core_current",
}
`)
testcases := []struct {
@@ -130,7 +136,7 @@
isApexContainer: false,
},
{
- moduleName: "foo",
+ moduleName: "food",
variant: "android_common_apex30",
isSystemContainer: true,
isApexContainer: true,
@@ -159,10 +165,11 @@
}
func TestNonUpdatableApexDepsContainers(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForApexTest,
java.PrepareForTestWithJavaSdkLibraryFiles,
- java.FixtureWithLastReleaseApis("mybootclasspathlib"),
+ java.FixtureWithLastReleaseApis("mybootclasspathlib", "bar"),
).RunTestWithBp(t, `
apex {
name: "myapex",
@@ -199,26 +206,30 @@
],
compile_dex: true,
static_libs: [
- "foo",
+ "food",
],
libs: [
- "bar",
+ "bar.stubs",
],
+ sdk_version: "current",
}
java_library {
- name: "foo",
+ name: "food",
srcs:[
"A.java",
],
apex_available: [
"myapex",
],
+ sdk_version: "core_current",
}
- java_library {
+ java_sdk_library {
name: "bar",
srcs:[
"A.java",
],
+ sdk_version: "none",
+ system_modules: "none",
}
`)
testcases := []struct {
@@ -246,7 +257,7 @@
isApexContainer: false,
},
{
- moduleName: "foo",
+ moduleName: "food",
variant: "android_common_apex10000",
isSystemContainer: true,
isApexContainer: true,
@@ -269,6 +280,7 @@
}
func TestUpdatableAndNonUpdatableApexesIdenticalMinSdkVersion(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForApexTest,
java.PrepareForTestWithJavaSdkLibraryFiles,
@@ -318,6 +330,7 @@
],
min_sdk_version: "30",
sdk_version: "current",
+ compile_dex: true,
}
`)
diff --git a/apex/deapexer.go b/apex/deapexer.go
index a673108..3b8233d 100644
--- a/apex/deapexer.go
+++ b/apex/deapexer.go
@@ -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 @@
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 @@
// 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 @@
// 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 @@
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
}
diff --git a/apex/dexpreopt_bootjars_test.go b/apex/dexpreopt_bootjars_test.go
index 95db37d..b51bb36 100644
--- a/apex/dexpreopt_bootjars_test.go
+++ b/apex/dexpreopt_bootjars_test.go
@@ -127,16 +127,29 @@
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)
@@ -155,6 +168,7 @@
}
func TestDexpreoptBootJarsWithSourceArtApex(t *testing.T) {
+ t.Parallel()
ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art"
expectedInputs := []string{
@@ -193,6 +207,7 @@
// The only difference is that the ART profile should be deapexed from the prebuilt APEX. Other
// inputs and outputs should be the same as above.
func TestDexpreoptBootJarsWithPrebuiltArtApex(t *testing.T) {
+ t.Parallel()
ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art"
expectedInputs := []string{
@@ -200,7 +215,7 @@
"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",
}
@@ -230,6 +245,7 @@
// Changes to the boot.zip structure may break the ART APK scanner.
func TestDexpreoptBootZip(t *testing.T) {
+ t.Parallel()
ruleFile := "boot.zip"
ctx := android.PathContextForTesting(android.TestArchConfig("", nil, "", nil))
@@ -258,6 +274,7 @@
// Multiple ART apexes might exist in the tree.
// The profile should correspond to the apex selected using release build flags
func TestDexpreoptProfileWithMultiplePrebuiltArtApexes(t *testing.T) {
+ t.Parallel()
ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art"
bp := `
// Platform.
@@ -384,12 +401,12 @@
{
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 {
@@ -409,3 +426,107 @@
android.AssertStringListContains(t, tc.desc, inputs, tc.expectedProfile)
}
}
+
+// Check that dexpreopt works with Google mainline prebuilts even in workspaces where source is missing
+func TestDexpreoptWithMainlinePrebuiltNoSource(t *testing.T) {
+ t.Parallel()
+ bp := `
+ // Platform.
+
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ fragments: [
+ {
+ apex: "com.android.art",
+ module: "art-bootclasspath-fragment",
+ },
+ ],
+ }
+
+ // Source AOSP ART apex
+ java_library {
+ name: "core-oj",
+ srcs: ["core-oj.java"],
+ installable: true,
+ apex_available: [
+ "com.android.art",
+ ],
+ }
+
+ bootclasspath_fragment {
+ name: "art-bootclasspath-fragment",
+ image_name: "art",
+ contents: ["core-oj"],
+ apex_available: [
+ "com.android.art",
+ ],
+ hidden_api: {
+ split_packages: ["*"],
+ },
+ }
+
+ apex_key {
+ name: "com.android.art.key",
+ public_key: "com.android.art.avbpubkey",
+ private_key: "com.android.art.pem",
+ }
+
+ apex {
+ name: "com.android.art",
+ key: "com.android.art.key",
+ bootclasspath_fragments: ["art-bootclasspath-fragment"],
+ updatable: false,
+ }
+
+
+ // Prebuilt Google ART APEX.
+
+ java_import {
+ name: "core-oj",
+ jars: ["core-oj.jar"],
+ apex_available: [
+ "com.android.art",
+ ],
+ }
+
+ prebuilt_bootclasspath_fragment {
+ name: "art-bootclasspath-fragment",
+ image_name: "art",
+ contents: ["core-oj"],
+ hidden_api: {
+ annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
+ metadata: "my-bootclasspath-fragment/metadata.csv",
+ index: "my-bootclasspath-fragment/index.csv",
+ stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
+ all_flags: "my-bootclasspath-fragment/all-flags.csv",
+ },
+ apex_available: [
+ "com.android.art",
+ ],
+ }
+
+ prebuilt_apex {
+ name: "com.google.android.art",
+ apex_name: "com.android.art",
+ src: "com.android.art-arm.apex",
+ exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
+ }
+
+ apex_contributions {
+ name: "art.prebuilt.contributions",
+ api_domain: "com.android.art",
+ contents: ["prebuilt_com.google.android.art"],
+ }
+ `
+ res := android.GroupFixturePreparers(
+ java.PrepareForTestWithDexpreopt,
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureConfigureBootJars("com.android.art:core-oj"),
+ PrepareForTestWithApexBuildComponents,
+ prepareForTestWithArtApex,
+ android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ART", "art.prebuilt.contributions"),
+ ).RunTestWithBp(t, bp)
+ if !java.CheckModuleHasDependency(t, res.TestContext, "dex_bootjars", "android_common", "prebuilt_com.google.android.art") {
+ t.Errorf("Expected dexpreopt to use prebuilt apex")
+ }
+}
diff --git a/apex/key.go b/apex/key.go
index e4214f0..1622c65 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -18,6 +18,7 @@
"fmt"
"android/soong/android"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -29,6 +30,7 @@
func registerApexKeyBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("apex_key", ApexKeyFactory)
+ ctx.RegisterParallelSingletonModuleType("all_apex_certs", allApexCertsFactory)
}
type apexKey struct {
@@ -155,3 +157,64 @@
android.WriteFileRuleVerbatim(ctx, path, entry.String())
return path
}
+
+var (
+ pemToDer = pctx.AndroidStaticRule("pem_to_der",
+ blueprint.RuleParams{
+ Command: `openssl x509 -inform PEM -outform DER -in $in -out $out`,
+ Description: "Convert certificate from PEM to DER format",
+ },
+ )
+)
+
+// all_apex_certs is a singleton module that collects the certs of all apexes in the tree.
+// It provides two types of output files
+// 1. .pem: This is usually the checked-in x509 certificate in PEM format
+// 2. .der: This is DER format of the certificate, and is generated from the PEM certificate using `openssl x509`
+func allApexCertsFactory() android.SingletonModule {
+ m := &allApexCerts{}
+ android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
+ return m
+}
+
+type allApexCerts struct {
+ android.SingletonModuleBase
+}
+
+func (_ *allApexCerts) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ var avbpubkeys android.Paths
+ var certificatesPem android.Paths
+ ctx.VisitDirectDeps(func(m android.Module) {
+ if apex, ok := m.(*apexBundle); ok {
+ pem, _ := apex.getCertificateAndPrivateKey(ctx)
+ if !android.ExistentPathForSource(ctx, pem.String()).Valid() {
+ if ctx.Config().AllowMissingDependencies() {
+ return
+ } else {
+ ctx.ModuleErrorf("Path %s is not valid\n", pem.String())
+ }
+ }
+ certificatesPem = append(certificatesPem, pem)
+ // avbpubkey for signing the apex payload
+ avbpubkeys = append(avbpubkeys, apex.publicKeyFile)
+ }
+ })
+ certificatesPem = android.SortedUniquePaths(certificatesPem) // For hermiticity
+ avbpubkeys = android.SortedUniquePaths(avbpubkeys) // For hermiticity
+ var certificatesDer android.Paths
+ for index, certificatePem := range certificatesPem {
+ certificateDer := android.PathForModuleOut(ctx, fmt.Sprintf("x509.%v.der", index))
+ ctx.Build(pctx, android.BuildParams{
+ Rule: pemToDer,
+ Input: certificatePem,
+ Output: certificateDer,
+ })
+ certificatesDer = append(certificatesDer, certificateDer)
+ }
+ ctx.SetOutputFiles(certificatesPem, ".pem")
+ ctx.SetOutputFiles(certificatesDer, ".der")
+ ctx.SetOutputFiles(avbpubkeys, ".avbpubkey")
+}
+
+func (_ *allApexCerts) GenerateSingletonBuildActions(ctx android.SingletonContext) {
+}
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 920fc0c..c13d599 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -36,6 +36,7 @@
)
func TestPlatformBootclasspath_Fragments(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
prepareForTestWithMyapex,
@@ -178,6 +179,7 @@
//
// TODO: Remove once all prebuilts use the filtered_... properties.
func TestPlatformBootclasspath_LegacyPrebuiltFragment(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
java.FixtureConfigureApexBootJars("myapex:foo"),
@@ -243,6 +245,7 @@
}
func TestPlatformBootclasspathDependencies(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
prepareForTestWithArtApex,
@@ -293,6 +296,7 @@
],
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
@@ -408,12 +412,16 @@
// The fragments.
`com.android.art:art-bootclasspath-fragment`,
`myapex:my-bootclasspath-fragment`,
+
+ // Impl lib of sdk_library for transitive srcjar generation
+ `platform:foo.impl`,
})
}
// TestPlatformBootclasspath_AlwaysUsePrebuiltSdks verifies that the build does not fail when
// AlwaysUsePrebuiltSdk() returns true.
func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
prepareForTestWithMyapex,
@@ -564,6 +572,9 @@
// The fragments.
"myapex:mybootclasspath-fragment",
"myapex:prebuilt_mybootclasspath-fragment",
+
+ // Impl lib of sdk_library for transitive srcjar generation
+ "platform:foo.impl",
})
}
@@ -587,6 +598,7 @@
// platform_bootclasspath's classpaths.proto config, if the apex does not generate its own config
// by setting generate_classpaths_proto property to false.
func TestPlatformBootclasspath_IncludesRemainingApexJars(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
prepareForTestWithMyapex,
@@ -641,11 +653,12 @@
true, // proto should be generated
"myapex:foo", // apex doesn't generate its own config, so must be in platform_bootclasspath
"bootclasspath.pb",
- "out/soong/target/product/test_device/system/etc/classpaths",
+ "out/target/product/test_device/system/etc/classpaths",
)
}
func TestBootJarNotInApex(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
PrepareForTestWithApexBuildComponents,
@@ -692,6 +705,7 @@
}
func TestBootFragmentNotInApex(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
PrepareForTestWithApexBuildComponents,
@@ -735,6 +749,7 @@
}
func TestNonBootJarInFragment(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
PrepareForTestWithApexBuildComponents,
@@ -791,8 +806,132 @@
`)
}
+// Skip bcp_fragment content validation of source apexes if prebuilts are active.
+func TestNonBootJarInPrebuilts(t *testing.T) {
+ t.Parallel()
+ 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) {
+ t.Parallel()
bp := `
apex {
name: "myapex",
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 9dc8a63..aaf2cb7 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -107,11 +107,6 @@
// 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
@@ -195,14 +190,12 @@
// 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
@@ -211,10 +204,7 @@
}
// 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)
@@ -263,29 +253,8 @@
return entriesList
}
-// 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
}
@@ -293,11 +262,6 @@
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)
@@ -310,12 +274,15 @@
}
// Implements android.DepInInSameApex
-func (p *prebuiltCommon) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
- tag := ctx.OtherModuleDependencyTag(dep)
+func (p *prebuiltCommon) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
_, ok := tag.(exportedDependencyTag)
return ok
}
+func (p *prebuiltCommon) IncomingDepIsInSameApex(tag blueprint.DependencyTag) bool {
+ return true
+}
+
// apexInfoMutator marks any modules for which this apex exports a file as requiring an apex
// specific variant and checks that they are supported.
//
@@ -342,10 +309,6 @@
// extra copying of files. Contrast that with source apex modules that has to build each variant
// from source.
func (p *prebuiltCommon) apexInfoMutator(mctx android.TopDownMutatorContext) {
-
- // Collect direct dependencies into contents.
- contents := make(map[string]android.ApexMembership)
-
// Collect the list of dependencies.
var dependencies []android.ApexModule
mctx.WalkDeps(func(child, parent android.Module) bool {
@@ -383,29 +346,19 @@
// behavior whether there is a corresponding source module present or not.
depName = android.RemoveOptionalPrebuiltPrefix(depName)
- // Remember if this module was added as a direct dependency.
- direct := parent == mctx.Module()
- contents[depName] = contents[depName].Add(direct)
-
// Add the module to the list of dependencies that need to have an APEX variant.
dependencies = append(dependencies, child.(android.ApexModule))
return true
})
- // Create contents for the prebuilt_apex and store it away for later use.
- apexContents := android.NewApexContents(contents)
- android.SetProvider(mctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{
- Contents: apexContents,
- })
+ android.SetProvider(mctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{})
// Create an ApexInfo for the prebuilt_apex.
apexVariationName := p.ApexVariationName()
apexInfo := android.ApexInfo{
ApexVariationName: apexVariationName,
InApexVariants: []string{apexVariationName},
- InApexModules: []string{p.BaseModuleName()}, // BaseModuleName() to avoid the prebuilt_ prefix.
- ApexContents: []*android.ApexContents{apexContents},
ForPrebuiltApex: true,
}
@@ -415,34 +368,6 @@
}
}
-// 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
@@ -450,7 +375,7 @@
inputApex android.Path
- provenanceMetaDataFile android.OutputPath
+ provenanceMetaDataFile android.Path
}
type ApexFileProperties struct {
@@ -485,11 +410,11 @@
// 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 {
@@ -522,7 +447,7 @@
// logic from reporting a more general, less useful message.
}
- return []string{src}
+ return src
}
type PrebuiltProperties struct {
@@ -539,35 +464,19 @@
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{}
@@ -601,7 +510,7 @@
})
// 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),
@@ -610,22 +519,7 @@
// 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 {
@@ -667,97 +561,50 @@
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 which will be used to determine the exported artfifacts from this prebuilt.
- 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
@@ -793,7 +640,7 @@
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) {
@@ -811,11 +658,13 @@
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)
@@ -837,7 +686,7 @@
ctx.SetOutputFiles(android.Paths{p.outputApex}, "")
}
-func (p *Prebuilt) ProvenanceMetaDataFile() android.OutputPath {
+func (p *Prebuilt) ProvenanceMetaDataFile() android.Path {
return p.provenanceMetaDataFile
}
@@ -851,26 +700,11 @@
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,
@@ -878,14 +712,16 @@
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 {
@@ -954,48 +790,18 @@
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)
}
@@ -1018,7 +824,15 @@
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
@@ -1028,7 +842,7 @@
}
ctx.Build(pctx, android.BuildParams{
Rule: buildRule,
- Input: inputApex,
+ Input: extractedApex,
Output: a.outputApex,
})
@@ -1037,11 +851,13 @@
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)
diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go
index 452a43e..7dbac5f 100644
--- a/apex/systemserver_classpath_fragment_test.go
+++ b/apex/systemserver_classpath_fragment_test.go
@@ -29,6 +29,7 @@
)
func TestSystemserverclasspathFragmentContents(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithSystemserverclasspathFragment,
prepareForTestWithMyapex,
@@ -80,6 +81,7 @@
apex_available: [
"myapex",
],
+ sdk_version: "core_current",
}
systemserverclasspath_fragment {
@@ -117,6 +119,7 @@
}
func TestSystemserverclasspathFragmentNoGeneratedProto(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithSystemserverclasspathFragment,
prepareForTestWithMyapex,
@@ -170,6 +173,7 @@
}
func TestSystemServerClasspathFragmentWithContentNotInMake(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForTestWithSystemserverclasspathFragment,
prepareForTestWithMyapex,
@@ -221,6 +225,7 @@
}
func TestPrebuiltSystemserverclasspathFragmentContents(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithSystemserverclasspathFragment,
prepareForTestWithMyapex,
@@ -276,8 +281,6 @@
java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{
`all_apex_contributions`,
`dex2oatd`,
- `prebuilt_myapex.apex.selector`,
- `prebuilt_myapex.deapexer`,
`prebuilt_mysystemserverclasspathfragment`,
})
@@ -285,10 +288,9 @@
`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",
@@ -299,6 +301,7 @@
}
func TestSystemserverclasspathFragmentStandaloneContents(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithSystemserverclasspathFragment,
prepareForTestWithMyapex,
@@ -350,6 +353,7 @@
apex_available: [
"myapex",
],
+ sdk_version: "core_current",
}
systemserverclasspath_fragment {
@@ -381,6 +385,7 @@
}
func TestPrebuiltStandaloneSystemserverclasspathFragmentContents(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithSystemserverclasspathFragment,
prepareForTestWithMyapex,
@@ -437,10 +442,9 @@
`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",
diff --git a/apex/testing.go b/apex/testing.go
index 3b200f0..a22f640 100644
--- a/apex/testing.go
+++ b/apex/testing.go
@@ -16,10 +16,15 @@
import "android/soong/android"
+const testDefaultUpdatableModuleVersion = "340090000"
+
var PrepareForTestWithApexBuildComponents = android.GroupFixturePreparers(
android.FixtureRegisterWithContext(registerApexBuildComponents),
android.FixtureRegisterWithContext(registerApexKeyBuildComponents),
android.FixtureRegisterWithContext(registerApexDepsInfoComponents),
+ android.FixtureAddTextFile("all_apex_certs/Android.bp", `
+ all_apex_certs { name: "all_apex_certs" }
+ `),
// Additional files needed in tests that disallow non-existent source files.
// This includes files that are needed by all, or at least most, instances of an apex module type.
android.MockFS{
@@ -28,5 +33,8 @@
"build/soong/scripts/gen_ndk_backedby_apex.sh": nil,
// Needed by prebuilt_apex.
"build/soong/scripts/unpack-prebuilt-apex.sh": nil,
+ // Needed by all_apex_certs
+ "build/make/target/product/security/testkey.x509.pem": nil,
}.AddToFixture(),
+ android.PrepareForTestWithBuildFlag("RELEASE_DEFAULT_UPDATABLE_MODULE_VERSION", testDefaultUpdatableModuleVersion),
)
diff --git a/apex/vndk.go b/apex/vndk.go
index 781aa3c..d88808b 100644
--- a/apex/vndk.go
+++ b/apex/vndk.go
@@ -20,6 +20,7 @@
"android/soong/android"
"android/soong/cc"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -54,30 +55,6 @@
Vndk_version *string
}
-func apexVndkMutator(mctx android.TopDownMutatorContext) {
- if ab, ok := mctx.Module().(*apexBundle); ok && ab.vndkApex {
- if ab.IsNativeBridgeSupported() {
- mctx.PropertyErrorf("native_bridge_supported", "%q doesn't support native bridge binary.", mctx.ModuleType())
- }
-
- vndkVersion := ab.vndkVersion()
- if vndkVersion != "" {
- apiLevel, err := android.ApiLevelFromUser(mctx, vndkVersion)
- if err != nil {
- mctx.PropertyErrorf("vndk_version", "%s", err.Error())
- return
- }
-
- targets := mctx.MultiTargets()
- if len(targets) > 0 && apiLevel.LessThan(cc.MinApiForArch(mctx, targets[0].Arch.ArchType)) {
- // Disable VNDK APEXes for VNDK versions less than the minimum supported API
- // level for the primary architecture.
- ab.Disable()
- }
- }
- }
-}
-
func apexVndkDepsMutator(mctx android.BottomUpMutatorContext) {
if m, ok := mctx.Module().(*cc.Module); ok && cc.IsForVndkApex(mctx, m) {
vndkVersion := m.VndkVersion()
@@ -90,11 +67,41 @@
vndkApexName := "com.android.vndk." + vndkVersion
if mctx.OtherModuleExists(vndkApexName) {
- mctx.AddReverseDependency(mctx.Module(), sharedLibTag, vndkApexName)
+ // Reverse dependencies must exactly specify the variant they want, starting from the
+ // current module's variant. But unlike cc modules, the vndk apex doesn't have
+ // arch/image/link variations, so we explicitly remove them here.
+ mctx.AddReverseVariationDependency([]blueprint.Variation{
+ {Mutator: "arch", Variation: "common"},
+ {Mutator: "image", Variation: ""},
+ {Mutator: "link", Variation: ""},
+ }, sharedLibTag, vndkApexName)
}
} else if a, ok := mctx.Module().(*apexBundle); ok && a.vndkApex {
- vndkVersion := proptools.StringDefault(a.vndkProperties.Vndk_version, "current")
- mctx.AddDependency(mctx.Module(), prebuiltTag, cc.VndkLibrariesTxtModules(vndkVersion, mctx)...)
+ if a.IsNativeBridgeSupported() {
+ mctx.PropertyErrorf("native_bridge_supported", "%q doesn't support native bridge binary.", mctx.ModuleType())
+ }
+
+ vndkVersion := a.vndkVersion()
+ if vndkVersion != "" {
+ apiLevel, err := android.ApiLevelFromUser(mctx, vndkVersion)
+ if err != nil {
+ mctx.PropertyErrorf("vndk_version", "%s", err.Error())
+ return
+ }
+
+ targets := mctx.MultiTargets()
+ if len(targets) > 0 && apiLevel.LessThan(cc.MinApiForArch(mctx, targets[0].Arch.ArchType)) {
+ // Disable VNDK APEXes for VNDK versions less than the minimum supported API
+ // level for the primary architecture.
+ a.Disable()
+ } else {
+ mctx.AddVariationDependencies(
+ mctx.Config().AndroidFirstDeviceTarget.Variations(),
+ prebuiltTag,
+ cc.VndkLibrariesTxtModules(vndkVersion, mctx)...,
+ )
+ }
+ }
}
}
diff --git a/bazel/Android.bp b/bazel/Android.bp
deleted file mode 100644
index f8273a8..0000000
--- a/bazel/Android.bp
+++ /dev/null
@@ -1,22 +0,0 @@
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-bootstrap_go_package {
- name: "soong-bazel",
- pkgPath: "android/soong/bazel",
- srcs: [
- "configurability.go",
- "properties.go",
- "testing.go",
- ],
- testSrcs: [
- "properties_test.go",
- ],
- pluginFor: [
- "soong_build",
- ],
- deps: [
- "blueprint",
- ],
-}
diff --git a/bazel/configurability.go b/bazel/configurability.go
deleted file mode 100644
index 2c9a536..0000000
--- a/bazel/configurability.go
+++ /dev/null
@@ -1,393 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bazel
-
-import (
- "fmt"
- "math"
- "sort"
- "strings"
-)
-
-const (
- // ArchType names in arch.go
- archArm = "arm"
- archArm64 = "arm64"
- archRiscv64 = "riscv64"
- archX86 = "x86"
- archX86_64 = "x86_64"
-
- // OsType names in arch.go
- OsAndroid = "android"
- OsDarwin = "darwin"
- OsLinux = "linux_glibc"
- osLinuxMusl = "linux_musl"
- osLinuxBionic = "linux_bionic"
- OsWindows = "windows"
-
- // Targets in arch.go
- osArchAndroidArm = "android_arm"
- OsArchAndroidArm64 = "android_arm64"
- osArchAndroidRiscv64 = "android_riscv64"
- osArchAndroidX86 = "android_x86"
- osArchAndroidX86_64 = "android_x86_64"
- osArchDarwinArm64 = "darwin_arm64"
- osArchDarwinX86_64 = "darwin_x86_64"
- osArchLinuxX86 = "linux_glibc_x86"
- osArchLinuxX86_64 = "linux_glibc_x86_64"
- osArchLinuxMuslArm = "linux_musl_arm"
- osArchLinuxMuslArm64 = "linux_musl_arm64"
- osArchLinuxMuslX86 = "linux_musl_x86"
- osArchLinuxMuslX86_64 = "linux_musl_x86_64"
- osArchLinuxBionicArm64 = "linux_bionic_arm64"
- osArchLinuxBionicX86_64 = "linux_bionic_x86_64"
- osArchWindowsX86 = "windows_x86"
- osArchWindowsX86_64 = "windows_x86_64"
-
- // This is the string representation of the default condition wherever a
- // configurable attribute is used in a select statement, i.e.
- // //conditions:default for Bazel.
- //
- // This is consistently named "conditions_default" to mirror the Soong
- // config variable default key in an Android.bp file, although there's no
- // integration with Soong config variables (yet).
- ConditionsDefaultConfigKey = "conditions_default"
-
- ConditionsDefaultSelectKey = "//conditions:default"
-
- productVariableBazelPackage = "//build/bazel/product_config/config_settings"
-
- AndroidAndInApex = "android-in_apex"
- AndroidPlatform = "system"
- Unbundled_app = "unbundled_app"
-
- InApex = "in_apex"
- NonApex = "non_apex"
-
- ErrorproneDisabled = "errorprone_disabled"
- // TODO: b/294868620 - Remove when completing the bug
- SanitizersEnabled = "sanitizers_enabled"
-)
-
-func PowerSetWithoutEmptySet[T any](items []T) [][]T {
- resultSize := int(math.Pow(2, float64(len(items))))
- powerSet := make([][]T, 0, resultSize-1)
- for i := 1; i < resultSize; i++ {
- combination := make([]T, 0)
- for j := 0; j < len(items); j++ {
- if (i>>j)%2 == 1 {
- combination = append(combination, items[j])
- }
- }
- powerSet = append(powerSet, combination)
- }
- return powerSet
-}
-
-func createPlatformArchMap() map[string]string {
- // Copy of archFeatures from android/arch_list.go because the bazel
- // package can't access the android package
- archFeatures := map[string][]string{
- "arm": {
- "neon",
- },
- "arm64": {
- "dotprod",
- },
- "riscv64": {},
- "x86": {
- "ssse3",
- "sse4",
- "sse4_1",
- "sse4_2",
- "aes_ni",
- "avx",
- "avx2",
- "avx512",
- "popcnt",
- "movbe",
- },
- "x86_64": {
- "ssse3",
- "sse4",
- "sse4_1",
- "sse4_2",
- "aes_ni",
- "avx",
- "avx2",
- "avx512",
- "popcnt",
- },
- }
- result := make(map[string]string)
- for arch, allFeatures := range archFeatures {
- result[arch] = "//build/bazel_common_rules/platforms/arch:" + arch
- // Sometimes we want to select on multiple features being active, so
- // add the power set of all possible features to the map. More details
- // in android.ModuleBase.GetArchVariantProperties
- for _, features := range PowerSetWithoutEmptySet(allFeatures) {
- sort.Strings(features)
- archFeaturesName := arch + "-" + strings.Join(features, "-")
- result[archFeaturesName] = "//build/bazel/platforms/arch/variants:" + archFeaturesName
- }
- }
- result[ConditionsDefaultConfigKey] = ConditionsDefaultSelectKey
- return result
-}
-
-var (
- // These are the list of OSes and architectures with a Bazel config_setting
- // and constraint value equivalent. These exist in arch.go, but the android
- // package depends on the bazel package, so a cyclic dependency prevents
- // using those variables here.
-
- // A map of architectures to the Bazel label of the constraint_value
- // for the @platforms//cpu:cpu constraint_setting
- platformArchMap = createPlatformArchMap()
-
- // A map of target operating systems to the Bazel label of the
- // constraint_value for the @platforms//os:os constraint_setting
- platformOsMap = map[string]string{
- OsAndroid: "//build/bazel_common_rules/platforms/os:android",
- OsDarwin: "//build/bazel_common_rules/platforms/os:darwin",
- OsLinux: "//build/bazel_common_rules/platforms/os:linux_glibc",
- osLinuxMusl: "//build/bazel_common_rules/platforms/os:linux_musl",
- osLinuxBionic: "//build/bazel_common_rules/platforms/os:linux_bionic",
- OsWindows: "//build/bazel_common_rules/platforms/os:windows",
- ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
- }
-
- platformOsArchMap = map[string]string{
- osArchAndroidArm: "//build/bazel_common_rules/platforms/os_arch:android_arm",
- OsArchAndroidArm64: "//build/bazel_common_rules/platforms/os_arch:android_arm64",
- osArchAndroidRiscv64: "//build/bazel_common_rules/platforms/os_arch:android_riscv64",
- osArchAndroidX86: "//build/bazel_common_rules/platforms/os_arch:android_x86",
- osArchAndroidX86_64: "//build/bazel_common_rules/platforms/os_arch:android_x86_64",
- osArchDarwinArm64: "//build/bazel_common_rules/platforms/os_arch:darwin_arm64",
- osArchDarwinX86_64: "//build/bazel_common_rules/platforms/os_arch:darwin_x86_64",
- osArchLinuxX86: "//build/bazel_common_rules/platforms/os_arch:linux_glibc_x86",
- osArchLinuxX86_64: "//build/bazel_common_rules/platforms/os_arch:linux_glibc_x86_64",
- osArchLinuxMuslArm: "//build/bazel_common_rules/platforms/os_arch:linux_musl_arm",
- osArchLinuxMuslArm64: "//build/bazel_common_rules/platforms/os_arch:linux_musl_arm64",
- osArchLinuxMuslX86: "//build/bazel_common_rules/platforms/os_arch:linux_musl_x86",
- osArchLinuxMuslX86_64: "//build/bazel_common_rules/platforms/os_arch:linux_musl_x86_64",
- osArchLinuxBionicArm64: "//build/bazel_common_rules/platforms/os_arch:linux_bionic_arm64",
- osArchLinuxBionicX86_64: "//build/bazel_common_rules/platforms/os_arch:linux_bionic_x86_64",
- osArchWindowsX86: "//build/bazel_common_rules/platforms/os_arch:windows_x86",
- osArchWindowsX86_64: "//build/bazel_common_rules/platforms/os_arch:windows_x86_64",
- ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
- }
-
- // Map where keys are OsType names, and values are slices containing the archs
- // that that OS supports.
- // These definitions copied from arch.go.
- // TODO(cparsons): Source from arch.go; this task is nontrivial, as it currently results
- // in a cyclic dependency.
- osToArchMap = map[string][]string{
- OsAndroid: {archArm, archArm64, archRiscv64, archX86, archX86_64},
- OsLinux: {archX86, archX86_64},
- osLinuxMusl: {archX86, archX86_64},
- OsDarwin: {archArm64, archX86_64},
- osLinuxBionic: {archArm64, archX86_64},
- // TODO(cparsons): According to arch.go, this should contain archArm, archArm64, as well.
- OsWindows: {archX86, archX86_64},
- }
-
- osAndInApexMap = map[string]string{
- AndroidAndInApex: "//build/bazel/rules/apex:android-in_apex",
- AndroidPlatform: "//build/bazel/rules/apex:system",
- Unbundled_app: "//build/bazel/rules/apex:unbundled_app",
- OsDarwin: "//build/bazel_common_rules/platforms/os:darwin",
- OsLinux: "//build/bazel_common_rules/platforms/os:linux_glibc",
- osLinuxMusl: "//build/bazel_common_rules/platforms/os:linux_musl",
- osLinuxBionic: "//build/bazel_common_rules/platforms/os:linux_bionic",
- OsWindows: "//build/bazel_common_rules/platforms/os:windows",
- ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
- }
-
- inApexMap = map[string]string{
- InApex: "//build/bazel/rules/apex:in_apex",
- NonApex: "//build/bazel/rules/apex:non_apex",
- ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
- }
-
- errorProneMap = map[string]string{
- ErrorproneDisabled: "//build/bazel/rules/java/errorprone:errorprone_globally_disabled",
- ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
- }
-
- // TODO: b/294868620 - Remove when completing the bug
- sanitizersEnabledMap = map[string]string{
- SanitizersEnabled: "//build/bazel/rules/cc:sanitizers_enabled",
- ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
- }
-)
-
-// basic configuration types
-type configurationType int
-
-const (
- noConfig configurationType = iota
- arch
- os
- osArch
- productVariables
- osAndInApex
- inApex
- errorProneDisabled
- // TODO: b/294868620 - Remove when completing the bug
- sanitizersEnabled
-)
-
-func osArchString(os string, arch string) string {
- return fmt.Sprintf("%s_%s", os, arch)
-}
-
-func (ct configurationType) String() string {
- return map[configurationType]string{
- noConfig: "no_config",
- arch: "arch",
- os: "os",
- osArch: "arch_os",
- productVariables: "product_variables",
- osAndInApex: "os_in_apex",
- inApex: "in_apex",
- errorProneDisabled: "errorprone_disabled",
- // TODO: b/294868620 - Remove when completing the bug
- sanitizersEnabled: "sanitizers_enabled",
- }[ct]
-}
-
-func (ct configurationType) validateConfig(config string) {
- switch ct {
- case noConfig:
- if config != "" {
- panic(fmt.Errorf("Cannot specify config with %s, but got %s", ct, config))
- }
- case arch:
- if _, ok := platformArchMap[config]; !ok {
- panic(fmt.Errorf("Unknown arch: %s", config))
- }
- case os:
- if _, ok := platformOsMap[config]; !ok {
- panic(fmt.Errorf("Unknown os: %s", config))
- }
- case osArch:
- if _, ok := platformOsArchMap[config]; !ok {
- panic(fmt.Errorf("Unknown os+arch: %s", config))
- }
- case productVariables:
- // do nothing
- case osAndInApex:
- // do nothing
- // this axis can contain additional per-apex keys
- case inApex:
- if _, ok := inApexMap[config]; !ok {
- panic(fmt.Errorf("Unknown in_apex config: %s", config))
- }
- case errorProneDisabled:
- if _, ok := errorProneMap[config]; !ok {
- panic(fmt.Errorf("Unknown errorprone config: %s", config))
- }
- // TODO: b/294868620 - Remove when completing the bug
- case sanitizersEnabled:
- if _, ok := sanitizersEnabledMap[config]; !ok {
- panic(fmt.Errorf("Unknown sanitizers_enabled config: %s", config))
- }
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct))
- }
-}
-
-// SelectKey returns the Bazel select key for a given configurationType and config string.
-func (ca ConfigurationAxis) SelectKey(config string) string {
- ca.validateConfig(config)
- switch ca.configurationType {
- case noConfig:
- panic(fmt.Errorf("SelectKey is unnecessary for noConfig ConfigurationType "))
- case arch:
- return platformArchMap[config]
- case os:
- return platformOsMap[config]
- case osArch:
- return platformOsArchMap[config]
- case productVariables:
- if config == ConditionsDefaultConfigKey {
- return ConditionsDefaultSelectKey
- }
- return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
- case osAndInApex:
- if ret, exists := osAndInApexMap[config]; exists {
- return ret
- }
- return config
- case inApex:
- return inApexMap[config]
- case errorProneDisabled:
- return errorProneMap[config]
- // TODO: b/294868620 - Remove when completing the bug
- case sanitizersEnabled:
- return sanitizersEnabledMap[config]
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType))
- }
-}
-
-var (
- // Indicating there is no configuration axis
- NoConfigAxis = ConfigurationAxis{configurationType: noConfig}
- // An axis for architecture-specific configurations
- ArchConfigurationAxis = ConfigurationAxis{configurationType: arch}
- // An axis for os-specific configurations
- OsConfigurationAxis = ConfigurationAxis{configurationType: os}
- // An axis for arch+os-specific configurations
- OsArchConfigurationAxis = ConfigurationAxis{configurationType: osArch}
- // An axis for os+in_apex-specific configurations
- OsAndInApexAxis = ConfigurationAxis{configurationType: osAndInApex}
- // An axis for in_apex-specific configurations
- InApexAxis = ConfigurationAxis{configurationType: inApex}
-
- ErrorProneAxis = ConfigurationAxis{configurationType: errorProneDisabled}
-
- // TODO: b/294868620 - Remove when completing the bug
- SanitizersEnabledAxis = ConfigurationAxis{configurationType: sanitizersEnabled}
-)
-
-// ProductVariableConfigurationAxis returns an axis for the given product variable
-func ProductVariableConfigurationAxis(archVariant bool, variable string) ConfigurationAxis {
- return ConfigurationAxis{
- configurationType: productVariables,
- subType: variable,
- archVariant: archVariant,
- }
-}
-
-// ConfigurationAxis is an independent axis for configuration, there should be no overlap between
-// elements within an axis.
-type ConfigurationAxis struct {
- configurationType
- // some configuration types (e.g. productVariables) have multiple independent axes, subType helps
- // distinguish between them without needing to list all 17 product variables.
- subType string
-
- archVariant bool
-}
-
-func (ca *ConfigurationAxis) less(other ConfigurationAxis) bool {
- if ca.configurationType == other.configurationType {
- return ca.subType < other.subType
- }
- return ca.configurationType < other.configurationType
-}
diff --git a/bazel/properties.go b/bazel/properties.go
deleted file mode 100644
index 9c63bc0..0000000
--- a/bazel/properties.go
+++ /dev/null
@@ -1,1467 +0,0 @@
-// Copyright 2020 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 bazel
-
-import (
- "fmt"
- "path/filepath"
- "reflect"
- "regexp"
- "sort"
- "strings"
-
- "github.com/google/blueprint"
-)
-
-// BazelTargetModuleProperties contain properties and metadata used for
-// Blueprint to BUILD file conversion.
-type BazelTargetModuleProperties struct {
- // The Bazel rule class for this target.
- Rule_class string `blueprint:"mutated"`
-
- // The target label for the bzl file containing the definition of the rule class.
- Bzl_load_location string `blueprint:"mutated"`
-}
-
-var productVariableSubstitutionPattern = regexp.MustCompile("%(d|s)")
-
-// Label is used to represent a Bazel compatible Label. Also stores the original
-// bp text to support string replacement.
-type Label struct {
- // The string representation of a Bazel target label. This can be a relative
- // or fully qualified label. These labels are used for generating BUILD
- // files with bp2build.
- Label string
-
- // The original Soong/Blueprint module name that the label was derived from.
- // This is used for replacing references to the original name with the new
- // label, for example in genrule cmds.
- //
- // While there is a reversible 1:1 mapping from the module name to Bazel
- // label with bp2build that could make computing the original module name
- // from the label automatic, it is not the case for handcrafted targets,
- // where modules can have a custom label mapping through the { bazel_module:
- // { label: <label> } } property.
- //
- // With handcrafted labels, those modules don't go through bp2build
- // conversion, but relies on handcrafted targets in the source tree.
- OriginalModuleName string
-}
-
-// LabelList is used to represent a list of Bazel labels.
-type LabelList struct {
- Includes []Label
- Excludes []Label
-}
-
-// MakeLabelList creates a LabelList from a list Label
-func MakeLabelList(labels []Label) LabelList {
- return LabelList{
- Includes: labels,
- Excludes: nil,
- }
-}
-
-func SortedConfigurationAxes[T any](m map[ConfigurationAxis]T) []ConfigurationAxis {
- keys := make([]ConfigurationAxis, 0, len(m))
- for k := range m {
- keys = append(keys, k)
- }
-
- sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
- return keys
-}
-
-// MakeLabelListFromTargetNames creates a LabelList from unqualified target names
-// This is a utiltity function for bp2build converters of Soong modules that have 1:many generated targets
-func MakeLabelListFromTargetNames(targetNames []string) LabelList {
- labels := []Label{}
- for _, name := range targetNames {
- label := Label{Label: ":" + name}
- labels = append(labels, label)
- }
- return MakeLabelList(labels)
-}
-
-func (ll *LabelList) Equals(other LabelList) bool {
- if len(ll.Includes) != len(other.Includes) || len(ll.Excludes) != len(other.Excludes) {
- return false
- }
- for i, _ := range ll.Includes {
- if ll.Includes[i] != other.Includes[i] {
- return false
- }
- }
- for i, _ := range ll.Excludes {
- if ll.Excludes[i] != other.Excludes[i] {
- return false
- }
- }
- return true
-}
-
-func (ll *LabelList) IsNil() bool {
- return ll.Includes == nil && ll.Excludes == nil
-}
-
-func (ll *LabelList) IsEmpty() bool {
- return len(ll.Includes) == 0 && len(ll.Excludes) == 0
-}
-
-func (ll *LabelList) deepCopy() LabelList {
- return LabelList{
- Includes: ll.Includes[:],
- Excludes: ll.Excludes[:],
- }
-}
-
-// uniqueParentDirectories returns a list of the unique parent directories for
-// all files in ll.Includes.
-func (ll *LabelList) uniqueParentDirectories() []string {
- dirMap := map[string]bool{}
- for _, label := range ll.Includes {
- dirMap[filepath.Dir(label.Label)] = true
- }
- dirs := []string{}
- for dir := range dirMap {
- dirs = append(dirs, dir)
- }
- return dirs
-}
-
-// Add inserts the label Label at the end of the LabelList.Includes.
-func (ll *LabelList) Add(label *Label) {
- if label == nil {
- return
- }
- ll.Includes = append(ll.Includes, *label)
-}
-
-// AddExclude inserts the label Label at the end of the LabelList.Excludes.
-func (ll *LabelList) AddExclude(label *Label) {
- if label == nil {
- return
- }
- ll.Excludes = append(ll.Excludes, *label)
-}
-
-// Append appends the fields of other labelList to the corresponding fields of ll.
-func (ll *LabelList) Append(other LabelList) {
- if len(ll.Includes) > 0 || len(other.Includes) > 0 {
- ll.Includes = append(ll.Includes, other.Includes...)
- }
- if len(ll.Excludes) > 0 || len(other.Excludes) > 0 {
- ll.Excludes = append(ll.Excludes, other.Excludes...)
- }
-}
-
-// Partition splits a LabelList into two LabelLists depending on the return value
-// of the predicate.
-// This function preserves the Includes and Excludes, but it does not provide
-// that information to the partition function.
-func (ll *LabelList) Partition(predicate func(label Label) bool) (LabelList, LabelList) {
- predicated := LabelList{}
- unpredicated := LabelList{}
- for _, include := range ll.Includes {
- if predicate(include) {
- predicated.Add(&include)
- } else {
- unpredicated.Add(&include)
- }
- }
- for _, exclude := range ll.Excludes {
- if predicate(exclude) {
- predicated.AddExclude(&exclude)
- } else {
- unpredicated.AddExclude(&exclude)
- }
- }
- return predicated, unpredicated
-}
-
-// UniqueSortedBazelLabels takes a []Label and deduplicates the labels, and returns
-// the slice in a sorted order.
-func UniqueSortedBazelLabels(originalLabels []Label) []Label {
- uniqueLabels := FirstUniqueBazelLabels(originalLabels)
- sort.SliceStable(uniqueLabels, func(i, j int) bool {
- return uniqueLabels[i].Label < uniqueLabels[j].Label
- })
- return uniqueLabels
-}
-
-func FirstUniqueBazelLabels(originalLabels []Label) []Label {
- var labels []Label
- found := make(map[string]bool, len(originalLabels))
- for _, l := range originalLabels {
- if _, ok := found[l.Label]; ok {
- continue
- }
- labels = append(labels, l)
- found[l.Label] = true
- }
- return labels
-}
-
-func FirstUniqueBazelLabelList(originalLabelList LabelList) LabelList {
- var uniqueLabelList LabelList
- uniqueLabelList.Includes = FirstUniqueBazelLabels(originalLabelList.Includes)
- uniqueLabelList.Excludes = FirstUniqueBazelLabels(originalLabelList.Excludes)
- return uniqueLabelList
-}
-
-func UniqueSortedBazelLabelList(originalLabelList LabelList) LabelList {
- var uniqueLabelList LabelList
- uniqueLabelList.Includes = UniqueSortedBazelLabels(originalLabelList.Includes)
- uniqueLabelList.Excludes = UniqueSortedBazelLabels(originalLabelList.Excludes)
- return uniqueLabelList
-}
-
-// Subtract needle from haystack
-func SubtractStrings(haystack []string, needle []string) []string {
- // This is really a set
- needleMap := make(map[string]bool)
- for _, s := range needle {
- needleMap[s] = true
- }
-
- var strings []string
- for _, s := range haystack {
- if exclude := needleMap[s]; !exclude {
- strings = append(strings, s)
- }
- }
-
- return strings
-}
-
-// Subtract needle from haystack
-func SubtractBazelLabels(haystack []Label, needle []Label) []Label {
- // This is really a set
- needleMap := make(map[Label]bool)
- for _, s := range needle {
- needleMap[s] = true
- }
-
- var labels []Label
- for _, label := range haystack {
- if exclude := needleMap[label]; !exclude {
- labels = append(labels, label)
- }
- }
-
- return labels
-}
-
-// Appends two LabelLists, returning the combined list.
-func AppendBazelLabelLists(a LabelList, b LabelList) LabelList {
- var result LabelList
- result.Includes = append(a.Includes, b.Includes...)
- result.Excludes = append(a.Excludes, b.Excludes...)
- return result
-}
-
-// Subtract needle from haystack
-func SubtractBazelLabelList(haystack LabelList, needle LabelList) LabelList {
- var result LabelList
- result.Includes = SubtractBazelLabels(haystack.Includes, needle.Includes)
- // NOTE: Excludes are intentionally not subtracted
- result.Excludes = haystack.Excludes
- return result
-}
-
-// FirstUniqueBazelLabelListAttribute takes a LabelListAttribute and makes the LabelList for
-// each axis/configuration by keeping the first instance of a Label and omitting all subsequent
-// repetitions.
-func FirstUniqueBazelLabelListAttribute(attr LabelListAttribute) LabelListAttribute {
- var result LabelListAttribute
- result.Value = FirstUniqueBazelLabelList(attr.Value)
- if attr.HasConfigurableValues() {
- result.ConfigurableValues = make(configurableLabelLists)
- }
- for axis, configToLabels := range attr.ConfigurableValues {
- for c, l := range configToLabels {
- result.SetSelectValue(axis, c, FirstUniqueBazelLabelList(l))
- }
- }
-
- return result
-}
-
-// SubtractBazelLabelListAttribute subtract needle from haystack for LabelList in each
-// axis/configuration.
-func SubtractBazelLabelListAttribute(haystack LabelListAttribute, needle LabelListAttribute) LabelListAttribute {
- var result LabelListAttribute
- result.Value = SubtractBazelLabelList(haystack.Value, needle.Value)
- if haystack.HasConfigurableValues() {
- result.ConfigurableValues = make(configurableLabelLists)
- }
- for axis, configToLabels := range haystack.ConfigurableValues {
- for haystackConfig, haystackLabels := range configToLabels {
- result.SetSelectValue(axis, haystackConfig, SubtractBazelLabelList(haystackLabels, needle.SelectValue(axis, haystackConfig)))
- }
- }
-
- return result
-}
-
-type Attribute interface {
- HasConfigurableValues() bool
-}
-
-type labelSelectValues map[string]*Label
-
-type configurableLabels map[ConfigurationAxis]labelSelectValues
-
-func (cl configurableLabels) setValueForAxis(axis ConfigurationAxis, config string, value *Label) {
- if cl[axis] == nil {
- cl[axis] = make(labelSelectValues)
- }
- cl[axis][config] = value
-}
-
-// Represents an attribute whose value is a single label
-type LabelAttribute struct {
- Value *Label
-
- ConfigurableValues configurableLabels
-}
-
-func (la *LabelAttribute) axisTypes() map[configurationType]bool {
- types := map[configurationType]bool{}
- for k := range la.ConfigurableValues {
- if len(la.ConfigurableValues[k]) > 0 {
- types[k.configurationType] = true
- }
- }
- return types
-}
-
-// Collapse reduces the configurable axes of the label attribute to a single axis.
-// This is necessary for final writing to bp2build, as a configurable label
-// attribute can only be comprised by a single select.
-func (la *LabelAttribute) Collapse() error {
- axisTypes := la.axisTypes()
- _, containsOs := axisTypes[os]
- _, containsArch := axisTypes[arch]
- _, containsOsArch := axisTypes[osArch]
- _, containsProductVariables := axisTypes[productVariables]
- if containsProductVariables {
- if containsOs || containsArch || containsOsArch {
- if containsArch {
- allProductVariablesAreArchVariant := true
- for k := range la.ConfigurableValues {
- if k.configurationType == productVariables && !k.archVariant {
- allProductVariablesAreArchVariant = false
- }
- }
- if !allProductVariablesAreArchVariant {
- return fmt.Errorf("label attribute could not be collapsed as it has two or more unrelated axes")
- }
- } else {
- return fmt.Errorf("label attribute could not be collapsed as it has two or more unrelated axes")
- }
- }
- }
- if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
- // If a bool attribute has both os and arch configuration axes, the only
- // way to successfully union their values is to increase the granularity
- // of the configuration criteria to os_arch.
- for osType, supportedArchs := range osToArchMap {
- for _, supportedArch := range supportedArchs {
- osArch := osArchString(osType, supportedArch)
- if archOsVal := la.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
- // Do nothing, as the arch_os is explicitly defined already.
- } else {
- archVal := la.SelectValue(ArchConfigurationAxis, supportedArch)
- osVal := la.SelectValue(OsConfigurationAxis, osType)
- if osVal != nil && archVal != nil {
- // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
- // runs after os mutator.
- la.SetSelectValue(OsArchConfigurationAxis, osArch, *archVal)
- } else if osVal != nil && archVal == nil {
- la.SetSelectValue(OsArchConfigurationAxis, osArch, *osVal)
- } else if osVal == nil && archVal != nil {
- la.SetSelectValue(OsArchConfigurationAxis, osArch, *archVal)
- }
- }
- }
- }
- // All os_arch values are now set. Clear os and arch axes.
- delete(la.ConfigurableValues, ArchConfigurationAxis)
- delete(la.ConfigurableValues, OsConfigurationAxis)
- }
- return nil
-}
-
-// HasConfigurableValues returns whether there are configurable values set for this label.
-func (la LabelAttribute) HasConfigurableValues() bool {
- for _, selectValues := range la.ConfigurableValues {
- if len(selectValues) > 0 {
- return true
- }
- }
- return false
-}
-
-// SetValue sets the base, non-configured value for the Label
-func (la *LabelAttribute) SetValue(value Label) {
- la.SetSelectValue(NoConfigAxis, "", value)
-}
-
-// SetSelectValue set a value for a bazel select for the given axis, config and value.
-func (la *LabelAttribute) SetSelectValue(axis ConfigurationAxis, config string, value Label) {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- la.Value = &value
- case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled:
- if la.ConfigurableValues == nil {
- la.ConfigurableValues = make(configurableLabels)
- }
- la.ConfigurableValues.setValueForAxis(axis, config, &value)
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SelectValue gets a value for a bazel select for the given axis and config.
-func (la *LabelAttribute) SelectValue(axis ConfigurationAxis, config string) *Label {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- return la.Value
- case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled:
- return la.ConfigurableValues[axis][config]
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
-func (la *LabelAttribute) SortedConfigurationAxes() []ConfigurationAxis {
- return SortedConfigurationAxes(la.ConfigurableValues)
-}
-
-// MakeLabelAttribute turns a string into a LabelAttribute
-func MakeLabelAttribute(label string) *LabelAttribute {
- return &LabelAttribute{
- Value: &Label{
- Label: label,
- },
- }
-}
-
-type configToBools map[string]bool
-
-func (ctb configToBools) setValue(config string, value *bool) {
- if value == nil {
- if _, ok := ctb[config]; ok {
- delete(ctb, config)
- }
- return
- }
- ctb[config] = *value
-}
-
-type configurableBools map[ConfigurationAxis]configToBools
-
-func (cb configurableBools) setValueForAxis(axis ConfigurationAxis, config string, value *bool) {
- if cb[axis] == nil {
- cb[axis] = make(configToBools)
- }
- cb[axis].setValue(config, value)
-}
-
-// BoolAttribute represents an attribute whose value is a single bool but may be configurable..
-type BoolAttribute struct {
- Value *bool
-
- ConfigurableValues configurableBools
-}
-
-// HasConfigurableValues returns whether there are configurable values for this attribute.
-func (ba BoolAttribute) HasConfigurableValues() bool {
- for _, cfgToBools := range ba.ConfigurableValues {
- if len(cfgToBools) > 0 {
- return true
- }
- }
- return false
-}
-
-// SetValue sets value for the no config axis
-func (ba *BoolAttribute) SetValue(value *bool) {
- ba.SetSelectValue(NoConfigAxis, "", value)
-}
-
-// SetSelectValue sets value for the given axis/config.
-func (ba *BoolAttribute) SetSelectValue(axis ConfigurationAxis, config string, value *bool) {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- ba.Value = value
- case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled:
- if ba.ConfigurableValues == nil {
- ba.ConfigurableValues = make(configurableBools)
- }
- ba.ConfigurableValues.setValueForAxis(axis, config, value)
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// ToLabelListAttribute creates and returns a LabelListAttribute from this
-// bool attribute, where each bool in this attribute corresponds to a
-// label list value in the resultant attribute.
-func (ba *BoolAttribute) ToLabelListAttribute(falseVal LabelList, trueVal LabelList) (LabelListAttribute, error) {
- getLabelList := func(boolPtr *bool) LabelList {
- if boolPtr == nil {
- return LabelList{nil, nil}
- } else if *boolPtr {
- return trueVal
- } else {
- return falseVal
- }
- }
-
- mainVal := getLabelList(ba.Value)
- if !ba.HasConfigurableValues() {
- return MakeLabelListAttribute(mainVal), nil
- }
-
- result := LabelListAttribute{}
- if err := ba.Collapse(); err != nil {
- return result, err
- }
-
- for axis, configToBools := range ba.ConfigurableValues {
- if len(configToBools) < 1 {
- continue
- }
- for config, boolPtr := range configToBools {
- val := getLabelList(&boolPtr)
- if !val.Equals(mainVal) {
- result.SetSelectValue(axis, config, val)
- }
- }
- result.SetSelectValue(axis, ConditionsDefaultConfigKey, mainVal)
- }
-
- return result, nil
-}
-
-// ToStringListAttribute creates a StringListAttribute from this BoolAttribute,
-// where each bool corresponds to a string list value generated by the provided
-// function.
-// TODO(b/271425661): Generalize this
-func (ba *BoolAttribute) ToStringListAttribute(valueFunc func(boolPtr *bool, axis ConfigurationAxis, config string) []string) (StringListAttribute, error) {
- mainVal := valueFunc(ba.Value, NoConfigAxis, "")
- if !ba.HasConfigurableValues() {
- return MakeStringListAttribute(mainVal), nil
- }
-
- result := StringListAttribute{}
- if err := ba.Collapse(); err != nil {
- return result, err
- }
-
- for axis, configToBools := range ba.ConfigurableValues {
- if len(configToBools) < 1 {
- continue
- }
- for config, boolPtr := range configToBools {
- val := valueFunc(&boolPtr, axis, config)
- if !reflect.DeepEqual(val, mainVal) {
- result.SetSelectValue(axis, config, val)
- }
- }
- result.SetSelectValue(axis, ConditionsDefaultConfigKey, mainVal)
- }
-
- return result, nil
-}
-
-// Collapse reduces the configurable axes of the boolean attribute to a single axis.
-// This is necessary for final writing to bp2build, as a configurable boolean
-// attribute can only be comprised by a single select.
-func (ba *BoolAttribute) Collapse() error {
- axisTypes := ba.axisTypes()
- _, containsOs := axisTypes[os]
- _, containsArch := axisTypes[arch]
- _, containsOsArch := axisTypes[osArch]
- _, containsProductVariables := axisTypes[productVariables]
- if containsProductVariables {
- if containsOs || containsArch || containsOsArch {
- return fmt.Errorf("boolean attribute could not be collapsed as it has two or more unrelated axes")
- }
- }
- if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
- // If a bool attribute has both os and arch configuration axes, the only
- // way to successfully union their values is to increase the granularity
- // of the configuration criteria to os_arch.
- for osType, supportedArchs := range osToArchMap {
- for _, supportedArch := range supportedArchs {
- osArch := osArchString(osType, supportedArch)
- if archOsVal := ba.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
- // Do nothing, as the arch_os is explicitly defined already.
- } else {
- archVal := ba.SelectValue(ArchConfigurationAxis, supportedArch)
- osVal := ba.SelectValue(OsConfigurationAxis, osType)
- if osVal != nil && archVal != nil {
- // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
- // runs after os mutator.
- ba.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
- } else if osVal != nil && archVal == nil {
- ba.SetSelectValue(OsArchConfigurationAxis, osArch, osVal)
- } else if osVal == nil && archVal != nil {
- ba.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
- }
- }
- }
- }
- // All os_arch values are now set. Clear os and arch axes.
- delete(ba.ConfigurableValues, ArchConfigurationAxis)
- delete(ba.ConfigurableValues, OsConfigurationAxis)
- // Verify post-condition; this should never fail, provided no additional
- // axes are introduced.
- if len(ba.ConfigurableValues) > 1 {
- panic(fmt.Errorf("error in collapsing attribute: %#v", ba))
- }
- }
- return nil
-}
-
-func (ba *BoolAttribute) axisTypes() map[configurationType]bool {
- types := map[configurationType]bool{}
- for k := range ba.ConfigurableValues {
- if len(ba.ConfigurableValues[k]) > 0 {
- types[k.configurationType] = true
- }
- }
- return types
-}
-
-// SelectValue gets the value for the given axis/config.
-func (ba BoolAttribute) SelectValue(axis ConfigurationAxis, config string) *bool {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- return ba.Value
- case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled:
- if v, ok := ba.ConfigurableValues[axis][config]; ok {
- return &v
- } else {
- return nil
- }
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
-func (ba *BoolAttribute) SortedConfigurationAxes() []ConfigurationAxis {
- return SortedConfigurationAxes(ba.ConfigurableValues)
-}
-
-// labelListSelectValues supports config-specific label_list typed Bazel attribute values.
-type labelListSelectValues map[string]LabelList
-
-func (ll labelListSelectValues) addSelects(label labelSelectValues) {
- for k, v := range label {
- if label == nil {
- continue
- }
- l := ll[k]
- (&l).Add(v)
- ll[k] = l
- }
-}
-
-func (ll labelListSelectValues) appendSelects(other labelListSelectValues, forceSpecifyEmptyList bool) {
- for k, v := range other {
- l := ll[k]
- if forceSpecifyEmptyList && l.IsNil() && !v.IsNil() {
- l.Includes = []Label{}
- }
- (&l).Append(v)
- ll[k] = l
- }
-}
-
-// HasConfigurableValues returns whether there are configurable values within this set of selects.
-func (ll labelListSelectValues) HasConfigurableValues() bool {
- for _, v := range ll {
- if v.Includes != nil {
- return true
- }
- }
- return false
-}
-
-// LabelListAttribute is used to represent a list of Bazel labels as an
-// attribute.
-type LabelListAttribute struct {
- // The non-configured attribute label list Value. Required.
- Value LabelList
-
- // The configured attribute label list Values. Optional
- // a map of independent configurability axes
- ConfigurableValues configurableLabelLists
-
- // If true, differentiate between "nil" and "empty" list. nil means that
- // this attribute should not be specified at all, and "empty" means that
- // the attribute should be explicitly specified as an empty list.
- // This mode facilitates use of attribute defaults: an empty list should
- // override the default.
- ForceSpecifyEmptyList bool
-
- // If true, signal the intent to the code generator to emit all select keys,
- // even if the Includes list for that key is empty. This mode facilitates
- // specific select statements where an empty list for a non-default select
- // key has a meaning.
- EmitEmptyList bool
-
- // If a property has struct tag "variant_prepend", this value should
- // be set to True, so that when bp2build generates BUILD.bazel, variant
- // properties(select ...) come before general properties.
- Prepend bool
-}
-
-type configurableLabelLists map[ConfigurationAxis]labelListSelectValues
-
-func (cll configurableLabelLists) setValueForAxis(axis ConfigurationAxis, config string, list LabelList) {
- if list.IsNil() {
- if _, ok := cll[axis][config]; ok {
- delete(cll[axis], config)
- }
- return
- }
- if cll[axis] == nil {
- cll[axis] = make(labelListSelectValues)
- }
-
- cll[axis][config] = list
-}
-
-func (cll configurableLabelLists) Append(other configurableLabelLists, forceSpecifyEmptyList bool) {
- for axis, otherSelects := range other {
- selects := cll[axis]
- if selects == nil {
- selects = make(labelListSelectValues, len(otherSelects))
- }
- selects.appendSelects(otherSelects, forceSpecifyEmptyList)
- cll[axis] = selects
- }
-}
-
-func (lla *LabelListAttribute) Clone() *LabelListAttribute {
- result := &LabelListAttribute{ForceSpecifyEmptyList: lla.ForceSpecifyEmptyList}
- return result.Append(*lla)
-}
-
-// MakeLabelListAttribute initializes a LabelListAttribute with the non-arch specific value.
-func MakeLabelListAttribute(value LabelList) LabelListAttribute {
- return LabelListAttribute{
- Value: value,
- ConfigurableValues: make(configurableLabelLists),
- }
-}
-
-// MakeSingleLabelListAttribute initializes a LabelListAttribute as a non-arch specific list with 1 element, the given Label.
-func MakeSingleLabelListAttribute(value Label) LabelListAttribute {
- return MakeLabelListAttribute(MakeLabelList([]Label{value}))
-}
-
-func (lla *LabelListAttribute) SetValue(list LabelList) {
- lla.SetSelectValue(NoConfigAxis, "", list)
-}
-
-// SetSelectValue set a value for a bazel select for the given axis, config and value.
-func (lla *LabelListAttribute) SetSelectValue(axis ConfigurationAxis, config string, list LabelList) {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- lla.Value = list
- case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled, sanitizersEnabled:
- if lla.ConfigurableValues == nil {
- lla.ConfigurableValues = make(configurableLabelLists)
- }
- lla.ConfigurableValues.setValueForAxis(axis, config, list)
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SelectValue gets a value for a bazel select for the given axis and config.
-func (lla *LabelListAttribute) SelectValue(axis ConfigurationAxis, config string) LabelList {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- return lla.Value
- case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled, sanitizersEnabled:
- return lla.ConfigurableValues[axis][config]
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
-func (lla *LabelListAttribute) SortedConfigurationAxes() []ConfigurationAxis {
- return SortedConfigurationAxes(lla.ConfigurableValues)
-}
-
-// Append all values, including os and arch specific ones, from another
-// LabelListAttribute to this LabelListAttribute. Returns this LabelListAttribute.
-func (lla *LabelListAttribute) Append(other LabelListAttribute) *LabelListAttribute {
- forceSpecifyEmptyList := lla.ForceSpecifyEmptyList || other.ForceSpecifyEmptyList
- if forceSpecifyEmptyList && lla.Value.IsNil() && !other.Value.IsNil() {
- lla.Value.Includes = []Label{}
- }
- lla.Value.Append(other.Value)
- if lla.ConfigurableValues == nil {
- lla.ConfigurableValues = make(configurableLabelLists)
- }
- lla.ConfigurableValues.Append(other.ConfigurableValues, forceSpecifyEmptyList)
- return lla
-}
-
-// Add inserts the labels for each axis of LabelAttribute at the end of corresponding axis's
-// LabelList within the LabelListAttribute
-func (lla *LabelListAttribute) Add(label *LabelAttribute) {
- if label == nil {
- return
- }
-
- lla.Value.Add(label.Value)
- if lla.ConfigurableValues == nil && label.ConfigurableValues != nil {
- lla.ConfigurableValues = make(configurableLabelLists)
- }
- for axis, _ := range label.ConfigurableValues {
- if _, exists := lla.ConfigurableValues[axis]; !exists {
- lla.ConfigurableValues[axis] = make(labelListSelectValues)
- }
- lla.ConfigurableValues[axis].addSelects(label.ConfigurableValues[axis])
- }
-}
-
-// HasConfigurableValues returns true if the attribute contains axis-specific label list values.
-func (lla LabelListAttribute) HasConfigurableValues() bool {
- for _, selectValues := range lla.ConfigurableValues {
- if len(selectValues) > 0 {
- return true
- }
- }
- return false
-}
-
-// HasAxisSpecificValues returns true if the attribute contains axis specific label list values from a given axis
-func (lla LabelListAttribute) HasAxisSpecificValues(axis ConfigurationAxis) bool {
- for _, values := range lla.ConfigurableValues[axis] {
- if !values.IsNil() {
- return true
- }
- }
- return false
-}
-
-// IsEmpty returns true if the attribute has no values under any configuration.
-func (lla LabelListAttribute) IsEmpty() bool {
- if len(lla.Value.Includes) > 0 {
- return false
- }
- for axis, _ := range lla.ConfigurableValues {
- if lla.ConfigurableValues[axis].HasConfigurableValues() {
- return false
- }
- }
- return true
-}
-
-// IsNil returns true if the attribute has not been set for any configuration.
-func (lla LabelListAttribute) IsNil() bool {
- if lla.Value.Includes != nil {
- return false
- }
- return !lla.HasConfigurableValues()
-}
-
-// Exclude for the given axis, config, removes Includes in labelList from Includes and appends them
-// to Excludes. This is to special case any excludes that are not specified in a bp file but need to
-// be removed, e.g. if they could cause duplicate element failures.
-func (lla *LabelListAttribute) Exclude(axis ConfigurationAxis, config string, labelList LabelList) {
- val := lla.SelectValue(axis, config)
- newList := SubtractBazelLabelList(val, labelList)
- newList.Excludes = append(newList.Excludes, labelList.Includes...)
- lla.SetSelectValue(axis, config, newList)
-}
-
-// ResolveExcludes handles excludes across the various axes, ensuring that items are removed from
-// the base value and included in default values as appropriate.
-func (lla *LabelListAttribute) ResolveExcludes() {
- // If there are OsAndInApexAxis, we need to use
- // * includes from the OS & in APEX Axis for non-Android configs for libraries that need to be
- // included in non-Android OSes
- // * excludes from the OS Axis for non-Android configs, to exclude libraries that should _not_
- // be included in the non-Android OSes
- if _, ok := lla.ConfigurableValues[OsAndInApexAxis]; ok {
- inApexLabels := lla.ConfigurableValues[OsAndInApexAxis][ConditionsDefaultConfigKey]
- for config, labels := range lla.ConfigurableValues[OsConfigurationAxis] {
- // OsAndroid has already handled its excludes.
- // We only need to copy the excludes from other arches, so if there are none, skip it.
- if config == OsAndroid || len(labels.Excludes) == 0 {
- continue
- }
- lla.ConfigurableValues[OsAndInApexAxis][config] = LabelList{
- Includes: inApexLabels.Includes,
- Excludes: labels.Excludes,
- }
- }
- }
-
- for axis, configToLabels := range lla.ConfigurableValues {
- baseLabels := lla.Value.deepCopy()
- for config, val := range configToLabels {
- // Exclude config-specific excludes from base value
- lla.Value = SubtractBazelLabelList(lla.Value, LabelList{Includes: val.Excludes})
-
- // add base values to config specific to add labels excluded by others in this axis
- // then remove all config-specific excludes
- allLabels := baseLabels.deepCopy()
- allLabels.Append(val)
- lla.ConfigurableValues[axis][config] = SubtractBazelLabelList(allLabels, LabelList{Includes: allLabels.Excludes})
- }
-
- // After going through all configs, delete the duplicates in the config
- // values that are already in the base Value.
- for config, val := range configToLabels {
- lla.ConfigurableValues[axis][config] = SubtractBazelLabelList(val, lla.Value)
- }
-
- // Now that the Value list is finalized for this axis, compare it with
- // the original list, and union the difference with the default
- // condition for the axis.
- difference := SubtractBazelLabelList(baseLabels, lla.Value)
- existingDefaults := lla.ConfigurableValues[axis][ConditionsDefaultConfigKey]
- existingDefaults.Append(difference)
- lla.ConfigurableValues[axis][ConditionsDefaultConfigKey] = FirstUniqueBazelLabelList(existingDefaults)
-
- // if everything ends up without includes, just delete the axis
- if !lla.ConfigurableValues[axis].HasConfigurableValues() {
- delete(lla.ConfigurableValues, axis)
- }
- }
-}
-
-// Partition splits a LabelListAttribute into two LabelListAttributes depending
-// on the return value of the predicate.
-// This function preserves the Includes and Excludes, but it does not provide
-// that information to the partition function.
-func (lla LabelListAttribute) Partition(predicate func(label Label) bool) (LabelListAttribute, LabelListAttribute) {
- predicated := LabelListAttribute{}
- unpredicated := LabelListAttribute{}
-
- valuePartitionTrue, valuePartitionFalse := lla.Value.Partition(predicate)
- predicated.SetValue(valuePartitionTrue)
- unpredicated.SetValue(valuePartitionFalse)
-
- for axis, selectValueLabelLists := range lla.ConfigurableValues {
- for config, labelList := range selectValueLabelLists {
- configPredicated, configUnpredicated := labelList.Partition(predicate)
- predicated.SetSelectValue(axis, config, configPredicated)
- unpredicated.SetSelectValue(axis, config, configUnpredicated)
- }
- }
-
- return predicated, unpredicated
-}
-
-// OtherModuleContext is a limited context that has methods with information about other modules.
-type OtherModuleContext interface {
- ModuleFromName(name string) (blueprint.Module, bool)
- OtherModuleType(m blueprint.Module) string
- OtherModuleName(m blueprint.Module) string
- OtherModuleDir(m blueprint.Module) string
- ModuleErrorf(fmt string, args ...interface{})
-}
-
-// LabelMapper is a function that takes a OtherModuleContext and returns a (potentially changed)
-// label and whether it was changed.
-type LabelMapper func(OtherModuleContext, Label) (string, bool)
-
-// LabelPartition contains descriptions of a partition for labels
-type LabelPartition struct {
- // Extensions to include in this partition
- Extensions []string
- // LabelMapper is a function that can map a label to a new label, and indicate whether to include
- // the mapped label in the partition
- LabelMapper LabelMapper
- // Whether to store files not included in any other partition in a group of LabelPartitions
- // Only one partition in a group of LabelPartitions can enabled Keep_remainder
- Keep_remainder bool
-}
-
-// LabelPartitions is a map of partition name to a LabelPartition describing the elements of the
-// partition
-type LabelPartitions map[string]LabelPartition
-
-// filter returns a pointer to a label if the label should be included in the partition or nil if
-// not.
-func (lf LabelPartition) filter(ctx OtherModuleContext, label Label) *Label {
- if lf.LabelMapper != nil {
- if newLabel, changed := lf.LabelMapper(ctx, label); changed {
- return &Label{newLabel, label.OriginalModuleName}
- }
- }
- for _, ext := range lf.Extensions {
- if strings.HasSuffix(label.Label, ext) {
- return &label
- }
- }
-
- return nil
-}
-
-// PartitionToLabelListAttribute is map of partition name to a LabelListAttribute
-type PartitionToLabelListAttribute map[string]LabelListAttribute
-
-type partitionToLabelList map[string]*LabelList
-
-func (p partitionToLabelList) appendIncludes(partition string, label Label) {
- if _, ok := p[partition]; !ok {
- p[partition] = &LabelList{}
- }
- p[partition].Includes = append(p[partition].Includes, label)
-}
-
-func (p partitionToLabelList) excludes(partition string, excludes []Label) {
- if _, ok := p[partition]; !ok {
- p[partition] = &LabelList{}
- }
- p[partition].Excludes = excludes
-}
-
-// PartitionLabelListAttribute partitions a LabelListAttribute into the requested partitions
-func PartitionLabelListAttribute(ctx OtherModuleContext, lla *LabelListAttribute, partitions LabelPartitions) PartitionToLabelListAttribute {
- ret := PartitionToLabelListAttribute{}
- var partitionNames []string
- // Stored as a pointer to distinguish nil (no remainder partition) from empty string partition
- var remainderPartition *string
- for p, f := range partitions {
- partitionNames = append(partitionNames, p)
- if f.Keep_remainder {
- if remainderPartition != nil {
- panic("only one partition can store the remainder")
- }
- // If we take the address of p in a loop, we'll end up with the last value of p in
- // remainderPartition, we want the requested partition
- capturePartition := p
- remainderPartition = &capturePartition
- }
- }
-
- partitionLabelList := func(axis ConfigurationAxis, config string) {
- value := lla.SelectValue(axis, config)
- partitionToLabels := partitionToLabelList{}
- for _, item := range value.Includes {
- wasFiltered := false
- var inPartition *string
- for partition, f := range partitions {
- filtered := f.filter(ctx, item)
- if filtered == nil {
- // did not match this filter, keep looking
- continue
- }
- wasFiltered = true
- partitionToLabels.appendIncludes(partition, *filtered)
- // don't need to check other partitions if this filter used the item,
- // continue checking if mapped to another name
- if *filtered == item {
- if inPartition != nil {
- ctx.ModuleErrorf("%q was found in multiple partitions: %q, %q", item.Label, *inPartition, partition)
- }
- capturePartition := partition
- inPartition = &capturePartition
- }
- }
-
- // if not specified in a partition, add to remainder partition if one exists
- if !wasFiltered && remainderPartition != nil {
- partitionToLabels.appendIncludes(*remainderPartition, item)
- }
- }
-
- // ensure empty lists are maintained
- if value.Excludes != nil {
- for _, partition := range partitionNames {
- partitionToLabels.excludes(partition, value.Excludes)
- }
- }
-
- for partition, list := range partitionToLabels {
- val := ret[partition]
- (&val).SetSelectValue(axis, config, *list)
- ret[partition] = val
- }
- }
-
- partitionLabelList(NoConfigAxis, "")
- for axis, configToList := range lla.ConfigurableValues {
- for config, _ := range configToList {
- partitionLabelList(axis, config)
- }
- }
- return ret
-}
-
-// StringAttribute corresponds to the string Bazel attribute type with
-// support for additional metadata, like configurations.
-type StringAttribute struct {
- // The base value of the string attribute.
- Value *string
-
- // The configured attribute label list Values. Optional
- // a map of independent configurability axes
- ConfigurableValues configurableStrings
-}
-
-type configurableStrings map[ConfigurationAxis]stringSelectValues
-
-func (cs configurableStrings) setValueForAxis(axis ConfigurationAxis, config string, str *string) {
- if cs[axis] == nil {
- cs[axis] = make(stringSelectValues)
- }
- cs[axis][config] = str
-}
-
-type stringSelectValues map[string]*string
-
-// HasConfigurableValues returns true if the attribute contains axis-specific string values.
-func (sa StringAttribute) HasConfigurableValues() bool {
- for _, selectValues := range sa.ConfigurableValues {
- if len(selectValues) > 0 {
- return true
- }
- }
- return false
-}
-
-// SetValue sets the base, non-configured value for the Label
-func (sa *StringAttribute) SetValue(value string) {
- sa.SetSelectValue(NoConfigAxis, "", &value)
-}
-
-// SetSelectValue set a value for a bazel select for the given axis, config and value.
-func (sa *StringAttribute) SetSelectValue(axis ConfigurationAxis, config string, str *string) {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- sa.Value = str
- case arch, os, osArch, productVariables, sanitizersEnabled:
- if sa.ConfigurableValues == nil {
- sa.ConfigurableValues = make(configurableStrings)
- }
- sa.ConfigurableValues.setValueForAxis(axis, config, str)
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SelectValue gets a value for a bazel select for the given axis and config.
-func (sa *StringAttribute) SelectValue(axis ConfigurationAxis, config string) *string {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- return sa.Value
- case arch, os, osArch, productVariables, sanitizersEnabled:
- if v, ok := sa.ConfigurableValues[axis][config]; ok {
- return v
- } else {
- return nil
- }
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
-func (sa *StringAttribute) SortedConfigurationAxes() []ConfigurationAxis {
- return SortedConfigurationAxes(sa.ConfigurableValues)
-}
-
-// Collapse reduces the configurable axes of the string attribute to a single axis.
-// This is necessary for final writing to bp2build, as a configurable string
-// attribute can only be comprised by a single select.
-func (sa *StringAttribute) Collapse() error {
- axisTypes := sa.axisTypes()
- _, containsOs := axisTypes[os]
- _, containsArch := axisTypes[arch]
- _, containsOsArch := axisTypes[osArch]
- _, containsProductVariables := axisTypes[productVariables]
- if containsProductVariables {
- if containsOs || containsArch || containsOsArch {
- return fmt.Errorf("string attribute could not be collapsed as it has two or more unrelated axes")
- }
- }
- if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
- // If a bool attribute has both os and arch configuration axes, the only
- // way to successfully union their values is to increase the granularity
- // of the configuration criteria to os_arch.
- for osType, supportedArchs := range osToArchMap {
- for _, supportedArch := range supportedArchs {
- osArch := osArchString(osType, supportedArch)
- if archOsVal := sa.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
- // Do nothing, as the arch_os is explicitly defined already.
- } else {
- archVal := sa.SelectValue(ArchConfigurationAxis, supportedArch)
- osVal := sa.SelectValue(OsConfigurationAxis, osType)
- if osVal != nil && archVal != nil {
- // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
- // runs after os mutator.
- sa.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
- } else if osVal != nil && archVal == nil {
- sa.SetSelectValue(OsArchConfigurationAxis, osArch, osVal)
- } else if osVal == nil && archVal != nil {
- sa.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
- }
- }
- }
- }
- /// All os_arch values are now set. Clear os and arch axes.
- delete(sa.ConfigurableValues, ArchConfigurationAxis)
- delete(sa.ConfigurableValues, OsConfigurationAxis)
- // Verify post-condition; this should never fail, provided no additional
- // axes are introduced.
- if len(sa.ConfigurableValues) > 1 {
- panic(fmt.Errorf("error in collapsing attribute: %#v", sa))
- }
- } else if containsProductVariables {
- usedBaseValue := false
- for a, configToProp := range sa.ConfigurableValues {
- if a.configurationType == productVariables {
- for c, p := range configToProp {
- if p == nil {
- sa.SetSelectValue(a, c, sa.Value)
- usedBaseValue = true
- }
- }
- }
- }
- if usedBaseValue {
- sa.Value = nil
- }
- }
- return nil
-}
-
-func (sa *StringAttribute) axisTypes() map[configurationType]bool {
- types := map[configurationType]bool{}
- for k := range sa.ConfigurableValues {
- if strs := sa.ConfigurableValues[k]; len(strs) > 0 {
- types[k.configurationType] = true
- }
- }
- return types
-}
-
-// StringListAttribute corresponds to the string_list Bazel attribute type with
-// support for additional metadata, like configurations.
-type StringListAttribute struct {
- // The base value of the string list attribute.
- Value []string
-
- // The configured attribute label list Values. Optional
- // a map of independent configurability axes
- ConfigurableValues configurableStringLists
-
- // If a property has struct tag "variant_prepend", this value should
- // be set to True, so that when bp2build generates BUILD.bazel, variant
- // properties(select ...) come before general properties.
- Prepend bool
-}
-
-// IsEmpty returns true if the attribute has no values under any configuration.
-func (sla StringListAttribute) IsEmpty() bool {
- return len(sla.Value) == 0 && !sla.HasConfigurableValues()
-}
-
-type configurableStringLists map[ConfigurationAxis]stringListSelectValues
-
-func (csl configurableStringLists) Append(other configurableStringLists) {
- for axis, otherSelects := range other {
- selects := csl[axis]
- if selects == nil {
- selects = make(stringListSelectValues, len(otherSelects))
- }
- selects.appendSelects(otherSelects)
- csl[axis] = selects
- }
-}
-
-func (csl configurableStringLists) setValueForAxis(axis ConfigurationAxis, config string, list []string) {
- if csl[axis] == nil {
- csl[axis] = make(stringListSelectValues)
- }
- csl[axis][config] = list
-}
-
-type stringListSelectValues map[string][]string
-
-func (sl stringListSelectValues) appendSelects(other stringListSelectValues) {
- for k, v := range other {
- sl[k] = append(sl[k], v...)
- }
-}
-
-func (sl stringListSelectValues) hasConfigurableValues(other stringListSelectValues) bool {
- for _, val := range sl {
- if len(val) > 0 {
- return true
- }
- }
- return false
-}
-
-// MakeStringListAttribute initializes a StringListAttribute with the non-arch specific value.
-func MakeStringListAttribute(value []string) StringListAttribute {
- // NOTE: These strings are not necessarily unique or sorted.
- return StringListAttribute{
- Value: value,
- ConfigurableValues: make(configurableStringLists),
- }
-}
-
-// HasConfigurableValues returns true if the attribute contains axis-specific string_list values.
-func (sla StringListAttribute) HasConfigurableValues() bool {
- for _, selectValues := range sla.ConfigurableValues {
- if len(selectValues) > 0 {
- return true
- }
- }
- return false
-}
-
-// Append appends all values, including os and arch specific ones, from another
-// StringListAttribute to this StringListAttribute
-func (sla *StringListAttribute) Append(other StringListAttribute) *StringListAttribute {
- sla.Value = append(sla.Value, other.Value...)
- if sla.ConfigurableValues == nil {
- sla.ConfigurableValues = make(configurableStringLists)
- }
- sla.ConfigurableValues.Append(other.ConfigurableValues)
- return sla
-}
-
-func (sla *StringListAttribute) Clone() *StringListAttribute {
- result := &StringListAttribute{}
- return result.Append(*sla)
-}
-
-// SetSelectValue set a value for a bazel select for the given axis, config and value.
-func (sla *StringListAttribute) SetSelectValue(axis ConfigurationAxis, config string, list []string) {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- sla.Value = list
- case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled, sanitizersEnabled:
- if sla.ConfigurableValues == nil {
- sla.ConfigurableValues = make(configurableStringLists)
- }
- sla.ConfigurableValues.setValueForAxis(axis, config, list)
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SelectValue gets a value for a bazel select for the given axis and config.
-func (sla *StringListAttribute) SelectValue(axis ConfigurationAxis, config string) []string {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- return sla.Value
- case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled, sanitizersEnabled:
- return sla.ConfigurableValues[axis][config]
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
-func (sla *StringListAttribute) SortedConfigurationAxes() []ConfigurationAxis {
- return SortedConfigurationAxes(sla.ConfigurableValues)
-}
-
-// DeduplicateAxesFromBase ensures no duplication of items between the no-configuration value and
-// configuration-specific values. For example, if we would convert this StringListAttribute as:
-//
-// ["a", "b", "c"] + select({
-// "//condition:one": ["a", "d"],
-// "//conditions:default": [],
-// })
-//
-// after this function, we would convert this StringListAttribute as:
-//
-// ["a", "b", "c"] + select({
-// "//condition:one": ["d"],
-// "//conditions:default": [],
-// })
-func (sla *StringListAttribute) DeduplicateAxesFromBase() {
- base := sla.Value
- for axis, configToList := range sla.ConfigurableValues {
- for config, list := range configToList {
- remaining := SubtractStrings(list, base)
- if len(remaining) == 0 {
- delete(sla.ConfigurableValues[axis], config)
- } else {
- sla.ConfigurableValues[axis][config] = remaining
- }
- }
- }
-}
-
-// TryVariableSubstitution, replace string substitution formatting within each string in slice with
-// Starlark string.format compatible tag for productVariable.
-func TryVariableSubstitutions(slice []string, productVariable string) ([]string, bool) {
- if len(slice) == 0 {
- return slice, false
- }
- ret := make([]string, 0, len(slice))
- changesMade := false
- for _, s := range slice {
- newS, changed := TryVariableSubstitution(s, productVariable)
- ret = append(ret, newS)
- changesMade = changesMade || changed
- }
- return ret, changesMade
-}
-
-// TryVariableSubstitution, replace string substitution formatting within s with Starlark
-// string.format compatible tag for productVariable.
-func TryVariableSubstitution(s string, productVariable string) (string, bool) {
- sub := productVariableSubstitutionPattern.ReplaceAllString(s, "$("+productVariable+")")
- return sub, s != sub
-}
-
-// StringMapAttribute is a map of strings.
-// The use case for this is storing the flag_values in a config_setting object.
-// Bazel rules do not support map attributes, and this should NOT be used in Bazel rules.
-type StringMapAttribute map[string]string
-
-// ConfigSettingAttributes stores the keys of a config_setting object.
-type ConfigSettingAttributes struct {
- // Each key in Flag_values is a label to a custom string_setting
- Flag_values StringMapAttribute
- // Each element in Constraint_values is a label to a constraint_value
- Constraint_values LabelListAttribute
-}
diff --git a/bazel/properties_test.go b/bazel/properties_test.go
deleted file mode 100644
index 751cb8b..0000000
--- a/bazel/properties_test.go
+++ /dev/null
@@ -1,836 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bazel
-
-import (
- "reflect"
- "strings"
- "testing"
-
- "github.com/google/blueprint/proptools"
-)
-
-func TestUniqueBazelLabels(t *testing.T) {
- testCases := []struct {
- originalLabels []Label
- expectedUniqueLabels []Label
- }{
- {
- originalLabels: []Label{
- {Label: "a"},
- {Label: "b"},
- {Label: "a"},
- {Label: "c"},
- // namespaces
- {Label: "//foo:bar", OriginalModuleName: "bar"}, // when referenced from foo namespace
- {Label: "//foo:bar", OriginalModuleName: "//foo:bar"}, // when reference from root namespace
- },
- expectedUniqueLabels: []Label{
- {Label: "//foo:bar", OriginalModuleName: "bar"},
- {Label: "a"},
- {Label: "b"},
- {Label: "c"},
- },
- },
- }
- for _, tc := range testCases {
- actualUniqueLabels := UniqueSortedBazelLabels(tc.originalLabels)
- if !reflect.DeepEqual(tc.expectedUniqueLabels, actualUniqueLabels) {
- t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabels, actualUniqueLabels)
- }
- }
-}
-
-func TestSubtractStrings(t *testing.T) {
- testCases := []struct {
- haystack []string
- needle []string
- expectedResult []string
- }{
- {
- haystack: []string{
- "a",
- "b",
- "c",
- },
- needle: []string{
- "a",
- },
- expectedResult: []string{
- "b", "c",
- },
- },
- }
- for _, tc := range testCases {
- actualResult := SubtractStrings(tc.haystack, tc.needle)
- if !reflect.DeepEqual(tc.expectedResult, actualResult) {
- t.Fatalf("Expected %v, got %v", tc.expectedResult, actualResult)
- }
- }
-}
-
-func TestSubtractBazelLabelList(t *testing.T) {
- testCases := []struct {
- haystack LabelList
- needle LabelList
- expectedResult LabelList
- }{
- {
- haystack: LabelList{
- Includes: []Label{
- {Label: "a"},
- {Label: "b"},
- {Label: "c"},
- },
- Excludes: []Label{
- {Label: "x"},
- {Label: "y"},
- {Label: "z"},
- },
- },
- needle: LabelList{
- Includes: []Label{
- {Label: "a"},
- },
- Excludes: []Label{
- {Label: "z"},
- },
- },
- // NOTE: Excludes are intentionally not subtracted
- expectedResult: LabelList{
- Includes: []Label{
- {Label: "b"},
- {Label: "c"},
- },
- Excludes: []Label{
- {Label: "x"},
- {Label: "y"},
- {Label: "z"},
- },
- },
- },
- }
- for _, tc := range testCases {
- actualResult := SubtractBazelLabelList(tc.haystack, tc.needle)
- if !reflect.DeepEqual(tc.expectedResult, actualResult) {
- t.Fatalf("Expected %v, got %v", tc.expectedResult, actualResult)
- }
- }
-}
-
-func TestSubtractBazelLabelListAttribute(t *testing.T) {
- testCases := []struct {
- haystack LabelListAttribute
- needle LabelListAttribute
- expected LabelListAttribute
- }{
- {
- haystack: LabelListAttribute{
- Value: makeLabelList(
- []string{"a", "b", "a", "c"},
- []string{"x", "x", "y", "z"},
- ),
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "arm": makeLabelList([]string{"arm_1", "arm_2"}, []string{}),
- "x86": makeLabelList([]string{"x86_3", "x86_4", "x86_5"}, []string{"x86_5"}),
- },
- },
- },
- needle: LabelListAttribute{
- Value: makeLabelList(
- []string{"d", "a"},
- []string{"x", "y2", "z2"},
- ),
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "arm": makeLabelList([]string{"arm_1", "arm_3"}, []string{}),
- "x86": makeLabelList([]string{"x86_3", "x86_4"}, []string{"x86_6"}),
- },
- },
- },
- expected: LabelListAttribute{
- Value: makeLabelList(
- []string{"b", "c"},
- []string{"x", "x", "y", "z"},
- ),
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "arm": makeLabelList([]string{"arm_2"}, []string{}),
- "x86": makeLabelList([]string{"x86_5"}, []string{"x86_5"}),
- },
- },
- ForceSpecifyEmptyList: false,
- EmitEmptyList: false,
- Prepend: false,
- },
- },
- }
- for _, tc := range testCases {
- got := SubtractBazelLabelListAttribute(tc.haystack, tc.needle)
- if !reflect.DeepEqual(tc.expected, got) {
- t.Fatalf("Expected\n%v, but got\n%v", tc.expected, got)
- }
- }
-}
-
-func TestFirstUniqueBazelLabelList(t *testing.T) {
- testCases := []struct {
- originalLabelList LabelList
- expectedUniqueLabelList LabelList
- }{
- {
- originalLabelList: LabelList{
- Includes: []Label{
- {Label: "a"},
- {Label: "b"},
- {Label: "a"},
- {Label: "c"},
- // namespaces
- {Label: "//foo:bar", OriginalModuleName: "bar"}, // when referenced from foo namespace
- {Label: "//foo:bar", OriginalModuleName: "//foo:bar"}, // when referenced from root namespace
- },
- Excludes: []Label{
- {Label: "x"},
- {Label: "x"},
- {Label: "y"},
- {Label: "z"},
- },
- },
- expectedUniqueLabelList: LabelList{
- Includes: []Label{
- {Label: "a"},
- {Label: "b"},
- {Label: "c"},
- {Label: "//foo:bar", OriginalModuleName: "bar"},
- },
- Excludes: []Label{
- {Label: "x"},
- {Label: "y"},
- {Label: "z"},
- },
- },
- },
- }
- for _, tc := range testCases {
- actualUniqueLabelList := FirstUniqueBazelLabelList(tc.originalLabelList)
- if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) {
- t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList)
- }
- }
-}
-
-func TestFirstUniqueBazelLabelListAttribute(t *testing.T) {
- testCases := []struct {
- originalLabelList LabelListAttribute
- expectedUniqueLabelList LabelListAttribute
- }{
- {
- originalLabelList: LabelListAttribute{
- Value: makeLabelList(
- []string{"a", "b", "a", "c"},
- []string{"x", "x", "y", "z"},
- ),
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "arm": makeLabelList([]string{"1", "2", "1"}, []string{}),
- "x86": makeLabelList([]string{"3", "4", "4"}, []string{"5", "5"}),
- },
- },
- },
- expectedUniqueLabelList: LabelListAttribute{
- Value: makeLabelList(
- []string{"a", "b", "c"},
- []string{"x", "y", "z"},
- ),
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "arm": makeLabelList([]string{"1", "2"}, []string{}),
- "x86": makeLabelList([]string{"3", "4"}, []string{"5"}),
- },
- },
- },
- },
- }
- for _, tc := range testCases {
- actualUniqueLabelList := FirstUniqueBazelLabelListAttribute(tc.originalLabelList)
- if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) {
- t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList)
- }
- }
-}
-
-func TestUniqueSortedBazelLabelList(t *testing.T) {
- testCases := []struct {
- originalLabelList LabelList
- expectedUniqueLabelList LabelList
- }{
- {
- originalLabelList: LabelList{
- Includes: []Label{
- {Label: "c"},
- {Label: "a"},
- {Label: "a"},
- {Label: "b"},
- },
- Excludes: []Label{
- {Label: "y"},
- {Label: "z"},
- {Label: "x"},
- {Label: "x"},
- },
- },
- expectedUniqueLabelList: LabelList{
- Includes: []Label{
- {Label: "a"},
- {Label: "b"},
- {Label: "c"},
- },
- Excludes: []Label{
- {Label: "x"},
- {Label: "y"},
- {Label: "z"},
- },
- },
- },
- }
- for _, tc := range testCases {
- actualUniqueLabelList := UniqueSortedBazelLabelList(tc.originalLabelList)
- if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) {
- t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList)
- }
- }
-}
-
-func makeLabels(labels ...string) []Label {
- var ret []Label
- for _, l := range labels {
- ret = append(ret, Label{Label: l})
- }
- return ret
-}
-
-func makeLabelList(includes, excludes []string) LabelList {
- return LabelList{
- Includes: makeLabels(includes...),
- Excludes: makeLabels(excludes...),
- }
-}
-
-func TestResolveExcludes(t *testing.T) {
- attr := LabelListAttribute{
- Value: makeLabelList(
- []string{
- "all_include",
- "arm_exclude",
- "android_exclude",
- "product_config_exclude",
- },
- []string{"all_exclude"},
- ),
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "arm": makeLabelList([]string{}, []string{"arm_exclude"}),
- "x86": makeLabelList([]string{"x86_include"}, []string{}),
- ConditionsDefaultConfigKey: makeLabelList([]string{"default_include"}, []string{}),
- },
- OsConfigurationAxis: labelListSelectValues{
- "android": makeLabelList([]string{}, []string{"android_exclude"}),
- "linux": makeLabelList([]string{"linux_include"}, []string{}),
- },
- OsArchConfigurationAxis: labelListSelectValues{
- "linux_x86": makeLabelList([]string{"linux_x86_include"}, []string{}),
- },
- ProductVariableConfigurationAxis(false, "product_with_defaults"): labelListSelectValues{
- "a": makeLabelList([]string{}, []string{"not_in_value"}),
- "b": makeLabelList([]string{"b_val"}, []string{}),
- "c": makeLabelList([]string{"c_val"}, []string{}),
- ConditionsDefaultConfigKey: makeLabelList([]string{"c_val", "default", "default2", "all_exclude"}, []string{}),
- },
- ProductVariableConfigurationAxis(false, "product_only_with_excludes"): labelListSelectValues{
- "a": makeLabelList([]string{}, []string{"product_config_exclude"}),
- },
- },
- }
-
- attr.ResolveExcludes()
-
- expectedBaseIncludes := []Label{{Label: "all_include"}}
- if !reflect.DeepEqual(expectedBaseIncludes, attr.Value.Includes) {
- t.Errorf("Expected Value includes %q, got %q", attr.Value.Includes, expectedBaseIncludes)
- }
- var nilLabels []Label
- expectedConfiguredIncludes := map[ConfigurationAxis]map[string][]Label{
- ArchConfigurationAxis: {
- "arm": nilLabels,
- "x86": makeLabels("arm_exclude", "x86_include"),
- ConditionsDefaultConfigKey: makeLabels("arm_exclude", "default_include"),
- },
- OsConfigurationAxis: {
- "android": nilLabels,
- "linux": makeLabels("android_exclude", "linux_include"),
- ConditionsDefaultConfigKey: makeLabels("android_exclude"),
- },
- OsArchConfigurationAxis: {
- "linux_x86": makeLabels("linux_x86_include"),
- ConditionsDefaultConfigKey: nilLabels,
- },
- ProductVariableConfigurationAxis(false, "product_with_defaults"): {
- "a": nilLabels,
- "b": makeLabels("b_val"),
- "c": makeLabels("c_val"),
- ConditionsDefaultConfigKey: makeLabels("c_val", "default", "default2"),
- },
- ProductVariableConfigurationAxis(false, "product_only_with_excludes"): {
- "a": nilLabels,
- ConditionsDefaultConfigKey: makeLabels("product_config_exclude"),
- },
- }
- for _, axis := range attr.SortedConfigurationAxes() {
- if _, ok := expectedConfiguredIncludes[axis]; !ok {
- t.Errorf("Found unexpected axis %s", axis)
- continue
- }
- expectedForAxis := expectedConfiguredIncludes[axis]
- gotForAxis := attr.ConfigurableValues[axis]
- if len(expectedForAxis) != len(gotForAxis) {
- t.Errorf("Expected %d configs for %s, got %d: %s", len(expectedForAxis), axis, len(gotForAxis), gotForAxis)
- }
- for config, value := range gotForAxis {
- if expected, ok := expectedForAxis[config]; ok {
- if !reflect.DeepEqual(expected, value.Includes) {
- t.Errorf("For %s,\nexpected: %#v\ngot %#v", axis, expected, value.Includes)
- }
- } else {
- t.Errorf("Got unexpected config %q for %s", config, axis)
- }
- }
- }
-}
-
-func TestLabelListAttributePartition(t *testing.T) {
- testCases := []struct {
- name string
- input LabelListAttribute
- predicated LabelListAttribute
- unpredicated LabelListAttribute
- predicate func(label Label) bool
- }{
- {
- name: "move all to predicated partition",
- input: MakeLabelListAttribute(makeLabelList(
- []string{"keep1", "throw1", "keep2", "throw2"},
- []string{"keep1", "throw1", "keep2", "throw2"},
- )),
- predicated: MakeLabelListAttribute(makeLabelList(
- []string{"keep1", "throw1", "keep2", "throw2"},
- []string{"keep1", "throw1", "keep2", "throw2"},
- )),
- unpredicated: LabelListAttribute{},
- predicate: func(label Label) bool {
- return true
- },
- },
- {
- name: "move all to unpredicated partition",
- input: MakeLabelListAttribute(makeLabelList(
- []string{"keep1", "throw1", "keep2", "throw2"},
- []string{"keep1", "throw1", "keep2", "throw2"},
- )),
- predicated: LabelListAttribute{},
- unpredicated: MakeLabelListAttribute(makeLabelList(
- []string{"keep1", "throw1", "keep2", "throw2"},
- []string{"keep1", "throw1", "keep2", "throw2"},
- )),
- predicate: func(label Label) bool {
- return false
- },
- },
- {
- name: "partition includes and excludes",
- input: MakeLabelListAttribute(makeLabelList(
- []string{"keep1", "throw1", "keep2", "throw2"},
- []string{"keep1", "throw1", "keep2", "throw2"},
- )),
- predicated: MakeLabelListAttribute(makeLabelList(
- []string{"keep1", "keep2"},
- []string{"keep1", "keep2"},
- )),
- unpredicated: MakeLabelListAttribute(makeLabelList(
- []string{"throw1", "throw2"},
- []string{"throw1", "throw2"},
- )),
- predicate: func(label Label) bool {
- return strings.HasPrefix(label.Label, "keep")
- },
- },
- {
- name: "partition excludes only",
- input: MakeLabelListAttribute(makeLabelList(
- []string{},
- []string{"keep1", "throw1", "keep2", "throw2"},
- )),
- predicated: MakeLabelListAttribute(makeLabelList(
- []string{},
- []string{"keep1", "keep2"},
- )),
- unpredicated: MakeLabelListAttribute(makeLabelList(
- []string{},
- []string{"throw1", "throw2"},
- )),
- predicate: func(label Label) bool {
- return strings.HasPrefix(label.Label, "keep")
- },
- },
- {
- name: "partition includes only",
- input: MakeLabelListAttribute(makeLabelList(
- []string{"keep1", "throw1", "keep2", "throw2"},
- []string{},
- )),
- predicated: MakeLabelListAttribute(makeLabelList(
- []string{"keep1", "keep2"},
- []string{},
- )),
- unpredicated: MakeLabelListAttribute(makeLabelList(
- []string{"throw1", "throw2"},
- []string{},
- )),
- predicate: func(label Label) bool {
- return strings.HasPrefix(label.Label, "keep")
- },
- },
- {
- name: "empty partition",
- input: MakeLabelListAttribute(makeLabelList([]string{}, []string{})),
- predicated: LabelListAttribute{},
- unpredicated: LabelListAttribute{},
- predicate: func(label Label) bool {
- return true
- },
- },
- }
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- predicated, unpredicated := tc.input.Partition(tc.predicate)
- if !predicated.Value.Equals(tc.predicated.Value) {
- t.Errorf("expected predicated labels to be %v; got %v", tc.predicated, predicated)
- }
- for axis, configs := range predicated.ConfigurableValues {
- tcConfigs, ok := tc.predicated.ConfigurableValues[axis]
- if !ok || !reflect.DeepEqual(configs, tcConfigs) {
- t.Errorf("expected predicated labels to be %v; got %v", tc.predicated, predicated)
- }
- }
- if !unpredicated.Value.Equals(tc.unpredicated.Value) {
- t.Errorf("expected unpredicated labels to be %v; got %v", tc.unpredicated, unpredicated)
- }
- for axis, configs := range unpredicated.ConfigurableValues {
- tcConfigs, ok := tc.unpredicated.ConfigurableValues[axis]
- if !ok || !reflect.DeepEqual(configs, tcConfigs) {
- t.Errorf("expected unpredicated labels to be %v; got %v", tc.unpredicated, unpredicated)
- }
- }
- })
- }
-}
-
-// labelAddSuffixForTypeMapper returns a LabelMapper that adds suffix to label name for modules of
-// typ
-func labelAddSuffixForTypeMapper(suffix, typ string) LabelMapper {
- return func(omc OtherModuleContext, label Label) (string, bool) {
- m, ok := omc.ModuleFromName(label.Label)
- if !ok {
- return label.Label, false
- }
- mTyp := omc.OtherModuleType(m)
- if typ == mTyp {
- return label.Label + suffix, true
- }
- return label.Label, false
- }
-}
-
-func TestPartitionLabelListAttribute(t *testing.T) {
- testCases := []struct {
- name string
- ctx *OtherModuleTestContext
- labelList LabelListAttribute
- filters LabelPartitions
- expected PartitionToLabelListAttribute
- expectedErrMsg *string
- }{
- {
- name: "no configurable values",
- ctx: &OtherModuleTestContext{},
- labelList: LabelListAttribute{
- Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}),
- },
- filters: LabelPartitions{
- "A": LabelPartition{Extensions: []string{".a"}},
- "B": LabelPartition{Extensions: []string{".b"}},
- "C": LabelPartition{Extensions: []string{".c"}},
- },
- expected: PartitionToLabelListAttribute{
- "A": LabelListAttribute{Value: makeLabelList([]string{"a.a"}, []string{})},
- "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})},
- "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
- },
- },
- {
- name: "no configurable values, remainder partition",
- ctx: &OtherModuleTestContext{},
- labelList: LabelListAttribute{
- Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}),
- },
- filters: LabelPartitions{
- "A": LabelPartition{Extensions: []string{".a"}, Keep_remainder: true},
- "B": LabelPartition{Extensions: []string{".b"}},
- "C": LabelPartition{Extensions: []string{".c"}},
- },
- expected: PartitionToLabelListAttribute{
- "A": LabelListAttribute{Value: makeLabelList([]string{"a.a", "d.d", "e.e"}, []string{})},
- "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})},
- "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
- },
- },
- {
- name: "no configurable values, empty partition",
- ctx: &OtherModuleTestContext{},
- labelList: LabelListAttribute{
- Value: makeLabelList([]string{"a.a", "c.c"}, []string{}),
- },
- filters: LabelPartitions{
- "A": LabelPartition{Extensions: []string{".a"}},
- "B": LabelPartition{Extensions: []string{".b"}},
- "C": LabelPartition{Extensions: []string{".c"}},
- },
- expected: PartitionToLabelListAttribute{
- "A": LabelListAttribute{Value: makeLabelList([]string{"a.a"}, []string{})},
- "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
- },
- },
- {
- name: "no configurable values, has map",
- ctx: &OtherModuleTestContext{
- Modules: []TestModuleInfo{{ModuleName: "srcs", Typ: "fg", Dir: "dir"}},
- },
- labelList: LabelListAttribute{
- Value: makeLabelList([]string{"a.a", "srcs", "b.b", "c.c"}, []string{}),
- },
- filters: LabelPartitions{
- "A": LabelPartition{Extensions: []string{".a"}, LabelMapper: labelAddSuffixForTypeMapper("_a", "fg")},
- "B": LabelPartition{Extensions: []string{".b"}},
- "C": LabelPartition{Extensions: []string{".c"}},
- },
- expected: PartitionToLabelListAttribute{
- "A": LabelListAttribute{Value: makeLabelList([]string{"a.a", "srcs_a"}, []string{})},
- "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})},
- "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
- },
- },
- {
- name: "configurable values, keeps empty if excludes",
- ctx: &OtherModuleTestContext{},
- labelList: LabelListAttribute{
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "x86": makeLabelList([]string{"a.a", "c.c"}, []string{}),
- "arm": makeLabelList([]string{"b.b"}, []string{}),
- "x86_64": makeLabelList([]string{"b.b"}, []string{"d.d"}),
- },
- },
- },
- filters: LabelPartitions{
- "A": LabelPartition{Extensions: []string{".a"}},
- "B": LabelPartition{Extensions: []string{".b"}},
- "C": LabelPartition{Extensions: []string{".c"}},
- },
- expected: PartitionToLabelListAttribute{
- "A": LabelListAttribute{
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "x86": makeLabelList([]string{"a.a"}, []string{}),
- "x86_64": makeLabelList([]string{}, []string{"c.c"}),
- },
- },
- },
- "B": LabelListAttribute{
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "arm": makeLabelList([]string{"b.b"}, []string{}),
- "x86_64": makeLabelList([]string{"b.b"}, []string{"c.c"}),
- },
- },
- },
- "C": LabelListAttribute{
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "x86": makeLabelList([]string{"c.c"}, []string{}),
- "x86_64": makeLabelList([]string{}, []string{"c.c"}),
- },
- },
- },
- },
- },
- {
- name: "error for multiple partitions same value",
- ctx: &OtherModuleTestContext{},
- labelList: LabelListAttribute{
- Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}),
- },
- filters: LabelPartitions{
- "A": LabelPartition{Extensions: []string{".a"}},
- "other A": LabelPartition{Extensions: []string{".a"}},
- },
- expected: PartitionToLabelListAttribute{},
- expectedErrMsg: proptools.StringPtr(`"a.a" was found in multiple partitions:`),
- },
- }
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- got := PartitionLabelListAttribute(tc.ctx, &tc.labelList, tc.filters)
-
- if hasErrors, expectsErr := len(tc.ctx.errors) > 0, tc.expectedErrMsg != nil; hasErrors != expectsErr {
- t.Errorf("Unexpected error(s): %q, expected: %q", tc.ctx.errors, *tc.expectedErrMsg)
- } else if tc.expectedErrMsg != nil {
- found := false
- for _, err := range tc.ctx.errors {
- if strings.Contains(err, *tc.expectedErrMsg) {
- found = true
- break
- }
- }
-
- if !found {
- t.Errorf("Expected error message: %q, got %q", *tc.expectedErrMsg, tc.ctx.errors)
- }
- return
- }
-
- if len(tc.expected) != len(got) {
- t.Errorf("Expected %d partitions, got %d partitions", len(tc.expected), len(got))
- }
- for partition, expectedLla := range tc.expected {
- gotLla, ok := got[partition]
- if !ok {
- t.Errorf("Expected partition %q, but it was not found %v", partition, got)
- continue
- }
- expectedLabelList := expectedLla.Value
- gotLabelList := gotLla.Value
- if !reflect.DeepEqual(expectedLabelList.Includes, gotLabelList.Includes) {
- t.Errorf("Expected no config includes %v, got %v", expectedLabelList.Includes, gotLabelList.Includes)
- }
- expectedAxes := expectedLla.SortedConfigurationAxes()
- gotAxes := gotLla.SortedConfigurationAxes()
- if !reflect.DeepEqual(expectedAxes, gotAxes) {
- t.Errorf("Expected axes %v, got %v (%#v)", expectedAxes, gotAxes, gotLla)
- }
- for _, axis := range expectedLla.SortedConfigurationAxes() {
- if _, exists := gotLla.ConfigurableValues[axis]; !exists {
- t.Errorf("Expected %s to be a supported axis, but it was not found", axis)
- }
- if expected, got := expectedLla.ConfigurableValues[axis], gotLla.ConfigurableValues[axis]; len(expected) != len(got) {
- t.Errorf("For axis %q: expected configs %v, got %v", axis, expected, got)
- }
- for config, expectedLabelList := range expectedLla.ConfigurableValues[axis] {
- gotLabelList, exists := gotLla.ConfigurableValues[axis][config]
- if !exists {
- t.Errorf("Expected %s to be a supported config, but config was not found", config)
- continue
- }
- if !reflect.DeepEqual(expectedLabelList.Includes, gotLabelList.Includes) {
- t.Errorf("Expected %s %s includes %v, got %v", axis, config, expectedLabelList.Includes, gotLabelList.Includes)
- }
- }
- }
- }
- })
- }
-}
-
-func TestDeduplicateAxesFromBase(t *testing.T) {
- attr := StringListAttribute{
- Value: []string{
- "all_include",
- "arm_include",
- "android_include",
- "linux_x86_include",
- },
- ConfigurableValues: configurableStringLists{
- ArchConfigurationAxis: stringListSelectValues{
- "arm": []string{"arm_include"},
- "x86": []string{"x86_include"},
- },
- OsConfigurationAxis: stringListSelectValues{
- "android": []string{"android_include"},
- "linux": []string{"linux_include"},
- },
- OsArchConfigurationAxis: stringListSelectValues{
- "linux_x86": {"linux_x86_include"},
- },
- ProductVariableConfigurationAxis(false, "a"): stringListSelectValues{
- "a": []string{"not_in_value"},
- },
- },
- }
-
- attr.DeduplicateAxesFromBase()
-
- expectedBaseIncludes := []string{
- "all_include",
- "arm_include",
- "android_include",
- "linux_x86_include",
- }
- if !reflect.DeepEqual(expectedBaseIncludes, attr.Value) {
- t.Errorf("Expected Value includes %q, got %q", attr.Value, expectedBaseIncludes)
- }
- expectedConfiguredIncludes := configurableStringLists{
- ArchConfigurationAxis: stringListSelectValues{
- "x86": []string{"x86_include"},
- },
- OsConfigurationAxis: stringListSelectValues{
- "linux": []string{"linux_include"},
- },
- OsArchConfigurationAxis: stringListSelectValues{},
- ProductVariableConfigurationAxis(false, "a"): stringListSelectValues{
- "a": []string{"not_in_value"},
- },
- }
- for _, axis := range attr.SortedConfigurationAxes() {
- if _, ok := expectedConfiguredIncludes[axis]; !ok {
- t.Errorf("Found unexpected axis %s", axis)
- continue
- }
- expectedForAxis := expectedConfiguredIncludes[axis]
- gotForAxis := attr.ConfigurableValues[axis]
- if len(expectedForAxis) != len(gotForAxis) {
- t.Errorf("Expected %d configs for %s, got %d: %s", len(expectedForAxis), axis, len(gotForAxis), gotForAxis)
- }
- for config, value := range gotForAxis {
- if expected, ok := expectedForAxis[config]; ok {
- if !reflect.DeepEqual(expected, value) {
- t.Errorf("For %s, expected: %#v, got %#v", axis, expected, value)
- }
- } else {
- t.Errorf("Got unexpected config %q for %s", config, axis)
- }
- }
- }
-}
diff --git a/bazel/testing.go b/bazel/testing.go
deleted file mode 100644
index 9a43b61..0000000
--- a/bazel/testing.go
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bazel
-
-import (
- "fmt"
-
- "github.com/google/blueprint"
-)
-
-// TestModuleInfo implements blueprint.Module interface with sufficient information to mock a subset of
-// a blueprint ModuleContext
-type TestModuleInfo struct {
- ModuleName string
- Typ string
- Dir string
-}
-
-// Name returns name for testModuleInfo -- required to implement blueprint.Module
-func (mi TestModuleInfo) Name() string {
- return mi.ModuleName
-}
-
-// GenerateBuildActions unused, but required to implmeent blueprint.Module
-func (mi TestModuleInfo) GenerateBuildActions(blueprint.ModuleContext) {}
-
-func (mi TestModuleInfo) equals(other TestModuleInfo) bool {
- return mi.ModuleName == other.ModuleName && mi.Typ == other.Typ && mi.Dir == other.Dir
-}
-
-// ensure testModuleInfo implements blueprint.Module
-var _ blueprint.Module = TestModuleInfo{}
-
-// OtherModuleTestContext is a mock context that implements OtherModuleContext
-type OtherModuleTestContext struct {
- Modules []TestModuleInfo
- errors []string
-}
-
-// ModuleFromName retrieves the testModuleInfo corresponding to name, if it exists
-func (omc *OtherModuleTestContext) ModuleFromName(name string) (blueprint.Module, bool) {
- for _, m := range omc.Modules {
- if m.ModuleName == name {
- return m, true
- }
- }
- return TestModuleInfo{}, false
-}
-
-// testModuleInfo returns the testModuleInfo corresponding to a blueprint.Module if it exists in omc
-func (omc *OtherModuleTestContext) testModuleInfo(m blueprint.Module) (TestModuleInfo, bool) {
- mi, ok := m.(TestModuleInfo)
- if !ok {
- return TestModuleInfo{}, false
- }
- for _, other := range omc.Modules {
- if other.equals(mi) {
- return mi, true
- }
- }
- return TestModuleInfo{}, false
-}
-
-// OtherModuleType returns type of m if it exists in omc
-func (omc *OtherModuleTestContext) OtherModuleType(m blueprint.Module) string {
- if mi, ok := omc.testModuleInfo(m); ok {
- return mi.Typ
- }
- return ""
-}
-
-// OtherModuleName returns name of m if it exists in omc
-func (omc *OtherModuleTestContext) OtherModuleName(m blueprint.Module) string {
- if mi, ok := omc.testModuleInfo(m); ok {
- return mi.ModuleName
- }
- return ""
-}
-
-// OtherModuleDir returns dir of m if it exists in omc
-func (omc *OtherModuleTestContext) OtherModuleDir(m blueprint.Module) string {
- if mi, ok := omc.testModuleInfo(m); ok {
- return mi.Dir
- }
- return ""
-}
-
-func (omc *OtherModuleTestContext) ModuleErrorf(format string, args ...interface{}) {
- omc.errors = append(omc.errors, fmt.Sprintf(format, args...))
-}
-
-// Ensure otherModuleTestContext implements OtherModuleContext
-var _ OtherModuleContext = &OtherModuleTestContext{}
diff --git a/bin/aninja b/bin/aninja
index 5acb968..5cb5a55 100755
--- a/bin/aninja
+++ b/bin/aninja
@@ -34,5 +34,5 @@
esac
cd $(gettop)
-prebuilts/build-tools/${host_arch}/bin/ninja -f out/combined-${TARGET_PRODUCT}.ninja "$@"
+prebuilts/build-tools/${host_arch}/bin/ninja -f $(getoutdir)/combined-${TARGET_PRODUCT}.ninja "$@"
diff --git a/bin/get_build_vars b/bin/get_build_vars
new file mode 100755
index 0000000..aa887c7
--- /dev/null
+++ b/bin/get_build_vars
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Get the value of build variables. The values are printed in a format suitable
+# for use in the import_build_vars function in build/make/shell_utils.sh
+#
+# For absolute variables, prefix the variable name with a '/'
+
+# Common script utilities
+source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../../make/shell_utils.sh
+
+require_top
+
+$TOP/build/soong/soong_ui.bash --dumpvars-mode \
+ --vars="$(printf '%s\n' "$@" | grep -v '^/')" \
+ --abs-vars="$(printf '%s\n' "$@" | grep '^/' | sed 's:^/::')" \
+ --var-prefix= \
+ --abs-var-prefix=
+
+exit $?
diff --git a/bin/mm b/bin/mm
index 6461b1e..6f1c934 100755
--- a/bin/mm
+++ b/bin/mm
@@ -19,6 +19,6 @@
require_top
-_wrap_build "$TOP/build/soong/soong_ui.bash" --build-mode --modules-in-a-dir-no-deps --dir="$(pwd)" "$@"
+_wrap_build "$TOP/build/soong/soong_ui.bash" --build-mode --modules-in-a-dir --dir="$(pwd)" "$@"
exit $?
diff --git a/bin/mmm b/bin/mmm
index ab3a632..d9190e5 100755
--- a/bin/mmm
+++ b/bin/mmm
@@ -19,6 +19,6 @@
require_top
-_wrap_build "$TOP/build/soong/soong_ui.bash" --build-mode --modules-in-dirs-no-deps --dir="$(pwd)" "$@"
+_wrap_build "$TOP/build/soong/soong_ui.bash" --build-mode --modules-in-dirs --dir="$(pwd)" "$@"
exit $?
diff --git a/bin/soongdbg b/bin/soongdbg
index 98d31eb..0807291 100755
--- a/bin/soongdbg
+++ b/bin/soongdbg
@@ -393,12 +393,42 @@
print(f" dep: {d.id}")
+class StarCommand:
+ help = "Print the dependencies and reverse dependencies of a module"
+
+ def args(self, parser):
+ parser.add_argument("module", nargs="+",
+ help="Module to print dependencies of")
+ parser.add_argument("--depth", type=int, required=True,
+ help="max depth of dependencies")
+ print_args(parser)
+
+ def run(self, args):
+ graph = load_graph()
+ nodes = set()
+ err = False
+ for id in args.module:
+ root = graph.nodes.get(id)
+ if not root:
+ sys.stderr.write(f"error: Can't find root: {id}\n")
+ err = True
+ continue
+ get_deps(nodes, root, args.depth, False, set(args.tag))
+ nodes.remove(root) # Remove it so get_deps doesn't bail out
+ get_deps(nodes, root, args.depth, True, set(args.tag))
+ if err:
+ sys.exit(1)
+ print_nodes(args, nodes, new_module_formatter(args))
+
+
+
COMMANDS = {
"between": BetweenCommand(),
"deps": DepsCommand(),
"id": IdCommand(),
"json": JsonCommand(),
"query": QueryCommand(),
+ "star": StarCommand(),
}
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
deleted file mode 100644
index ba12682..0000000
--- a/bp2build/Android.bp
+++ /dev/null
@@ -1,43 +0,0 @@
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-bootstrap_go_package {
- name: "soong-bp2build",
- pkgPath: "android/soong/bp2build",
- srcs: [
- "androidbp_to_build_templates.go",
- "build_conversion.go",
- "bzl_conversion.go",
- "configurability.go",
- "constants.go",
- "conversion.go",
- ],
- deps: [
- "blueprint-bootstrap",
- "soong-aidl-library",
- "soong-aconfig",
- "soong-android",
- "soong-android-allowlists",
- "soong-android-soongconfig",
- "soong-apex",
- "soong-bazel",
- "soong-cc",
- "soong-cc-config",
- "soong-etc",
- "soong-genrule",
- "soong-linkerconfig",
- "soong-python",
- "soong-rust",
- "soong-sh",
- "soong-shared",
- "soong-starlark-format",
- "soong-ui-metrics",
- ],
- testSrcs: [
- "conversion_test.go",
- ],
- pluginFor: [
- "soong_build",
- ],
-}
diff --git a/bp2build/androidbp_to_build_templates.go b/bp2build/androidbp_to_build_templates.go
deleted file mode 100644
index 9b21c32..0000000
--- a/bp2build/androidbp_to_build_templates.go
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2020 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-const (
- // The default `load` preamble for every generated queryview BUILD file.
- soongModuleLoad = `package(default_visibility = ["//visibility:public"])
-load("//build/bazel/queryview_rules:soong_module.bzl", "soong_module")
-
-`
-
- // A macro call in the BUILD file representing a Soong module, with space
- // for expanding more attributes.
- soongModuleTargetTemplate = `soong_module(
- name = "%s",
- soong_module_name = "%s",
- soong_module_type = "%s",
- soong_module_variant = "%s",
- soong_module_deps = %s,
-%s)`
-
- ruleTargetTemplate = `%s(
- name = "%s",
-%s)`
-
- unnamedRuleTargetTemplate = `%s(
-%s)`
-
- // A simple provider to mark and differentiate Soong module rule shims from
- // regular Bazel rules. Every Soong module rule shim returns a
- // SoongModuleInfo provider, and can only depend on rules returning
- // SoongModuleInfo in the `soong_module_deps` attribute.
- providersBzl = `SoongModuleInfo = provider(
- fields = {
- "name": "Name of module",
- "type": "Type of module",
- "variant": "Variant of module",
- },
-)
-`
-
- // The soong_module rule implementation in a .bzl file.
- soongModuleBzl = `
-%s
-
-load("//build/bazel/queryview_rules:providers.bzl", "SoongModuleInfo")
-
-def _generic_soong_module_impl(ctx):
- return [
- SoongModuleInfo(
- name = ctx.attr.soong_module_name,
- type = ctx.attr.soong_module_type,
- variant = ctx.attr.soong_module_variant,
- ),
- ]
-
-generic_soong_module = rule(
- implementation = _generic_soong_module_impl,
- attrs = {
- "soong_module_name": attr.string(mandatory = True),
- "soong_module_type": attr.string(mandatory = True),
- "soong_module_variant": attr.string(),
- "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
- },
-)
-
-soong_module_rule_map = {
-%s}
-
-_SUPPORTED_TYPES = ["bool", "int", "string"]
-
-def _is_supported_type(value):
- if type(value) in _SUPPORTED_TYPES:
- return True
- elif type(value) == "list":
- supported = True
- for v in value:
- supported = supported and type(v) in _SUPPORTED_TYPES
- return supported
- else:
- return False
-
-# soong_module is a macro that supports arbitrary kwargs, and uses soong_module_type to
-# expand to the right underlying shim.
-def soong_module(name, soong_module_type, **kwargs):
- soong_module_rule = soong_module_rule_map.get(soong_module_type)
-
- if soong_module_rule == None:
- # This module type does not have an existing rule to map to, so use the
- # generic_soong_module rule instead.
- generic_soong_module(
- name = name,
- soong_module_type = soong_module_type,
- soong_module_name = kwargs.pop("soong_module_name", ""),
- soong_module_variant = kwargs.pop("soong_module_variant", ""),
- soong_module_deps = kwargs.pop("soong_module_deps", []),
- )
- else:
- supported_kwargs = dict()
- for key, value in kwargs.items():
- if _is_supported_type(value):
- supported_kwargs[key] = value
- soong_module_rule(
- name = name,
- **supported_kwargs,
- )
-`
-
- // A rule shim for representing a Soong module type and its properties.
- moduleRuleShim = `
-def _%[1]s_impl(ctx):
- return [SoongModuleInfo()]
-
-%[1]s = rule(
- implementation = _%[1]s_impl,
- attrs = %[2]s
-)
-`
-)
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
deleted file mode 100644
index bd56768..0000000
--- a/bp2build/build_conversion.go
+++ /dev/null
@@ -1,640 +0,0 @@
-// Copyright 2020 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-/*
-For shareable/common functionality for conversion from soong-module to build files
-for queryview/bp2build
-*/
-
-import (
- "fmt"
- "reflect"
- "sort"
- "strings"
-
- "android/soong/android"
- "android/soong/bazel"
- "android/soong/starlark_fmt"
- "github.com/google/blueprint"
- "github.com/google/blueprint/proptools"
-)
-
-type BazelAttributes struct {
- Attrs map[string]string
-}
-
-type BazelLoadSymbol struct {
- // The name of the symbol in the file being loaded
- symbol string
- // The name the symbol wil have in this file. Can be left blank to use the same name as symbol.
- alias string
-}
-
-type BazelLoad struct {
- file string
- symbols []BazelLoadSymbol
-}
-
-type BazelTarget struct {
- name string
- packageName string
- content string
- ruleClass string
- loads []BazelLoad
-}
-
-// Label is the fully qualified Bazel label constructed from the BazelTarget's
-// package name and target name.
-func (t BazelTarget) Label() string {
- if t.packageName == "." {
- return "//:" + t.name
- } else {
- return "//" + t.packageName + ":" + t.name
- }
-}
-
-// PackageName returns the package of the Bazel target.
-// Defaults to root of tree.
-func (t BazelTarget) PackageName() string {
- if t.packageName == "" {
- return "."
- }
- return t.packageName
-}
-
-// BazelTargets is a typedef for a slice of BazelTarget objects.
-type BazelTargets []BazelTarget
-
-func (targets BazelTargets) packageRule() *BazelTarget {
- for _, target := range targets {
- if target.ruleClass == "package" {
- return &target
- }
- }
- return nil
-}
-
-// sort a list of BazelTargets in-place, by name, and by generated/handcrafted types.
-func (targets BazelTargets) sort() {
- sort.Slice(targets, func(i, j int) bool {
- return targets[i].name < targets[j].name
- })
-}
-
-// String returns the string representation of BazelTargets, without load
-// statements (use LoadStatements for that), since the targets are usually not
-// adjacent to the load statements at the top of the BUILD file.
-func (targets BazelTargets) String() string {
- var res strings.Builder
- for i, target := range targets {
- if target.ruleClass != "package" {
- res.WriteString(target.content)
- }
- if i != len(targets)-1 {
- res.WriteString("\n\n")
- }
- }
- return res.String()
-}
-
-// LoadStatements return the string representation of the sorted and deduplicated
-// Starlark rule load statements needed by a group of BazelTargets.
-func (targets BazelTargets) LoadStatements() string {
- // First, merge all the load statements from all the targets onto one list
- bzlToLoadedSymbols := map[string][]BazelLoadSymbol{}
- for _, target := range targets {
- for _, load := range target.loads {
- outer:
- for _, symbol := range load.symbols {
- alias := symbol.alias
- if alias == "" {
- alias = symbol.symbol
- }
- for _, otherSymbol := range bzlToLoadedSymbols[load.file] {
- otherAlias := otherSymbol.alias
- if otherAlias == "" {
- otherAlias = otherSymbol.symbol
- }
- if symbol.symbol == otherSymbol.symbol && alias == otherAlias {
- continue outer
- } else if alias == otherAlias {
- panic(fmt.Sprintf("Conflicting destination (%s) for loads of %s and %s", alias, symbol.symbol, otherSymbol.symbol))
- }
- }
- bzlToLoadedSymbols[load.file] = append(bzlToLoadedSymbols[load.file], symbol)
- }
- }
- }
-
- var loadStatements strings.Builder
- for i, bzl := range android.SortedKeys(bzlToLoadedSymbols) {
- symbols := bzlToLoadedSymbols[bzl]
- loadStatements.WriteString("load(\"")
- loadStatements.WriteString(bzl)
- loadStatements.WriteString("\", ")
- sort.Slice(symbols, func(i, j int) bool {
- if symbols[i].symbol < symbols[j].symbol {
- return true
- }
- return symbols[i].alias < symbols[j].alias
- })
- for j, symbol := range symbols {
- if symbol.alias != "" && symbol.alias != symbol.symbol {
- loadStatements.WriteString(symbol.alias)
- loadStatements.WriteString(" = ")
- }
- loadStatements.WriteString("\"")
- loadStatements.WriteString(symbol.symbol)
- loadStatements.WriteString("\"")
- if j != len(symbols)-1 {
- loadStatements.WriteString(", ")
- }
- }
- loadStatements.WriteString(")")
- if i != len(bzlToLoadedSymbols)-1 {
- loadStatements.WriteString("\n")
- }
- }
- return loadStatements.String()
-}
-
-type bpToBuildContext interface {
- ModuleName(module blueprint.Module) string
- ModuleDir(module blueprint.Module) string
- ModuleSubDir(module blueprint.Module) string
- ModuleType(module blueprint.Module) string
-
- VisitAllModules(visit func(blueprint.Module))
- VisitDirectDeps(module blueprint.Module, visit func(blueprint.Module))
-}
-
-type CodegenContext struct {
- config android.Config
- context *android.Context
- mode CodegenMode
- additionalDeps []string
- unconvertedDepMode unconvertedDepsMode
- topDir string
-}
-
-func (ctx *CodegenContext) Mode() CodegenMode {
- return ctx.mode
-}
-
-// CodegenMode is an enum to differentiate code-generation modes.
-type CodegenMode int
-
-const (
- // QueryView - generate BUILD files with targets representing fully mutated
- // Soong modules, representing the fully configured Soong module graph with
- // variants and dependency edges.
- //
- // This mode is used for discovering and introspecting the existing Soong
- // module graph.
- QueryView CodegenMode = iota
-)
-
-type unconvertedDepsMode int
-
-const (
- // Include a warning in conversion metrics about converted modules with unconverted direct deps
- warnUnconvertedDeps unconvertedDepsMode = iota
- // Error and fail conversion if encountering a module with unconverted direct deps
- // Enabled by setting environment variable `BP2BUILD_ERROR_UNCONVERTED`
- errorModulesUnconvertedDeps
-)
-
-func (mode CodegenMode) String() string {
- switch mode {
- case QueryView:
- return "QueryView"
- default:
- return fmt.Sprintf("%d", mode)
- }
-}
-
-// AddNinjaFileDeps adds dependencies on the specified files to be added to the ninja manifest. The
-// primary builder will be rerun whenever the specified files are modified. Allows us to fulfill the
-// PathContext interface in order to add dependencies on hand-crafted BUILD files. Note: must also
-// call AdditionalNinjaDeps and add them manually to the ninja file.
-func (ctx *CodegenContext) AddNinjaFileDeps(deps ...string) {
- ctx.additionalDeps = append(ctx.additionalDeps, deps...)
-}
-
-// AdditionalNinjaDeps returns additional ninja deps added by CodegenContext
-func (ctx *CodegenContext) AdditionalNinjaDeps() []string {
- return ctx.additionalDeps
-}
-
-func (ctx *CodegenContext) Config() android.Config { return ctx.config }
-func (ctx *CodegenContext) Context() *android.Context { return ctx.context }
-
-// NewCodegenContext creates a wrapper context that conforms to PathContext for
-// writing BUILD files in the output directory.
-func NewCodegenContext(config android.Config, context *android.Context, mode CodegenMode, topDir string) *CodegenContext {
- var unconvertedDeps unconvertedDepsMode
- return &CodegenContext{
- context: context,
- config: config,
- mode: mode,
- unconvertedDepMode: unconvertedDeps,
- topDir: topDir,
- }
-}
-
-// props is an unsorted map. This function ensures that
-// the generated attributes are sorted to ensure determinism.
-func propsToAttributes(props map[string]string) string {
- var attributes string
- for _, propName := range android.SortedKeys(props) {
- attributes += fmt.Sprintf(" %s = %s,\n", propName, props[propName])
- }
- return attributes
-}
-
-type conversionResults struct {
- buildFileToTargets map[string]BazelTargets
- moduleNameToPartition map[string]string
-}
-
-func (r conversionResults) BuildDirToTargets() map[string]BazelTargets {
- return r.buildFileToTargets
-}
-
-func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (conversionResults, []error) {
- ctx.Context().BeginEvent("GenerateBazelTargets")
- defer ctx.Context().EndEvent("GenerateBazelTargets")
- buildFileToTargets := make(map[string]BazelTargets)
-
- dirs := make(map[string]bool)
- moduleNameToPartition := make(map[string]string)
-
- var errs []error
-
- bpCtx := ctx.Context()
- bpCtx.VisitAllModules(func(m blueprint.Module) {
- dir := bpCtx.ModuleDir(m)
- dirs[dir] = true
-
- var targets []BazelTarget
-
- switch ctx.Mode() {
- case QueryView:
- // Blocklist certain module types from being generated.
- if canonicalizeModuleType(bpCtx.ModuleType(m)) == "package" {
- // package module name contain slashes, and thus cannot
- // be mapped cleanly to a bazel label.
- return
- }
- t, err := generateSoongModuleTarget(bpCtx, m)
- if err != nil {
- errs = append(errs, err)
- }
- targets = append(targets, t)
- default:
- errs = append(errs, fmt.Errorf("Unknown code-generation mode: %s", ctx.Mode()))
- return
- }
-
- for _, target := range targets {
- targetDir := target.PackageName()
- buildFileToTargets[targetDir] = append(buildFileToTargets[targetDir], target)
- }
- })
-
- if len(errs) > 0 {
- return conversionResults{}, errs
- }
-
- if generateFilegroups {
- // Add a filegroup target that exposes all sources in the subtree of this package
- // NOTE: This also means we generate a BUILD file for every Android.bp file (as long as it has at least one module)
- //
- // This works because: https://bazel.build/reference/be/functions#exports_files
- // "As a legacy behaviour, also files mentioned as input to a rule are exported with the
- // default visibility until the flag --incompatible_no_implicit_file_export is flipped. However, this behavior
- // should not be relied upon and actively migrated away from."
- //
- // TODO(b/198619163): We should change this to export_files(glob(["**/*"])) instead, but doing that causes these errors:
- // "Error in exports_files: generated label '//external/avb:avbtool' conflicts with existing py_binary rule"
- // So we need to solve all the "target ... is both a rule and a file" warnings first.
- for dir := range dirs {
- buildFileToTargets[dir] = append(buildFileToTargets[dir], BazelTarget{
- name: "bp2build_all_srcs",
- content: `filegroup(name = "bp2build_all_srcs", srcs = glob(["**/*"]), tags = ["manual"])`,
- ruleClass: "filegroup",
- })
- }
- }
-
- return conversionResults{
- buildFileToTargets: buildFileToTargets,
- moduleNameToPartition: moduleNameToPartition,
- }, errs
-}
-
-// Convert a module and its deps and props into a Bazel macro/rule
-// representation in the BUILD file.
-func generateSoongModuleTarget(ctx bpToBuildContext, m blueprint.Module) (BazelTarget, error) {
- props, err := getBuildProperties(ctx, m)
-
- // TODO(b/163018919): DirectDeps can have duplicate (module, variant)
- // items, if the modules are added using different DependencyTag. Figure
- // out the implications of that.
- depLabels := map[string]bool{}
- if aModule, ok := m.(android.Module); ok {
- ctx.VisitDirectDeps(aModule, func(depModule blueprint.Module) {
- depLabels[qualifiedTargetLabel(ctx, depModule)] = true
- })
- }
-
- for p := range ignoredPropNames {
- delete(props.Attrs, p)
- }
- attributes := propsToAttributes(props.Attrs)
-
- depLabelList := "[\n"
- for depLabel := range depLabels {
- depLabelList += fmt.Sprintf(" %q,\n", depLabel)
- }
- depLabelList += " ]"
-
- targetName := targetNameWithVariant(ctx, m)
- return BazelTarget{
- name: targetName,
- packageName: ctx.ModuleDir(m),
- content: fmt.Sprintf(
- soongModuleTargetTemplate,
- targetName,
- ctx.ModuleName(m),
- canonicalizeModuleType(ctx.ModuleType(m)),
- ctx.ModuleSubDir(m),
- depLabelList,
- attributes),
- }, err
-}
-
-func getBuildProperties(ctx bpToBuildContext, m blueprint.Module) (BazelAttributes, error) {
- // TODO: this omits properties for blueprint modules (blueprint_go_binary,
- // bootstrap_go_binary, bootstrap_go_package), which will have to be handled separately.
- if aModule, ok := m.(android.Module); ok {
- return extractModuleProperties(aModule.GetProperties(), false)
- }
-
- return BazelAttributes{}, nil
-}
-
-// Generically extract module properties and types into a map, keyed by the module property name.
-func extractModuleProperties(props []interface{}, checkForDuplicateProperties bool) (BazelAttributes, error) {
- ret := map[string]string{}
-
- // Iterate over this android.Module's property structs.
- for _, properties := range props {
- propertiesValue := reflect.ValueOf(properties)
- // Check that propertiesValue is a pointer to the Properties struct, like
- // *cc.BaseLinkerProperties or *java.CompilerProperties.
- //
- // propertiesValue can also be type-asserted to the structs to
- // manipulate internal props, if needed.
- if isStructPtr(propertiesValue.Type()) {
- structValue := propertiesValue.Elem()
- ok, err := extractStructProperties(structValue, 0)
- if err != nil {
- return BazelAttributes{}, err
- }
- for k, v := range ok {
- if existing, exists := ret[k]; checkForDuplicateProperties && exists {
- return BazelAttributes{}, fmt.Errorf(
- "%s (%v) is present in properties whereas it should be consolidated into a commonAttributes",
- k, existing)
- }
- ret[k] = v
- }
- } else {
- return BazelAttributes{},
- fmt.Errorf(
- "properties must be a pointer to a struct, got %T",
- propertiesValue.Interface())
- }
- }
-
- return BazelAttributes{
- Attrs: ret,
- }, nil
-}
-
-func isStructPtr(t reflect.Type) bool {
- return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
-}
-
-// prettyPrint a property value into the equivalent Starlark representation
-// recursively.
-func prettyPrint(propertyValue reflect.Value, indent int, emitZeroValues bool) (string, error) {
- if !emitZeroValues && isZero(propertyValue) {
- // A property value being set or unset actually matters -- Soong does set default
- // values for unset properties, like system_shared_libs = ["libc", "libm", "libdl"] at
- // https://cs.android.com/android/platform/superproject/+/main:build/soong/cc/linker.go;l=281-287;drc=f70926eef0b9b57faf04c17a1062ce50d209e480
- //
- // In Bazel-parlance, we would use "attr.<type>(default = <default
- // value>)" to set the default value of unset attributes. In the cases
- // where the bp2build converter didn't set the default value within the
- // mutator when creating the BazelTargetModule, this would be a zero
- // value. For those cases, we return an empty string so we don't
- // unnecessarily generate empty values.
- return "", nil
- }
-
- switch propertyValue.Kind() {
- case reflect.String:
- return fmt.Sprintf("\"%v\"", escapeString(propertyValue.String())), nil
- case reflect.Bool:
- return starlark_fmt.PrintBool(propertyValue.Bool()), nil
- case reflect.Int, reflect.Uint, reflect.Int64:
- return fmt.Sprintf("%v", propertyValue.Interface()), nil
- case reflect.Ptr:
- return prettyPrint(propertyValue.Elem(), indent, emitZeroValues)
- case reflect.Slice:
- elements := make([]string, 0, propertyValue.Len())
- for i := 0; i < propertyValue.Len(); i++ {
- val, err := prettyPrint(propertyValue.Index(i), indent, emitZeroValues)
- if err != nil {
- return "", err
- }
- if val != "" {
- elements = append(elements, val)
- }
- }
- return starlark_fmt.PrintList(elements, indent, func(s string) string {
- return "%s"
- }), nil
-
- case reflect.Struct:
- // Special cases where the bp2build sends additional information to the codegenerator
- // by wrapping the attributes in a custom struct type.
- if attr, ok := propertyValue.Interface().(bazel.Attribute); ok {
- return prettyPrintAttribute(attr, indent)
- } else if label, ok := propertyValue.Interface().(bazel.Label); ok {
- return fmt.Sprintf("%q", label.Label), nil
- }
-
- // Sort and print the struct props by the key.
- structProps, err := extractStructProperties(propertyValue, indent)
-
- if err != nil {
- return "", err
- }
-
- if len(structProps) == 0 {
- return "", nil
- }
- return starlark_fmt.PrintDict(structProps, indent), nil
- case reflect.Interface:
- // TODO(b/164227191): implement pretty print for interfaces.
- // Interfaces are used for for arch, multilib and target properties.
- return "", nil
- case reflect.Map:
- if v, ok := propertyValue.Interface().(bazel.StringMapAttribute); ok {
- return starlark_fmt.PrintStringStringDict(v, indent), nil
- }
- return "", fmt.Errorf("bp2build expects map of type map[string]string for field: %s", propertyValue)
- default:
- return "", fmt.Errorf(
- "unexpected kind for property struct field: %s", propertyValue.Kind())
- }
-}
-
-// Converts a reflected property struct value into a map of property names and property values,
-// which each property value correctly pretty-printed and indented at the right nest level,
-// since property structs can be nested. In Starlark, nested structs are represented as nested
-// dicts: https://docs.bazel.build/skylark/lib/dict.html
-func extractStructProperties(structValue reflect.Value, indent int) (map[string]string, error) {
- if structValue.Kind() != reflect.Struct {
- return map[string]string{}, fmt.Errorf("Expected a reflect.Struct type, but got %s", structValue.Kind())
- }
-
- var err error
-
- ret := map[string]string{}
- structType := structValue.Type()
- for i := 0; i < structValue.NumField(); i++ {
- field := structType.Field(i)
- if shouldSkipStructField(field) {
- continue
- }
-
- fieldValue := structValue.Field(i)
- if isZero(fieldValue) {
- // Ignore zero-valued fields
- continue
- }
-
- // if the struct is embedded (anonymous), flatten the properties into the containing struct
- if field.Anonymous {
- if field.Type.Kind() == reflect.Ptr {
- fieldValue = fieldValue.Elem()
- }
- if fieldValue.Type().Kind() == reflect.Struct {
- propsToMerge, err := extractStructProperties(fieldValue, indent)
- if err != nil {
- return map[string]string{}, err
- }
- for prop, value := range propsToMerge {
- ret[prop] = value
- }
- continue
- }
- }
-
- propertyName := proptools.PropertyNameForField(field.Name)
- var prettyPrintedValue string
- prettyPrintedValue, err = prettyPrint(fieldValue, indent+1, false)
- if err != nil {
- return map[string]string{}, fmt.Errorf(
- "Error while parsing property: %q. %s",
- propertyName,
- err)
- }
- if prettyPrintedValue != "" {
- ret[propertyName] = prettyPrintedValue
- }
- }
-
- return ret, nil
-}
-
-func isZero(value reflect.Value) bool {
- switch value.Kind() {
- case reflect.Func, reflect.Map, reflect.Slice:
- return value.IsNil()
- case reflect.Array:
- valueIsZero := true
- for i := 0; i < value.Len(); i++ {
- valueIsZero = valueIsZero && isZero(value.Index(i))
- }
- return valueIsZero
- case reflect.Struct:
- valueIsZero := true
- for i := 0; i < value.NumField(); i++ {
- valueIsZero = valueIsZero && isZero(value.Field(i))
- }
- return valueIsZero
- case reflect.Ptr:
- if !value.IsNil() {
- return isZero(reflect.Indirect(value))
- } else {
- return true
- }
- // Always print bool/strings, if you want a bool/string attribute to be able to take the default value, use a
- // pointer instead
- case reflect.Bool, reflect.String:
- return false
- default:
- if !value.IsValid() {
- return true
- }
- zeroValue := reflect.Zero(value.Type())
- result := value.Interface() == zeroValue.Interface()
- return result
- }
-}
-
-func escapeString(s string) string {
- s = strings.ReplaceAll(s, "\\", "\\\\")
-
- // b/184026959: Reverse the application of some common control sequences.
- // These must be generated literally in the BUILD file.
- s = strings.ReplaceAll(s, "\t", "\\t")
- s = strings.ReplaceAll(s, "\n", "\\n")
- s = strings.ReplaceAll(s, "\r", "\\r")
-
- return strings.ReplaceAll(s, "\"", "\\\"")
-}
-
-func targetNameWithVariant(c bpToBuildContext, logicModule blueprint.Module) string {
- name := ""
- if c.ModuleSubDir(logicModule) != "" {
- // TODO(b/162720883): Figure out a way to drop the "--" variant suffixes.
- name = c.ModuleName(logicModule) + "--" + c.ModuleSubDir(logicModule)
- } else {
- name = c.ModuleName(logicModule)
- }
-
- return strings.Replace(name, "//", "", 1)
-}
-
-func qualifiedTargetLabel(c bpToBuildContext, logicModule blueprint.Module) string {
- return fmt.Sprintf("//%s:%s", c.ModuleDir(logicModule), targetNameWithVariant(c, logicModule))
-}
diff --git a/bp2build/bzl_conversion.go b/bp2build/bzl_conversion.go
deleted file mode 100644
index e774fdf..0000000
--- a/bp2build/bzl_conversion.go
+++ /dev/null
@@ -1,237 +0,0 @@
-// Copyright 2020 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
- "android/soong/android"
- "fmt"
- "reflect"
- "runtime"
- "sort"
- "strings"
-
- "github.com/google/blueprint/proptools"
-)
-
-var (
- // An allowlist of prop types that are surfaced from module props to rule
- // attributes. (nested) dictionaries are notably absent here, because while
- // Soong supports multi value typed and nested dictionaries, Bazel's rule
- // attr() API supports only single-level string_dicts.
- allowedPropTypes = map[string]bool{
- "int": true, // e.g. 42
- "bool": true, // e.g. True
- "string_list": true, // e.g. ["a", "b"]
- "string": true, // e.g. "a"
- }
-)
-
-type rule struct {
- name string
- attrs string
-}
-
-type RuleShim struct {
- // The rule class shims contained in a bzl file. e.g. ["cc_object", "cc_library", ..]
- rules []string
-
- // The generated string content of the bzl file.
- content string
-}
-
-// Create <module>.bzl containing Bazel rule shims for every module type available in Soong and
-// user-specified Go plugins.
-//
-// This function reuses documentation generation APIs to ensure parity between modules-as-docs
-// and modules-as-code, including the names and types of morule properties.
-func CreateRuleShims(moduleTypeFactories map[string]android.ModuleFactory) map[string]RuleShim {
- ruleShims := map[string]RuleShim{}
- for pkg, rules := range generateRules(moduleTypeFactories) {
- shim := RuleShim{
- rules: make([]string, 0, len(rules)),
- }
- shim.content = "load(\"//build/bazel/queryview_rules:providers.bzl\", \"SoongModuleInfo\")\n"
-
- bzlFileName := strings.ReplaceAll(pkg, "android/soong/", "")
- bzlFileName = strings.ReplaceAll(bzlFileName, ".", "_")
- bzlFileName = strings.ReplaceAll(bzlFileName, "/", "_")
-
- for _, r := range rules {
- shim.content += fmt.Sprintf(moduleRuleShim, r.name, r.attrs)
- shim.rules = append(shim.rules, r.name)
- }
- sort.Strings(shim.rules)
- ruleShims[bzlFileName] = shim
- }
- return ruleShims
-}
-
-// Generate the content of soong_module.bzl with the rule shim load statements
-// and mapping of module_type to rule shim map for every module type in Soong.
-func generateSoongModuleBzl(bzlLoads map[string]RuleShim) string {
- var loadStmts string
- var moduleRuleMap string
- for _, bzlFileName := range android.SortedKeys(bzlLoads) {
- loadStmt := "load(\"//build/bazel/queryview_rules:"
- loadStmt += bzlFileName
- loadStmt += ".bzl\""
- ruleShim := bzlLoads[bzlFileName]
- for _, rule := range ruleShim.rules {
- loadStmt += fmt.Sprintf(", %q", rule)
- moduleRuleMap += " \"" + rule + "\": " + rule + ",\n"
- }
- loadStmt += ")\n"
- loadStmts += loadStmt
- }
-
- return fmt.Sprintf(soongModuleBzl, loadStmts, moduleRuleMap)
-}
-
-func generateRules(moduleTypeFactories map[string]android.ModuleFactory) map[string][]rule {
- // TODO: add shims for bootstrap/blueprint go modules types
-
- rules := make(map[string][]rule)
- // TODO: allow registration of a bzl rule when registring a factory
- for _, moduleType := range android.SortedKeys(moduleTypeFactories) {
- factory := moduleTypeFactories[moduleType]
- factoryName := runtime.FuncForPC(reflect.ValueOf(factory).Pointer()).Name()
- pkg := strings.Split(factoryName, ".")[0]
- attrs := `{
- "soong_module_name": attr.string(mandatory = True),
- "soong_module_variant": attr.string(),
- "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
-`
- attrs += getAttributes(factory)
- attrs += " },"
-
- r := rule{
- name: canonicalizeModuleType(moduleType),
- attrs: attrs,
- }
-
- rules[pkg] = append(rules[pkg], r)
- }
- return rules
-}
-
-type property struct {
- name string
- starlarkAttrType string
- properties []property
-}
-
-const (
- attributeIndent = " "
-)
-
-func (p *property) attributeString() string {
- if !shouldGenerateAttribute(p.name) {
- return ""
- }
-
- if _, ok := allowedPropTypes[p.starlarkAttrType]; !ok {
- // a struct -- let's just comment out sub-props
- s := fmt.Sprintf(attributeIndent+"# %s start\n", p.name)
- for _, nestedP := range p.properties {
- s += "# " + nestedP.attributeString()
- }
- s += fmt.Sprintf(attributeIndent+"# %s end\n", p.name)
- return s
- }
- return fmt.Sprintf(attributeIndent+"%q: attr.%s(),\n", p.name, p.starlarkAttrType)
-}
-
-func extractPropertyDescriptionsFromStruct(structType reflect.Type) []property {
- properties := make([]property, 0)
- for i := 0; i < structType.NumField(); i++ {
- field := structType.Field(i)
- if shouldSkipStructField(field) {
- continue
- }
- subProps := extractPropertyDescriptions(field.Name, field.Type)
- // if the struct is embedded (anonymous), flatten the properties into the containing struct
- if field.Anonymous {
- for _, prop := range subProps {
- properties = append(properties, prop.properties...)
- }
- } else {
- properties = append(properties, subProps...)
- }
- }
- return properties
-}
-
-func extractPropertyDescriptions(name string, t reflect.Type) []property {
- name = proptools.PropertyNameForField(name)
-
- // TODO: handle android:paths tags, they should be changed to label types
-
- starlarkAttrType := fmt.Sprintf("%s", t.Name())
- props := make([]property, 0)
-
- switch t.Kind() {
- case reflect.Bool, reflect.String:
- // do nothing
- case reflect.Uint, reflect.Int, reflect.Int64:
- starlarkAttrType = "int"
- case reflect.Slice:
- if t.Elem().Kind() != reflect.String {
- // TODO: handle lists of non-strings (currently only list of Dist)
- return []property{}
- }
- starlarkAttrType = "string_list"
- case reflect.Struct:
- props = extractPropertyDescriptionsFromStruct(t)
- case reflect.Ptr:
- return extractPropertyDescriptions(name, t.Elem())
- case reflect.Interface:
- // Interfaces are used for for arch, multilib and target properties, which are handled at runtime.
- // These will need to be handled in a bazel-specific version of the arch mutator.
- return []property{}
- }
-
- prop := property{
- name: name,
- starlarkAttrType: starlarkAttrType,
- properties: props,
- }
-
- return []property{prop}
-}
-
-func getPropertyDescriptions(props []interface{}) []property {
- // there may be duplicate properties, e.g. from defaults libraries
- propertiesByName := make(map[string]property)
- for _, p := range props {
- for _, prop := range extractPropertyDescriptionsFromStruct(reflect.ValueOf(p).Elem().Type()) {
- propertiesByName[prop.name] = prop
- }
- }
-
- properties := make([]property, 0, len(propertiesByName))
- for _, key := range android.SortedKeys(propertiesByName) {
- properties = append(properties, propertiesByName[key])
- }
-
- return properties
-}
-
-func getAttributes(factory android.ModuleFactory) string {
- attrs := ""
- for _, p := range getPropertyDescriptions(factory().GetProperties()) {
- attrs += p.attributeString()
- }
- return attrs
-}
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
deleted file mode 100644
index 3d9f0a2..0000000
--- a/bp2build/configurability.go
+++ /dev/null
@@ -1,328 +0,0 @@
-package bp2build
-
-import (
- "fmt"
- "reflect"
-
- "android/soong/android"
- "android/soong/bazel"
- "android/soong/starlark_fmt"
-)
-
-// Configurability support for bp2build.
-
-type selects map[string]reflect.Value
-
-func getStringValue(str bazel.StringAttribute) (reflect.Value, []selects) {
- value := reflect.ValueOf(str.Value)
-
- if !str.HasConfigurableValues() {
- return value, []selects{}
- }
-
- ret := selects{}
- for _, axis := range str.SortedConfigurationAxes() {
- configToStrs := str.ConfigurableValues[axis]
- for config, strs := range configToStrs {
- selectKey := axis.SelectKey(config)
- ret[selectKey] = reflect.ValueOf(strs)
- }
- }
-
- // if there is a select, use the base value as the conditions default value
- if len(ret) > 0 {
- if _, ok := ret[bazel.ConditionsDefaultSelectKey]; !ok {
- ret[bazel.ConditionsDefaultSelectKey] = value
- value = reflect.Zero(value.Type())
- }
- }
-
- return value, []selects{ret}
-}
-
-func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects, bool) {
- value := reflect.ValueOf(list.Value)
- prepend := list.Prepend
- if !list.HasConfigurableValues() {
- return value, []selects{}, prepend
- }
-
- var ret []selects
- for _, axis := range list.SortedConfigurationAxes() {
- configToLists := list.ConfigurableValues[axis]
- archSelects := map[string]reflect.Value{}
- for config, labels := range configToLists {
- selectKey := axis.SelectKey(config)
- archSelects[selectKey] = reflect.ValueOf(labels)
- }
- if len(archSelects) > 0 {
- ret = append(ret, archSelects)
- }
- }
-
- return value, ret, prepend
-}
-
-func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) {
- value := reflect.ValueOf(label.Value)
- if !label.HasConfigurableValues() {
- return value, []selects{}
- }
-
- ret := selects{}
- for _, axis := range label.SortedConfigurationAxes() {
- configToLabels := label.ConfigurableValues[axis]
- for config, labels := range configToLabels {
- selectKey := axis.SelectKey(config)
- ret[selectKey] = reflect.ValueOf(labels)
- }
- }
-
- // if there is a select, use the base value as the conditions default value
- if len(ret) > 0 {
- ret[bazel.ConditionsDefaultSelectKey] = value
- value = reflect.Zero(value.Type())
- }
-
- return value, []selects{ret}
-}
-
-func getBoolValue(boolAttr bazel.BoolAttribute) (reflect.Value, []selects) {
- value := reflect.ValueOf(boolAttr.Value)
- if !boolAttr.HasConfigurableValues() {
- return value, []selects{}
- }
-
- ret := selects{}
- for _, axis := range boolAttr.SortedConfigurationAxes() {
- configToBools := boolAttr.ConfigurableValues[axis]
- for config, bools := range configToBools {
- selectKey := axis.SelectKey(config)
- ret[selectKey] = reflect.ValueOf(bools)
- }
- }
- // if there is a select, use the base value as the conditions default value
- if len(ret) > 0 {
- ret[bazel.ConditionsDefaultSelectKey] = value
- value = reflect.Zero(value.Type())
- }
-
- return value, []selects{ret}
-}
-func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects, bool) {
- value := reflect.ValueOf(list.Value.Includes)
- prepend := list.Prepend
- var ret []selects
- for _, axis := range list.SortedConfigurationAxes() {
- configToLabels := list.ConfigurableValues[axis]
- if !configToLabels.HasConfigurableValues() {
- continue
- }
- archSelects := map[string]reflect.Value{}
- defaultVal := configToLabels[bazel.ConditionsDefaultConfigKey]
- // Skip empty list values unless ether EmitEmptyList is true, or these values differ from the default.
- emitEmptyList := list.EmitEmptyList || len(defaultVal.Includes) > 0
- for config, labels := range configToLabels {
- // Omit any entries in the map which match the default value, for brevity.
- if config != bazel.ConditionsDefaultConfigKey && labels.Equals(defaultVal) {
- continue
- }
- selectKey := axis.SelectKey(config)
- if use, value := labelListSelectValue(selectKey, labels, emitEmptyList); use {
- archSelects[selectKey] = value
- }
- }
- if len(archSelects) > 0 {
- ret = append(ret, archSelects)
- }
- }
-
- return value, ret, prepend
-}
-
-func labelListSelectValue(selectKey string, list bazel.LabelList, emitEmptyList bool) (bool, reflect.Value) {
- if selectKey == bazel.ConditionsDefaultSelectKey || emitEmptyList || len(list.Includes) > 0 {
- return true, reflect.ValueOf(list.Includes)
- } else if len(list.Excludes) > 0 {
- // if there is still an excludes -- we need to have an empty list for this select & use the
- // value in conditions default Includes
- return true, reflect.ValueOf([]string{})
- }
- return false, reflect.Zero(reflect.TypeOf([]string{}))
-}
-
-var (
- emptyBazelList = "[]"
- bazelNone = "None"
-)
-
-// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
-// select statements.
-func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
- var value reflect.Value
- // configurableAttrs is the list of individual select statements to be
- // concatenated together. These select statements should be along different
- // axes. For example, one element may be
- // `select({"//color:red": "one", "//color:green": "two"})`, and the second
- // element may be `select({"//animal:cat": "three", "//animal:dog": "four"}).
- // These selects should be sorted by axis identifier.
- var configurableAttrs []selects
- var prepend bool
- var defaultSelectValue *string
- var emitZeroValues bool
- // If true, print the default attribute value, even if the attribute is zero.
- shouldPrintDefault := false
- switch list := v.(type) {
- case bazel.StringAttribute:
- if err := list.Collapse(); err != nil {
- return "", err
- }
- value, configurableAttrs = getStringValue(list)
- defaultSelectValue = &bazelNone
- case bazel.StringListAttribute:
- value, configurableAttrs, prepend = getStringListValues(list)
- defaultSelectValue = &emptyBazelList
- case bazel.LabelListAttribute:
- value, configurableAttrs, prepend = getLabelListValues(list)
- emitZeroValues = list.EmitEmptyList
- defaultSelectValue = &emptyBazelList
- if list.ForceSpecifyEmptyList && (!value.IsNil() || list.HasConfigurableValues()) {
- shouldPrintDefault = true
- }
- case bazel.LabelAttribute:
- if err := list.Collapse(); err != nil {
- return "", err
- }
- value, configurableAttrs = getLabelValue(list)
- defaultSelectValue = &bazelNone
- case bazel.BoolAttribute:
- if err := list.Collapse(); err != nil {
- return "", err
- }
- value, configurableAttrs = getBoolValue(list)
- defaultSelectValue = &bazelNone
- default:
- return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
- }
-
- var err error
- ret := ""
- if value.Kind() != reflect.Invalid {
- s, err := prettyPrint(value, indent, false) // never emit zero values for the base value
- if err != nil {
- return ret, err
- }
-
- ret += s
- }
- // Convenience function to prepend/append selects components to an attribute value.
- concatenateSelects := func(selectsData selects, defaultValue *string, s string, prepend bool) (string, error) {
- selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent, emitZeroValues)
- if err != nil {
- return "", err
- }
- var left, right string
- if prepend {
- left, right = selectMap, s
- } else {
- left, right = s, selectMap
- }
- if left != "" && right != "" {
- left += " + "
- }
- left += right
-
- return left, nil
- }
-
- for _, configurableAttr := range configurableAttrs {
- ret, err = concatenateSelects(configurableAttr, defaultSelectValue, ret, prepend)
- if err != nil {
- return "", err
- }
- }
-
- if ret == "" && shouldPrintDefault {
- return *defaultSelectValue, nil
- }
- return ret, nil
-}
-
-// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
-// to construct a select map for any kind of attribute type.
-func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *string, indent int, emitZeroValues bool) (string, error) {
- if selectMap == nil {
- return "", nil
- }
-
- var selects string
- for _, selectKey := range android.SortedKeys(selectMap) {
- if selectKey == bazel.ConditionsDefaultSelectKey {
- // Handle default condition later.
- continue
- }
- value := selectMap[selectKey]
- if isZero(value) && !emitZeroValues && isZero(selectMap[bazel.ConditionsDefaultSelectKey]) {
- // Ignore zero values to not generate empty lists. However, always note zero values if
- // the default value is non-zero.
- continue
- }
- s, err := prettyPrintSelectEntry(value, selectKey, indent, true)
- if err != nil {
- return "", err
- }
- // s could still be an empty string, e.g. unset slices of structs with
- // length of 0.
- if s != "" {
- selects += s + ",\n"
- }
- }
-
- if len(selects) == 0 {
- // If there is a default value, and there are no selects for this axis, print that without any selects.
- if val, exists := selectMap[bazel.ConditionsDefaultSelectKey]; exists {
- return prettyPrint(val, indent, emitZeroValues)
- }
- // No conditions (or all values are empty lists), so no need for a map.
- return "", nil
- }
-
- // Create the map.
- ret := "select({\n"
- ret += selects
-
- // Handle the default condition
- s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent, emitZeroValues)
- if err != nil {
- return "", err
- }
- if s != "" {
- // Print the custom default value.
- ret += s
- ret += ",\n"
- } else if defaultValue != nil {
- // Print an explicit empty list (the default value) even if the value is
- // empty, to avoid errors about not finding a configuration that matches.
- ret += fmt.Sprintf("%s\"%s\": %s,\n", starlark_fmt.Indention(indent+1), bazel.ConditionsDefaultSelectKey, *defaultValue)
- }
-
- ret += starlark_fmt.Indention(indent)
- ret += "})"
-
- return ret, nil
-}
-
-// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
-// with a provided key.
-func prettyPrintSelectEntry(value reflect.Value, key string, indent int, emitZeroValues bool) (string, error) {
- s := starlark_fmt.Indention(indent + 1)
- v, err := prettyPrint(value, indent+1, emitZeroValues)
- if err != nil {
- return "", err
- }
- if v == "" {
- return "", nil
- }
- s += fmt.Sprintf("\"%s\": %s", key, v)
- return s, nil
-}
diff --git a/bp2build/constants.go b/bp2build/constants.go
deleted file mode 100644
index 4870dff..0000000
--- a/bp2build/constants.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2020 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-var (
- // When both a BUILD and BUILD.bazel file are exist in the same package, the BUILD.bazel file will
- // be preferred for use within a Bazel build.
-
- // The file name used for automatically generated files.
- GeneratedBuildFileName = "BUILD.bazel"
-
- // The file name used for hand-crafted build targets.
- // NOTE: It is okay that this matches GeneratedBuildFileName, since we generate BUILD files in a different directory to source files
- // FIXME: Because there are hundreds of existing BUILD.bazel files in the AOSP tree, we should pick another name here, like BUILD.android
- HandcraftedBuildFileName = "BUILD.bazel"
-)
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
deleted file mode 100644
index 9f1aa09..0000000
--- a/bp2build/conversion.go
+++ /dev/null
@@ -1,120 +0,0 @@
-package bp2build
-
-import (
- "reflect"
- "strings"
-
- "android/soong/android"
- "github.com/google/blueprint/proptools"
-)
-
-type BazelFile struct {
- Dir string
- Basename string
- Contents string
-}
-
-func CreateBazelFiles(ruleShims map[string]RuleShim, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
- var files []BazelFile
-
- if mode == QueryView {
- // Write top level WORKSPACE.
- files = append(files, newFile("", "WORKSPACE", ""))
-
- // Used to denote that the top level directory is a package.
- files = append(files, newFile("", GeneratedBuildFileName, ""))
-
- files = append(files, newFile(bazelRulesSubDir, GeneratedBuildFileName, ""))
-
- // These files are only used for queryview.
- files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl))
-
- for bzlFileName, ruleShim := range ruleShims {
- files = append(files, newFile(bazelRulesSubDir, bzlFileName+".bzl", ruleShim.content))
- }
- files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims)))
- }
-
- files = append(files, createBuildFiles(buildToTargets, mode)...)
-
- return files
-}
-
-func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
- files := make([]BazelFile, 0, len(buildToTargets))
- for _, dir := range android.SortedKeys(buildToTargets) {
- targets := buildToTargets[dir]
- targets.sort()
-
- var content string
- if mode == QueryView {
- content = soongModuleLoad
- }
- if content != "" {
- // If there are load statements, add a couple of newlines.
- content += "\n\n"
- }
- content += targets.String()
- files = append(files, newFile(dir, GeneratedBuildFileName, content))
- }
- return files
-}
-
-func newFile(dir, basename, content string) BazelFile {
- return BazelFile{
- Dir: dir,
- Basename: basename,
- Contents: content,
- }
-}
-
-const (
- bazelRulesSubDir = "build/bazel/queryview_rules"
-)
-
-var (
- // Certain module property names are blocklisted/ignored here, for the reasons commented.
- ignoredPropNames = map[string]bool{
- "name": true, // redundant, since this is explicitly generated for every target
- "from": true, // reserved keyword
- "in": true, // reserved keyword
- "size": true, // reserved for tests
- "arch": true, // interface prop type is not supported yet.
- "multilib": true, // interface prop type is not supported yet.
- "target": true, // interface prop type is not supported yet.
- "visibility": true, // Bazel has native visibility semantics. Handle later.
- "features": true, // There is already a built-in attribute 'features' which cannot be overridden.
- "for": true, // reserved keyword, b/233579439
- "versions_with_info": true, // TODO(b/245730552) struct properties not fully supported
- }
-)
-
-func shouldGenerateAttribute(prop string) bool {
- return !ignoredPropNames[prop]
-}
-
-func shouldSkipStructField(field reflect.StructField) bool {
- if field.PkgPath != "" && !field.Anonymous {
- // Skip unexported fields. Some properties are
- // internal to Soong only, and these fields do not have PkgPath.
- return true
- }
- // fields with tag `blueprint:"mutated"` are exported to enable modification in mutators, etc.
- // but cannot be set in a .bp file
- if proptools.HasTag(field, "blueprint", "mutated") {
- return true
- }
- return false
-}
-
-// FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as
-// testonly = True, forcing other rules that depend on _test rules to also be
-// marked as testonly = True. This semantic constraint is not present in Soong.
-// To work around, rename "*_test" rules to "*_test_".
-func canonicalizeModuleType(moduleName string) string {
- if strings.HasSuffix(moduleName, "_test") {
- return moduleName + "_"
- }
-
- return moduleName
-}
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
deleted file mode 100644
index 2f806fa..0000000
--- a/bp2build/conversion_test.go
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2020 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
- "sort"
- "testing"
-)
-
-type bazelFilepath struct {
- dir string
- basename string
-}
-
-func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) {
- files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, QueryView)
- expectedFilePaths := []bazelFilepath{
- {
- dir: "",
- basename: "BUILD.bazel",
- },
- {
- dir: "",
- basename: "WORKSPACE",
- },
- {
- dir: bazelRulesSubDir,
- basename: "BUILD.bazel",
- },
- {
- dir: bazelRulesSubDir,
- basename: "providers.bzl",
- },
- {
- dir: bazelRulesSubDir,
- basename: "soong_module.bzl",
- },
- }
-
- // Compare number of files
- if a, e := len(files), len(expectedFilePaths); a != e {
- t.Errorf("Expected %d files, got %d", e, a)
- }
-
- // Sort the files to be deterministic
- sort.Slice(files, func(i, j int) bool {
- if dir1, dir2 := files[i].Dir, files[j].Dir; dir1 == dir2 {
- return files[i].Basename < files[j].Basename
- } else {
- return dir1 < dir2
- }
- })
-
- // Compare the file contents
- for i := range files {
- actualFile, expectedFile := files[i], expectedFilePaths[i]
-
- if actualFile.Dir != expectedFile.dir || actualFile.Basename != expectedFile.basename {
- t.Errorf("Did not find expected file %s/%s", actualFile.Dir, actualFile.Basename)
- } else if actualFile.Basename == "BUILD.bazel" || actualFile.Basename == "WORKSPACE" {
- if actualFile.Contents != "" {
- t.Errorf("Expected %s to have no content.", actualFile)
- }
- } else if actualFile.Contents == "" {
- t.Errorf("Contents of %s unexpected empty.", actualFile)
- }
- }
-}
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 6445394..3f34382 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -56,6 +56,7 @@
)
func registerBpfBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("bpf_defaults", defaultsFactory)
ctx.RegisterModuleType("bpf", BpfFactory)
}
@@ -77,10 +78,16 @@
// the C/C++ module.
Cflags []string
- // directories (relative to the root of the source tree) that will
- // be added to the include paths using -I.
+ // list of directories relative to the root of the source tree that
+ // will be added to the include paths using -I.
+ // If possible, don't use this. If adding paths from the current
+ // directory, use local_include_dirs. If adding paths from other
+ // modules, use export_include_dirs in that module.
Include_dirs []string
+ // list of directories relative to the Blueprint file that will be
+ // added to the include path using -I.
+ Local_include_dirs []string
// optional subdirectory under which this module is installed into.
Sub_dir string
@@ -94,7 +101,7 @@
type bpf struct {
android.ModuleBase
-
+ android.DefaultableModuleBase
properties BpfProperties
objs android.Paths
@@ -102,41 +109,41 @@
var _ android.ImageInterface = (*bpf)(nil)
-func (bpf *bpf) ImageMutatorBegin(ctx android.BaseModuleContext) {}
+func (bpf *bpf) ImageMutatorBegin(ctx android.ImageInterfaceContext) {}
-func (bpf *bpf) VendorVariantNeeded(ctx android.BaseModuleContext) bool {
+func (bpf *bpf) VendorVariantNeeded(ctx android.ImageInterfaceContext) bool {
return proptools.Bool(bpf.properties.Vendor)
}
-func (bpf *bpf) ProductVariantNeeded(ctx android.BaseModuleContext) bool {
+func (bpf *bpf) ProductVariantNeeded(ctx android.ImageInterfaceContext) bool {
return false
}
-func (bpf *bpf) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+func (bpf *bpf) CoreVariantNeeded(ctx android.ImageInterfaceContext) bool {
return !proptools.Bool(bpf.properties.Vendor)
}
-func (bpf *bpf) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (bpf *bpf) RamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return false
}
-func (bpf *bpf) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (bpf *bpf) VendorRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return false
}
-func (bpf *bpf) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (bpf *bpf) DebugRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return false
}
-func (bpf *bpf) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
+func (bpf *bpf) RecoveryVariantNeeded(ctx android.ImageInterfaceContext) bool {
return false
}
-func (bpf *bpf) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+func (bpf *bpf) ExtraImageVariations(ctx android.ImageInterfaceContext) []string {
return nil
}
-func (bpf *bpf) SetImageVariation(ctx android.BaseModuleContext, variation string) {
+func (bpf *bpf) SetImageVariation(ctx android.ImageInterfaceContext, variation string) {
bpf.properties.VendorInternal = variation == "vendor"
}
@@ -157,12 +164,16 @@
// The architecture doesn't matter here, but asm/types.h is included by linux/types.h.
"-isystem bionic/libc/kernel/uapi/asm-arm64",
"-isystem bionic/libc/kernel/android/uapi",
- "-I packages/modules/Connectivity/staticlibs/native/bpf_headers/include/bpf",
+ "-I packages/modules/Connectivity/bpf/headers/include",
// TODO(b/149785767): only give access to specific file with AID_* constants
"-I system/core/libcutils/include",
"-I " + ctx.ModuleDir(),
}
+ for _, dir := range android.PathsForModuleSrc(ctx, bpf.properties.Local_include_dirs) {
+ cflags = append(cflags, "-I "+dir.String())
+ }
+
for _, dir := range android.PathsForSource(ctx, bpf.properties.Include_dirs) {
cflags = append(cflags, "-I "+dir.String())
}
@@ -219,8 +230,6 @@
ctx.PackageFile(installDir, obj.Base(), obj)
}
- android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
-
ctx.SetOutputFiles(bpf.objs, "")
}
@@ -264,6 +273,26 @@
}
}
+type Defaults struct {
+ android.ModuleBase
+ android.DefaultsModuleBase
+}
+
+func defaultsFactory() android.Module {
+ return DefaultsFactory()
+}
+
+func DefaultsFactory(props ...interface{}) android.Module {
+ module := &Defaults{}
+
+ module.AddProperties(props...)
+ module.AddProperties(&BpfProperties{})
+
+ android.InitDefaultsModule(module)
+
+ return module
+}
+
func (bpf *bpf) SubDir() string {
return bpf.properties.Sub_dir
}
@@ -274,5 +303,7 @@
module.AddProperties(&module.properties)
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+
return module
}
diff --git a/testing/code_metadata_internal_proto/Android.bp b/bpf/libbpf/Android.bp
similarity index 60%
copy from testing/code_metadata_internal_proto/Android.bp
copy to bpf/libbpf/Android.bp
index a534cc2..f0ba90f 100644
--- a/testing/code_metadata_internal_proto/Android.bp
+++ b/bpf/libbpf/Android.bp
@@ -1,29 +1,38 @@
-// Copyright 2022 Google Inc. All rights reserved.
+//
+// Copyright (C) 2024 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+//
package {
default_applicable_licenses: ["Android-Apache-2.0"],
}
bootstrap_go_package {
- name: "soong-testing-code_metadata_internal_proto",
- pkgPath: "android/soong/testing/code_metadata_internal_proto",
+ name: "soong-libbpf",
+ pkgPath: "android/soong/bpf/libbpf",
deps: [
- "golang-protobuf-reflect-protoreflect",
- "golang-protobuf-runtime-protoimpl",
- ],
- srcs: [
- "code_metadata_internal.pb.go",
+ "blueprint",
+ "blueprint-proptools",
+ "soong-android",
+ "soong-cc",
+ "soong-cc-config",
],
+ srcs: [
+ "libbpf_prog.go",
+ ],
+ testSrcs: [
+ "libbpf_prog_test.go",
+ ],
+ pluginFor: ["soong_build"],
}
diff --git a/bpf/libbpf/libbpf_prog.go b/bpf/libbpf/libbpf_prog.go
new file mode 100644
index 0000000..44013e5
--- /dev/null
+++ b/bpf/libbpf/libbpf_prog.go
@@ -0,0 +1,309 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package libbpf_prog
+
+import (
+ "fmt"
+ "io"
+ "runtime"
+ "strings"
+
+ "android/soong/android"
+ "android/soong/cc"
+ "android/soong/genrule"
+
+ "github.com/google/blueprint"
+)
+
+type libbpfProgDepType struct {
+ blueprint.BaseDependencyTag
+}
+
+func init() {
+ registerLibbpfProgBuildComponents(android.InitRegistrationContext)
+ pctx.Import("android/soong/cc/config")
+ pctx.StaticVariable("relPwd", cc.PwdPrefix())
+}
+
+var (
+ pctx = android.NewPackageContext("android/soong/bpf/libbpf_prog")
+
+ libbpfProgCcRule = pctx.AndroidStaticRule("libbpfProgCcRule",
+ blueprint.RuleParams{
+ Depfile: "${out}.d",
+ Deps: blueprint.DepsGCC,
+ Command: "$relPwd $ccCmd --target=bpf -c $cFlags -MD -MF ${out}.d -o $out $in",
+ CommandDeps: []string{"$ccCmd"},
+ },
+ "ccCmd", "cFlags")
+
+ libbpfProgStripRule = pctx.AndroidStaticRule("libbpfProgStripRule",
+ blueprint.RuleParams{
+ Command: `$stripCmd --strip-unneeded --remove-section=.rel.BTF ` +
+ `--remove-section=.rel.BTF.ext --remove-section=.BTF.ext $in -o $out`,
+ CommandDeps: []string{"$stripCmd"},
+ },
+ "stripCmd")
+
+ libbpfProgDepTag = libbpfProgDepType{}
+)
+
+func registerLibbpfProgBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("libbpf_defaults", defaultsFactory)
+ ctx.RegisterModuleType("libbpf_prog", LibbpfProgFactory)
+}
+
+var PrepareForTestWithLibbpfProg = android.GroupFixturePreparers(
+ android.FixtureRegisterWithContext(registerLibbpfProgBuildComponents),
+ android.FixtureAddFile("libbpf_headers/Foo.h", nil),
+ android.FixtureAddFile("libbpf_headers/Android.bp", []byte(`
+ genrule {
+ name: "libbpf_headers",
+ out: ["foo.h",],
+ }
+ `)),
+ genrule.PrepareForTestWithGenRuleBuildComponents,
+)
+
+type LibbpfProgProperties struct {
+ // source paths to the files.
+ Srcs []string `android:"path"`
+
+ // additional cflags that should be used to build the libbpf variant of
+ // the C/C++ module.
+ Cflags []string `android:"arch_variant"`
+
+ // list of directories relative to the Blueprint file that will
+ // be added to the include path using -I
+ Local_include_dirs []string `android:"arch_variant"`
+
+ Header_libs []string `android:"arch_variant"`
+
+ // optional subdirectory under which this module is installed into.
+ Relative_install_path string
+}
+
+type libbpfProg struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+ properties LibbpfProgProperties
+ objs android.Paths
+}
+
+var _ android.ImageInterface = (*libbpfProg)(nil)
+
+func (libbpf *libbpfProg) ImageMutatorBegin(ctx android.ImageInterfaceContext) {}
+
+func (libbpf *libbpfProg) VendorVariantNeeded(ctx android.ImageInterfaceContext) bool {
+ return false
+}
+
+func (libbpf *libbpfProg) ProductVariantNeeded(ctx android.ImageInterfaceContext) bool {
+ return false
+}
+
+func (libbpf *libbpfProg) CoreVariantNeeded(ctx android.ImageInterfaceContext) bool {
+ return true
+}
+
+func (libbpf *libbpfProg) RamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
+ return false
+}
+
+func (libbpf *libbpfProg) VendorRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
+ return false
+}
+
+func (libbpf *libbpfProg) DebugRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
+ return false
+}
+
+func (libbpf *libbpfProg) RecoveryVariantNeeded(ctx android.ImageInterfaceContext) bool {
+ return false
+}
+
+func (libbpf *libbpfProg) ExtraImageVariations(ctx android.ImageInterfaceContext) []string {
+ return nil
+}
+
+func (libbpf *libbpfProg) SetImageVariation(ctx android.ImageInterfaceContext, variation string) {
+}
+
+func (libbpf *libbpfProg) DepsMutator(ctx android.BottomUpMutatorContext) {
+ ctx.AddDependency(ctx.Module(), libbpfProgDepTag, "libbpf_headers")
+ ctx.AddVariationDependencies(nil, cc.HeaderDepTag(), libbpf.properties.Header_libs...)
+}
+
+func (libbpf *libbpfProg) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ var cFlagsDeps android.Paths
+ cflags := []string{
+ "-nostdlibinc",
+
+ // Make paths in deps files relative
+ "-no-canonical-prefixes",
+
+ "-O2",
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ // Flag to assist with the transition to libbpf
+ "-DENABLE_LIBBPF",
+ "-isystem bionic/libc/include",
+ "-isystem bionic/libc/kernel/uapi",
+ // The architecture doesn't matter here, but asm/types.h is included by linux/types.h.
+ "-isystem bionic/libc/kernel/uapi/asm-arm64",
+ "-isystem bionic/libc/kernel/android/uapi",
+ "-I " + ctx.ModuleDir(),
+ "-g", //Libbpf builds require BTF data
+ }
+
+ if runtime.GOOS != "darwin" {
+ cflags = append(cflags, "-fdebug-prefix-map=/proc/self/cwd=")
+ }
+
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ depTag := ctx.OtherModuleDependencyTag(dep)
+ if depTag == libbpfProgDepTag {
+ if genRule, ok := dep.(genrule.SourceFileGenerator); ok {
+ cFlagsDeps = append(cFlagsDeps, genRule.GeneratedDeps()...)
+ dirs := genRule.GeneratedHeaderDirs()
+ for _, dir := range dirs {
+ cflags = append(cflags, "-I "+dir.String())
+ }
+ } else {
+ depName := ctx.OtherModuleName(dep)
+ ctx.ModuleErrorf("module %q is not a genrule", depName)
+ }
+ } else if depTag == cc.HeaderDepTag() {
+ depExporterInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider)
+ for _, dir := range depExporterInfo.IncludeDirs {
+ cflags = append(cflags, "-I "+dir.String())
+ }
+ }
+ })
+
+ for _, dir := range android.PathsForModuleSrc(ctx, libbpf.properties.Local_include_dirs) {
+ cflags = append(cflags, "-I "+dir.String())
+ }
+
+ cflags = append(cflags, libbpf.properties.Cflags...)
+
+ srcs := android.PathsForModuleSrc(ctx, libbpf.properties.Srcs)
+
+ for _, src := range srcs {
+ if strings.ContainsRune(src.Base(), '_') {
+ ctx.ModuleErrorf("invalid character '_' in source name")
+ }
+ obj := android.ObjPathWithExt(ctx, "unstripped", src, "bpf")
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: libbpfProgCcRule,
+ Input: src,
+ Implicits: cFlagsDeps,
+ Output: obj,
+ Args: map[string]string{
+ "cFlags": strings.Join(cflags, " "),
+ "ccCmd": "${config.ClangBin}/clang",
+ },
+ })
+
+ objStripped := android.ObjPathWithExt(ctx, "", src, "bpf")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: libbpfProgStripRule,
+ Input: obj,
+ Output: objStripped,
+ Args: map[string]string{
+ "stripCmd": "${config.ClangBin}/llvm-strip",
+ },
+ })
+ libbpf.objs = append(libbpf.objs, objStripped.WithoutRel())
+ }
+
+ installDir := android.PathForModuleInstall(ctx, "etc", "bpf")
+ if len(libbpf.properties.Relative_install_path) > 0 {
+ installDir = installDir.Join(ctx, libbpf.properties.Relative_install_path)
+ }
+ for _, obj := range libbpf.objs {
+ ctx.PackageFile(installDir, obj.Base(), obj)
+ }
+
+ ctx.SetOutputFiles(libbpf.objs, "")
+}
+
+func (libbpf *libbpfProg) AndroidMk() android.AndroidMkData {
+ return android.AndroidMkData{
+ Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+ var names []string
+ fmt.Fprintln(w)
+ fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
+ fmt.Fprintln(w)
+ var localModulePath string
+ localModulePath = "LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/bpf"
+ if len(libbpf.properties.Relative_install_path) > 0 {
+ localModulePath += "/" + libbpf.properties.Relative_install_path
+ }
+ for _, obj := range libbpf.objs {
+ objName := name + "_" + obj.Base()
+ names = append(names, objName)
+ fmt.Fprintln(w, "include $(CLEAR_VARS)", " # libbpf.libbpf.obj")
+ fmt.Fprintln(w, "LOCAL_MODULE := ", objName)
+ fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", obj.String())
+ fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", obj.Base())
+ fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
+ fmt.Fprintln(w, localModulePath)
+ // AconfigUpdateAndroidMkData may have added elements to Extra. Process them here.
+ for _, extra := range data.Extra {
+ extra(w, nil)
+ }
+ fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
+ fmt.Fprintln(w)
+ }
+ fmt.Fprintln(w, "include $(CLEAR_VARS)", " # libbpf.libbpf")
+ fmt.Fprintln(w, "LOCAL_MODULE := ", name)
+ android.AndroidMkEmitAssignList(w, "LOCAL_REQUIRED_MODULES", names)
+ fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
+ },
+ }
+}
+
+type Defaults struct {
+ android.ModuleBase
+ android.DefaultsModuleBase
+}
+
+func defaultsFactory() android.Module {
+ return DefaultsFactory()
+}
+
+func DefaultsFactory(props ...interface{}) android.Module {
+ module := &Defaults{}
+
+ module.AddProperties(props...)
+ module.AddProperties(&LibbpfProgProperties{})
+
+ android.InitDefaultsModule(module)
+
+ return module
+}
+
+func LibbpfProgFactory() android.Module {
+ module := &libbpfProg{}
+
+ module.AddProperties(&module.properties)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ android.InitDefaultableModule(module)
+
+ return module
+}
diff --git a/bpf/libbpf/libbpf_prog_test.go b/bpf/libbpf/libbpf_prog_test.go
new file mode 100644
index 0000000..2b3b378
--- /dev/null
+++ b/bpf/libbpf/libbpf_prog_test.go
@@ -0,0 +1,70 @@
+// 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 libbpf_prog
+
+import (
+ "os"
+ "testing"
+
+ "android/soong/android"
+ "android/soong/cc"
+)
+
+func TestMain(m *testing.M) {
+ os.Exit(m.Run())
+}
+
+var prepareForLibbpfProgTest = android.GroupFixturePreparers(
+ cc.PrepareForTestWithCcDefaultModules,
+ android.FixtureMergeMockFs(
+ map[string][]byte{
+ "bpf.c": nil,
+ "bpf_invalid_name.c": nil,
+ "BpfTest.cpp": nil,
+ },
+ ),
+ PrepareForTestWithLibbpfProg,
+)
+
+func TestLibbpfProgDataDependency(t *testing.T) {
+ bp := `
+ libbpf_prog {
+ name: "bpf.bpf",
+ srcs: ["bpf.c"],
+ }
+
+ cc_test {
+ name: "vts_test_binary_bpf_module",
+ compile_multilib: "first",
+ srcs: ["BpfTest.cpp"],
+ data: [":bpf.bpf"],
+ gtest: false,
+ }
+ `
+
+ prepareForLibbpfProgTest.RunTestWithBp(t, bp)
+}
+
+func TestLibbpfProgSourceName(t *testing.T) {
+ bp := `
+ libbpf_prog {
+ name: "bpf_invalid_name.bpf",
+ srcs: ["bpf_invalid_name.c"],
+ }
+ `
+ prepareForLibbpfProgTest.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(
+ `invalid character '_' in source name`)).
+ RunTestWithBp(t, bp)
+}
diff --git a/build_kzip.bash b/build_kzip.bash
index 4c42048..850aeda 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -40,6 +40,7 @@
merge_zips
xref_cxx
xref_java
+ xref_kotlin
# TODO: b/286390153 - reenable rust
# xref_rust
)
diff --git a/build_test.bash b/build_test.bash
deleted file mode 100755
index defdd82..0000000
--- a/build_test.bash
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/bin/bash -eu
-#
-# Copyright 2017 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.
-
-#
-# This file is used in our continous build infrastructure to run a variety of
-# tests related to the build system.
-#
-# Currently, it's used to build and run multiproduct_kati, so it'll attempt
-# to build ninja files for every product in the tree. I expect this to
-# evolve as we find interesting things to test or track performance for.
-#
-
-# Products that are broken or otherwise don't work with multiproduct_kati
-SKIPPED_PRODUCTS=(
- # These products are for soong-only builds, and will fail the kati stage.
- linux_bionic
- mainline_sdk
- ndk
-
- # New architecture bringup, fails without ALLOW_MISSING_DEPENDENCIES=true
- aosp_riscv64
-)
-
-# To track how long we took to startup.
-case $(uname -s) in
- Darwin)
- export TRACE_BEGIN_SOONG=`$T/prebuilts/build-tools/path/darwin-x86/date +%s%3N`
- ;;
- *)
- export TRACE_BEGIN_SOONG=$(date +%s%N)
- ;;
-esac
-
-# Remove BUILD_NUMBER so that incremental builds on build servers don't
-# re-read makefiles every time.
-unset BUILD_NUMBER
-
-export TOP=$(cd $(dirname ${BASH_SOURCE[0]})/../..; PWD= /bin/pwd)
-cd "${TOP}"
-source "${TOP}/build/soong/scripts/microfactory.bash"
-
-case $(uname) in
- Linux)
- if [[ -f /lib/x86_64-linux-gnu/libSegFault.so ]]; then
- export LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so
- export SEGFAULT_USE_ALTSTACK=1
- fi
- ulimit -a
- ;;
-esac
-
-echo
-echo "Free disk space:"
-# Ignore df errors because it errors out on gvfsd file systems
-# but still displays most of the useful info we need
-df -h || true
-
-echo
-echo "Running Bazel smoke test..."
-STANDALONE_BAZEL=true "${TOP}/build/bazel/bin/bazel" --batch --max_idle_secs=1 help
-
-echo
-echo "Running Soong test..."
-soong_build_go multiproduct_kati android/soong/cmd/multiproduct_kati
-exec "$(getoutdir)/multiproduct_kati" --skip-products "$(echo "${SKIPPED_PRODUCTS[@]-}" | tr ' ' ',')" "$@"
diff --git a/cc/Android.bp b/cc/Android.bp
index e68e4a3..3b29ae8 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -7,6 +7,7 @@
pkgPath: "android/soong/cc",
deps: [
"blueprint",
+ "blueprint-depset",
"blueprint-pathtools",
"soong",
"soong-aconfig",
@@ -16,8 +17,6 @@
"soong-etc",
"soong-fuzz",
"soong-genrule",
- "soong-multitree",
- "soong-testing",
"soong-tradefed",
],
srcs: [
@@ -28,6 +27,7 @@
"builder.go",
"cc.go",
"ccdeps.go",
+ "cc_preprocess_no_configuration.go",
"check.go",
"coverage.go",
"gen.go",
@@ -65,7 +65,6 @@
"library.go",
"library_headers.go",
"library_sdk_member.go",
- "library_stub.go",
"native_bridge_sdk_trait.go",
"object.go",
"test.go",
@@ -90,6 +89,7 @@
testSrcs: [
"afdo_test.go",
"binary_test.go",
+ "cc_preprocess_no_configuration_test.go",
"cc_test.go",
"cc_test_only_property_test.go",
"cmake_snapshot_test.go",
@@ -104,6 +104,7 @@
"orderfile_test.go",
"prebuilt_test.go",
"proto_test.go",
+ "sabi_test.go",
"sanitize_test.go",
"sdk_test.go",
"test_data_test.go",
@@ -118,4 +119,34 @@
"cmake_module_cc.txt",
],
pluginFor: ["soong_build"],
+ // Used by plugins
+ visibility: ["//visibility:public"],
+}
+
+phony {
+ name: "llndk_libs",
+ required: [
+ "libEGL",
+ "libGLESv1_CM",
+ "libGLESv2",
+ "libGLESv3",
+ "libRS",
+ "libandroid_net",
+ "libapexsupport",
+ "libbinder_ndk",
+ "libc",
+ "libcgrouprc",
+ "libclang_rt.asan",
+ "libdl",
+ "libft2",
+ "liblog",
+ "libm",
+ "libmediandk",
+ "libnativewindow",
+ "libselinux",
+ "libsync",
+ "libvendorsupport",
+ "libvndksupport",
+ "libvulkan",
+ ],
}
diff --git a/cc/TEST_MAPPING b/cc/TEST_MAPPING
new file mode 100644
index 0000000..be2809d
--- /dev/null
+++ b/cc/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "bionic"
+ }
+ ]
+}
diff --git a/cc/afdo.go b/cc/afdo.go
index 14d105e..828e494 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -65,8 +65,8 @@
}
func getFdoProfilePathFromDep(ctx ModuleContext) string {
- fdoProfileDeps := ctx.GetDirectDepsWithTag(FdoProfileTag)
- if len(fdoProfileDeps) > 0 && fdoProfileDeps[0] != nil {
+ fdoProfileDeps := ctx.GetDirectDepsProxyWithTag(FdoProfileTag)
+ if len(fdoProfileDeps) > 0 {
if info, ok := android.OtherModuleProvider(ctx, fdoProfileDeps[0], FdoProfileProvider); ok {
return info.Path.String()
}
@@ -163,7 +163,7 @@
}
// TODO(b/324141705): this is designed to prevent propagating AFDO from static libraries that have afdo: true set, but
- // it should be m.static() && !m.staticBinary() so that static binaries use AFDO variants of dependencies.
+ // it should be m.staticLibrary() so that static binaries use AFDO variants of dependencies.
if m.static() {
return ""
}
@@ -188,7 +188,7 @@
if variation == "" {
// The empty variation is either a module that has enabled AFDO for itself, or the non-AFDO
// variant of a dependency.
- if m.afdo.afdoEnabled() && !(m.static() && !m.staticBinary()) && !m.Host() {
+ if m.afdo.afdoEnabled() && !m.staticLibrary() && !m.Host() {
m.afdo.addDep(ctx, ctx.ModuleName())
}
} else {
diff --git a/cc/androidmk.go b/cc/androidmk.go
index cecaae2..03f229e 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -21,7 +21,6 @@
"strings"
"android/soong/android"
- "android/soong/multitree"
)
var (
@@ -37,7 +36,7 @@
type AndroidMkContext interface {
BaseModuleName() string
Target() android.Target
- subAndroidMk(*android.AndroidMkEntries, interface{})
+ subAndroidMk(android.Config, *android.AndroidMkInfo, interface{})
Arch() android.Arch
Os() android.OsType
Host() bool
@@ -49,112 +48,124 @@
InRecovery() bool
NotInPlatform() bool
InVendorOrProduct() bool
+ ArchSpecific() bool
}
-type subAndroidMkProvider interface {
- AndroidMkEntries(AndroidMkContext, *android.AndroidMkEntries)
+type subAndroidMkProviderInfoProducer interface {
+ prepareAndroidMKProviderInfo(android.Config, AndroidMkContext, *android.AndroidMkInfo)
}
-func (c *Module) subAndroidMk(entries *android.AndroidMkEntries, obj interface{}) {
+type subAndroidMkFooterInfoProducer interface {
+ prepareAndroidMKFooterInfo(android.Config, AndroidMkContext, *android.AndroidMkInfo)
+}
+
+func (c *Module) subAndroidMk(config android.Config, entries *android.AndroidMkInfo, obj interface{}) {
if c.subAndroidMkOnce == nil {
- c.subAndroidMkOnce = make(map[subAndroidMkProvider]bool)
+ c.subAndroidMkOnce = make(map[subAndroidMkProviderInfoProducer]bool)
}
- if androidmk, ok := obj.(subAndroidMkProvider); ok {
+ if androidmk, ok := obj.(subAndroidMkProviderInfoProducer); ok {
if !c.subAndroidMkOnce[androidmk] {
c.subAndroidMkOnce[androidmk] = true
- androidmk.AndroidMkEntries(c, entries)
+ androidmk.prepareAndroidMKProviderInfo(config, c, entries)
}
}
}
-func (c *Module) AndroidMkEntries() []android.AndroidMkEntries {
+var _ android.AndroidMkProviderInfoProducer = (*Module)(nil)
+
+func (c *Module) PrepareAndroidMKProviderInfo(config android.Config) *android.AndroidMkProviderInfo {
if c.hideApexVariantFromMake || c.Properties.HideFromMake {
- return []android.AndroidMkEntries{{
- Disabled: true,
- }}
+ return &android.AndroidMkProviderInfo{
+ PrimaryInfo: android.AndroidMkInfo{
+ Disabled: true,
+ },
+ }
}
- entries := android.AndroidMkEntries{
- OutputFile: c.outputFile,
- // TODO(jiyong): add the APEXes providing shared libs to the required
- // modules Currently, adding c.Properties.ApexesProvidingSharedLibs is
- // causing multiple ART APEXes (com.android.art and com.android.art.debug)
- // to be installed. And this is breaking some older devices (like marlin)
- // where system.img is small.
- Required: c.Properties.AndroidMkRuntimeLibs,
- OverrideName: c.BaseModuleName(),
- Include: "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk",
-
- ExtraEntries: []android.AndroidMkExtraEntriesFunc{
- func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- if len(c.Properties.Logtags) > 0 {
- entries.AddStrings("LOCAL_SOONG_LOGTAGS_FILES", c.logtagsPaths.Strings()...)
- }
- // Note: Pass the exact value of AndroidMkSystemSharedLibs to the Make
- // world, even if it is an empty list. In the Make world,
- // LOCAL_SYSTEM_SHARED_LIBRARIES defaults to "none", which is expanded
- // to the default list of system shared libs by the build system.
- // Soong computes the exact list of system shared libs, so we have to
- // override the default value when the list of libs is actually empty.
- entries.SetString("LOCAL_SYSTEM_SHARED_LIBRARIES", strings.Join(c.Properties.AndroidMkSystemSharedLibs, " "))
- if len(c.Properties.AndroidMkSharedLibs) > 0 {
- entries.AddStrings("LOCAL_SHARED_LIBRARIES", c.Properties.AndroidMkSharedLibs...)
- }
- if len(c.Properties.AndroidMkRuntimeLibs) > 0 {
- entries.AddStrings("LOCAL_RUNTIME_LIBRARIES", c.Properties.AndroidMkRuntimeLibs...)
- }
- entries.SetString("LOCAL_SOONG_LINK_TYPE", c.makeLinkType)
- if c.InVendor() {
- entries.SetBool("LOCAL_IN_VENDOR", true)
- } else if c.InProduct() {
- entries.SetBool("LOCAL_IN_PRODUCT", true)
- }
- if c.Properties.SdkAndPlatformVariantVisibleToMake {
- // Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite
- // dependencies to the .sdk suffix when building a module that uses the SDK.
- entries.SetString("SOONG_SDK_VARIANT_MODULES",
- "$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))")
- }
- entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", c.IsSkipInstall())
- },
- },
- ExtraFooters: []android.AndroidMkExtraFootersFunc{
- func(w io.Writer, name, prefix, moduleDir string) {
- if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake &&
- c.CcLibraryInterface() && c.Shared() {
- // Using the SDK variant as a JNI library needs a copy of the .so that
- // is not named .sdk.so so that it can be packaged into the APK with
- // the right name.
- fmt.Fprintln(w, "$(eval $(call copy-one-file,",
- "$(LOCAL_BUILT_MODULE),",
- "$(patsubst %.sdk.so,%.so,$(LOCAL_BUILT_MODULE))))")
- }
- },
+ providerData := android.AndroidMkProviderInfo{
+ PrimaryInfo: android.AndroidMkInfo{
+ OutputFile: c.outputFile,
+ Required: c.Properties.AndroidMkRuntimeLibs,
+ OverrideName: c.BaseModuleName(),
+ Include: "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk",
+ EntryMap: make(map[string][]string),
},
}
+ entries := &providerData.PrimaryInfo
+ if len(c.Properties.Logtags) > 0 {
+ entries.AddStrings("LOCAL_SOONG_LOGTAGS_FILES", c.logtagsPaths.Strings()...)
+ }
+ // Note: Pass the exact value of AndroidMkSystemSharedLibs to the Make
+ // world, even if it is an empty list. In the Make world,
+ // LOCAL_SYSTEM_SHARED_LIBRARIES defaults to "none", which is expanded
+ // to the default list of system shared libs by the build system.
+ // Soong computes the exact list of system shared libs, so we have to
+ // override the default value when the list of libs is actually empty.
+ entries.SetString("LOCAL_SYSTEM_SHARED_LIBRARIES", strings.Join(c.Properties.AndroidMkSystemSharedLibs, " "))
+ if len(c.Properties.AndroidMkSharedLibs) > 0 {
+ entries.AddStrings("LOCAL_SHARED_LIBRARIES", c.Properties.AndroidMkSharedLibs...)
+ }
+ if len(c.Properties.AndroidMkRuntimeLibs) > 0 {
+ entries.AddStrings("LOCAL_RUNTIME_LIBRARIES", c.Properties.AndroidMkRuntimeLibs...)
+ }
+ entries.SetString("LOCAL_SOONG_LINK_TYPE", c.makeLinkType)
+ if c.InVendor() {
+ entries.SetBool("LOCAL_IN_VENDOR", true)
+ } else if c.InProduct() {
+ entries.SetBool("LOCAL_IN_PRODUCT", true)
+ }
+ if c.Properties.SdkAndPlatformVariantVisibleToMake {
+ // Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite
+ // dependencies to the .sdk suffix when building a module that uses the SDK.
+ entries.SetString("SOONG_SDK_VARIANT_MODULES",
+ "$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))")
+ }
+ entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", c.IsSkipInstall())
+
for _, feature := range c.features {
- c.subAndroidMk(&entries, feature)
+ c.subAndroidMk(config, entries, feature)
}
- c.subAndroidMk(&entries, c.compiler)
- c.subAndroidMk(&entries, c.linker)
+ c.subAndroidMk(config, entries, c.compiler)
+ c.subAndroidMk(config, entries, c.linker)
if c.sanitize != nil {
- c.subAndroidMk(&entries, c.sanitize)
+ c.subAndroidMk(config, entries, c.sanitize)
}
- c.subAndroidMk(&entries, c.installer)
+ c.subAndroidMk(config, entries, c.installer)
entries.SubName += c.Properties.SubName
- return []android.AndroidMkEntries{entries}
+ // The footer info comes at the last step, previously it was achieved by
+ // calling some extra footer function that were added earlier. Because we no
+ // longer use these extra footer functions, we need to put this step at the
+ // last one.
+ if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake &&
+ c.CcLibraryInterface() && c.Shared() {
+ // Using the SDK variant as a JNI library needs a copy of the .so that
+ // is not named .sdk.so so that it can be packaged into the APK with
+ // the right name.
+ entries.FooterStrings = []string{
+ fmt.Sprintf("%s %s %s", "$(eval $(call copy-one-file,",
+ "$(LOCAL_BUILT_MODULE),",
+ "$(patsubst %.sdk.so,%.so,$(LOCAL_BUILT_MODULE))))")}
+ }
+
+ for _, obj := range []interface{}{c.compiler, c.linker, c.sanitize, c.installer} {
+ if obj == nil {
+ continue
+ }
+ if p, ok := obj.(subAndroidMkFooterInfoProducer); ok {
+ p.prepareAndroidMKFooterInfo(config, c, entries)
+ }
+ }
+
+ return &providerData
}
-func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkEntries) {
+func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkInfo) {
if len(extraTestConfigs) > 0 {
- entries.ExtraEntries = append(entries.ExtraEntries,
- func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", extraTestConfigs.Strings()...)
- })
+ entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", extraTestConfigs.Strings()...)
}
}
@@ -170,7 +181,7 @@
return overrides
}
-func (library *libraryDecorator) androidMkWriteExportedFlags(entries *android.AndroidMkEntries) {
+func (library *libraryDecorator) androidMkWriteExportedFlags(entries *android.AndroidMkInfo) {
var exportedFlags []string
var includeDirs android.Paths
var systemIncludeDirs android.Paths
@@ -201,7 +212,7 @@
}
}
-func (library *libraryDecorator) androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries *android.AndroidMkEntries) {
+func (library *libraryDecorator) androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries *android.AndroidMkInfo) {
if !library.static() {
entries.AddPaths("LOCAL_ADDITIONAL_DEPENDENCIES", library.sAbiDiff)
}
@@ -214,23 +225,21 @@
}
}
-func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+func (library *libraryDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
if library.static() {
entries.Class = "STATIC_LIBRARIES"
} else if library.shared() {
entries.Class = "SHARED_LIBRARIES"
- entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_SOONG_TOC", library.toc().String())
- if !library.buildStubs() && library.unstrippedOutputFile != nil {
- entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", library.unstrippedOutputFile.String())
- }
- if len(library.Properties.Overrides) > 0 {
- entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, library.Properties.Overrides), " "))
- }
- if len(library.postInstallCmds) > 0 {
- entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(library.postInstallCmds, "&& "))
- }
- })
+ entries.SetString("LOCAL_SOONG_TOC", library.toc().String())
+ if !library.BuildStubs() && library.unstrippedOutputFile != nil {
+ entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", library.unstrippedOutputFile.String())
+ }
+ if len(library.Properties.Overrides) > 0 {
+ entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, library.Properties.Overrides), " "))
+ }
+ if len(library.postInstallCmds) > 0 {
+ entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(library.postInstallCmds, "&& "))
+ }
} else if library.header() {
entries.Class = "HEADER_LIBRARIES"
}
@@ -239,34 +248,30 @@
entries.DistFiles = android.MakeDefaultDistFiles(library.distFile)
}
- entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- library.androidMkWriteExportedFlags(entries)
- library.androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries)
+ library.androidMkWriteExportedFlags(entries)
+ library.androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries)
- if entries.OutputFile.Valid() {
- _, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base())
- entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
- }
+ if entries.OutputFile.Valid() {
+ _, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base())
+ entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+ }
- if library.coverageOutputFile.Valid() {
- entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", library.coverageOutputFile.String())
- }
- })
+ if library.coverageOutputFile.Valid() {
+ entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", library.coverageOutputFile.String())
+ }
- if library.shared() && !library.buildStubs() {
- ctx.subAndroidMk(entries, library.baseInstaller)
+ if library.shared() && !library.BuildStubs() {
+ ctx.subAndroidMk(config, entries, library.baseInstaller)
} else {
- if library.buildStubs() && library.stubsVersion() != "" {
- entries.SubName = "." + library.stubsVersion()
+ if library.BuildStubs() && library.StubsVersion() != "" {
+ entries.SubName = "." + library.StubsVersion()
}
- entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- // library.makeUninstallable() depends on this to bypass HideFromMake() for
- // static libraries.
- entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
- if library.buildStubs() {
- entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
- }
- })
+ // library.makeUninstallable() depends on this to bypass HideFromMake() for
+ // static libraries.
+ entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+ if library.BuildStubs() {
+ entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
+ }
}
// If a library providing a stub is included in an APEX, the private APIs of the library
// is accessible only inside the APEX. From outside of the APEX, clients can only use the
@@ -276,248 +281,222 @@
// very early stage in the boot process).
if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.NotInPlatform() &&
!ctx.InRamdisk() && !ctx.InVendorRamdisk() && !ctx.InRecovery() && !ctx.InVendorOrProduct() && !ctx.static() {
- if library.buildStubs() && library.isLatestStubVersion() {
+ if library.BuildStubs() && library.isLatestStubVersion() {
entries.SubName = ""
}
- if !library.buildStubs() {
+ if !library.BuildStubs() {
entries.SubName = ".bootstrap"
}
}
}
-func (object *objectLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+func (object *objectLinker) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
entries.Class = "STATIC_LIBRARIES"
- entries.ExtraFooters = append(entries.ExtraFooters,
- func(w io.Writer, name, prefix, moduleDir string) {
- out := entries.OutputFile.Path()
- varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, entries.SubName)
-
- fmt.Fprintf(w, "\n%s := %s\n", varname, out.String())
- fmt.Fprintln(w, ".KATI_READONLY: "+varname)
- })
}
-func (test *testDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
- entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- if len(test.InstallerProperties.Test_suites) > 0 {
- entries.AddCompatibilityTestSuites(test.InstallerProperties.Test_suites...)
+func (object *objectLinker) prepareAndroidMKFooterInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
+ out := entries.OutputFile.Path()
+ name := ctx.BaseModuleName()
+ if entries.OverrideName != "" {
+ name = entries.OverrideName
+ }
+
+ prefix := ""
+ if ctx.ArchSpecific() {
+ switch ctx.Os().Class {
+ case android.Host:
+ if ctx.Target().HostCross {
+ prefix = "HOST_CROSS_"
+ } else {
+ prefix = "HOST_"
+ }
+ case android.Device:
+ prefix = "TARGET_"
+
}
- })
+
+ if ctx.Arch().ArchType != config.Targets[ctx.Os()][0].Arch.ArchType {
+ prefix = "2ND_" + prefix
+ }
+ }
+
+ varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, entries.SubName)
+
+ entries.FooterStrings = append(entries.FooterStrings,
+ fmt.Sprintf("\n%s := %s\n.KATI_READONLY: %s", varname, out.String(), varname))
}
-func (binary *binaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
- ctx.subAndroidMk(entries, binary.baseInstaller)
+func (test *testDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
+ if len(test.InstallerProperties.Test_suites) > 0 {
+ entries.AddCompatibilityTestSuites(test.InstallerProperties.Test_suites...)
+ }
+}
+
+func (binary *binaryDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
+ ctx.subAndroidMk(config, entries, binary.baseInstaller)
entries.Class = "EXECUTABLES"
entries.DistFiles = binary.distFiles
- entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", binary.unstrippedOutputFile.String())
- if len(binary.symlinks) > 0 {
- entries.AddStrings("LOCAL_MODULE_SYMLINKS", binary.symlinks...)
- }
+ entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", binary.unstrippedOutputFile.String())
+ if len(binary.symlinks) > 0 {
+ entries.AddStrings("LOCAL_MODULE_SYMLINKS", binary.symlinks...)
+ }
- if binary.coverageOutputFile.Valid() {
- entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", binary.coverageOutputFile.String())
- }
+ if binary.coverageOutputFile.Valid() {
+ entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", binary.coverageOutputFile.String())
+ }
- if len(binary.Properties.Overrides) > 0 {
- entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, binary.Properties.Overrides), " "))
- }
- if len(binary.postInstallCmds) > 0 {
- entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(binary.postInstallCmds, "&& "))
- }
- })
+ if len(binary.Properties.Overrides) > 0 {
+ entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, binary.Properties.Overrides), " "))
+ }
+ if len(binary.postInstallCmds) > 0 {
+ entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(binary.postInstallCmds, "&& "))
+ }
}
-func (benchmark *benchmarkDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
- ctx.subAndroidMk(entries, benchmark.binaryDecorator)
+func (benchmark *benchmarkDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
+ ctx.subAndroidMk(config, entries, benchmark.binaryDecorator)
entries.Class = "NATIVE_TESTS"
- entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- if len(benchmark.Properties.Test_suites) > 0 {
- entries.AddCompatibilityTestSuites(benchmark.Properties.Test_suites...)
- }
- if benchmark.testConfig != nil {
- entries.SetString("LOCAL_FULL_TEST_CONFIG", benchmark.testConfig.String())
- }
- entries.SetBool("LOCAL_NATIVE_BENCHMARK", true)
- if !BoolDefault(benchmark.Properties.Auto_gen_config, true) {
- entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
- }
- })
+ if len(benchmark.Properties.Test_suites) > 0 {
+ entries.AddCompatibilityTestSuites(benchmark.Properties.Test_suites...)
+ }
+ if benchmark.testConfig != nil {
+ entries.SetString("LOCAL_FULL_TEST_CONFIG", benchmark.testConfig.String())
+ }
+ entries.SetBool("LOCAL_NATIVE_BENCHMARK", true)
+ if !BoolDefault(benchmark.Properties.Auto_gen_config, true) {
+ entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
+ }
}
-func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
- ctx.subAndroidMk(entries, test.binaryDecorator)
- ctx.subAndroidMk(entries, test.testDecorator)
+func (test *testBinary) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
+ ctx.subAndroidMk(config, entries, test.binaryDecorator)
+ ctx.subAndroidMk(config, entries, test.testDecorator)
entries.Class = "NATIVE_TESTS"
- entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- if test.testConfig != nil {
- entries.SetString("LOCAL_FULL_TEST_CONFIG", test.testConfig.String())
- }
- if !BoolDefault(test.Properties.Auto_gen_config, true) {
- entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
- }
- entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", test.Properties.Test_mainline_modules...)
+ if test.testConfig != nil {
+ entries.SetString("LOCAL_FULL_TEST_CONFIG", test.testConfig.String())
+ }
+ if !BoolDefault(test.Properties.Auto_gen_config, true) {
+ entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
+ }
+ entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", test.Properties.Test_mainline_modules...)
- entries.SetBoolIfTrue("LOCAL_COMPATIBILITY_PER_TESTCASE_DIRECTORY", Bool(test.Properties.Per_testcase_directory))
- if len(test.Properties.Data_bins) > 0 {
- entries.AddStrings("LOCAL_TEST_DATA_BINS", test.Properties.Data_bins...)
- }
+ entries.SetBoolIfTrue("LOCAL_COMPATIBILITY_PER_TESTCASE_DIRECTORY", Bool(test.Properties.Per_testcase_directory))
+ if len(test.Properties.Data_bins) > 0 {
+ entries.AddStrings("LOCAL_TEST_DATA_BINS", test.Properties.Data_bins...)
+ }
- test.Properties.Test_options.CommonTestOptions.SetAndroidMkEntries(entries)
- })
+ test.Properties.Test_options.CommonTestOptions.SetAndroidMkInfoEntries(entries)
androidMkWriteExtraTestConfigs(test.extraTestConfigs, entries)
}
-func (fuzz *fuzzBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
- ctx.subAndroidMk(entries, fuzz.binaryDecorator)
+func (fuzz *fuzzBinary) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
+ ctx.subAndroidMk(config, entries, fuzz.binaryDecorator)
- entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetBool("LOCAL_IS_FUZZ_TARGET", true)
- if fuzz.installedSharedDeps != nil {
- // TOOD: move to install dep
- entries.AddStrings("LOCAL_FUZZ_INSTALLED_SHARED_DEPS", fuzz.installedSharedDeps...)
- }
- })
+ entries.SetBool("LOCAL_IS_FUZZ_TARGET", true)
+ if fuzz.installedSharedDeps != nil {
+ // TOOD: move to install dep
+ entries.AddStrings("LOCAL_FUZZ_INSTALLED_SHARED_DEPS", fuzz.installedSharedDeps...)
+ }
}
-func (test *testLibrary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
- ctx.subAndroidMk(entries, test.libraryDecorator)
- ctx.subAndroidMk(entries, test.testDecorator)
+func (test *testLibrary) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
+ ctx.subAndroidMk(config, entries, test.libraryDecorator)
+ ctx.subAndroidMk(config, entries, test.testDecorator)
}
-func (installer *baseInstaller) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+func (installer *baseInstaller) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
if installer.path == (android.InstallPath{}) {
return
}
- entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- path, file := filepath.Split(installer.path.String())
- stem, suffix, _ := android.SplitFileExt(file)
- entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
- entries.SetString("LOCAL_MODULE_PATH", path)
- entries.SetString("LOCAL_MODULE_STEM", stem)
- })
+ path, file := filepath.Split(installer.path.String())
+ stem, suffix, _ := android.SplitFileExt(file)
+ entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+ entries.SetString("LOCAL_MODULE_PATH", path)
+ entries.SetString("LOCAL_MODULE_STEM", stem)
}
-func (c *stubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+func (c *stubDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
entries.SubName = ndkLibrarySuffix + "." + c.apiLevel.String()
entries.Class = "SHARED_LIBRARIES"
- if !c.buildStubs() {
+ if !c.BuildStubs() {
entries.Disabled = true
return
}
- entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- path, file := filepath.Split(c.installPath.String())
- stem, suffix, _ := android.SplitFileExt(file)
- entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
- entries.SetString("LOCAL_MODULE_PATH", path)
- entries.SetString("LOCAL_MODULE_STEM", stem)
- entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
- if c.parsedCoverageXmlPath.String() != "" {
- entries.SetString("SOONG_NDK_API_XML", "$(SOONG_NDK_API_XML) "+c.parsedCoverageXmlPath.String())
- }
- entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) // Stubs should not be installed
- })
+ path, file := filepath.Split(c.installPath.String())
+ stem, suffix, _ := android.SplitFileExt(file)
+ entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+ entries.SetString("LOCAL_MODULE_PATH", path)
+ entries.SetString("LOCAL_MODULE_STEM", stem)
+ entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
+ if c.parsedCoverageXmlPath.String() != "" {
+ entries.SetString("SOONG_NDK_API_XML", "$(SOONG_NDK_API_XML) "+c.parsedCoverageXmlPath.String())
+ }
+ entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) // Stubs should not be installed
}
-func (c *vndkPrebuiltLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+func (c *vndkPrebuiltLibraryDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
entries.Class = "SHARED_LIBRARIES"
entries.SubName = c.androidMkSuffix
- entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- c.libraryDecorator.androidMkWriteExportedFlags(entries)
+ c.libraryDecorator.androidMkWriteExportedFlags(entries)
- // Specifying stem is to pass check_elf_files when vendor modules link against vndk prebuilt.
- // We can't use install path because VNDKs are not installed. Instead, Srcs is directly used.
- _, file := filepath.Split(c.properties.Srcs[0])
- stem, suffix, ext := android.SplitFileExt(file)
- entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
- entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
- entries.SetString("LOCAL_MODULE_STEM", stem)
+ // Specifying stem is to pass check_elf_files when vendor modules link against vndk prebuilt.
+ // We can't use install path because VNDKs are not installed. Instead, Srcs is directly used.
+ _, file := filepath.Split(c.properties.Srcs[0])
+ stem, suffix, ext := android.SplitFileExt(file)
+ entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+ entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+ entries.SetString("LOCAL_MODULE_STEM", stem)
- if c.tocFile.Valid() {
- entries.SetString("LOCAL_SOONG_TOC", c.tocFile.String())
- }
+ if c.tocFile.Valid() {
+ entries.SetString("LOCAL_SOONG_TOC", c.tocFile.String())
+ }
- // VNDK libraries available to vendor are not installed because
- // they are packaged in VNDK APEX and installed by APEX packages (apex/apex.go)
- entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
- })
+ // VNDK libraries available to vendor are not installed because
+ // they are packaged in VNDK APEX and installed by APEX packages (apex/apex.go)
+ entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
}
-func (p *prebuiltLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
- entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- if p.properties.Check_elf_files != nil {
- entries.SetBool("LOCAL_CHECK_ELF_FILES", *p.properties.Check_elf_files)
- } else {
- // soong_cc_rust_prebuilt.mk does not include check_elf_file.mk by default
- // because cc_library_shared and cc_binary use soong_cc_rust_prebuilt.mk as well.
- // In order to turn on prebuilt ABI checker, set `LOCAL_CHECK_ELF_FILES` to
- // true if `p.properties.Check_elf_files` is not specified.
- entries.SetBool("LOCAL_CHECK_ELF_FILES", true)
- }
- })
+func (p *prebuiltLinker) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
+ if p.properties.Check_elf_files != nil {
+ entries.SetBool("LOCAL_CHECK_ELF_FILES", *p.properties.Check_elf_files)
+ } else {
+ // soong_cc_rust_prebuilt.mk does not include check_elf_file.mk by default
+ // because cc_library_shared and cc_binary use soong_cc_rust_prebuilt.mk as well.
+ // In order to turn on prebuilt ABI checker, set `LOCAL_CHECK_ELF_FILES` to
+ // true if `p.properties.Check_elf_files` is not specified.
+ entries.SetBool("LOCAL_CHECK_ELF_FILES", true)
+ }
}
-func (p *prebuiltLibraryLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
- ctx.subAndroidMk(entries, p.libraryDecorator)
+func (p *prebuiltLibraryLinker) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
+ ctx.subAndroidMk(config, entries, p.libraryDecorator)
if p.shared() {
- ctx.subAndroidMk(entries, &p.prebuiltLinker)
+ ctx.subAndroidMk(config, entries, &p.prebuiltLinker)
androidMkWritePrebuiltOptions(p.baseLinker, entries)
}
}
-func (p *prebuiltBinaryLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
- ctx.subAndroidMk(entries, p.binaryDecorator)
- ctx.subAndroidMk(entries, &p.prebuiltLinker)
+func (p *prebuiltBinaryLinker) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
+ ctx.subAndroidMk(config, entries, p.binaryDecorator)
+ ctx.subAndroidMk(config, entries, &p.prebuiltLinker)
androidMkWritePrebuiltOptions(p.baseLinker, entries)
}
-func (a *apiLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
- entries.Class = "SHARED_LIBRARIES"
- entries.SubName += multitree.GetApiImportSuffix()
-
- entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- a.libraryDecorator.androidMkWriteExportedFlags(entries)
- src := *a.properties.Src
- path, file := filepath.Split(src)
- stem, suffix, ext := android.SplitFileExt(file)
- entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
- entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
- entries.SetString("LOCAL_MODULE_STEM", stem)
- entries.SetString("LOCAL_MODULE_PATH", path)
- entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
- entries.SetString("LOCAL_SOONG_TOC", a.toc().String())
- })
-}
-
-func (a *apiHeadersDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
- entries.Class = "HEADER_LIBRARIES"
- entries.SubName += multitree.GetApiImportSuffix()
-
- entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- a.libraryDecorator.androidMkWriteExportedFlags(entries)
- entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
- })
-}
-
-func androidMkWritePrebuiltOptions(linker *baseLinker, entries *android.AndroidMkEntries) {
+func androidMkWritePrebuiltOptions(linker *baseLinker, entries *android.AndroidMkInfo) {
allow := linker.Properties.Allow_undefined_symbols
if allow != nil {
- entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetBool("LOCAL_ALLOW_UNDEFINED_SYMBOLS", *allow)
- })
+ entries.SetBool("LOCAL_ALLOW_UNDEFINED_SYMBOLS", *allow)
}
ignore := linker.Properties.Ignore_max_page_size
if ignore != nil {
- entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetBool("LOCAL_IGNORE_MAX_PAGE_SIZE", *ignore)
- })
+ entries.SetBool("LOCAL_IGNORE_MAX_PAGE_SIZE", *ignore)
}
}
diff --git a/cc/api_level.go b/cc/api_level.go
index 69a0d3a..deca723 100644
--- a/cc/api_level.go
+++ b/cc/api_level.go
@@ -41,12 +41,25 @@
}
}
-func nativeApiLevelFromUser(ctx android.BaseModuleContext,
- raw string) (android.ApiLevel, error) {
+// Native API levels cannot be less than the MinApiLevelForArch. This function
+// sets the lower bound of the API level with the MinApiLevelForArch.
+func nativeClampedApiLevel(ctx android.BaseModuleContext,
+ apiLevel android.ApiLevel) android.ApiLevel {
min := MinApiForArch(ctx, ctx.Arch().ArchType)
+
+ if apiLevel.LessThan(min) {
+ return min
+ }
+
+ return apiLevel
+}
+
+func NativeApiLevelFromUser(ctx android.BaseModuleContext,
+ raw string) (android.ApiLevel, error) {
+
if raw == "minimum" {
- return min, nil
+ return MinApiForArch(ctx, ctx.Arch().ArchType), nil
}
value, err := android.ApiLevelFromUser(ctx, raw)
@@ -54,16 +67,13 @@
return android.NoneApiLevel, err
}
- if value.LessThan(min) {
- return min, nil
- }
-
- return value, nil
+ return nativeClampedApiLevel(ctx, value), nil
}
func nativeApiLevelOrPanic(ctx android.BaseModuleContext,
raw string) android.ApiLevel {
- value, err := nativeApiLevelFromUser(ctx, raw)
+
+ value, err := NativeApiLevelFromUser(ctx, raw)
if err != nil {
panic(err.Error())
}
diff --git a/cc/binary.go b/cc/binary.go
index 2ac9a45..4b77bea 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -505,7 +505,7 @@
// The original path becomes a symlink to the corresponding file in the
// runtime APEX.
translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
- if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !ctx.Host() && ctx.directlyInAnyApex() &&
+ if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !ctx.Host() && !ctx.isSdkVariant() &&
!translatedArch && ctx.apexVariationName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() &&
!ctx.inVendorRamdisk() {
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index 8a7ea88..4063714 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -132,7 +132,7 @@
if ccModule.linker != nil {
specifiedDeps := specifiedDeps{}
- specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx, ccModule, specifiedDeps)
+ specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx.SdkModuleContext(), ccModule, specifiedDeps)
p.SharedLibs = specifiedDeps.sharedLibs
p.SystemSharedLibs = specifiedDeps.systemSharedLibs
diff --git a/cc/builder.go b/cc/builder.go
index cd535c1..c94a674 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -472,15 +472,25 @@
}
// Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
-func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs, timeoutTidySrcs android.Paths,
- flags builderFlags, pathDeps android.Paths, cFlagsDeps android.Paths) Objects {
+func transformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles, noTidySrcs, timeoutTidySrcs android.Paths,
+ flags builderFlags, pathDeps android.Paths, cFlagsDeps android.Paths, sharedFlags *SharedFlags) Objects {
+
+ // Not all source files produce a .o; a Rust source provider
+ // may provide both a .c and a .rs file (e.g. rust_bindgen).
+ srcObjFiles := android.Paths{}
+ for _, src := range srcFiles {
+ if src.Ext() != ".rs" {
+ srcObjFiles = append(srcObjFiles, src)
+ }
+ }
+
// Source files are one-to-one with tidy, coverage, or kythe files, if enabled.
- objFiles := make(android.Paths, len(srcFiles))
+ objFiles := make(android.Paths, len(srcObjFiles))
var tidyFiles android.Paths
noTidySrcsMap := make(map[string]bool)
var tidyVars string
if flags.tidy {
- tidyFiles = make(android.Paths, 0, len(srcFiles))
+ tidyFiles = make(android.Paths, 0, len(srcObjFiles))
for _, path := range noTidySrcs {
noTidySrcsMap[path.String()] = true
}
@@ -495,11 +505,11 @@
}
var coverageFiles android.Paths
if flags.gcovCoverage {
- coverageFiles = make(android.Paths, 0, len(srcFiles))
+ coverageFiles = make(android.Paths, 0, len(srcObjFiles))
}
var kytheFiles android.Paths
if flags.emitXrefs && ctx.Module() == ctx.PrimaryModule() {
- kytheFiles = make(android.Paths, 0, len(srcFiles))
+ kytheFiles = make(android.Paths, 0, len(srcObjFiles))
}
// Produce fully expanded flags for use by C tools, C compiles, C++ tools, C++ compiles, and asm compiles
@@ -548,16 +558,14 @@
var sAbiDumpFiles android.Paths
if flags.sAbiDump {
- sAbiDumpFiles = make(android.Paths, 0, len(srcFiles))
+ sAbiDumpFiles = make(android.Paths, 0, len(srcObjFiles))
}
// Multiple source files have build rules usually share the same cFlags or tidyFlags.
- // Define only one version in this module and share it in multiple build rules.
- // To simplify the code, the shared variables are all named as $flags<nnn>.
- shared := ctx.getSharedFlags()
-
+ // SharedFlags provides one version for this module and shares it in multiple build rules.
+ // To simplify the code, the SharedFlags variables are all named as $flags<nnn>.
// Share flags only when there are multiple files or tidy rules.
- var hasMultipleRules = len(srcFiles) > 1 || flags.tidy
+ var hasMultipleRules = len(srcObjFiles) > 1 || flags.tidy
var shareFlags = func(kind string, flags string) string {
if !hasMultipleRules || len(flags) < 60 {
@@ -566,17 +574,17 @@
return flags
}
mapKey := kind + flags
- n, ok := shared.flagsMap[mapKey]
+ n, ok := sharedFlags.FlagsMap[mapKey]
if !ok {
- shared.numSharedFlags += 1
- n = strconv.Itoa(shared.numSharedFlags)
- shared.flagsMap[mapKey] = n
+ sharedFlags.NumSharedFlags += 1
+ n = strconv.Itoa(sharedFlags.NumSharedFlags)
+ sharedFlags.FlagsMap[mapKey] = n
ctx.Variable(pctx, kind+n, flags)
}
return "$" + kind + n
}
- for i, srcFile := range srcFiles {
+ for i, srcFile := range srcObjFiles {
objFile := android.ObjPathWithExt(ctx, subdir, srcFile, "o")
objFiles[i] = objFile
@@ -821,7 +829,7 @@
return nil
}
- output := android.PathForModuleOut(ctx, "generated_rust_staticlib", "lib"+ctx.ModuleName()+"_rust_staticlib.a")
+ output := android.PathForModuleOut(ctx, "generated_rust_staticlib", "librustlibs.a")
stemFile := output.ReplaceExtension(ctx, "rs")
crateNames := []string{}
@@ -853,6 +861,27 @@
return strings.Join(lines, "\n")
}
+func BuildRustStubs(ctx android.ModuleContext, outputFile android.ModuleOutPath,
+ stubObjs Objects, ccFlags Flags) {
+
+ // Instantiate paths
+ sharedLibs := android.Paths{}
+ staticLibs := android.Paths{}
+ lateStaticLibs := android.Paths{}
+ wholeStaticLibs := android.Paths{}
+ deps := android.Paths{}
+ implicitOutputs := android.WritablePaths{}
+ validations := android.Paths{}
+ crtBegin := android.Paths{}
+ crtEnd := android.Paths{}
+ groupLate := false
+
+ builderFlags := flagsToBuilderFlags(ccFlags)
+ transformObjToDynamicBinary(ctx, stubObjs.objFiles, sharedLibs, staticLibs,
+ lateStaticLibs, wholeStaticLibs, deps, crtBegin, crtEnd,
+ groupLate, builderFlags, outputFile, implicitOutputs, validations)
+}
+
// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
// and shared libraries, to a shared library (.so) or dynamic executable
func transformObjToDynamicBinary(ctx android.ModuleContext,
@@ -945,7 +974,7 @@
func transformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Paths, soFile android.Path,
baseName string, exportedIncludeDirs []string, symbolFile android.OptionalPath,
excludedSymbolVersions, excludedSymbolTags, includedSymbolTags []string,
- api string, isLlndk bool) android.Path {
+ api string) android.Path {
outputFile := android.PathForModuleOut(ctx, baseName+".lsdump")
@@ -966,9 +995,6 @@
for _, tag := range includedSymbolTags {
symbolFilterStr += " --include-symbol-tag " + tag
}
- if isLlndk {
- symbolFilterStr += " --symbol-tag-policy MatchTagOnly"
- }
apiLevelsJson := android.GetApiLevelsJson(ctx)
implicits = append(implicits, apiLevelsJson)
symbolFilterStr += " --api-map " + apiLevelsJson.String()
diff --git a/cc/cc.go b/cc/cc.go
index 947dc1a..0279928 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -19,24 +19,161 @@
// is handled in builder.go
import (
+ "errors"
"fmt"
"io"
+ "slices"
"strconv"
"strings"
- "android/soong/testing"
-
"github.com/google/blueprint"
+ "github.com/google/blueprint/depset"
"github.com/google/blueprint/proptools"
"android/soong/aidl_library"
"android/soong/android"
"android/soong/cc/config"
"android/soong/fuzz"
- "android/soong/genrule"
- "android/soong/multitree"
)
+type CcMakeVarsInfo struct {
+ WarningsAllowed string
+ UsingWnoError string
+ MissingProfile string
+}
+
+var CcMakeVarsInfoProvider = blueprint.NewProvider[*CcMakeVarsInfo]()
+
+type CcObjectInfo struct {
+ ObjFiles android.Paths
+ TidyFiles android.Paths
+ KytheFiles android.Paths
+}
+
+var CcObjectInfoProvider = blueprint.NewProvider[CcObjectInfo]()
+
+type AidlInterfaceInfo struct {
+ // list of aidl_interface sources
+ Sources []string
+ // root directory of AIDL sources
+ AidlRoot string
+ // AIDL backend language (e.g. "cpp", "ndk")
+ Lang string
+ // list of flags passed to AIDL generator
+ Flags []string
+}
+
+type CompilerInfo struct {
+ Srcs android.Paths
+ // list of module-specific flags that will be used for C and C++ compiles.
+ Cflags proptools.Configurable[[]string]
+ AidlInterfaceInfo AidlInterfaceInfo
+ LibraryDecoratorInfo *LibraryDecoratorInfo
+}
+
+type LinkerInfo struct {
+ WholeStaticLibs proptools.Configurable[[]string]
+ // list of modules that should be statically linked into this module.
+ StaticLibs proptools.Configurable[[]string]
+ // list of modules that should be dynamically linked into this module.
+ SharedLibs proptools.Configurable[[]string]
+ // list of modules that should only provide headers for this module.
+ HeaderLibs proptools.Configurable[[]string]
+ ImplementationModuleName *string
+
+ BinaryDecoratorInfo *BinaryDecoratorInfo
+ LibraryDecoratorInfo *LibraryDecoratorInfo
+ TestBinaryInfo *TestBinaryInfo
+ BenchmarkDecoratorInfo *BenchmarkDecoratorInfo
+ ObjectLinkerInfo *ObjectLinkerInfo
+ StubDecoratorInfo *StubDecoratorInfo
+}
+
+type BinaryDecoratorInfo struct{}
+type LibraryDecoratorInfo struct {
+ ExportIncludeDirs proptools.Configurable[[]string]
+ InjectBsslHash bool
+}
+
+type SnapshotInfo struct {
+ SnapshotAndroidMkSuffix string
+}
+
+type TestBinaryInfo struct {
+ Gtest bool
+}
+type BenchmarkDecoratorInfo struct{}
+
+type StubDecoratorInfo struct{}
+
+type ObjectLinkerInfo struct{}
+
+type LibraryInfo struct {
+ BuildStubs bool
+}
+
+// Common info about the cc module.
+type CcInfo struct {
+ IsPrebuilt bool
+ CmakeSnapshotSupported bool
+ HasLlndkStubs bool
+ CompilerInfo *CompilerInfo
+ LinkerInfo *LinkerInfo
+ SnapshotInfo *SnapshotInfo
+ LibraryInfo *LibraryInfo
+}
+
+var CcInfoProvider = blueprint.NewProvider[*CcInfo]()
+
+type LinkableInfo struct {
+ // StaticExecutable returns true if this is a binary module with "static_executable: true".
+ StaticExecutable bool
+ Static bool
+ Shared bool
+ HasStubsVariants bool
+ StubsVersion string
+ IsStubs bool
+ UnstrippedOutputFile android.Path
+ OutputFile android.OptionalPath
+ CoverageFiles android.Paths
+ // CoverageOutputFile returns the output archive of gcno coverage information files.
+ CoverageOutputFile android.OptionalPath
+ SAbiDumpFiles android.Paths
+ // Partition returns the partition string for this module.
+ Partition string
+ CcLibrary bool
+ CcLibraryInterface bool
+ RustLibraryInterface bool
+ // CrateName returns the crateName for a Rust library
+ CrateName string
+ // DepFlags returns a slice of Rustc string flags
+ ExportedCrateLinkDirs []string
+ // This can be different from the one on CommonModuleInfo
+ BaseModuleName string
+ HasNonSystemVariants bool
+ IsLlndk bool
+ // True if the library is in the configs known NDK list.
+ IsNdk bool
+ InVendorOrProduct bool
+ // SubName returns the modules SubName, used for image and NDK/SDK variations.
+ SubName string
+ InRamdisk bool
+ OnlyInRamdisk bool
+ InVendorRamdisk bool
+ OnlyInVendorRamdisk bool
+ InRecovery bool
+ OnlyInRecovery bool
+ Installable *bool
+ // RelativeInstallPath returns the relative install path for this module.
+ RelativeInstallPath string
+ // TODO(b/362509506): remove this once all apex_exclude uses are switched to stubs.
+ RustApexExclude bool
+ // Bootstrap tests if this module is allowed to use non-APEX version of libraries.
+ Bootstrap bool
+}
+
+var LinkableInfoProvider = blueprint.NewProvider[*LinkableInfo]()
+
func init() {
RegisterCCBuildComponents(android.InitRegistrationContext)
@@ -49,10 +186,10 @@
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.Transition("sdk", &sdkTransitionMutator{})
- ctx.BottomUp("llndk", llndkMutator).Parallel()
+ ctx.BottomUp("llndk", llndkMutator)
ctx.Transition("link", &linkageTransitionMutator{})
ctx.Transition("version", &versionTransitionMutator{})
- ctx.BottomUp("begin", BeginMutator).Parallel()
+ ctx.BottomUp("begin", BeginMutator)
})
ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
@@ -60,10 +197,10 @@
san.registerMutators(ctx)
}
- ctx.TopDown("sanitize_runtime_deps", sanitizerRuntimeDepsMutator).Parallel()
- ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator).Parallel()
+ ctx.BottomUp("sanitize_runtime_deps", sanitizerRuntimeDepsMutator)
+ ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator)
- ctx.TopDown("fuzz_deps", fuzzMutatorDeps)
+ ctx.Transition("fuzz", &fuzzTransitionMutator{})
ctx.Transition("coverage", &coverageTransitionMutator{})
@@ -73,13 +210,13 @@
ctx.Transition("lto", <oTransitionMutator{})
- ctx.BottomUp("check_linktype", checkLinkTypeMutator).Parallel()
- ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
+ ctx.BottomUp("check_linktype", checkLinkTypeMutator)
+ ctx.BottomUp("double_loadable", checkDoubleLoadableLibraries)
})
- ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.PostApexMutators(func(ctx android.RegisterMutatorsContext) {
// sabi mutator needs to be run after apex mutator finishes.
- ctx.TopDown("sabi_deps", sabiDepsMutator)
+ ctx.Transition("sabi", &sabiTransitionMutator{})
})
ctx.RegisterParallelSingletonType("kythe_extract_all", kytheExtractAllFactory)
@@ -120,9 +257,10 @@
ObjFiles []string
- GeneratedSources []string
- GeneratedHeaders []string
- GeneratedDeps []string
+ GeneratedSources []string
+ GeneratedHeaders []string
+ DeviceFirstGeneratedHeaders []string
+ GeneratedDeps []string
ReexportGeneratedHeaders []string
@@ -138,7 +276,7 @@
// LLNDK headers for the ABI checker to check LLNDK implementation library.
// An LLNDK implementation is the core variant. LLNDK header libs are reexported by the vendor variant.
- // The core variant cannot depend on the vendor variant because of the order of CreateVariations.
+ // The core variant cannot depend on the vendor variant because of the order of imageTransitionMutator.Split().
// Instead, the LLNDK implementation depends on the LLNDK header libs.
LlndkHeaderLibs []string
}
@@ -170,7 +308,7 @@
RustRlibDeps []RustRlibDep
// Transitive static library dependencies of static libraries for use in ordering.
- TranstiveStaticLibrariesForOrdering *android.DepSet[android.Path]
+ TranstiveStaticLibrariesForOrdering depset.DepSet[android.Path]
// Paths to .o files
Objs Objects
@@ -214,6 +352,9 @@
// LLNDK headers for the ABI checker to check LLNDK implementation library.
LlndkIncludeDirs android.Paths
LlndkSystemIncludeDirs android.Paths
+
+ directImplementationDeps android.Paths
+ transitiveImplementationDeps []depset.DepSet[android.Path]
}
// LocalOrGlobalFlags contains flags that need to have values set globally by the build system or locally by the module
@@ -314,15 +455,14 @@
// If true, always create an sdk variant and don't create a platform variant.
Sdk_variant_only *bool
- AndroidMkSharedLibs []string `blueprint:"mutated"`
- AndroidMkStaticLibs []string `blueprint:"mutated"`
- AndroidMkRlibs []string `blueprint:"mutated"`
- AndroidMkRuntimeLibs []string `blueprint:"mutated"`
- AndroidMkWholeStaticLibs []string `blueprint:"mutated"`
- AndroidMkHeaderLibs []string `blueprint:"mutated"`
- HideFromMake bool `blueprint:"mutated"`
- PreventInstall bool `blueprint:"mutated"`
- ApexesProvidingSharedLibs []string `blueprint:"mutated"`
+ AndroidMkSharedLibs []string `blueprint:"mutated"`
+ AndroidMkStaticLibs []string `blueprint:"mutated"`
+ AndroidMkRlibs []string `blueprint:"mutated"`
+ AndroidMkRuntimeLibs []string `blueprint:"mutated"`
+ AndroidMkWholeStaticLibs []string `blueprint:"mutated"`
+ AndroidMkHeaderLibs []string `blueprint:"mutated"`
+ HideFromMake bool `blueprint:"mutated"`
+ PreventInstall bool `blueprint:"mutated"`
// Set by DepsMutator.
AndroidMkSystemSharedLibs []string `blueprint:"mutated"`
@@ -390,11 +530,6 @@
// variant to have a ".sdk" suffix.
SdkAndPlatformVariantVisibleToMake bool `blueprint:"mutated"`
- // List of APEXes that this module has private access to for testing purpose. The module
- // can depend on libraries that are not exported by the APEXes and use private symbols
- // from the exported libraries.
- Test_for []string `android:"arch_variant"`
-
Target struct {
Platform struct {
// List of modules required by the core variant.
@@ -491,13 +626,13 @@
type ModuleContextIntf interface {
static() bool
staticBinary() bool
+ staticLibrary() bool
testBinary() bool
testLibrary() bool
header() bool
binary() bool
object() bool
toolchain() config.Toolchain
- canUseSdk() bool
useSdk() bool
sdkVersion() string
minSdkVersion() string
@@ -521,22 +656,20 @@
isFuzzer() bool
isNDKStubLibrary() bool
useClangLld(actx ModuleContext) bool
- isForPlatform() bool
apexVariationName() string
- apexSdkVersion() android.ApiLevel
bootstrap() bool
nativeCoverage() bool
- directlyInAnyApex() bool
isPreventInstall() bool
isCfiAssemblySupportEnabled() bool
getSharedFlags() *SharedFlags
notInPlatform() bool
optimizeForSize() bool
+ getOrCreateMakeVarsInfo() *CcMakeVarsInfo
}
type SharedFlags struct {
- numSharedFlags int
- flagsMap map[string]string
+ NumSharedFlags int
+ FlagsMap map[string]string
}
type ModuleContext interface {
@@ -613,7 +746,7 @@
coverageOutputFilePath() android.OptionalPath
// Get the deps that have been explicitly specified in the properties.
- linkerSpecifiedDeps(ctx android.ConfigAndErrorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps
+ linkerSpecifiedDeps(ctx android.ConfigurableEvaluatorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps
moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON)
}
@@ -640,10 +773,6 @@
installInRoot() bool
}
-type xref interface {
- XrefCcFiles() android.Paths
-}
-
type overridable interface {
overriddenModules() []string
}
@@ -798,7 +927,7 @@
dataLibDepTag = dependencyTag{name: "data lib"}
dataBinDepTag = dependencyTag{name: "data bin"}
runtimeDepTag = installDependencyTag{name: "runtime lib"}
- stubImplDepTag = dependencyTag{name: "stub_impl"}
+ StubImplDepTag = dependencyTag{name: "stub_impl"}
JniFuzzLibTag = dependencyTag{name: "jni_fuzz_lib_tag"}
FdoProfileTag = dependencyTag{name: "fdo_profile"}
aidlLibraryTag = dependencyTag{name: "aidl_library"}
@@ -824,6 +953,11 @@
return depTag == runtimeDepTag
}
+func ExcludeInApexDepTag(depTag blueprint.DependencyTag) bool {
+ ccLibDepTag, ok := depTag.(libraryDependencyTag)
+ return ok && ccLibDepTag.excludeInApex
+}
+
// Module contains the properties and members used by all C/C++ module types, and implements
// the blueprint.Module interface. It delegates to compiler, linker, and installer interfaces
// to construct the output file. Behavior can be customized with a Customizer, or "decorator",
@@ -846,9 +980,10 @@
sourceProperties android.SourceProperties
// initialize before calling Init
- hod android.HostOrDeviceSupported
- multilib android.Multilib
- testModule bool
+ hod android.HostOrDeviceSupported
+ multilib android.Multilib
+ testModule bool
+ incremental bool
// Allowable SdkMemberTypes of this module type.
sdkMemberTypes []android.SdkMemberType
@@ -879,7 +1014,7 @@
cachedToolchain config.Toolchain
- subAndroidMkOnce map[subAndroidMkProvider]bool
+ subAndroidMkOnce map[subAndroidMkProviderInfoProducer]bool
// Flags used to compile this module
flags Flags
@@ -891,12 +1026,6 @@
staticAnalogue *StaticLibraryInfo
makeLinkType string
- // Kythe (source file indexer) paths for this compilation module
- kytheFiles android.Paths
- // Object .o file output paths for this compilation module
- objFiles android.Paths
- // Tidy .tidy file output paths for this compilation module
- tidyFiles android.Paths
// For apex variants, this is set as apex.min_sdk_version
apexSdkVersion android.ApiLevel
@@ -914,8 +1043,16 @@
hasSysprop bool
hasWinMsg bool
hasYacc bool
+
+ makeVarsInfo *CcMakeVarsInfo
}
+func (c *Module) IncrementalSupported() bool {
+ return c.incremental
+}
+
+var _ blueprint.Incremental = (*Module)(nil)
+
func (c *Module) AddJSONData(d *map[string]interface{}) {
c.AndroidModuleBase().AddJSONData(d)
(*d)["Cc"] = map[string]interface{}{
@@ -945,7 +1082,6 @@
"IsLlndk": c.IsLlndk(),
"IsVendorPublicLibrary": c.IsVendorPublicLibrary(),
"ApexSdkVersion": c.apexSdkVersion,
- "TestFor": c.TestFor(),
"AidlSrcs": c.hasAidl,
"LexSrcs": c.hasLex,
"ProtoSrcs": c.hasProto,
@@ -970,7 +1106,7 @@
return c.Properties.HideFromMake
}
-func (c *Module) RequiredModuleNames(ctx android.ConfigAndErrorContext) []string {
+func (c *Module) RequiredModuleNames(ctx android.ConfigurableEvaluatorContext) []string {
required := android.CopyOf(c.ModuleBase.RequiredModuleNames(ctx))
if c.ImageVariation().Variation == android.CoreVariation {
required = append(required, c.Properties.Target.Platform.Required...)
@@ -1045,7 +1181,21 @@
return String(c.Properties.Min_sdk_version)
}
-func (c *Module) isCrt() bool {
+func (c *Module) SetSdkVersion(s string) {
+ c.Properties.Sdk_version = StringPtr(s)
+}
+
+func (c *Module) SetMinSdkVersion(s string) {
+ c.Properties.Min_sdk_version = StringPtr(s)
+}
+
+func (c *Module) SetStl(s string) {
+ if c.stl != nil {
+ c.stl.Properties.Stl = StringPtr(s)
+ }
+}
+
+func (c *Module) IsCrt() bool {
if linker, ok := c.linker.(*objectLinker); ok {
return linker.isCrt()
}
@@ -1053,7 +1203,7 @@
}
func (c *Module) SplitPerApiLevel() bool {
- return c.canUseSdk() && c.isCrt()
+ return CanUseSdk(c) && c.IsCrt()
}
func (c *Module) AlwaysSdk() bool {
@@ -1073,7 +1223,7 @@
}
func (c *Module) CcLibraryInterface() bool {
- if _, ok := c.linker.(libraryInterface); ok {
+ if c.library != nil {
return true
}
return false
@@ -1167,11 +1317,6 @@
return false
}
-func (c *Module) IsRustFFI() bool {
- // cc modules are not Rust modules
- return false
-}
-
func (c *Module) Module() android.Module {
return c
}
@@ -1191,6 +1336,13 @@
var _ LinkableInterface = (*Module)(nil)
+func (c *Module) VersionedInterface() VersionedInterface {
+ if c.library != nil {
+ return c.library
+ }
+ return nil
+}
+
func (c *Module) UnstrippedOutputFile() android.Path {
if c.linker != nil {
return c.linker.unstrippedOutputFilePath()
@@ -1275,13 +1427,13 @@
return c.Properties.VndkVersion != ""
}
-func (c *Module) canUseSdk() bool {
- return c.Os() == android.Android && c.Target().NativeBridge == android.NativeBridgeDisabled &&
+func CanUseSdk(c LinkableInterface) bool {
+ return c.Module().Target().Os == android.Android && c.Target().NativeBridge == android.NativeBridgeDisabled &&
!c.InVendorOrProduct() && !c.InRamdisk() && !c.InRecovery() && !c.InVendorRamdisk()
}
func (c *Module) UseSdk() bool {
- if c.canUseSdk() {
+ if CanUseSdk(c) {
return String(c.Properties.Sdk_version) != ""
}
return false
@@ -1300,13 +1452,13 @@
}
func (m *Module) NeedsLlndkVariants() bool {
- lib := moduleLibraryInterface(m)
- return lib != nil && (lib.hasLLNDKStubs() || lib.hasLLNDKHeaders())
+ lib := moduleVersionedInterface(m)
+ return lib != nil && (lib.HasLLNDKStubs() || lib.HasLLNDKHeaders())
}
func (m *Module) NeedsVendorPublicLibraryVariants() bool {
- lib := moduleLibraryInterface(m)
- return lib != nil && (lib.hasVendorPublicLibrary())
+ lib := moduleVersionedInterface(m)
+ return lib != nil && (lib.HasVendorPublicLibrary())
}
// IsVendorPublicLibrary returns true for vendor public libraries.
@@ -1326,13 +1478,13 @@
}
func (c *Module) HasLlndkStubs() bool {
- lib := moduleLibraryInterface(c)
- return lib != nil && lib.hasLLNDKStubs()
+ lib := moduleVersionedInterface(c)
+ return lib != nil && lib.HasLLNDKStubs()
}
func (c *Module) StubsVersion() string {
- if lib, ok := c.linker.(versionedInterface); ok {
- return lib.stubsVersion()
+ if lib, ok := c.linker.(VersionedInterface); ok {
+ return lib.StubsVersion()
}
panic(fmt.Errorf("StubsVersion called on non-versioned module: %q", c.BaseModuleName()))
}
@@ -1341,7 +1493,7 @@
// and does not set llndk.vendor_available: false.
func (c *Module) isImplementationForLLNDKPublic() bool {
library, _ := c.library.(*libraryDecorator)
- return library != nil && library.hasLLNDKStubs() &&
+ return library != nil && library.HasLLNDKStubs() &&
!Bool(library.Properties.Llndk.Private)
}
@@ -1380,21 +1532,25 @@
func (c *Module) IsStubs() bool {
if lib := c.library; lib != nil {
- return lib.buildStubs()
+ return lib.BuildStubs()
}
return false
}
func (c *Module) HasStubsVariants() bool {
if lib := c.library; lib != nil {
- return lib.hasStubsVariants()
+ return lib.HasStubsVariants()
}
return false
}
+func (c *Module) RustApexExclude() bool {
+ return false
+}
+
func (c *Module) IsStubsImplementationRequired() bool {
if lib := c.library; lib != nil {
- return lib.isStubsImplementationRequired()
+ return lib.IsStubsImplementationRequired()
}
return false
}
@@ -1403,21 +1559,21 @@
// the implementation. If it is an implementation library it returns its own name.
func (c *Module) ImplementationModuleName(ctx android.BaseModuleContext) string {
name := ctx.OtherModuleName(c)
- if versioned, ok := c.linker.(versionedInterface); ok {
- name = versioned.implementationModuleName(name)
+ if versioned, ok := c.linker.(VersionedInterface); ok {
+ name = versioned.ImplementationModuleName(name)
}
return name
}
-// Similar to ImplementationModuleName, but uses the Make variant of the module
+// Similar to ImplementationModuleNameByCtx, but uses the Make variant of the module
// name as base name, for use in AndroidMk output. E.g. for a prebuilt module
// where the Soong name is prebuilt_foo, this returns foo (which works in Make
// under the premise that the prebuilt module overrides its source counterpart
// if it is exposed to Make).
func (c *Module) ImplementationModuleNameForMake(ctx android.BaseModuleContext) string {
name := c.BaseModuleName()
- if versioned, ok := c.linker.(versionedInterface); ok {
- name = versioned.implementationModuleName(name)
+ if versioned, ok := c.linker.(VersionedInterface); ok {
+ name = versioned.ImplementationModuleName(name)
}
return name
}
@@ -1456,10 +1612,6 @@
return isBionic(name)
}
-func (c *Module) XrefCcFiles() android.Paths {
- return c.kytheFiles
-}
-
func (c *Module) isCfiAssemblySupportEnabled() bool {
return c.sanitize != nil &&
Bool(c.sanitize.Properties.Sanitize.Config.Cfi_assembly_support)
@@ -1501,6 +1653,10 @@
return ctx.mod.staticBinary()
}
+func (ctx *moduleContextImpl) staticLibrary() bool {
+ return ctx.mod.staticLibrary()
+}
+
func (ctx *moduleContextImpl) testBinary() bool {
return ctx.mod.testBinary()
}
@@ -1525,10 +1681,6 @@
return ctx.mod.OptimizeForSize()
}
-func (ctx *moduleContextImpl) canUseSdk() bool {
- return ctx.mod.canUseSdk()
-}
-
func (ctx *moduleContextImpl) useSdk() bool {
return ctx.mod.UseSdk()
}
@@ -1540,22 +1692,23 @@
return ""
}
-func (ctx *moduleContextImpl) minSdkVersion() string {
- ver := ctx.mod.MinSdkVersion()
- if ver == "apex_inherit" && !ctx.isForPlatform() {
- ver = ctx.apexSdkVersion().String()
+func MinSdkVersion(mod VersionedLinkableInterface, ctxIsForPlatform bool, device bool,
+ platformSdkVersion string) string {
+
+ ver := mod.MinSdkVersion()
+ if ver == "apex_inherit" && !ctxIsForPlatform {
+ ver = mod.ApexSdkVersion().String()
}
if ver == "apex_inherit" || ver == "" {
- ver = ctx.sdkVersion()
+ ver = mod.SdkVersion()
}
- if ctx.ctx.Device() {
- config := ctx.ctx.Config()
- if ctx.inVendor() {
- // If building for vendor with final API, then use the latest _stable_ API as "current".
- if config.VendorApiLevelFrozen() && (ver == "" || ver == "current") {
- ver = config.PlatformSdkVersion().String()
- }
+ if device {
+ // When building for vendor/product, use the latest _stable_ API as "current".
+ // This is passed to clang/aidl compilers so that compiled/generated code works
+ // with the system.
+ if (mod.InVendor() || mod.InProduct()) && (ver == "" || ver == "current") {
+ ver = platformSdkVersion
}
}
@@ -1569,19 +1722,19 @@
// support such an old version. The version is set to the later version in case when the
// non-sdk variant is for the platform, or the min_sdk_version of the containing APEX if
// it's for an APEX.
- if ctx.mod.isCrt() && !ctx.isSdkVariant() {
- if ctx.isForPlatform() {
+ if mod.IsCrt() && !mod.IsSdkVariant() {
+ if ctxIsForPlatform {
ver = strconv.Itoa(android.FutureApiLevelInt)
} else { // for apex
- ver = ctx.apexSdkVersion().String()
+ ver = mod.ApexSdkVersion().String()
if ver == "" { // in case when min_sdk_version was not set by the APEX
- ver = ctx.sdkVersion()
+ ver = mod.SdkVersion()
}
}
}
// Also make sure that minSdkVersion is not greater than sdkVersion, if they are both numbers
- sdkVersionInt, err := strconv.Atoi(ctx.sdkVersion())
+ sdkVersionInt, err := strconv.Atoi(mod.SdkVersion())
minSdkVersionInt, err2 := strconv.Atoi(ver)
if err == nil && err2 == nil {
if sdkVersionInt < minSdkVersionInt {
@@ -1591,6 +1744,14 @@
return ver
}
+func (ctx *moduleContextImpl) minSdkVersion() string {
+ platformSdkVersion := ""
+ if ctx.ctx.Device() {
+ platformSdkVersion = ctx.ctx.Config().PlatformSdkVersion().String()
+ }
+ return MinSdkVersion(ctx.mod, CtxIsForPlatform(ctx.ctx), ctx.ctx.Device(), platformSdkVersion)
+}
+
func (ctx *moduleContextImpl) isSdkVariant() bool {
return ctx.mod.IsSdkVariant()
}
@@ -1654,8 +1815,8 @@
return ctx.mod.BaseModuleName()
}
-func (ctx *moduleContextImpl) isForPlatform() bool {
- apexInfo, _ := android.ModuleProvider(ctx.ctx, android.ApexInfoProvider)
+func CtxIsForPlatform(ctx android.BaseModuleContext) bool {
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
return apexInfo.IsForPlatform()
}
@@ -1664,10 +1825,6 @@
return apexInfo.ApexVariationName
}
-func (ctx *moduleContextImpl) apexSdkVersion() android.ApiLevel {
- return ctx.mod.apexSdkVersion
-}
-
func (ctx *moduleContextImpl) bootstrap() bool {
return ctx.mod.Bootstrap()
}
@@ -1676,19 +1833,15 @@
return ctx.mod.nativeCoverage()
}
-func (ctx *moduleContextImpl) directlyInAnyApex() bool {
- return ctx.mod.DirectlyInAnyApex()
-}
-
func (ctx *moduleContextImpl) isPreventInstall() bool {
return ctx.mod.Properties.PreventInstall
}
func (ctx *moduleContextImpl) getSharedFlags() *SharedFlags {
shared := &ctx.mod.sharedFlags
- if shared.flagsMap == nil {
- shared.numSharedFlags = 0
- shared.flagsMap = make(map[string]string)
+ if shared.FlagsMap == nil {
+ shared.NumSharedFlags = 0
+ shared.FlagsMap = make(map[string]string)
}
return shared
}
@@ -1701,6 +1854,13 @@
return ctx.mod.NotInPlatform()
}
+func (ctx *moduleContextImpl) getOrCreateMakeVarsInfo() *CcMakeVarsInfo {
+ if ctx.mod.makeVarsInfo == nil {
+ ctx.mod.makeVarsInfo = &CcMakeVarsInfo{}
+ }
+ return ctx.mod.makeVarsInfo
+}
+
func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
return &Module{
hod: hod,
@@ -1745,6 +1905,14 @@
return name
}
+func (c *Module) Multilib() string {
+ return c.Arch().ArchType.Multilib
+}
+
+func (c *Module) ApexSdkVersion() android.ApiLevel {
+ return c.apexSdkVersion
+}
+
func (c *Module) Symlinks() []string {
if p, ok := c.installer.(interface {
symlinkList() []string
@@ -1862,7 +2030,7 @@
// Returns true if a stub library could be installed in multiple apexes
func (c *Module) stubLibraryMultipleApexViolation(ctx android.ModuleContext) bool {
// If this is not an apex variant, no check necessary
- if !c.InAnyApex() {
+ if info, ok := android.ModuleProvider(ctx, android.ApexInfoProvider); !ok || info.IsForPlatform() {
return false
}
// If this is not a stub library, no check necessary
@@ -1875,13 +2043,13 @@
return false
}
- _, aaWithoutTestApexes, _ := android.ListSetDifference(c.ApexAvailable(), c.TestApexes())
// Stub libraries should not have more than one apex_available
- if len(aaWithoutTestApexes) > 1 {
+ apexAvailable := android.FirstUniqueStrings(c.ApexAvailable())
+ if len(apexAvailable) > 1 {
return true
}
// Stub libraries should not use the wildcard
- if aaWithoutTestApexes[0] == android.AvailableToAnyApex {
+ if apexAvailable[0] == android.AvailableToAnyApex {
return true
}
// Default: no violation
@@ -2024,9 +2192,6 @@
if ctx.Failed() {
return
}
- c.kytheFiles = objs.kytheFiles
- c.objFiles = objs.objFiles
- c.tidyFiles = objs.tidyFiles
}
if c.linker != nil {
@@ -2037,12 +2202,11 @@
c.outputFile = android.OptionalPathForPath(outputFile)
c.maybeUnhideFromMake()
- }
- if c.testModule {
- android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
- }
- android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: deps.GeneratedSources.Strings()})
+ android.SetProvider(ctx, ImplementationDepInfoProvider, &ImplementationDepInfo{
+ ImplementationDeps: depset.New(depset.PREORDER, deps.directImplementationDeps, deps.transitiveImplementationDeps),
+ })
+ }
if Bool(c.Properties.Cmake_snapshot_supported) {
android.SetProvider(ctx, cmakeSnapshotSourcesProvider, android.GlobFiles(ctx, ctx.ModuleDir()+"/**/*", nil))
@@ -2094,7 +2258,140 @@
c.hasYacc = b.hasSrcExt(ctx, ".y") || b.hasSrcExt(ctx, ".yy")
}
+ ccObjectInfo := CcObjectInfo{
+ KytheFiles: objs.kytheFiles,
+ }
+ if !ctx.Config().KatiEnabled() || !android.ShouldSkipAndroidMkProcessing(ctx, c) {
+ ccObjectInfo.ObjFiles = objs.objFiles
+ ccObjectInfo.TidyFiles = objs.tidyFiles
+ }
+ if len(ccObjectInfo.KytheFiles)+len(ccObjectInfo.ObjFiles)+len(ccObjectInfo.TidyFiles) > 0 {
+ android.SetProvider(ctx, CcObjectInfoProvider, ccObjectInfo)
+ }
+
+ linkableInfo := CreateCommonLinkableInfo(ctx, c)
+ if lib, ok := c.linker.(VersionedInterface); ok {
+ linkableInfo.StubsVersion = lib.StubsVersion()
+ }
+ if c.linker != nil {
+ if library, ok := c.linker.(libraryInterface); ok {
+ linkableInfo.Static = library.static()
+ linkableInfo.Shared = library.shared()
+ linkableInfo.CoverageFiles = library.objs().coverageFiles
+ linkableInfo.SAbiDumpFiles = library.objs().sAbiDumpFiles
+ }
+ }
+ android.SetProvider(ctx, LinkableInfoProvider, linkableInfo)
+
+ ccInfo := CcInfo{
+ IsPrebuilt: c.IsPrebuilt(),
+ CmakeSnapshotSupported: proptools.Bool(c.Properties.Cmake_snapshot_supported),
+ HasLlndkStubs: c.HasLlndkStubs(),
+ }
+ if c.compiler != nil {
+ ccInfo.CompilerInfo = &CompilerInfo{
+ Srcs: c.compiler.(CompiledInterface).Srcs(),
+ Cflags: c.compiler.baseCompilerProps().Cflags,
+ AidlInterfaceInfo: AidlInterfaceInfo{
+ Sources: c.compiler.baseCompilerProps().AidlInterface.Sources,
+ AidlRoot: c.compiler.baseCompilerProps().AidlInterface.AidlRoot,
+ Lang: c.compiler.baseCompilerProps().AidlInterface.Lang,
+ Flags: c.compiler.baseCompilerProps().AidlInterface.Flags,
+ },
+ }
+ switch decorator := c.compiler.(type) {
+ case *libraryDecorator:
+ ccInfo.CompilerInfo.LibraryDecoratorInfo = &LibraryDecoratorInfo{
+ ExportIncludeDirs: decorator.flagExporter.Properties.Export_include_dirs,
+ }
+ }
+ }
+ if c.linker != nil {
+ ccInfo.LinkerInfo = &LinkerInfo{
+ WholeStaticLibs: c.linker.baseLinkerProps().Whole_static_libs,
+ StaticLibs: c.linker.baseLinkerProps().Static_libs,
+ SharedLibs: c.linker.baseLinkerProps().Shared_libs,
+ HeaderLibs: c.linker.baseLinkerProps().Header_libs,
+ }
+ switch decorator := c.linker.(type) {
+ case *binaryDecorator:
+ ccInfo.LinkerInfo.BinaryDecoratorInfo = &BinaryDecoratorInfo{}
+ case *libraryDecorator:
+ ccInfo.LinkerInfo.LibraryDecoratorInfo = &LibraryDecoratorInfo{
+ InjectBsslHash: Bool(c.linker.(*libraryDecorator).Properties.Inject_bssl_hash),
+ }
+ case *testBinary:
+ ccInfo.LinkerInfo.TestBinaryInfo = &TestBinaryInfo{
+ Gtest: decorator.testDecorator.gtest(),
+ }
+ case *benchmarkDecorator:
+ ccInfo.LinkerInfo.BenchmarkDecoratorInfo = &BenchmarkDecoratorInfo{}
+ case *objectLinker:
+ ccInfo.LinkerInfo.ObjectLinkerInfo = &ObjectLinkerInfo{}
+ case *stubDecorator:
+ ccInfo.LinkerInfo.StubDecoratorInfo = &StubDecoratorInfo{}
+ }
+
+ if s, ok := c.linker.(SnapshotInterface); ok {
+ ccInfo.SnapshotInfo = &SnapshotInfo{
+ SnapshotAndroidMkSuffix: s.SnapshotAndroidMkSuffix(),
+ }
+ }
+ if v, ok := c.linker.(VersionedInterface); ok {
+ name := v.ImplementationModuleName(ctx.OtherModuleName(c))
+ ccInfo.LinkerInfo.ImplementationModuleName = &name
+ }
+ }
+ if c.library != nil {
+ ccInfo.LibraryInfo = &LibraryInfo{
+ BuildStubs: c.library.BuildStubs(),
+ }
+ }
+ android.SetProvider(ctx, CcInfoProvider, &ccInfo)
+
c.setOutputFiles(ctx)
+
+ if c.makeVarsInfo != nil {
+ android.SetProvider(ctx, CcMakeVarsInfoProvider, c.makeVarsInfo)
+ }
+}
+
+func CreateCommonLinkableInfo(ctx android.ModuleContext, mod VersionedLinkableInterface) *LinkableInfo {
+ return &LinkableInfo{
+ StaticExecutable: mod.StaticExecutable(),
+ HasStubsVariants: mod.HasStubsVariants(),
+ OutputFile: mod.OutputFile(),
+ UnstrippedOutputFile: mod.UnstrippedOutputFile(),
+ CoverageOutputFile: mod.CoverageOutputFile(),
+ Partition: mod.Partition(),
+ IsStubs: mod.IsStubs(),
+ CcLibrary: mod.CcLibrary(),
+ CcLibraryInterface: mod.CcLibraryInterface(),
+ RustLibraryInterface: mod.RustLibraryInterface(),
+ BaseModuleName: mod.BaseModuleName(),
+ IsLlndk: mod.IsLlndk(),
+ IsNdk: mod.IsNdk(ctx.Config()),
+ HasNonSystemVariants: mod.HasNonSystemVariants(),
+ SubName: mod.SubName(),
+ InVendorOrProduct: mod.InVendorOrProduct(),
+ InRamdisk: mod.InRamdisk(),
+ OnlyInRamdisk: mod.OnlyInRamdisk(),
+ InVendorRamdisk: mod.InVendorRamdisk(),
+ OnlyInVendorRamdisk: mod.OnlyInVendorRamdisk(),
+ InRecovery: mod.InRecovery(),
+ OnlyInRecovery: mod.OnlyInRecovery(),
+ Installable: mod.Installable(),
+ RelativeInstallPath: mod.RelativeInstallPath(),
+ // TODO(b/362509506): remove this once all apex_exclude uses are switched to stubs.
+ RustApexExclude: mod.RustApexExclude(),
+ Bootstrap: mod.Bootstrap(),
+ }
+}
+
+func setOutputFilesIfNotEmpty(ctx ModuleContext, files android.Paths, tag string) {
+ if len(files) > 0 {
+ ctx.SetOutputFiles(files, tag)
+ }
}
func (c *Module) setOutputFiles(ctx ModuleContext) {
@@ -2112,25 +2409,42 @@
func buildComplianceMetadataInfo(ctx ModuleContext, c *Module, deps PathDeps) {
// Dump metadata that can not be done in android/compliance-metadata.go
complianceMetadataInfo := ctx.ComplianceMetadataInfo()
- complianceMetadataInfo.SetStringValue(android.ComplianceMetadataProp.IS_STATIC_LIB, strconv.FormatBool(ctx.static()))
+ complianceMetadataInfo.SetStringValue(android.ComplianceMetadataProp.IS_STATIC_LIB, strconv.FormatBool(ctx.static() || ctx.ModuleType() == "cc_object"))
complianceMetadataInfo.SetStringValue(android.ComplianceMetadataProp.BUILT_FILES, c.outputFile.String())
// Static deps
- staticDeps := ctx.GetDirectDepsWithTag(StaticDepTag(false))
+ staticDeps := ctx.GetDirectDepsProxyWithTag(StaticDepTag(false))
staticDepNames := make([]string, 0, len(staticDeps))
for _, dep := range staticDeps {
staticDepNames = append(staticDepNames, dep.Name())
}
+ // Process CrtBegin and CrtEnd as static libs
+ ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) {
+ depName := ctx.OtherModuleName(dep)
+ depTag := ctx.OtherModuleDependencyTag(dep)
+ switch depTag {
+ case CrtBeginDepTag:
+ staticDepNames = append(staticDepNames, depName)
+ case CrtEndDepTag:
+ staticDepNames = append(staticDepNames, depName)
+ }
+ })
- staticDepPaths := make([]string, 0, len(deps.StaticLibs))
+ staticDepPaths := make([]string, 0, len(deps.StaticLibs)+len(deps.CrtBegin)+len(deps.CrtEnd))
for _, dep := range deps.StaticLibs {
staticDepPaths = append(staticDepPaths, dep.String())
}
+ for _, dep := range deps.CrtBegin {
+ staticDepPaths = append(staticDepPaths, dep.String())
+ }
+ for _, dep := range deps.CrtEnd {
+ staticDepPaths = append(staticDepPaths, dep.String())
+ }
complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.STATIC_DEPS, android.FirstUniqueStrings(staticDepNames))
complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.STATIC_DEP_FILES, android.FirstUniqueStrings(staticDepPaths))
// Whole static deps
- wholeStaticDeps := ctx.GetDirectDepsWithTag(StaticDepTag(true))
+ wholeStaticDeps := ctx.GetDirectDepsProxyWithTag(StaticDepTag(true))
wholeStaticDepNames := make([]string, 0, len(wholeStaticDeps))
for _, dep := range wholeStaticDeps {
wholeStaticDepNames = append(wholeStaticDepNames, dep.Name())
@@ -2142,6 +2456,14 @@
}
complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.WHOLE_STATIC_DEPS, android.FirstUniqueStrings(wholeStaticDepNames))
complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.WHOLE_STATIC_DEP_FILES, android.FirstUniqueStrings(wholeStaticDepPaths))
+
+ // Header libs
+ headerLibDeps := ctx.GetDirectDepsProxyWithTag(HeaderDepTag())
+ headerLibDepNames := make([]string, 0, len(headerLibDeps))
+ for _, dep := range headerLibDeps {
+ headerLibDepNames = append(headerLibDepNames, dep.Name())
+ }
+ complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.HEADER_LIBS, android.FirstUniqueStrings(headerLibDepNames))
}
func (c *Module) maybeUnhideFromMake() {
@@ -2170,6 +2492,7 @@
// modules can be hidden from make as some are needed for resolving make side
// dependencies.
c.HideFromMake()
+ c.SkipInstall()
} else if !installable(c, apexInfo) {
c.SkipInstall()
}
@@ -2220,7 +2543,7 @@
c.orderfile.begin(ctx)
}
if ctx.useSdk() && c.IsSdkVariant() {
- version, err := nativeApiLevelFromUser(ctx, ctx.sdkVersion())
+ version, err := NativeApiLevelFromUser(ctx, ctx.sdkVersion())
if err != nil {
ctx.PropertyErrorf("sdk_version", err.Error())
c.Properties.Sdk_version = nil
@@ -2258,6 +2581,10 @@
deps.RuntimeLibs = android.LastUniqueStrings(deps.RuntimeLibs)
deps.LlndkHeaderLibs = android.LastUniqueStrings(deps.LlndkHeaderLibs)
+ if err := checkConflictingExplicitVersions(deps.SharedLibs); err != nil {
+ ctx.PropertyErrorf("shared_libs", "%s", err.Error())
+ }
+
for _, lib := range deps.ReexportSharedLibHeaders {
if !inList(lib, deps.SharedLibs) {
ctx.PropertyErrorf("export_shared_lib_headers", "Shared library not in shared_libs: '%s'", lib)
@@ -2285,6 +2612,26 @@
return deps
}
+func checkConflictingExplicitVersions(libs []string) error {
+ withoutVersion := func(s string) string {
+ name, _ := StubsLibNameAndVersion(s)
+ return name
+ }
+ var errs []error
+ for i, lib := range libs {
+ libName := withoutVersion(lib)
+ libsToCompare := libs[i+1:]
+ j := slices.IndexFunc(libsToCompare, func(s string) bool {
+ return withoutVersion(s) == libName
+ })
+ if j >= 0 {
+ errs = append(errs, fmt.Errorf("duplicate shared libraries with different explicit versions: %q and %q",
+ lib, libsToCompare[j]))
+ }
+ }
+ return errors.Join(errs...)
+}
+
func (c *Module) beginMutator(actx android.BottomUpMutatorContext) {
ctx := &baseModuleContext{
BaseModuleContext: actx,
@@ -2346,9 +2693,16 @@
if version != "" && canBeOrLinkAgainstVersionVariants(mod) {
// Version is explicitly specified. i.e. libFoo#30
+ if version == "impl" {
+ version = ""
+ }
variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
if tag, ok := depTag.(libraryDependencyTag); ok {
tag.explicitlyVersioned = true
+ // depTag is an interface that contains a concrete non-pointer struct. That makes the local
+ // tag variable a copy of the contents of depTag, and updating it doesn't change depTag. Reassign
+ // the modified copy to depTag.
+ depTag = tag
} else {
panic(fmt.Errorf("Unexpected dependency tag: %T", depTag))
}
@@ -2361,24 +2715,6 @@
}
}
-func GetApiImports(c LinkableInterface, actx android.BottomUpMutatorContext) multitree.ApiImportInfo {
- apiImportInfo := multitree.ApiImportInfo{}
-
- if c.Device() {
- var apiImportModule []blueprint.Module
- if actx.OtherModuleExists("api_imports") {
- apiImportModule = actx.AddDependency(c, nil, "api_imports")
- if len(apiImportModule) > 0 && apiImportModule[0] != nil {
- apiInfo, _ := android.OtherModuleProvider(actx, apiImportModule[0], multitree.ApiImportsProvider)
- apiImportInfo = apiInfo
- android.SetProvider(actx, multitree.ApiImportsProvider, apiInfo)
- }
- }
- }
-
- return apiImportInfo
-}
-
func GetReplaceModuleName(lib string, replaceMap map[string]string) string {
if snapshot, ok := replaceMap[lib]; ok {
return snapshot
@@ -2448,11 +2784,6 @@
// NDK Variant
return true
}
-
- if c.isImportedApiLibrary() {
- // API Library should depend on API headers
- return true
- }
}
return false
@@ -2472,19 +2803,10 @@
ctx.ctx = ctx
deps := c.deps(ctx)
- apiImportInfo := GetApiImports(c, actx)
apiNdkLibs := []string{}
apiLateNdkLibs := []string{}
- if c.shouldUseApiSurface() {
- deps.SharedLibs, apiNdkLibs = rewriteLibsForApiImports(c, deps.SharedLibs, apiImportInfo.SharedLibs, ctx.Config())
- deps.LateSharedLibs, apiLateNdkLibs = rewriteLibsForApiImports(c, deps.LateSharedLibs, apiImportInfo.SharedLibs, ctx.Config())
- deps.SystemSharedLibs, _ = rewriteLibsForApiImports(c, deps.SystemSharedLibs, apiImportInfo.SharedLibs, ctx.Config())
- deps.ReexportHeaderLibHeaders, _ = rewriteLibsForApiImports(c, deps.ReexportHeaderLibHeaders, apiImportInfo.SharedLibs, ctx.Config())
- deps.ReexportSharedLibHeaders, _ = rewriteLibsForApiImports(c, deps.ReexportSharedLibHeaders, apiImportInfo.SharedLibs, ctx.Config())
- }
-
c.Properties.AndroidMkSystemSharedLibs = deps.SystemSharedLibs
variantNdkLibs := []string{}
@@ -2501,15 +2823,16 @@
depTag.reexportFlags = true
}
- // Check header lib replacement from API surface first, and then check again with VSDK
- if c.shouldUseApiSurface() {
- lib = GetReplaceModuleName(lib, apiImportInfo.HeaderLibs)
- }
-
if c.isNDKStubLibrary() {
- // ndk_headers do not have any variations
- actx.AddFarVariationDependencies([]blueprint.Variation{}, depTag, lib)
- } else if c.IsStubs() && !c.isImportedApiLibrary() {
+ variationExists := actx.OtherModuleDependencyVariantExists(nil, lib)
+ if variationExists {
+ actx.AddVariationDependencies(nil, depTag, lib)
+ } else {
+ // dependencies to ndk_headers fall here as ndk_headers do not have
+ // any variants.
+ actx.AddFarVariationDependencies([]blueprint.Variation{}, depTag, lib)
+ }
+ } else if c.IsStubs() {
actx.AddFarVariationDependencies(append(ctx.Target().Variations(), c.ImageVariation()),
depTag, lib)
} else {
@@ -2585,22 +2908,12 @@
}
name, version := StubsLibNameAndVersion(lib)
- if apiLibraryName, ok := apiImportInfo.SharedLibs[name]; ok && !ctx.OtherModuleExists(name) {
- name = apiLibraryName
- }
sharedLibNames = append(sharedLibNames, name)
variations := []blueprint.Variation{
{Mutator: "link", Variation: "shared"},
}
-
- if _, ok := apiImportInfo.ApexSharedLibs[name]; !ok || ctx.OtherModuleExists(name) {
- AddSharedLibDependenciesWithVersions(ctx, c, variations, depTag, name, version, false)
- }
-
- if apiLibraryName, ok := apiImportInfo.ApexSharedLibs[name]; ok {
- AddSharedLibDependenciesWithVersions(ctx, c, variations, depTag, apiLibraryName, version, false)
- }
+ AddSharedLibDependenciesWithVersions(ctx, c, variations, depTag, name, version, false)
}
for _, lib := range deps.LateStaticLibs {
@@ -2651,6 +2964,11 @@
actx.AddDependency(c, depTag, gen)
}
+ for _, gen := range deps.DeviceFirstGeneratedHeaders {
+ depTag := genHeaderDepTag
+ actx.AddVariationDependencies(ctx.Config().AndroidFirstDeviceTarget.Variations(), depTag, gen)
+ }
+
crtVariations := GetCrtVariations(ctx, c)
actx.AddVariationDependencies(crtVariations, objDepTag, deps.ObjFiles...)
for _, crt := range deps.CrtBegin {
@@ -2695,7 +3013,6 @@
)
}
- updateImportedLibraryDependency(ctx)
}
func BeginMutator(ctx android.BottomUpMutatorContext) {
@@ -2724,10 +3041,6 @@
return
}
- // TODO(b/244244438) : Remove this once all variants are implemented
- if ccFrom, ok := from.(*Module); ok && ccFrom.isImportedApiLibrary() {
- return
- }
if from.SdkVersion() == "" {
// Platform code can link to anything
return
@@ -2744,16 +3057,13 @@
// Recovery code is not NDK
return
}
+ // Change this to LinkableInterface if Rust gets NDK support, which stubDecorators are for
if c, ok := to.(*Module); ok {
if c.StubDecorator() {
// These aren't real libraries, but are the stub shared libraries that are included in
// the NDK.
return
}
- if c.isImportedApiLibrary() {
- // Imported library from the API surface is a stub library built against interface definition.
- return
- }
}
if strings.HasPrefix(ctx.ModuleName(), "libclang_rt.") && to.Module().Name() == "libc++" {
@@ -2834,7 +3144,7 @@
// If a library has a vendor variant and is a (transitive) dependency of an LLNDK library,
// it is subject to be double loaded. Such lib should be explicitly marked as double_loadable: true
// or as vndk-sp (vndk: { enabled: true, support_system_process: true}).
-func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) {
+func checkDoubleLoadableLibraries(ctx android.BottomUpMutatorContext) {
check := func(child, parent android.Module) bool {
to, ok := child.(*Module)
if !ok {
@@ -2854,7 +3164,7 @@
if depTag == staticVariantTag {
return false
}
- if depTag == stubImplDepTag {
+ if depTag == StubImplDepTag {
return false
}
if depTag == android.RequiredDepTag {
@@ -2885,7 +3195,7 @@
}
if module, ok := ctx.Module().(*Module); ok {
if lib, ok := module.linker.(*libraryDecorator); ok && lib.shared() {
- if lib.hasLLNDKStubs() {
+ if lib.HasLLNDKStubs() {
ctx.WalkDeps(check)
}
}
@@ -2929,48 +3239,7 @@
skipModuleList := map[string]bool{}
- var apiImportInfo multitree.ApiImportInfo
- hasApiImportInfo := false
-
- ctx.VisitDirectDeps(func(dep android.Module) {
- if dep.Name() == "api_imports" {
- apiImportInfo, _ = android.OtherModuleProvider(ctx, dep, multitree.ApiImportsProvider)
- hasApiImportInfo = true
- }
- })
-
- if hasApiImportInfo {
- targetStubModuleList := map[string]string{}
- targetOrigModuleList := map[string]string{}
-
- // Search for dependency which both original module and API imported library with APEX stub exists
- ctx.VisitDirectDeps(func(dep android.Module) {
- depName := ctx.OtherModuleName(dep)
- if apiLibrary, ok := apiImportInfo.ApexSharedLibs[depName]; ok {
- targetStubModuleList[apiLibrary] = depName
- }
- })
- ctx.VisitDirectDeps(func(dep android.Module) {
- depName := ctx.OtherModuleName(dep)
- if origLibrary, ok := targetStubModuleList[depName]; ok {
- targetOrigModuleList[origLibrary] = depName
- }
- })
-
- // Decide which library should be used between original and API imported library
- ctx.VisitDirectDeps(func(dep android.Module) {
- depName := ctx.OtherModuleName(dep)
- if apiLibrary, ok := targetOrigModuleList[depName]; ok {
- if ShouldUseStubForApex(ctx, dep) {
- skipModuleList[depName] = true
- } else {
- skipModuleList[apiLibrary] = true
- }
- }
- })
- }
-
- ctx.VisitDirectDeps(func(dep android.Module) {
+ ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) {
depName := ctx.OtherModuleName(dep)
depTag := ctx.OtherModuleDependencyTag(dep)
@@ -2979,8 +3248,17 @@
return
}
+ var ccInfo *CcInfo
+ v, hasCcInfo := android.OtherModuleProvider(ctx, dep, CcInfoProvider)
+ if hasCcInfo {
+ ccInfo = v
+ }
+ linkableInfo, hasLinkableInfo := android.OtherModuleProvider(ctx, dep, LinkableInfoProvider)
if depTag == android.DarwinUniversalVariantTag {
- depPaths.DarwinSecondArchOutput = dep.(*Module).OutputFile()
+ if !hasCcInfo {
+ panic(fmt.Errorf("dep is not a cc module: %s", dep.String()))
+ }
+ depPaths.DarwinSecondArchOutput = linkableInfo.OutputFile
return
}
@@ -2993,34 +3271,32 @@
}
}
- ccDep, ok := dep.(LinkableInterface)
- if !ok {
-
+ if !hasLinkableInfo {
// handling for a few module types that aren't cc Module but that are also supported
+ genRule, ok := android.OtherModuleProvider(ctx, dep, android.GeneratedSourceInfoProvider)
switch depTag {
case genSourceDepTag:
- if genRule, ok := dep.(genrule.SourceFileGenerator); ok {
+ if ok {
depPaths.GeneratedSources = append(depPaths.GeneratedSources,
- genRule.GeneratedSourceFiles()...)
+ genRule.GeneratedSourceFiles...)
} else {
ctx.ModuleErrorf("module %q is not a gensrcs or genrule", depName)
}
// Support exported headers from a generated_sources dependency
fallthrough
case genHeaderDepTag, genHeaderExportDepTag:
- if genRule, ok := dep.(genrule.SourceFileGenerator); ok {
+ if ok {
depPaths.GeneratedDeps = append(depPaths.GeneratedDeps,
- genRule.GeneratedDeps()...)
- dirs := genRule.GeneratedHeaderDirs()
+ genRule.GeneratedDeps...)
+ dirs := genRule.GeneratedHeaderDirs
depPaths.IncludeDirs = append(depPaths.IncludeDirs, dirs...)
if depTag == genHeaderExportDepTag {
depPaths.ReexportedDirs = append(depPaths.ReexportedDirs, dirs...)
depPaths.ReexportedGeneratedHeaders = append(depPaths.ReexportedGeneratedHeaders,
- genRule.GeneratedSourceFiles()...)
- depPaths.ReexportedDeps = append(depPaths.ReexportedDeps, genRule.GeneratedDeps()...)
+ genRule.GeneratedSourceFiles...)
+ depPaths.ReexportedDeps = append(depPaths.ReexportedDeps, genRule.GeneratedDeps...)
// Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library.
c.sabi.Properties.ReexportedIncludes = append(c.sabi.Properties.ReexportedIncludes, dirs.Strings()...)
-
}
} else {
ctx.ModuleErrorf("module %q is not a genrule", depName)
@@ -3041,13 +3317,14 @@
return
}
- if dep.Target().Os != ctx.Os() {
- ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
+ commonInfo := android.OtherModuleProviderOrDefault(ctx, dep, android.CommonModuleInfoKey)
+ if commonInfo.Target.Os != ctx.Os() {
+ ctx.ModuleErrorf("OS mismatch between %q (%s) and %q (%s)", ctx.ModuleName(), ctx.Os().Name, depName, dep.Target().Os.Name)
return
}
- if dep.Target().Arch.ArchType != ctx.Arch().ArchType {
+ if commonInfo.Target.Arch.ArchType != ctx.Arch().ArchType {
ctx.ModuleErrorf("Arch mismatch between %q(%v) and %q(%v)",
- ctx.ModuleName(), ctx.Arch().ArchType, depName, dep.Target().Arch.ArchType)
+ ctx.ModuleName(), ctx.Arch().ArchType, depName, commonInfo.Target.Arch.ArchType)
return
}
@@ -3056,7 +3333,7 @@
// The reuseObjTag dependency still exists because the LinkageMutator runs before the
// version mutator, so the stubs variant is created from the shared variant that
// already has the reuseObjTag dependency on the static variant.
- if !c.library.buildStubs() {
+ if !c.library.BuildStubs() {
staticAnalogue, _ := android.OtherModuleProvider(ctx, dep, StaticLibraryInfoProvider)
objs := staticAnalogue.ReuseObjects
depPaths.Objs = depPaths.Objs.Append(objs)
@@ -3072,7 +3349,7 @@
depPaths.LlndkSystemIncludeDirs = append(depPaths.LlndkSystemIncludeDirs, depExporterInfo.SystemIncludeDirs...)
}
- linkFile := ccDep.OutputFile()
+ linkFile := linkableInfo.OutputFile
if libDepTag, ok := depTag.(libraryDependencyTag); ok {
// Only use static unwinder for legacy (min_sdk_version = 29) apexes (b/144430859)
@@ -3126,6 +3403,16 @@
linkFile = android.OptionalPathForPath(sharedLibraryInfo.SharedLibrary)
depFile = sharedLibraryInfo.TableOfContents
+ if !sharedLibraryInfo.IsStubs {
+ // TODO(b/362509506): remove this additional check once all apex_exclude uses are switched to stubs.
+ if !linkableInfo.RustApexExclude {
+ depPaths.directImplementationDeps = append(depPaths.directImplementationDeps, android.OutputFileForModule(ctx, dep, ""))
+ if info, ok := android.OtherModuleProvider(ctx, dep, ImplementationDepInfoProvider); ok {
+ depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps)
+ }
+ }
+ }
+
ptr = &depPaths.SharedLibs
switch libDepTag.Order {
case earlyLibraryDependency:
@@ -3143,8 +3430,8 @@
}
case libDepTag.static():
- if ccDep.RustLibraryInterface() {
- rlibDep := RustRlibDep{LibPath: linkFile.Path(), CrateName: ccDep.CrateName(), LinkDirs: ccDep.ExportedCrateLinkDirs()}
+ if linkableInfo.RustLibraryInterface {
+ rlibDep := RustRlibDep{LibPath: linkFile.Path(), CrateName: linkableInfo.CrateName, LinkDirs: linkableInfo.ExportedCrateLinkDirs}
depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, rlibDep)
depPaths.IncludeDirs = append(depPaths.IncludeDirs, depExporterInfo.IncludeDirs...)
if libDepTag.wholeStatic {
@@ -3221,8 +3508,8 @@
}
}
- if libDepTag.static() && !libDepTag.wholeStatic && !ccDep.RustLibraryInterface() {
- if !ccDep.CcLibraryInterface() || !ccDep.Static() {
+ if libDepTag.static() && !libDepTag.wholeStatic && !linkableInfo.RustLibraryInterface {
+ if !linkableInfo.CcLibraryInterface || !linkableInfo.Static {
ctx.ModuleErrorf("module %q not a static library", depName)
return
}
@@ -3230,16 +3517,15 @@
// When combining coverage files for shared libraries and executables, coverage files
// in static libraries act as if they were whole static libraries. The same goes for
// source based Abi dump files.
- if c, ok := ccDep.(*Module); ok {
- staticLib := c.linker.(libraryInterface)
+ if hasCcInfo {
depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
- staticLib.objs().coverageFiles...)
+ linkableInfo.CoverageFiles...)
depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles,
- staticLib.objs().sAbiDumpFiles...)
+ linkableInfo.SAbiDumpFiles...)
} else {
// Handle non-CC modules here
depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
- ccDep.CoverageFiles()...)
+ linkableInfo.CoverageFiles...)
}
}
@@ -3285,30 +3571,18 @@
c.sabi.Properties.ReexportedSystemIncludes, depExporterInfo.SystemIncludeDirs.Strings()...)
}
- makeLibName := MakeLibName(ctx, c, ccDep, ccDep.BaseModuleName()) + libDepTag.makeSuffix
+ makeLibName := MakeLibName(ccInfo, linkableInfo, &commonInfo, linkableInfo.BaseModuleName) + libDepTag.makeSuffix
switch {
case libDepTag.header():
c.Properties.AndroidMkHeaderLibs = append(
c.Properties.AndroidMkHeaderLibs, makeLibName)
case libDepTag.shared():
- if lib := moduleLibraryInterface(dep); lib != nil {
- if lib.buildStubs() && dep.(android.ApexModule).InAnyApex() {
- // Add the dependency to the APEX(es) providing the library so that
- // m <module> can trigger building the APEXes as well.
- depApexInfo, _ := android.OtherModuleProvider(ctx, dep, android.ApexInfoProvider)
- for _, an := range depApexInfo.InApexVariants {
- c.Properties.ApexesProvidingSharedLibs = append(
- c.Properties.ApexesProvidingSharedLibs, an)
- }
- }
- }
-
// Note: the order of libs in this list is not important because
// they merely serve as Make dependencies and do not affect this lib itself.
c.Properties.AndroidMkSharedLibs = append(
c.Properties.AndroidMkSharedLibs, makeLibName)
case libDepTag.static():
- if !ccDep.RustLibraryInterface() {
+ if !linkableInfo.RustLibraryInterface {
if libDepTag.wholeStatic {
c.Properties.AndroidMkWholeStaticLibs = append(
c.Properties.AndroidMkWholeStaticLibs, makeLibName)
@@ -3324,7 +3598,7 @@
switch depTag {
case runtimeDepTag:
c.Properties.AndroidMkRuntimeLibs = append(
- c.Properties.AndroidMkRuntimeLibs, MakeLibName(ctx, c, ccDep, ccDep.BaseModuleName())+libDepTag.makeSuffix)
+ c.Properties.AndroidMkRuntimeLibs, MakeLibName(ccInfo, linkableInfo, &commonInfo, linkableInfo.BaseModuleName)+libDepTag.makeSuffix)
case objDepTag:
depPaths.Objs.objFiles = append(depPaths.Objs.objFiles, linkFile.Path())
case CrtBeginDepTag:
@@ -3364,27 +3638,30 @@
return depPaths
}
-func ShouldUseStubForApex(ctx android.ModuleContext, dep android.Module) bool {
- depName := ctx.OtherModuleName(dep)
- thisModule, ok := ctx.Module().(android.ApexModule)
- if !ok {
- panic(fmt.Errorf("Not an APEX module: %q", ctx.ModuleName()))
- }
-
+func ShouldUseStubForApex(ctx android.ModuleContext, parent android.Module, dep android.ModuleProxy) bool {
inVendorOrProduct := false
bootstrap := false
- if linkable, ok := ctx.Module().(LinkableInterface); !ok {
- panic(fmt.Errorf("Not a Linkable module: %q", ctx.ModuleName()))
+ if ctx.EqualModules(ctx.Module(), parent) {
+ if linkable, ok := parent.(LinkableInterface); !ok {
+ ctx.ModuleErrorf("Not a Linkable module: %q", ctx.ModuleName())
+ } else {
+ inVendorOrProduct = linkable.InVendorOrProduct()
+ bootstrap = linkable.Bootstrap()
+ }
} else {
- inVendorOrProduct = linkable.InVendorOrProduct()
- bootstrap = linkable.Bootstrap()
+ if linkable, ok := android.OtherModuleProvider(ctx, parent, LinkableInfoProvider); !ok {
+ ctx.ModuleErrorf("Not a Linkable module: %q", ctx.ModuleName())
+ } else {
+ inVendorOrProduct = linkable.InVendorOrProduct
+ bootstrap = linkable.Bootstrap
+ }
}
- apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+ apexInfo, _ := android.OtherModuleProvider(ctx, parent, android.ApexInfoProvider)
useStubs := false
- if lib := moduleLibraryInterface(dep); lib.buildStubs() && inVendorOrProduct { // LLNDK
+ if android.OtherModuleProviderOrDefault(ctx, dep, LinkableInfoProvider).IsStubs && inVendorOrProduct { // LLNDK
if !apexInfo.IsForPlatform() {
// For platform libraries, use current version of LLNDK
// If this is for use_vendor apex we will apply the same rules
@@ -3396,51 +3673,12 @@
// platform APIs, use stubs only when it is from an APEX (and not from
// platform) However, for host, ramdisk, vendor_ramdisk, recovery or
// bootstrap modules, always link to non-stub variant
- isNotInPlatform := dep.(android.ApexModule).NotInPlatform()
+ isNotInPlatform := android.OtherModuleProviderOrDefault(ctx, dep, android.CommonModuleInfoKey).NotInPlatform
- isApexImportedApiLibrary := false
-
- if cc, ok := dep.(*Module); ok {
- if apiLibrary, ok := cc.linker.(*apiLibraryDecorator); ok {
- if apiLibrary.hasApexStubs() {
- isApexImportedApiLibrary = true
- }
- }
- }
-
- useStubs = (isNotInPlatform || isApexImportedApiLibrary) && !bootstrap
-
- if useStubs {
- // Another exception: if this module is a test for an APEX, then
- // it is linked with the non-stub variant of a module in the APEX
- // as if this is part of the APEX.
- testFor, _ := android.ModuleProvider(ctx, android.ApexTestForInfoProvider)
- for _, apexContents := range testFor.ApexContents {
- if apexContents.DirectlyInApex(depName) {
- useStubs = false
- break
- }
- }
- }
- if useStubs {
- // Yet another exception: If this module and the dependency are
- // available to the same APEXes then skip stubs between their
- // platform variants. This complements the test_for case above,
- // which avoids the stubs on a direct APEX library dependency, by
- // avoiding stubs for indirect test dependencies as well.
- //
- // TODO(b/183882457): This doesn't work if the two libraries have
- // only partially overlapping apex_available. For that test_for
- // modules would need to be split into APEX variants and resolved
- // separately for each APEX they have access to.
- if !isApexImportedApiLibrary && android.AvailableToSameApexes(thisModule, dep.(android.ApexModule)) {
- useStubs = false
- }
- }
+ useStubs = isNotInPlatform && !bootstrap
} else {
- // If building for APEX, use stubs when the parent is in any APEX that
- // the child is not in.
- useStubs = !android.DirectlyInAllApexes(apexInfo, depName)
+ // If building for APEX, always use stubs (can be bypassed by depending on <dep>#impl)
+ useStubs = true
}
return useStubs
@@ -3453,7 +3691,7 @@
// library bar which provides stable interface and exists in the platform, foo uses the stub variant
// of bar. If bar doesn't provide a stable interface (i.e. buildStubs() == false) or is in the
// same APEX as foo, the non-stub variant of bar is used.
-func ChooseStubOrImpl(ctx android.ModuleContext, dep android.Module) (SharedLibraryInfo, FlagExporterInfo) {
+func ChooseStubOrImpl(ctx android.ModuleContext, dep android.ModuleProxy) (SharedLibraryInfo, FlagExporterInfo) {
depTag := ctx.OtherModuleDependencyTag(dep)
libDepTag, ok := depTag.(libraryDependencyTag)
if !ok || !libDepTag.shared() {
@@ -3466,7 +3704,7 @@
if !libDepTag.explicitlyVersioned && len(sharedLibraryStubsInfo.SharedStubLibraries) > 0 {
// when to use (unspecified) stubs, use the latest one.
- if ShouldUseStubForApex(ctx, dep) {
+ if ShouldUseStubForApex(ctx, ctx.Module(), dep) {
stubs := sharedLibraryStubsInfo.SharedStubLibraries
toUse := stubs[len(stubs)-1]
sharedLibraryInfo = toUse.SharedLibraryInfo
@@ -3478,19 +3716,17 @@
// orderStaticModuleDeps rearranges the order of the static library dependencies of the module
// to match the topological order of the dependency tree, including any static analogues of
-// direct shared libraries. It returns the ordered static dependencies, and an android.DepSet
+// direct shared libraries. It returns the ordered static dependencies, and a depset.DepSet
// of the transitive dependencies.
-func orderStaticModuleDeps(staticDeps []StaticLibraryInfo, sharedDeps []SharedLibraryInfo) (ordered android.Paths, transitive *android.DepSet[android.Path]) {
- transitiveStaticLibsBuilder := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL)
+func orderStaticModuleDeps(staticDeps []StaticLibraryInfo, sharedDeps []SharedLibraryInfo) (ordered android.Paths, transitive depset.DepSet[android.Path]) {
+ transitiveStaticLibsBuilder := depset.NewBuilder[android.Path](depset.TOPOLOGICAL)
var staticPaths android.Paths
for _, staticDep := range staticDeps {
staticPaths = append(staticPaths, staticDep.StaticLibrary)
transitiveStaticLibsBuilder.Transitive(staticDep.TransitiveStaticLibrariesForOrdering)
}
for _, sharedDep := range sharedDeps {
- if sharedDep.TransitiveStaticLibrariesForOrdering != nil {
- transitiveStaticLibsBuilder.Transitive(sharedDep.TransitiveStaticLibrariesForOrdering)
- }
+ transitiveStaticLibsBuilder.Transitive(sharedDep.TransitiveStaticLibrariesForOrdering)
}
transitiveStaticLibs := transitiveStaticLibsBuilder.Build()
@@ -3516,32 +3752,29 @@
return libName
}
-func MakeLibName(ctx android.ModuleContext, c LinkableInterface, ccDep LinkableInterface, depName string) string {
+func MakeLibName(ccInfo *CcInfo, linkableInfo *LinkableInfo, commonInfo *android.CommonModuleInfo, depName string) string {
libName := BaseLibName(depName)
- ccDepModule, _ := ccDep.(*Module)
- isLLndk := ccDepModule != nil && ccDepModule.IsLlndk()
- nonSystemVariantsExist := ccDep.HasNonSystemVariants() || isLLndk
+ isLLndk := ccInfo != nil && linkableInfo.IsLlndk
+ nonSystemVariantsExist := linkableInfo.HasNonSystemVariants || isLLndk
- if ccDepModule != nil {
+ if ccInfo != nil {
// Use base module name for snapshots when exporting to Makefile.
- if snapshotPrebuilt, ok := ccDepModule.linker.(SnapshotInterface); ok {
- baseName := ccDepModule.BaseModuleName()
-
- return baseName + snapshotPrebuilt.SnapshotAndroidMkSuffix()
+ if ccInfo.SnapshotInfo != nil {
+ return linkableInfo.BaseModuleName + ccInfo.SnapshotInfo.SnapshotAndroidMkSuffix
}
}
- if ccDep.InVendorOrProduct() && nonSystemVariantsExist {
+ if linkableInfo.InVendorOrProduct && nonSystemVariantsExist {
// The vendor and product modules in Make will have been renamed to not conflict with the
// core module, so update the dependency name here accordingly.
- return libName + ccDep.SubName()
- } else if ccDep.InRamdisk() && !ccDep.OnlyInRamdisk() {
+ return libName + linkableInfo.SubName
+ } else if linkableInfo.InRamdisk && !linkableInfo.OnlyInRamdisk {
return libName + RamdiskSuffix
- } else if ccDep.InVendorRamdisk() && !ccDep.OnlyInVendorRamdisk() {
+ } else if linkableInfo.InVendorRamdisk && !linkableInfo.OnlyInVendorRamdisk {
return libName + VendorRamdiskSuffix
- } else if ccDep.InRecovery() && !ccDep.OnlyInRecovery() {
+ } else if linkableInfo.InRecovery && !linkableInfo.OnlyInRecovery {
return libName + RecoverySuffix
- } else if ccDep.Target().NativeBridge == android.NativeBridgeEnabled {
+ } else if commonInfo.Target.NativeBridge == android.NativeBridgeEnabled {
return libName + NativeBridgeSuffix
} else {
return libName
@@ -3605,6 +3838,15 @@
return false
}
+func (c *Module) staticLibrary() bool {
+ if static, ok := c.linker.(interface {
+ staticLibrary() bool
+ }); ok {
+ return static.staticLibrary()
+ }
+ return false
+}
+
func (c *Module) staticBinary() bool {
if static, ok := c.linker.(interface {
staticBinary() bool
@@ -3669,6 +3911,10 @@
return false
}
+func (c *Module) ForceDisableSanitizers() {
+ c.sanitize.Properties.ForceDisable = true
+}
+
func (c *Module) StaticExecutable() bool {
if b, ok := c.linker.(*binaryDecorator); ok {
return b.static()
@@ -3724,23 +3970,24 @@
if lib := c.library; lib != nil {
// Stub libs and prebuilt libs in a versioned SDK are not
// installable to APEX even though they are shared libs.
- return lib.shared() && !lib.buildStubs()
+ return lib.shared() && !lib.BuildStubs()
}
return false
}
func (c *Module) AvailableFor(what string) bool {
- if linker, ok := c.linker.(interface {
- availableFor(string) bool
- }); ok {
- return c.ApexModuleBase.AvailableFor(what) || linker.availableFor(what)
- } else {
- return c.ApexModuleBase.AvailableFor(what)
- }
+ return android.CheckAvailableForApex(what, c.ApexAvailableFor())
}
-func (c *Module) TestFor() []string {
- return c.Properties.Test_for
+func (c *Module) ApexAvailableFor() []string {
+ list := c.ApexModuleBase.ApexAvailable()
+ if linker, ok := c.linker.(interface {
+ apexAvailable() []string
+ }); ok {
+ list = append(list, linker.apexAvailable()...)
+ }
+
+ return android.FirstUniqueStrings(list)
}
func (c *Module) EverInstallable() bool {
@@ -3798,36 +4045,8 @@
var _ android.ApexModule = (*Module)(nil)
// Implements android.ApexModule
-func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
- depTag := ctx.OtherModuleDependencyTag(dep)
- libDepTag, isLibDepTag := depTag.(libraryDependencyTag)
-
- if cc, ok := dep.(*Module); ok {
- if cc.HasStubsVariants() {
- if isLibDepTag && libDepTag.shared() {
- // dynamic dep to a stubs lib crosses APEX boundary
- return false
- }
- if IsRuntimeDepTag(depTag) {
- // runtime dep to a stubs lib also crosses APEX boundary
- return false
- }
- }
- if cc.IsLlndk() {
- return false
- }
- if isLibDepTag && c.static() && libDepTag.shared() {
- // shared_lib dependency from a static lib is considered as crossing
- // the APEX boundary because the dependency doesn't actually is
- // linked; the dependency is used only during the compilation phase.
- return false
- }
-
- if isLibDepTag && libDepTag.excludeInApex {
- return false
- }
- }
- if depTag == stubImplDepTag {
+func (c *Module) OutgoingDepIsInSameApex(depTag blueprint.DependencyTag) bool {
+ if depTag == StubImplDepTag {
// We don't track from an implementation library to its stubs.
return false
}
@@ -3837,6 +4056,40 @@
// APEX.
return false
}
+
+ libDepTag, isLibDepTag := depTag.(libraryDependencyTag)
+ if isLibDepTag && c.static() && libDepTag.shared() {
+ // shared_lib dependency from a static lib is considered as crossing
+ // the APEX boundary because the dependency doesn't actually is
+ // linked; the dependency is used only during the compilation phase.
+ return false
+ }
+
+ if isLibDepTag && libDepTag.excludeInApex {
+ return false
+ }
+
+ return true
+}
+
+func (c *Module) IncomingDepIsInSameApex(depTag blueprint.DependencyTag) bool {
+ if c.HasStubsVariants() {
+ if IsSharedDepTag(depTag) {
+ // dynamic dep to a stubs lib crosses APEX boundary
+ return false
+ }
+ if IsRuntimeDepTag(depTag) {
+ // runtime dep to a stubs lib also crosses APEX boundary
+ return false
+ }
+ if IsHeaderDepTag(depTag) {
+ return false
+ }
+ }
+ if c.IsLlndk() {
+ return false
+ }
+
return true
}
@@ -4017,11 +4270,6 @@
return c.Properties.IsSdkVariant
}
-func (c *Module) isImportedApiLibrary() bool {
- _, ok := c.linker.(*apiLibraryDecorator)
- return ok
-}
-
func kytheExtractAllFactory() android.Singleton {
return &kytheExtractAllSingleton{}
}
@@ -4031,9 +4279,10 @@
func (ks *kytheExtractAllSingleton) GenerateBuildActions(ctx android.SingletonContext) {
var xrefTargets android.Paths
- ctx.VisitAllModules(func(module android.Module) {
- if ccModule, ok := module.(xref); ok {
- xrefTargets = append(xrefTargets, ccModule.XrefCcFiles()...)
+ ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
+ files := android.OtherModuleProviderOrDefault(ctx, module, CcObjectInfoProvider).KytheFiles
+ if len(files) > 0 {
+ xrefTargets = append(xrefTargets, files...)
}
})
// TODO(asmundak): Perhaps emit a rule to output a warning if there were no xrefTargets
diff --git a/cc/cc_preprocess_no_configuration.go b/cc/cc_preprocess_no_configuration.go
new file mode 100644
index 0000000..3d4b077
--- /dev/null
+++ b/cc/cc_preprocess_no_configuration.go
@@ -0,0 +1,115 @@
+// 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 cc
+
+import (
+ "android/soong/android"
+ "slices"
+ "strings"
+)
+
+func init() {
+ RegisterCCPreprocessNoConfiguration(android.InitRegistrationContext)
+}
+
+func RegisterCCPreprocessNoConfiguration(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("cc_preprocess_no_configuration", ccPreprocessNoConfigurationFactory)
+}
+
+// cc_preprocess_no_configuration modules run the c preprocessor on a single input source file.
+// They also have "no configuration", meaning they don't have an arch or os associated with them,
+// they should be thought of as pure textual transformations of the input file. In some cases this
+// is good, in others you might want to do different transformations depending on what arch the
+// result will be compiled in, in which case you can use cc_object instead of this module.
+func ccPreprocessNoConfigurationFactory() android.Module {
+ m := &ccPreprocessNoConfiguration{}
+ m.AddProperties(&m.properties)
+ android.InitAndroidModule(m)
+ return m
+}
+
+type ccPreprocessNoConfigurationProps struct {
+ // Called Srcs for consistency with the other cc module types, but only accepts 1 input source
+ // file.
+ Srcs []string `android:"path"`
+ // The flags to pass to the c compiler. Must include -E in order to enable preprocessing-only
+ // mode.
+ Cflags []string `android:"path"`
+}
+
+type ccPreprocessNoConfiguration struct {
+ android.ModuleBase
+ properties ccPreprocessNoConfigurationProps
+}
+
+func (m *ccPreprocessNoConfiguration) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ srcs := android.PathsForModuleSrc(ctx, m.properties.Srcs)
+ if len(srcs) != 1 {
+ ctx.PropertyErrorf("Srcs", "cc_preprocess_no_configuration only accepts 1 source file, found: %v", srcs.Strings())
+ return
+ }
+ src := srcs[0]
+
+ hasE := false
+ for _, cflag := range m.properties.Cflags {
+ if cflag == "-E" {
+ hasE = true
+ break
+ } else if cflag == "-P" || strings.HasPrefix(cflag, "-D") {
+ // do nothing, allow it
+ } else {
+ ctx.PropertyErrorf("Cflags", "cc_preprocess_no_configuration only allows -D and -P flags, found: %q", cflag)
+ return
+ }
+ }
+ if !hasE {
+ ctx.PropertyErrorf("Cflags", "cc_preprocess_no_configuration must have a -E cflag")
+ return
+ }
+
+ cflags := slices.Clone(m.properties.Cflags)
+
+ // Match behavior of other cc modules:
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/soong/cc/compiler.go;l=422;drc=7297f05ee8cda422ccb32c4af4d9d715d6bac10e
+ cflags = append(cflags, "-I"+ctx.ModuleDir())
+
+ var ccCmd string
+ switch src.Ext() {
+ case ".c":
+ ccCmd = "clang"
+ case ".cpp", ".cc", ".cxx", ".mm":
+ ccCmd = "clang++"
+ default:
+ ctx.PropertyErrorf("srcs", "File %s has unknown extension. Supported extensions: .c, .cpp, .cc, .cxx, .mm", src)
+ return
+ }
+
+ ccCmd = "${config.ClangBin}/" + ccCmd
+
+ outFile := android.PathForModuleOut(ctx, src.Base())
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: cc,
+ Description: ccCmd + " " + src.Rel(),
+ Output: outFile,
+ Input: src,
+ Args: map[string]string{
+ "cFlags": strings.Join(cflags, " "),
+ "ccCmd": ccCmd,
+ },
+ })
+
+ ctx.SetOutputFiles([]android.Path{outFile}, "")
+}
diff --git a/cc/cc_preprocess_no_configuration_test.go b/cc/cc_preprocess_no_configuration_test.go
new file mode 100644
index 0000000..c6eae4c
--- /dev/null
+++ b/cc/cc_preprocess_no_configuration_test.go
@@ -0,0 +1,43 @@
+// Copyright 2019 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 cc
+
+import (
+ "android/soong/android"
+ "testing"
+)
+
+func TestCcPreprocessNoConfiguration(t *testing.T) {
+ bp := `
+ cc_preprocess_no_configuration {
+ name: "foo",
+ srcs: ["main.cc"],
+ cflags: ["-E", "-DANDROID"],
+ }
+ `
+
+ fixture := android.GroupFixturePreparers(
+ android.PrepareForIntegrationTestWithAndroid,
+ android.FixtureRegisterWithContext(RegisterCCPreprocessNoConfiguration),
+ android.FixtureAddTextFile("foo/bar/Android.bp", bp),
+ )
+
+ result := fixture.RunTest(t)
+
+ foo := result.ModuleForTests("foo", "")
+ actual := foo.Rule("cc").Args["cFlags"]
+ expected := "-E -DANDROID -Ifoo/bar"
+ android.AssertStringEquals(t, "cflags should be correct", expected, actual)
+}
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 79e386f..98af7b6 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -20,6 +20,7 @@
"reflect"
"regexp"
"runtime"
+ "slices"
"strings"
"testing"
@@ -39,9 +40,6 @@
var prepareForCcTest = android.GroupFixturePreparers(
PrepareForIntegrationTestWithCc,
- android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.VendorApiLevel = StringPtr("202404")
- }),
)
var apexVariationName = "apex28"
@@ -49,17 +47,30 @@
func registerTestMutators(ctx android.RegistrationContext) {
ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("apex", testApexMutator).Parallel()
+ ctx.Transition("apex", &testApexTransitionMutator{})
})
}
-func testApexMutator(mctx android.BottomUpMutatorContext) {
- modules := mctx.CreateVariations(apexVariationName)
+type testApexTransitionMutator struct{}
+
+func (t *testApexTransitionMutator) Split(ctx android.BaseModuleContext) []string {
+ return []string{apexVariationName}
+}
+
+func (t *testApexTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+ return sourceVariation
+}
+
+func (t *testApexTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+ return incomingVariation
+}
+
+func (t *testApexTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
apexInfo := android.ApexInfo{
ApexVariationName: apexVariationName,
MinSdkVersion: android.ApiLevelForTest(apexVersion),
}
- mctx.SetVariationProvider(modules[0], android.ApexInfoProvider, apexInfo)
+ android.SetProvider(ctx, android.ApexInfoProvider, apexInfo)
}
// testCcWithConfig runs tests using the prepareForCcTest
@@ -368,7 +379,7 @@
if !strings.HasSuffix(outputPath, "/main_test") {
t.Errorf("expected test output file to be 'main_test', but was '%s'", outputPath)
}
- entries := android.AndroidMkEntriesForTest(t, ctx, module)[0]
+ entries := android.AndroidMkInfoForTest(t, ctx, module).PrimaryInfo
if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][0], ":test_lib.so:foo/bar/baz") {
t.Errorf("expected LOCAL_TEST_DATA to end with `:test_lib.so:foo/bar/baz`,"+
" but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][0])
@@ -396,7 +407,7 @@
ctx := prepareForCcTest.RunTestWithBp(t, bp).TestContext
module := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon").Module()
- entries := android.AndroidMkEntriesForTest(t, ctx, module)[0]
+ entries := android.AndroidMkInfoForTest(t, ctx, module).PrimaryInfo
compatEntries := entries.EntryMap["LOCAL_COMPATIBILITY_SUITE"]
if len(compatEntries) != 2 {
t.Errorf("expected two elements in LOCAL_COMPATIBILITY_SUITE. got %d", len(compatEntries))
@@ -428,7 +439,7 @@
ctx := prepareForCcTest.RunTestWithBp(t, bp).TestContext
module := ctx.ModuleForTests("main_test_lib", "android_arm_armv7-a-neon_shared").Module()
- entries := android.AndroidMkEntriesForTest(t, ctx, module)[0]
+ entries := android.AndroidMkInfoForTest(t, ctx, module).PrimaryInfo
compatEntries := entries.EntryMap["LOCAL_COMPATIBILITY_SUITE"]
if len(compatEntries) != 2 {
t.Errorf("expected two elements in LOCAL_COMPATIBILITY_SUITE. got %d", len(compatEntries))
@@ -927,7 +938,7 @@
cc_prebuilt_library_shared {
name: "libllndkprebuilt",
- stubs: { versions: ["1", "2"] },
+ stubs: { versions: ["1", "2"] , symbol_file: "libllndkprebuilt.map.txt" },
llndk: {
symbol_file: "libllndkprebuilt.map.txt",
},
@@ -994,7 +1005,7 @@
android.AssertArrayString(t, "variants for llndk stubs", expected, actual)
params := result.ModuleForTests("libllndk", "android_vendor_arm_armv7-a-neon_shared").Description("generate stub")
- android.AssertSame(t, "use Vendor API level for default stubs", "202404", params.Args["apiLevel"])
+ android.AssertSame(t, "use Vendor API level for default stubs", "35", params.Args["apiLevel"])
checkExportedIncludeDirs := func(module, variant string, expectedSystemDirs []string, expectedDirs ...string) {
t.Helper()
@@ -1417,7 +1428,7 @@
if !strings.HasSuffix(outputPath, "/main_test") {
t.Errorf("expected test output file to be 'main_test', but was '%s'", outputPath)
}
- entries := android.AndroidMkEntriesForTest(t, ctx, module)[0]
+ entries := android.AndroidMkInfoForTest(t, ctx, module).PrimaryInfo
if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][0], ":test_lib.so:foo/bar/baz") {
t.Errorf("expected LOCAL_TEST_DATA to end with `:test_lib.so:foo/bar/baz`,"+
" but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][0])
@@ -1491,111 +1502,6 @@
}
}
-func TestStubsForLibraryInMultipleApexes(t *testing.T) {
- t.Parallel()
- ctx := testCc(t, `
- cc_library_shared {
- name: "libFoo",
- srcs: ["foo.c"],
- stubs: {
- symbol_file: "foo.map.txt",
- versions: ["current"],
- },
- apex_available: ["bar", "a1"],
- }
-
- cc_library_shared {
- name: "libBar",
- srcs: ["bar.c"],
- shared_libs: ["libFoo"],
- apex_available: ["a1"],
- }
-
- cc_library_shared {
- name: "libA1",
- srcs: ["a1.c"],
- shared_libs: ["libFoo"],
- apex_available: ["a1"],
- }
-
- cc_library_shared {
- name: "libBarA1",
- srcs: ["bara1.c"],
- shared_libs: ["libFoo"],
- apex_available: ["bar", "a1"],
- }
-
- cc_library_shared {
- name: "libAnyApex",
- srcs: ["anyApex.c"],
- shared_libs: ["libFoo"],
- apex_available: ["//apex_available:anyapex"],
- }
-
- cc_library_shared {
- name: "libBaz",
- srcs: ["baz.c"],
- shared_libs: ["libFoo"],
- apex_available: ["baz"],
- }
-
- cc_library_shared {
- name: "libQux",
- srcs: ["qux.c"],
- shared_libs: ["libFoo"],
- apex_available: ["qux", "bar"],
- }`)
-
- variants := ctx.ModuleVariantsForTests("libFoo")
- expectedVariants := []string{
- "android_arm64_armv8-a_shared",
- "android_arm64_armv8-a_shared_current",
- "android_arm_armv7-a-neon_shared",
- "android_arm_armv7-a-neon_shared_current",
- }
- variantsMismatch := false
- if len(variants) != len(expectedVariants) {
- variantsMismatch = true
- } else {
- for _, v := range expectedVariants {
- if !inList(v, variants) {
- variantsMismatch = false
- }
- }
- }
- if variantsMismatch {
- t.Errorf("variants of libFoo expected:\n")
- for _, v := range expectedVariants {
- t.Errorf("%q\n", v)
- }
- t.Errorf(", but got:\n")
- for _, v := range variants {
- t.Errorf("%q\n", v)
- }
- }
-
- linkAgainstFoo := []string{"libBarA1"}
- linkAgainstFooStubs := []string{"libBar", "libA1", "libBaz", "libQux", "libAnyApex"}
-
- libFooPath := "libFoo/android_arm64_armv8-a_shared/libFoo.so"
- for _, lib := range linkAgainstFoo {
- libLinkRule := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld")
- libFlags := libLinkRule.Args["libFlags"]
- if !strings.Contains(libFlags, libFooPath) {
- t.Errorf("%q: %q is not found in %q", lib, libFooPath, libFlags)
- }
- }
-
- libFooStubPath := "libFoo/android_arm64_armv8-a_shared_current/libFoo.so"
- for _, lib := range linkAgainstFooStubs {
- libLinkRule := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld")
- libFlags := libLinkRule.Args["libFlags"]
- if !strings.Contains(libFlags, libFooStubPath) {
- t.Errorf("%q: %q is not found in %q", lib, libFooStubPath, libFlags)
- }
- }
-}
-
func TestVersioningMacro(t *testing.T) {
t.Parallel()
for _, tc := range []struct{ moduleName, expected string }{
@@ -1890,11 +1796,11 @@
moduleName = "afl_fuzz_static_lib"
checkPcGuardFlag(moduleName, variant+"_static", false)
- checkPcGuardFlag(moduleName, variant+"_static_fuzzer", true)
+ checkPcGuardFlag(moduleName, variant+"_static_fuzzer_afl", true)
moduleName = "second_static_lib"
checkPcGuardFlag(moduleName, variant+"_static", false)
- checkPcGuardFlag(moduleName, variant+"_static_fuzzer", true)
+ checkPcGuardFlag(moduleName, variant+"_static_fuzzer_afl", true)
ctx.ModuleForTests("afl_fuzz_shared_lib",
"android_arm64_armv8-a_shared").Rule("cc")
@@ -2720,6 +2626,11 @@
func TestIncludeDirectoryOrdering(t *testing.T) {
t.Parallel()
+
+ expectedPlatformFlags := []string{
+ "-nostdlibinc",
+ }
+
baseExpectedFlags := []string{
"${config.ArmThumbCflags}",
"${config.ArmCflags}",
@@ -2729,10 +2640,18 @@
"${config.ArmToolchainCflags}",
"${config.ArmArmv7ANeonCflags}",
"${config.ArmGenericCflags}",
+ }
+
+ expectedTargetNDKFlags := []string{
"-target",
"armv7a-linux-androideabi21",
}
+ expectedTargetPlatformFlags := []string{
+ "-target",
+ "armv7a-linux-androideabi10000",
+ }
+
expectedIncludes := []string{
"external/foo/android_arm_export_include_dirs",
"external/foo/lib32_export_include_dirs",
@@ -2760,6 +2679,9 @@
"external/foo/libarm",
"external/foo/lib32",
"external/foo/libandroid_arm",
+ }
+
+ expectedNDKSTLIncludes := []string{
"defaults/cc/common/ndk_libc++_shared_include_dirs",
}
@@ -2770,38 +2692,92 @@
cstd := []string{"-std=gnu17", "-std=conly"}
cppstd := []string{"-std=gnu++20", "-std=cpp", "-fno-rtti"}
- lastIncludes := []string{
- "out/soong/ndk/sysroot/usr/include",
- "out/soong/ndk/sysroot/usr/include/arm-linux-androideabi",
+ lastNDKFlags := []string{
+ "--sysroot",
+ "out/soong/ndk/sysroot",
}
- combineSlices := func(slices ...[]string) []string {
- var ret []string
- for _, s := range slices {
- ret = append(ret, s...)
- }
- return ret
+ lastPlatformIncludes := []string{
+ "${config.CommonGlobalIncludes}",
}
testCases := []struct {
- name string
- src string
- expected []string
+ name string
+ src string
+ expectedNDK []string
+ expectedPlatform []string
}{
{
- name: "c",
- src: "foo.c",
- expected: combineSlices(baseExpectedFlags, conly, expectedIncludes, cflags, cstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"}),
+ name: "c",
+ src: "foo.c",
+ expectedNDK: slices.Concat(
+ baseExpectedFlags,
+ expectedTargetNDKFlags,
+ conly,
+ expectedIncludes,
+ expectedNDKSTLIncludes,
+ cflags,
+ cstd,
+ lastNDKFlags,
+ []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"},
+ ),
+ expectedPlatform: slices.Concat(
+ expectedPlatformFlags,
+ baseExpectedFlags,
+ expectedTargetPlatformFlags,
+ conly,
+ expectedIncludes,
+ cflags,
+ cstd,
+ lastPlatformIncludes,
+ []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"},
+ ),
},
{
- name: "cc",
- src: "foo.cc",
- expected: combineSlices(baseExpectedFlags, cppOnly, expectedIncludes, cflags, cppstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"}),
+ name: "cc",
+ src: "foo.cc",
+ expectedNDK: slices.Concat(
+ baseExpectedFlags,
+ expectedTargetNDKFlags,
+ cppOnly,
+ expectedIncludes,
+ expectedNDKSTLIncludes,
+ cflags,
+ cppstd,
+ lastNDKFlags,
+ []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"},
+ ),
+ expectedPlatform: slices.Concat(
+ expectedPlatformFlags,
+ baseExpectedFlags,
+ expectedTargetPlatformFlags,
+ cppOnly,
+ expectedIncludes,
+ cflags,
+ cppstd,
+ lastPlatformIncludes,
+ []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"},
+ ),
},
{
- name: "assemble",
- src: "foo.s",
- expected: combineSlices(baseExpectedFlags, []string{"${config.CommonGlobalAsflags}"}, expectedIncludes, lastIncludes),
+ name: "assemble",
+ src: "foo.s",
+ expectedNDK: slices.Concat(
+ baseExpectedFlags,
+ expectedTargetNDKFlags,
+ []string{"${config.CommonGlobalAsflags}"},
+ expectedIncludes,
+ expectedNDKSTLIncludes,
+ lastNDKFlags,
+ ),
+ expectedPlatform: slices.Concat(
+ expectedPlatformFlags,
+ baseExpectedFlags,
+ expectedTargetPlatformFlags,
+ []string{"${config.CommonGlobalAsflags}"},
+ expectedIncludes,
+ lastPlatformIncludes,
+ ),
},
}
@@ -2896,25 +2872,34 @@
`, lib, lib)
}
- ctx := android.GroupFixturePreparers(
- PrepareForIntegrationTestWithCc,
- android.FixtureAddTextFile("external/foo/Android.bp", bp),
- ).RunTest(t)
- cflags := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_sdk_static").Output("obj/external/foo/foo.o").Args["cFlags"]
+ runTest := func(t *testing.T, variant string, expected []string) {
+ ctx := android.GroupFixturePreparers(
+ PrepareForIntegrationTestWithCc,
+ android.FixtureAddTextFile("external/foo/Android.bp", bp),
+ ).RunTest(t)
+ cflags := ctx.ModuleForTests("libfoo", variant).Output("obj/external/foo/foo.o").Args["cFlags"]
- var includes []string
- flags := strings.Split(cflags, " ")
- for _, flag := range flags {
- if strings.HasPrefix(flag, "-I") {
- includes = append(includes, strings.TrimPrefix(flag, "-I"))
- } else if flag == "-isystem" {
- // skip isystem, include next
- } else if len(flag) > 0 {
- includes = append(includes, flag)
+ var includes []string
+ flags := strings.Split(cflags, " ")
+ for _, flag := range flags {
+ if strings.HasPrefix(flag, "-I") {
+ includes = append(includes, strings.TrimPrefix(flag, "-I"))
+ } else if flag == "-isystem" {
+ // skip isystem, include next
+ } else if len(flag) > 0 {
+ includes = append(includes, flag)
+ }
}
+
+ android.AssertArrayString(t, "includes", expected, includes)
}
- android.AssertArrayString(t, "includes", tc.expected, includes)
+ t.Run("platform", func(t *testing.T) {
+ runTest(t, "android_arm_armv7-a-neon_static", tc.expectedPlatform)
+ })
+ t.Run("ndk", func(t *testing.T) {
+ runTest(t, "android_arm_armv7-a-neon_sdk_static", tc.expectedNDK)
+ })
})
}
@@ -3165,7 +3150,7 @@
testDepWithVariant("product")
}
-func TestVendorSdkVersion(t *testing.T) {
+func TestVendorOrProductVariantUsesPlatformSdkVersionAsDefault(t *testing.T) {
t.Parallel()
bp := `
@@ -3173,31 +3158,29 @@
name: "libfoo",
srcs: ["libfoo.cc"],
vendor_available: true,
+ product_available: true,
}
cc_library {
name: "libbar",
srcs: ["libbar.cc"],
vendor_available: true,
+ product_available: true,
min_sdk_version: "29",
}
`
ctx := prepareForCcTest.RunTestWithBp(t, bp)
- testSdkVersionFlag := func(module, version string) {
- flags := ctx.ModuleForTests(module, "android_vendor_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
- android.AssertStringDoesContain(t, "min sdk version", flags, "-target aarch64-linux-android"+version)
+ testSdkVersionFlag := func(module, variant, version string) {
+ flags := ctx.ModuleForTests(module, "android_"+variant+"_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
+ android.AssertStringDoesContain(t, "target SDK version", flags, "-target aarch64-linux-android"+version)
}
- testSdkVersionFlag("libfoo", "10000")
- testSdkVersionFlag("libbar", "29")
-
- ctx = android.GroupFixturePreparers(
- prepareForCcTest,
- android.PrepareForTestWithBuildFlag("RELEASE_BOARD_API_LEVEL_FROZEN", "true"),
- ).RunTestWithBp(t, bp)
- testSdkVersionFlag("libfoo", "30")
- testSdkVersionFlag("libbar", "29")
+ testSdkVersionFlag("libfoo", "vendor", "30")
+ testSdkVersionFlag("libfoo", "product", "30")
+ // target SDK version can be set explicitly with min_sdk_version
+ testSdkVersionFlag("libbar", "vendor", "29")
+ testSdkVersionFlag("libbar", "product", "29")
}
func TestClangVerify(t *testing.T) {
@@ -3228,3 +3211,20 @@
t.Errorf("expected %q in cflags, got %q", "-Xclang -verify", cFlags_cv)
}
}
+
+func TestCheckConflictingExplicitVersions(t *testing.T) {
+ PrepareForIntegrationTestWithCc.
+ ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(
+ `shared_libs: duplicate shared libraries with different explicit versions: "libbar" and "libbar#impl"`,
+ )).
+ RunTestWithBp(t, `
+ cc_library {
+ name: "libfoo",
+ shared_libs: ["libbar", "libbar#impl"],
+ }
+
+ cc_library {
+ name: "libbar",
+ }
+ `)
+}
diff --git a/cc/check.go b/cc/check.go
index e3af3b2..8e2844f 100644
--- a/cc/check.go
+++ b/cc/check.go
@@ -40,6 +40,10 @@
ctx.PropertyErrorf(prop, "Bad flag: `%s`, use native_coverage instead", flag)
} else if flag == "-fwhole-program-vtables" {
ctx.PropertyErrorf(prop, "Bad flag: `%s`, use whole_program_vtables instead", flag)
+ } else if flag == "-gsplit-dwarf" {
+ ctx.PropertyErrorf(prop, "Bad flag: `%s`, soong cannot track dependencies to split dwarf debuginfo", flag)
+ } else if flag == "-fno-integrated-as" {
+ ctx.PropertyErrorf("Bad flag: `%s` is disallowed as it may invoke the `as` from the build host", flag)
} else if flag == "-Weverything" {
if !ctx.Config().IsEnvTrue("ANDROID_TEMPORARILY_ALLOW_WEVERYTHING") {
ctx.PropertyErrorf(prop, "-Weverything is not allowed in Android.bp files. "+
diff --git a/cc/cmake_module_aidl.txt b/cc/cmake_module_aidl.txt
index 84755a3..3622648 100644
--- a/cc/cmake_module_aidl.txt
+++ b/cc/cmake_module_aidl.txt
@@ -1,11 +1,11 @@
# <<.M.Name>>
-<<setList .M.Name "_SRCS" "" (getAidlSources .M)>>
+<<setList .M.Name "_SRCS" "" (getAidlSources .CcInfo)>>
-<<setList .M.Name "_AIDLFLAGS" "" (getCompilerProperties .M).AidlInterface.Flags>>
+<<setList .M.Name "_AIDLFLAGS" "" (getAidlInterface .CcInfo).Flags>>
-add_aidl_library(<<.M.Name>> <<(getCompilerProperties .M).AidlInterface.Lang>>
- "${ANDROID_BUILD_TOP}/<<.Ctx.OtherModuleDir .M>>/<<(getCompilerProperties .M).AidlInterface.AidlRoot>>"
+add_aidl_library(<<.M.Name>> <<(getAidlInterface .CcInfo).Lang>>
+ "${ANDROID_BUILD_TOP}/<<.Ctx.OtherModuleDir .M>>/<<(getAidlInterface .CcInfo).AidlRoot>>"
"${<<.M.Name>>_SRCS}"
"${<<.M.Name>>_AIDLFLAGS}")
add_library(android::<<.M.Name>> ALIAS <<.M.Name>>)
diff --git a/cc/cmake_module_cc.txt b/cc/cmake_module_cc.txt
index 0f6e62f..a57e053 100644
--- a/cc/cmake_module_cc.txt
+++ b/cc/cmake_module_cc.txt
@@ -1,14 +1,14 @@
-<<$srcs := getSources .M>>
-<<$includeDirs := getIncludeDirs .Ctx .M>>
-<<$cflags := getCflagsProperty .Ctx .M>>
+<<$srcs := getSources .Ctx .CcInfo>>
+<<$includeDirs := getIncludeDirs .Ctx .M .CcInfo>>
+<<$cflags := getCflagsProperty .Ctx .CcInfo>>
<<$deps := mapLibraries .Ctx .M (concat5
-(getWholeStaticLibsProperty .Ctx .M)
-(getStaticLibsProperty .Ctx .M)
-(getSharedLibsProperty .Ctx .M)
-(getHeaderLibsProperty .Ctx .M)
-(getExtraLibs .M)
+(getWholeStaticLibsProperty .Ctx .CcInfo)
+(getStaticLibsProperty .Ctx .CcInfo)
+(getSharedLibsProperty .Ctx .CcInfo)
+(getHeaderLibsProperty .Ctx .CcInfo)
+(getExtraLibs .CcInfo)
) .Pprop.LibraryMapping>>
-<<$moduleType := getModuleType .M>>
+<<$moduleType := getModuleType .CcInfo>>
<<$moduleTypeCmake := "executable">>
<<if eq $moduleType "library">>
<<$moduleTypeCmake = "library">>
diff --git a/cc/cmake_snapshot.go b/cc/cmake_snapshot.go
index 61fa46d..71fbcce 100644
--- a/cc/cmake_snapshot.go
+++ b/cc/cmake_snapshot.go
@@ -196,39 +196,36 @@
return list.String()
},
- "getSources": func(m *Module) android.Paths {
- return m.compiler.(CompiledInterface).Srcs()
+ "getSources": func(ctx android.ModuleContext, info *CcInfo) android.Paths {
+ return info.CompilerInfo.Srcs
},
"getModuleType": getModuleType,
- "getCompilerProperties": func(m *Module) BaseCompilerProperties {
- return m.compiler.baseCompilerProps()
+ "getAidlInterface": func(info *CcInfo) AidlInterfaceInfo {
+ return info.CompilerInfo.AidlInterfaceInfo
},
- "getCflagsProperty": func(ctx android.ModuleContext, m *Module) []string {
- prop := m.compiler.baseCompilerProps().Cflags
+ "getCflagsProperty": func(ctx android.ModuleContext, info *CcInfo) []string {
+ prop := info.CompilerInfo.Cflags
return prop.GetOrDefault(ctx, nil)
},
- "getLinkerProperties": func(m *Module) BaseLinkerProperties {
- return m.linker.baseLinkerProps()
- },
- "getWholeStaticLibsProperty": func(ctx android.ModuleContext, m *Module) []string {
- prop := m.linker.baseLinkerProps().Whole_static_libs
+ "getWholeStaticLibsProperty": func(ctx android.ModuleContext, info *CcInfo) []string {
+ prop := info.LinkerInfo.WholeStaticLibs
return prop.GetOrDefault(ctx, nil)
},
- "getStaticLibsProperty": func(ctx android.ModuleContext, m *Module) []string {
- prop := m.linker.baseLinkerProps().Static_libs
+ "getStaticLibsProperty": func(ctx android.ModuleContext, info *CcInfo) []string {
+ prop := info.LinkerInfo.StaticLibs
return prop.GetOrDefault(ctx, nil)
},
- "getSharedLibsProperty": func(ctx android.ModuleContext, m *Module) []string {
- prop := m.linker.baseLinkerProps().Shared_libs
+ "getSharedLibsProperty": func(ctx android.ModuleContext, info *CcInfo) []string {
+ prop := info.LinkerInfo.SharedLibs
return prop.GetOrDefault(ctx, nil)
},
- "getHeaderLibsProperty": func(ctx android.ModuleContext, m *Module) []string {
- prop := m.linker.baseLinkerProps().Header_libs
+ "getHeaderLibsProperty": func(ctx android.ModuleContext, info *CcInfo) []string {
+ prop := info.LinkerInfo.HeaderLibs
return prop.GetOrDefault(ctx, nil)
},
"getExtraLibs": getExtraLibs,
"getIncludeDirs": getIncludeDirs,
- "mapLibraries": func(ctx android.ModuleContext, m *Module, libs []string, mapping map[string]LibraryMappingProperty) []string {
+ "mapLibraries": func(ctx android.ModuleContext, m android.ModuleProxy, libs []string, mapping map[string]LibraryMappingProperty) []string {
var mappedLibs []string
for _, lib := range libs {
mappedLib, exists := mapping[lib]
@@ -249,8 +246,8 @@
mappedLibs = slices.Compact(mappedLibs)
return mappedLibs
},
- "getAidlSources": func(m *Module) []string {
- aidlInterface := m.compiler.baseCompilerProps().AidlInterface
+ "getAidlSources": func(info *CcInfo) []string {
+ aidlInterface := info.CompilerInfo.AidlInterfaceInfo
aidlRoot := aidlInterface.AidlRoot + string(filepath.Separator)
if aidlInterface.AidlRoot == "" {
aidlRoot = ""
@@ -340,14 +337,14 @@
moduleDirs := map[string][]string{}
sourceFiles := map[string]android.Path{}
visitedModules := map[string]bool{}
- var pregeneratedModules []*Module
- ctx.WalkDeps(func(dep_a android.Module, parent android.Module) bool {
- moduleName := ctx.OtherModuleName(dep_a)
+ var pregeneratedModules []android.ModuleProxy
+ ctx.WalkDepsProxy(func(dep, parent android.ModuleProxy) bool {
+ moduleName := ctx.OtherModuleName(dep)
if visited := visitedModules[moduleName]; visited {
return false // visit only once
}
visitedModules[moduleName] = true
- dep, ok := dep_a.(*Module)
+ ccInfo, ok := android.OtherModuleProvider(ctx, dep, CcInfoProvider)
if !ok {
return false // not a cc module
}
@@ -363,15 +360,15 @@
if slices.Contains(ignoredSystemLibs, moduleName) {
return false // system libs built in-tree for Android
}
- if dep.IsPrebuilt() {
+ if ccInfo.IsPrebuilt {
return false // prebuilts are not supported
}
- if dep.compiler == nil {
+ if ccInfo.CompilerInfo == nil {
return false // unsupported module type
}
- isAidlModule := dep.compiler.baseCompilerProps().AidlInterface.Lang != ""
+ isAidlModule := ccInfo.CompilerInfo.AidlInterfaceInfo.Lang != ""
- if !proptools.Bool(dep.Properties.Cmake_snapshot_supported) {
+ if !ccInfo.CmakeSnapshotSupported {
ctx.OtherModulePropertyErrorf(dep, "cmake_snapshot_supported",
"CMake snapshots not supported, despite being a dependency for %s",
ctx.OtherModuleName(parent))
@@ -389,12 +386,14 @@
}
moduleFragment := executeTemplate(templateToUse, &templateBuffer, struct {
Ctx *android.ModuleContext
- M *Module
+ M android.ModuleProxy
+ CcInfo *CcInfo
Snapshot *CmakeSnapshot
Pprop *cmakeProcessedProperties
}{
&ctx,
dep,
+ ccInfo,
m,
&pprop,
})
@@ -415,7 +414,7 @@
// Enumerate sources for pregenerated modules
if m.Properties.Include_sources {
for _, dep := range pregeneratedModules {
- if !proptools.Bool(dep.Properties.Cmake_snapshot_supported) {
+ if !android.OtherModuleProviderOrDefault(ctx, dep, CcInfoProvider).CmakeSnapshotSupported {
ctx.OtherModulePropertyErrorf(dep, "cmake_snapshot_supported",
"Pregenerated CMake snapshots not supported, despite being requested for %s",
ctx.ModuleName())
@@ -484,14 +483,14 @@
// Packaging all make files into the zip file
makefilesRspFile := android.PathForModuleObj(ctx, ctx.ModuleName()+"_makefiles.rsp")
zipCmd.
- FlagWithArg("-C ", android.PathForModuleGen(ctx).OutputPath.String()).
+ FlagWithArg("-C ", android.PathForModuleGen(ctx).String()).
FlagWithRspFileInputList("-r ", makefilesRspFile, makefilesList)
// Packaging all prebuilts into the zip file
if len(m.Properties.Prebuilts) > 0 {
var prebuiltsList android.Paths
- ctx.VisitDirectDepsWithTag(cmakeSnapshotPrebuiltTag, func(dep android.Module) {
+ ctx.VisitDirectDepsProxyWithTag(cmakeSnapshotPrebuiltTag, func(dep android.ModuleProxy) {
for _, file := range android.OtherModuleProviderOrDefault(
ctx, dep, android.InstallFilesProvider).InstallFiles {
prebuiltsList = append(prebuiltsList, file)
@@ -523,40 +522,37 @@
}}
}
-func getModuleType(m *Module) string {
- switch m.linker.(type) {
- case *binaryDecorator:
+func getModuleType(info *CcInfo) string {
+ if info.LinkerInfo.BinaryDecoratorInfo != nil {
return "executable"
- case *libraryDecorator:
+ } else if info.LinkerInfo.LibraryDecoratorInfo != nil {
return "library"
- case *testBinary:
+ } else if info.LinkerInfo.TestBinaryInfo != nil || info.LinkerInfo.BenchmarkDecoratorInfo != nil {
return "test"
- case *benchmarkDecorator:
- return "test"
+ } else if info.LinkerInfo.ObjectLinkerInfo != nil {
+ return "object"
}
- panic(fmt.Sprintf("Unexpected module type: %T", m.linker))
+ panic(fmt.Sprintf("Unexpected module type for LinkerInfo"))
}
-func getExtraLibs(m *Module) []string {
- switch decorator := m.linker.(type) {
- case *testBinary:
- if decorator.testDecorator.gtest() {
+func getExtraLibs(info *CcInfo) []string {
+ if info.LinkerInfo.TestBinaryInfo != nil {
+ if info.LinkerInfo.TestBinaryInfo.Gtest {
return []string{
"libgtest",
"libgtest_main",
}
}
- case *benchmarkDecorator:
+ } else if info.LinkerInfo.BenchmarkDecoratorInfo != nil {
return []string{"libgoogle-benchmark"}
}
return nil
}
-func getIncludeDirs(ctx android.ModuleContext, m *Module) []string {
+func getIncludeDirs(ctx android.ModuleContext, m android.ModuleProxy, info *CcInfo) []string {
moduleDir := ctx.OtherModuleDir(m) + string(filepath.Separator)
- switch decorator := m.compiler.(type) {
- case *libraryDecorator:
- return sliceWithPrefix(moduleDir, decorator.flagExporter.Properties.Export_include_dirs.GetOrDefault(ctx, nil))
+ if info.CompilerInfo.LibraryDecoratorInfo != nil {
+ return sliceWithPrefix(moduleDir, info.CompilerInfo.LibraryDecoratorInfo.ExportIncludeDirs.GetOrDefault(ctx, nil))
}
return nil
}
diff --git a/cc/compdb.go b/cc/compdb.go
index b33f490..4132e09 100644
--- a/cc/compdb.go
+++ b/cc/compdb.go
@@ -146,6 +146,8 @@
isAsm = false
isCpp = true
clangPath = cxxPath
+ case ".o":
+ return nil
default:
log.Print("Unknown file extension " + src.Ext() + " on file " + src.String())
isAsm = true
@@ -185,6 +187,10 @@
}
for _, src := range srcs {
if _, ok := builds[src.String()]; !ok {
+ args := getArguments(src, ctx, ccModule, ccPath, cxxPath)
+ if args == nil {
+ continue
+ }
builds[src.String()] = compDbEntry{
Directory: android.AbsSrcDirForExistingUseCases(),
Arguments: getArguments(src, ctx, ccModule, ccPath, cxxPath),
diff --git a/cc/compiler.go b/cc/compiler.go
index 396ec88..3730bbe 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -78,11 +78,11 @@
// If possible, don't use this. If adding paths from the current directory use
// local_include_dirs, if adding paths from other modules use export_include_dirs in
// that module.
- Include_dirs []string `android:"arch_variant,variant_prepend"`
+ Include_dirs proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"`
// list of directories relative to the Blueprints file that will
// be added to the include path using -I
- Local_include_dirs []string `android:"arch_variant,variant_prepend"`
+ Local_include_dirs proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"`
// Add the directory containing the Android.bp file to the list of include
// directories. Defaults to true.
@@ -100,6 +100,11 @@
// of genrule modules.
Generated_headers proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"`
+ // Same as generated_headers, but the dependencies will be added based on the first supported
+ // arch variant and the device os variant. This can be useful for creating a host tool that
+ // embeds a copy of a device tool, that it then extracts and pushes to a device at runtime.
+ Device_first_generated_headers proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"`
+
// pass -frtti instead of -fno-rtti
Rtti *bool `android:"arch_variant"`
@@ -228,9 +233,6 @@
Static *bool `android:"arch_variant"`
} `android:"arch_variant"`
- // Stores the original list of source files before being cleared by library reuse
- OriginalSrcs proptools.Configurable[[]string] `blueprint:"mutated"`
-
// Build and link with OpenMP
Openmp *bool `android:"arch_variant"`
}
@@ -297,6 +299,7 @@
deps.GeneratedSources = append(deps.GeneratedSources, compiler.Properties.Generated_sources...)
deps.GeneratedSources = removeListFromList(deps.GeneratedSources, compiler.Properties.Exclude_generated_sources)
deps.GeneratedHeaders = append(deps.GeneratedHeaders, compiler.Properties.Generated_headers.GetOrDefault(ctx, nil)...)
+ deps.DeviceFirstGeneratedHeaders = append(deps.DeviceFirstGeneratedHeaders, compiler.Properties.Device_first_generated_headers.GetOrDefault(ctx, nil)...)
deps.AidlLibs = append(deps.AidlLibs, compiler.Properties.Aidl.Libs...)
android.ProtoDeps(ctx, &compiler.Proto)
@@ -357,16 +360,49 @@
}
}
+func AddTargetFlags(ctx android.ModuleContext, flags Flags, tc config.Toolchain, version string, bpf bool) Flags {
+ target := "-target " + tc.ClangTriple()
+ if ctx.Os().Class == android.Device {
+ if version == "" || version == "current" {
+ target += strconv.Itoa(android.FutureApiLevelInt)
+ } else {
+ apiLevel := nativeApiLevelOrPanic(ctx, version)
+ target += strconv.Itoa(apiLevel.FinalOrFutureInt())
+ }
+ }
+
+ // bpf targets don't need the default target triple. b/308826679
+ if bpf {
+ target = "--target=bpf"
+ }
+
+ flags.Global.CFlags = append(flags.Global.CFlags, target)
+ flags.Global.AsFlags = append(flags.Global.AsFlags, target)
+ flags.Global.LdFlags = append(flags.Global.LdFlags, target)
+
+ return flags
+}
+
// Create a Flags struct that collects the compile flags from global values,
// per-target values, module type values, and per-module Blueprints properties
func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
tc := ctx.toolchain()
modulePath := ctx.ModuleDir()
- srcs := compiler.Properties.Srcs.GetOrDefault(ctx, nil)
- exclude_srcs := compiler.Properties.Exclude_srcs.GetOrDefault(ctx, nil)
- compiler.srcsBeforeGen = android.PathsForModuleSrcExcludes(ctx, srcs, exclude_srcs)
- compiler.srcsBeforeGen = append(compiler.srcsBeforeGen, deps.GeneratedSources...)
+ reuseObjs := false
+ if len(ctx.GetDirectDepsProxyWithTag(reuseObjTag)) > 0 {
+ reuseObjs = true
+ }
+
+ // If a reuseObjTag dependency exists then this module is reusing the objects (generally the shared variant
+ // reusing objects from the static variant), and doesn't need to compile any sources of its own.
+ var srcs []string
+ if !reuseObjs {
+ srcs = compiler.Properties.Srcs.GetOrDefault(ctx, nil)
+ exclude_srcs := compiler.Properties.Exclude_srcs.GetOrDefault(ctx, nil)
+ compiler.srcsBeforeGen = android.PathsForModuleSrcExcludes(ctx, srcs, exclude_srcs)
+ compiler.srcsBeforeGen = append(compiler.srcsBeforeGen, deps.GeneratedSources...)
+ }
cflags := compiler.Properties.Cflags.GetOrDefault(ctx, nil)
cppflags := compiler.Properties.Cppflags.GetOrDefault(ctx, nil)
@@ -398,13 +434,13 @@
}
// Include dir cflags
- localIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Local_include_dirs)
+ localIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Local_include_dirs.GetOrDefault(ctx, nil))
if len(localIncludeDirs) > 0 {
f := includeDirsToFlags(localIncludeDirs)
flags.Local.CommonFlags = append(flags.Local.CommonFlags, f)
flags.Local.YasmFlags = append(flags.Local.YasmFlags, f)
}
- rootIncludeDirs := android.PathsForSource(ctx, compiler.Properties.Include_dirs)
+ rootIncludeDirs := android.PathsForSource(ctx, compiler.Properties.Include_dirs.GetOrDefault(ctx, nil))
if len(rootIncludeDirs) > 0 {
f := includeDirsToFlags(rootIncludeDirs)
flags.Local.CommonFlags = append(flags.Local.CommonFlags, f)
@@ -423,32 +459,34 @@
}
if ctx.useSdk() {
- // TODO: Switch to --sysroot.
// The NDK headers are installed to a common sysroot. While a more
// typical Soong approach would be to only make the headers for the
// library you're using available, we're trying to emulate the NDK
// behavior here, and the NDK always has all the NDK headers available.
flags.SystemIncludeFlags = append(flags.SystemIncludeFlags,
- "-isystem "+getCurrentIncludePath(ctx).String(),
- "-isystem "+getCurrentIncludePath(ctx).Join(ctx, config.NDKTriple(tc)).String())
+ "--sysroot "+getNdkSysrootBase(ctx).String())
+ } else if ctx.Device() {
+ flags.Global.CommonFlags = append(flags.Global.CFlags, "-nostdlibinc")
}
if ctx.InVendorOrProduct() {
flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_VNDK__")
if ctx.inVendor() {
flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_VENDOR__")
-
- vendorApiLevel := ctx.Config().VendorApiLevel()
- if vendorApiLevel == "" {
- // TODO(b/314036847): This is a fallback for UDC targets.
- // This must be a build failure when UDC is no longer built
- // from this source tree.
- vendorApiLevel = ctx.Config().PlatformSdkVersion().String()
- }
- flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_VENDOR_API__="+vendorApiLevel)
} else if ctx.inProduct() {
flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_PRODUCT__")
}
+
+ // Define __ANDROID_VENDOR_API__ for both product and vendor variants
+ // because they both use the same LLNDK libraries.
+ vendorApiLevel := ctx.Config().VendorApiLevel()
+ if vendorApiLevel == "" {
+ // TODO(b/314036847): This is a fallback for UDC targets.
+ // This must be a build failure when UDC is no longer built
+ // from this source tree.
+ vendorApiLevel = ctx.Config().PlatformSdkVersion().String()
+ }
+ flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_VENDOR_API__="+vendorApiLevel)
}
if ctx.inRecovery() {
@@ -498,25 +536,7 @@
flags.Local.ConlyFlags = config.ClangFilterUnknownCflags(flags.Local.ConlyFlags)
flags.Local.LdFlags = config.ClangFilterUnknownCflags(flags.Local.LdFlags)
- target := "-target " + tc.ClangTriple()
- if ctx.Os().Class == android.Device {
- version := ctx.minSdkVersion()
- if version == "" || version == "current" {
- target += strconv.Itoa(android.FutureApiLevelInt)
- } else {
- apiLevel := nativeApiLevelOrPanic(ctx, version)
- target += strconv.Itoa(apiLevel.FinalOrFutureInt())
- }
- }
-
- // bpf targets don't need the default target triple. b/308826679
- if proptools.Bool(compiler.Properties.Bpf_target) {
- target = "--target=bpf"
- }
-
- flags.Global.CFlags = append(flags.Global.CFlags, target)
- flags.Global.AsFlags = append(flags.Global.AsFlags, target)
- flags.Global.LdFlags = append(flags.Global.LdFlags, target)
+ flags = AddTargetFlags(ctx, flags, tc, ctx.minSdkVersion(), Bool(compiler.Properties.Bpf_target))
hod := "Host"
if ctx.Os().Class == android.Device {
@@ -670,10 +690,10 @@
if len(srcs) > 0 {
module := ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
if inList("-Wno-error", flags.Local.CFlags) || inList("-Wno-error", flags.Local.CppFlags) {
- addToModuleList(ctx, modulesUsingWnoErrorKey, module)
+ ctx.getOrCreateMakeVarsInfo().UsingWnoError = module
} else if !inList("-Werror", flags.Local.CFlags) && !inList("-Werror", flags.Local.CppFlags) {
if warningsAreAllowed(ctx.ModuleDir()) {
- addToModuleList(ctx, modulesWarningsAllowedKey, module)
+ ctx.getOrCreateMakeVarsInfo().WarningsAllowed = module
} else {
flags.Local.CFlags = append([]string{"-Werror"}, flags.Local.CFlags...)
}
@@ -686,7 +706,9 @@
if ctx.optimizeForSize() {
flags.Local.CFlags = append(flags.Local.CFlags, "-Oz")
- flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-enable-ml-inliner=release")
+ if !ctx.Config().IsEnvFalse("THINLTO_USE_MLGO") {
+ flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-enable-ml-inliner=release")
+ }
}
// Exclude directories from manual binder interface allowed list.
@@ -719,11 +741,6 @@
return true
}
}
- for _, src := range compiler.Properties.OriginalSrcs.GetOrDefault(ctx, nil) {
- if filepath.Ext(src) == ext {
- return true
- }
- }
return false
}
@@ -773,7 +790,7 @@
objs := compileObjs(ctx, buildFlags, "", srcs,
append(android.PathsForModuleSrc(ctx, compiler.Properties.Tidy_disabled_srcs), compiler.generatedSources...),
android.PathsForModuleSrc(ctx, compiler.Properties.Tidy_timeout_srcs),
- pathDeps, compiler.cFlagsDeps)
+ pathDeps, compiler.cFlagsDeps, ctx.getSharedFlags())
if ctx.Failed() {
return Objects{}
@@ -783,10 +800,12 @@
}
// Compile a list of source files into objects a specified subdirectory
-func compileObjs(ctx ModuleContext, flags builderFlags, subdir string,
- srcFiles, noTidySrcs, timeoutTidySrcs, pathDeps android.Paths, cFlagsDeps android.Paths) Objects {
+func compileObjs(ctx android.ModuleContext, flags builderFlags, subdir string,
+ srcFiles, noTidySrcs, timeoutTidySrcs, pathDeps android.Paths, cFlagsDeps android.Paths,
+ sharedFlags *SharedFlags) Objects {
- return transformSourceToObj(ctx, subdir, srcFiles, noTidySrcs, timeoutTidySrcs, flags, pathDeps, cFlagsDeps)
+ return transformSourceToObj(ctx, subdir, srcFiles, noTidySrcs, timeoutTidySrcs, flags, pathDeps, cFlagsDeps,
+ sharedFlags)
}
// Properties for rust_bindgen related to generating rust bindings.
@@ -795,7 +814,7 @@
type RustBindgenClangProperties struct {
// list of directories relative to the Blueprints file that will
// be added to the include path using -I
- Local_include_dirs []string `android:"arch_variant,variant_prepend"`
+ Local_include_dirs proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"`
// list of static libraries that provide headers for this binding.
Static_libs proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"`
diff --git a/cc/config/Android.bp b/cc/config/Android.bp
index 289409f..f514db6 100644
--- a/cc/config/Android.bp
+++ b/cc/config/Android.bp
@@ -35,4 +35,8 @@
testSrcs: [
"tidy_test.go",
],
+ visibility: [
+ "//build/soong:__subpackages__",
+ "//prebuilts/clang/host/linux-x86/soong",
+ ],
}
diff --git a/cc/config/OWNERS b/cc/config/OWNERS
index c78b6d5..2668fdd 100644
--- a/cc/config/OWNERS
+++ b/cc/config/OWNERS
@@ -1,3 +1,2 @@
per-file vndk.go = smoreland@google.com, victoryang@google.com
-per-file clang.go,global.go,tidy.go = appujee@google.com, pirama@google.com, srhines@google.com, yabinc@google.com, yikong@google.com, zijunzhao@google.com
-
+per-file clang.go,global.go,tidy.go = appujee@google.com, pirama@google.com, srhines@google.com, yabinc@google.com, yikong@google.com, rprichard@google.com, sharjeelkhan@google.com
\ No newline at end of file
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index beb68e1..0dcf2cf 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -41,11 +41,18 @@
"armv8-2a-dotprod": []string{
"-march=armv8.2-a+dotprod",
},
+ // On ARMv9 and later, Pointer Authentication Codes (PAC) are mandatory,
+ // so -fstack-protector is unnecessary.
"armv9-a": []string{
"-march=armv8.2-a+dotprod",
"-mbranch-protection=standard",
"-fno-stack-protector",
},
+ "armv9-2a": []string{
+ "-march=armv9.2-a",
+ "-mbranch-protection=standard",
+ "-fno-stack-protector",
+ },
}
arm64Ldflags = []string{
@@ -111,11 +118,9 @@
pctx.StaticVariable("Arm64Cppflags", strings.Join(arm64Cppflags, " "))
- pctx.StaticVariable("Arm64Armv8ACflags", strings.Join(arm64ArchVariantCflags["armv8-a"], " "))
- pctx.StaticVariable("Arm64Armv8ABranchProtCflags", strings.Join(arm64ArchVariantCflags["armv8-a-branchprot"], " "))
- pctx.StaticVariable("Arm64Armv82ACflags", strings.Join(arm64ArchVariantCflags["armv8-2a"], " "))
- pctx.StaticVariable("Arm64Armv82ADotprodCflags", strings.Join(arm64ArchVariantCflags["armv8-2a-dotprod"], " "))
- pctx.StaticVariable("Arm64Armv9ACflags", strings.Join(arm64ArchVariantCflags["armv9-a"], " "))
+ for variant, cflags := range arm64ArchVariantCflags {
+ pctx.StaticVariable("Arm64"+variant+"VariantCflags", strings.Join(cflags, " "))
+ }
pctx.StaticVariable("Arm64CortexA53Cflags", strings.Join(arm64CpuVariantCflags["cortex-a53"], " "))
pctx.StaticVariable("Arm64CortexA55Cflags", strings.Join(arm64CpuVariantCflags["cortex-a55"], " "))
@@ -127,14 +132,6 @@
}
var (
- arm64ArchVariantCflagsVar = map[string]string{
- "armv8-a": "${config.Arm64Armv8ACflags}",
- "armv8-a-branchprot": "${config.Arm64Armv8ABranchProtCflags}",
- "armv8-2a": "${config.Arm64Armv82ACflags}",
- "armv8-2a-dotprod": "${config.Arm64Armv82ADotprodCflags}",
- "armv9-a": "${config.Arm64Armv9ACflags}",
- }
-
arm64CpuVariantCflagsVar = map[string]string{
"cortex-a53": "${config.Arm64CortexA53Cflags}",
"cortex-a55": "${config.Arm64CortexA55Cflags}",
@@ -204,18 +201,12 @@
}
func arm64ToolchainFactory(arch android.Arch) Toolchain {
- switch arch.ArchVariant {
- case "armv8-a":
- case "armv8-a-branchprot":
- case "armv8-2a":
- case "armv8-2a-dotprod":
- case "armv9-a":
- // Nothing extra for armv8-a/armv8-2a
- default:
- panic(fmt.Sprintf("Unknown ARM architecture version: %q", arch.ArchVariant))
+ // Error now rather than having a confusing Ninja error
+ if _, ok := arm64ArchVariantCflags[arch.ArchVariant]; !ok {
+ panic(fmt.Sprintf("Unknown ARM64 architecture version: %q", arch.ArchVariant))
}
- toolchainCflags := []string{arm64ArchVariantCflagsVar[arch.ArchVariant]}
+ toolchainCflags := []string{"${config.Arm64" + arch.ArchVariant + "VariantCflags}"}
toolchainCflags = append(toolchainCflags,
variantOrDefault(arm64CpuVariantCflagsVar, arch.CpuVariant))
diff --git a/cc/config/arm64_linux_host.go b/cc/config/arm64_linux_host.go
index 438e0e6..a19b0ed 100644
--- a/cc/config/arm64_linux_host.go
+++ b/cc/config/arm64_linux_host.go
@@ -87,8 +87,8 @@
}
func linuxBionicArm64ToolchainFactory(arch android.Arch) Toolchain {
- archVariant := "armv8-a" // for host, default to armv8-a
- toolchainCflags := []string{arm64ArchVariantCflagsVar[archVariant]}
+ // for host, default to armv8-a
+ toolchainCflags := []string{"-march=armv8-a"}
// We don't specify CPU architecture for host. Conservatively assume
// the host CPU needs the fix
diff --git a/cc/config/darwin_host.go b/cc/config/darwin_host.go
index 1783f49..716965a 100644
--- a/cc/config/darwin_host.go
+++ b/cc/config/darwin_host.go
@@ -54,6 +54,7 @@
"12",
"13",
"14",
+ "15",
}
darwinAvailableLibraries = append(
diff --git a/cc/config/global.go b/cc/config/global.go
index 0e8fff6..4407967 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -72,6 +72,9 @@
// Warnings disabled by default.
+ // We should encourage use of C23 features even when the whole project
+ // isn't C23-ready.
+ "-Wno-c23-extensions",
// Designated initializer syntax is recommended by the Google C++ style
// and is OK to use even if not formally supported by the chosen C++
// version.
@@ -172,7 +175,6 @@
"-Werror=address",
"-Werror=sequence-point",
"-Werror=format-security",
- "-nostdlibinc",
}
commonGlobalLldflags = []string{
@@ -236,12 +238,14 @@
// opting into the warning.
noOverrideGlobalCflags = []string{
"-Werror=bool-operation",
+ "-Werror=dangling",
"-Werror=format-insufficient-args",
"-Werror=implicit-int-float-conversion",
"-Werror=int-in-bool-context",
"-Werror=int-to-pointer-cast",
"-Werror=pointer-to-int-cast",
"-Werror=xor-used-as-pow",
+ "-Wimplicit-int-float-conversion",
// http://b/161386391 for -Wno-void-pointer-to-enum-cast
"-Wno-void-pointer-to-enum-cast",
// http://b/161386391 for -Wno-void-pointer-to-int-cast
@@ -286,15 +290,12 @@
// New warnings to be fixed after clang-r468909
"-Wno-error=deprecated-builtins", // http://b/241601211
"-Wno-error=deprecated", // in external/googletest/googletest
- // New warnings to be fixed after clang-r475365
- "-Wno-error=single-bit-bitfield-constant-conversion", // http://b/243965903
- "-Wno-error=enum-constexpr-conversion", // http://b/243964282
// New warnings to be fixed after clang-r522817
"-Wno-error=invalid-offsetof",
- "-Wno-error=thread-safety-reference-return",
// Allow using VLA CXX extension.
"-Wno-vla-cxx-extension",
+ "-Wno-cast-function-type-mismatch",
}
noOverride64GlobalCflags = []string{}
@@ -362,8 +363,6 @@
"-Wno-array-parameter",
"-Wno-gnu-offsetof-extensions",
"-Wno-pessimizing-move",
- // TODO: Enable this warning http://b/315245071
- "-Wno-fortify-source",
}
llvmNextExtraCommonGlobalCflags = []string{
@@ -383,7 +382,7 @@
// prebuilts/clang default settings.
ClangDefaultBase = "prebuilts/clang/host"
- ClangDefaultVersion = "clang-r530567"
+ ClangDefaultVersion = "clang-r536225"
ClangDefaultShortVersion = "19"
// Directories with warnings from Android.bp files.
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index 5aa2a7e..e7ac038 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -40,6 +40,9 @@
"-march=x86-64",
},
+ "alderlake": []string{
+ "-march=alderlake",
+ },
"broadwell": []string{
"-march=broadwell",
},
diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go
index 4b0041c..a92881d 100644
--- a/cc/config/x86_device.go
+++ b/cc/config/x86_device.go
@@ -42,6 +42,9 @@
"x86_64": []string{
"-march=prescott",
},
+ "alderlake": []string{
+ "-march=alderlake",
+ },
"atom": []string{
"-march=atom",
},
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index a4d43b9..505ddfa 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -106,10 +106,13 @@
}
windowsAvailableLibraries = addPrefix([]string{
+ "bcrypt",
+ "dbghelp",
"gdi32",
"imagehlp",
"iphlpapi",
"netapi32",
+ "ntdll",
"oleaut32",
"ole32",
"opengl32",
diff --git a/cc/coverage.go b/cc/coverage.go
index a7618dd..c8ff82b 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -145,7 +145,7 @@
// Even if we don't have coverage enabled, if any of our object files were compiled
// with coverage, then we need to add --coverage to our ldflags.
if !cov.linkCoverage {
- if ctx.static() && !ctx.staticBinary() {
+ if ctx.staticLibrary() {
// For static libraries, the only thing that changes our object files
// are included whole static libraries, so check to see if any of
// those have coverage enabled.
@@ -354,10 +354,10 @@
}
}
-func parseSymbolFileForAPICoverage(ctx ModuleContext, symbolFile string) android.ModuleOutPath {
+func ParseSymbolFileForAPICoverage(ctx android.ModuleContext, symbolFile string) android.ModuleOutPath {
apiLevelsJson := android.GetApiLevelsJson(ctx)
symbolFilePath := android.PathForModuleSrc(ctx, symbolFile)
- outputFile := ctx.baseModuleName() + ".xml"
+ outputFile := ctx.Module().(LinkableInterface).BaseModuleName() + ".xml"
parsedApiCoveragePath := android.PathForModuleOut(ctx, outputFile)
rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
diff --git a/cc/fuzz.go b/cc/fuzz.go
index d9e221b..a8e4cb7 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -57,38 +57,76 @@
return []interface{}{&fuzzer.Properties}
}
-func fuzzMutatorDeps(mctx android.TopDownMutatorContext) {
- currentModule, ok := mctx.Module().(*Module)
+// fuzzTransitionMutator creates variants to propagate the FuzzFramework value down to dependencies.
+type fuzzTransitionMutator struct{}
+
+func (f *fuzzTransitionMutator) Split(ctx android.BaseModuleContext) []string {
+ return []string{""}
+}
+
+func (f *fuzzTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+ m, ok := ctx.Module().(*Module)
+ if !ok {
+ return ""
+ }
+
+ if m.fuzzer == nil {
+ return ""
+ }
+
+ if m.sanitize == nil {
+ return ""
+ }
+
+ isFuzzerPointer := m.sanitize.getSanitizerBoolPtr(Fuzzer)
+ if isFuzzerPointer == nil || !*isFuzzerPointer {
+ return ""
+ }
+
+ if m.fuzzer.Properties.FuzzFramework != "" {
+ return m.fuzzer.Properties.FuzzFramework.Variant()
+ }
+
+ return sourceVariation
+}
+
+func (f *fuzzTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+ m, ok := ctx.Module().(*Module)
+ if !ok {
+ return ""
+ }
+
+ if m.fuzzer == nil {
+ return ""
+ }
+
+ if m.sanitize == nil {
+ return ""
+ }
+
+ isFuzzerPointer := m.sanitize.getSanitizerBoolPtr(Fuzzer)
+ if isFuzzerPointer == nil || !*isFuzzerPointer {
+ return ""
+ }
+
+ return incomingVariation
+}
+
+func (f *fuzzTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
+ m, ok := ctx.Module().(*Module)
if !ok {
return
}
- if currentModule.fuzzer == nil {
+ if m.fuzzer == nil {
return
}
- mctx.WalkDeps(func(child android.Module, parent android.Module) bool {
- c, ok := child.(*Module)
- if !ok {
- return false
- }
-
- if c.sanitize == nil {
- return false
- }
-
- isFuzzerPointer := c.sanitize.getSanitizerBoolPtr(Fuzzer)
- if isFuzzerPointer == nil || !*isFuzzerPointer {
- return false
- }
-
- if c.fuzzer == nil {
- return false
- }
-
- c.fuzzer.Properties.FuzzFramework = currentModule.fuzzer.Properties.FuzzFramework
- return true
- })
+ if variation != "" {
+ m.fuzzer.Properties.FuzzFramework = fuzz.FrameworkFromVariant(variation)
+ m.SetHideFromMake()
+ m.SetPreventInstall()
+ }
}
// cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at
@@ -173,29 +211,30 @@
moduleInfoJSON.Class = []string{"EXECUTABLES"}
}
-// IsValidSharedDependency takes a module and determines if it is a unique shared library
+// isValidSharedDependency takes a module and determines if it is a unique shared library
// that should be installed in the fuzz target output directories. This function
// returns true, unless:
// - The module is not an installable shared library, or
// - The module is a header or stub, or
// - The module is a prebuilt and its source is available, or
// - The module is a versioned member of an SDK snapshot.
-func IsValidSharedDependency(dependency android.Module) bool {
+func isValidSharedDependency(ctx android.ModuleContext, dependency android.ModuleProxy) bool {
// TODO(b/144090547): We should be parsing these modules using
// ModuleDependencyTag instead of the current brute-force checking.
- linkable, ok := dependency.(LinkableInterface)
- if !ok || !linkable.CcLibraryInterface() {
+ linkable, ok := android.OtherModuleProvider(ctx, dependency, LinkableInfoProvider)
+ if !ok || !linkable.CcLibraryInterface {
// Discard non-linkables.
return false
}
- if !linkable.Shared() {
+ if !linkable.Shared {
// Discard static libs.
return false
}
- if lib := moduleLibraryInterface(dependency); lib != nil && lib.buildStubs() && linkable.CcLibrary() {
+ ccInfo, hasCcInfo := android.OtherModuleProvider(ctx, dependency, CcInfoProvider)
+ if hasCcInfo && ccInfo.LibraryInfo != nil && ccInfo.LibraryInfo.BuildStubs && linkable.CcLibrary {
// Discard stubs libs (only CCLibrary variants). Prebuilt libraries should not
// be excluded on the basis of they're not CCLibrary()'s.
return false
@@ -204,13 +243,13 @@
// We discarded module stubs libraries above, but the LLNDK prebuilts stubs
// libraries must be handled differently - by looking for the stubDecorator.
// Discard LLNDK prebuilts stubs as well.
- if ccLibrary, isCcLibrary := dependency.(*Module); isCcLibrary {
- if _, isLLndkStubLibrary := ccLibrary.linker.(*stubDecorator); isLLndkStubLibrary {
+ if hasCcInfo {
+ if ccInfo.LinkerInfo != nil && ccInfo.LinkerInfo.StubDecoratorInfo != nil {
return false
}
// Discard installable:false libraries because they are expected to be absent
// in runtime.
- if !proptools.BoolDefault(ccLibrary.Installable(), true) {
+ if !proptools.BoolDefault(linkable.Installable, true) {
return false
}
}
@@ -218,7 +257,7 @@
// If the same library is present both as source and a prebuilt we must pick
// only one to avoid a conflict. Always prefer the source since the prebuilt
// probably won't be built with sanitizers enabled.
- if prebuilt := android.GetEmbeddedPrebuilt(dependency); prebuilt != nil && prebuilt.SourceExists() {
+ if prebuilt, ok := android.OtherModuleProvider(ctx, dependency, android.PrebuiltModuleInfoProvider); ok && prebuilt.SourceExists {
return false
}
@@ -250,7 +289,7 @@
}
func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) {
- fuzzBin.fuzzPackagedModule = PackageFuzzModule(ctx, fuzzBin.fuzzPackagedModule, pctx)
+ fuzzBin.fuzzPackagedModule = PackageFuzzModule(ctx, fuzzBin.fuzzPackagedModule)
installBase := "fuzz"
@@ -307,10 +346,13 @@
fuzzBin.binaryDecorator.baseInstaller.install(ctx, file)
}
-func PackageFuzzModule(ctx android.ModuleContext, fuzzPackagedModule fuzz.FuzzPackagedModule, pctx android.PackageContext) fuzz.FuzzPackagedModule {
+func PackageFuzzModule(ctx android.ModuleContext, fuzzPackagedModule fuzz.FuzzPackagedModule) fuzz.FuzzPackagedModule {
fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Corpus)
+ fuzzPackagedModule.Corpus = append(fuzzPackagedModule.Corpus, android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Device_common_corpus)...)
fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Data)
+ fuzzPackagedModule.Data = append(fuzzPackagedModule.Data, android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Device_common_data)...)
+ fuzzPackagedModule.Data = append(fuzzPackagedModule.Data, android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Device_first_data)...)
if fuzzPackagedModule.FuzzProperties.Dictionary != nil {
fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *fuzzPackagedModule.FuzzProperties.Dictionary)
@@ -566,17 +608,17 @@
// VisitDirectDeps is used first to avoid incorrectly using the core libraries (sanitizer
// runtimes, libc, libdl, etc.) from a dependency. This may cause issues when dependencies
// have explicit sanitizer tags, as we may get a dependency on an unsanitized libc, etc.
-func CollectAllSharedDependencies(ctx android.ModuleContext) (android.RuleBuilderInstalls, []android.Module) {
+func CollectAllSharedDependencies(ctx android.ModuleContext) (android.RuleBuilderInstalls, []android.ModuleProxy) {
seen := make(map[string]bool)
recursed := make(map[string]bool)
- deps := []android.Module{}
+ deps := []android.ModuleProxy{}
var sharedLibraries android.RuleBuilderInstalls
// Enumerate the first level of dependencies, as we discard all non-library
// modules in the BFS loop below.
- ctx.VisitDirectDeps(func(dep android.Module) {
- if !IsValidSharedDependency(dep) {
+ ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) {
+ if !isValidSharedDependency(ctx, dep) {
return
}
sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, dep, SharedLibraryInfoProvider)
@@ -594,19 +636,21 @@
sharedLibraries = append(sharedLibraries, ruleBuilderInstall)
})
- ctx.WalkDeps(func(child, parent android.Module) bool {
+ ctx.WalkDepsProxy(func(child, _ android.ModuleProxy) bool {
// If this is a Rust module which is not rust_ffi_shared, we still want to bundle any transitive
- // shared dependencies (even for rust_ffi_rlib or rust_ffi_static)
- if rustmod, ok := child.(LinkableInterface); ok && rustmod.RustLibraryInterface() && !rustmod.Shared() {
- if recursed[ctx.OtherModuleName(child)] {
- return false
+ // shared dependencies (even for rust_ffi_static)
+ if info, ok := android.OtherModuleProvider(ctx, child, LinkableInfoProvider); ok {
+ if info.RustLibraryInterface && !info.Shared {
+ if recursed[ctx.OtherModuleName(child)] {
+ return false
+ }
+ recursed[ctx.OtherModuleName(child)] = true
+ return true
}
- recursed[ctx.OtherModuleName(child)] = true
- return true
}
- if !IsValidSharedDependency(child) {
+ if !isValidSharedDependency(ctx, child) {
return false
}
sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, child, SharedLibraryInfoProvider)
diff --git a/cc/generated_cc_library.go b/cc/generated_cc_library.go
index b1084e4..709586b 100644
--- a/cc/generated_cc_library.go
+++ b/cc/generated_cc_library.go
@@ -18,7 +18,7 @@
"android/soong/android"
)
-func GeneratedCcLibraryModuleFactory(moduleName string, callbacks Generator) android.Module {
+func GeneratedCcLibraryModuleFactory(callbacks Generator) android.Module {
module, _ := NewLibrary(android.HostAndDeviceSupported)
// Can be used as both a static and a shared library.
diff --git a/cc/genrule.go b/cc/genrule.go
index fe3b127..bd6c5f1 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -77,41 +77,41 @@
var _ android.ImageInterface = (*GenruleExtraProperties)(nil)
-func (g *GenruleExtraProperties) ImageMutatorBegin(ctx android.BaseModuleContext) {}
+func (g *GenruleExtraProperties) ImageMutatorBegin(ctx android.ImageInterfaceContext) {}
-func (g *GenruleExtraProperties) VendorVariantNeeded(ctx android.BaseModuleContext) bool {
+func (g *GenruleExtraProperties) VendorVariantNeeded(ctx android.ImageInterfaceContext) bool {
return Bool(g.Vendor_available) || Bool(g.Odm_available) || ctx.SocSpecific() || ctx.DeviceSpecific()
}
-func (g *GenruleExtraProperties) ProductVariantNeeded(ctx android.BaseModuleContext) bool {
+func (g *GenruleExtraProperties) ProductVariantNeeded(ctx android.ImageInterfaceContext) bool {
return Bool(g.Product_available) || ctx.ProductSpecific()
}
-func (g *GenruleExtraProperties) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+func (g *GenruleExtraProperties) CoreVariantNeeded(ctx android.ImageInterfaceContext) bool {
return !(ctx.SocSpecific() || ctx.DeviceSpecific() || ctx.ProductSpecific())
}
-func (g *GenruleExtraProperties) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (g *GenruleExtraProperties) RamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return Bool(g.Ramdisk_available)
}
-func (g *GenruleExtraProperties) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (g *GenruleExtraProperties) VendorRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return Bool(g.Vendor_ramdisk_available)
}
-func (g *GenruleExtraProperties) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (g *GenruleExtraProperties) DebugRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return false
}
-func (g *GenruleExtraProperties) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
+func (g *GenruleExtraProperties) RecoveryVariantNeeded(ctx android.ImageInterfaceContext) bool {
// If the build is using a snapshot, the recovery variant under AOSP directories
// is not needed.
return Bool(g.Recovery_available)
}
-func (g *GenruleExtraProperties) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+func (g *GenruleExtraProperties) ExtraImageVariations(ctx android.ImageInterfaceContext) []string {
return nil
}
-func (g *GenruleExtraProperties) SetImageVariation(ctx android.BaseModuleContext, variation string) {
+func (g *GenruleExtraProperties) SetImageVariation(ctx android.ImageInterfaceContext, variation string) {
}
diff --git a/cc/image.go b/cc/image.go
index 7594a08..9766af3 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -177,10 +177,7 @@
IsSnapshotPrebuilt() bool
// SnapshotVersion returns the snapshot version for this module.
- SnapshotVersion(mctx android.BaseModuleContext) string
-
- // SdkVersion returns the SDK version for this module.
- SdkVersion() string
+ SnapshotVersion(mctx android.ImageInterfaceContext) string
// ExtraVariants returns the list of extra variants this module requires.
ExtraVariants() []string
@@ -209,7 +206,7 @@
var _ ImageMutatableModule = (*Module)(nil)
-func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) {
+func (m *Module) ImageMutatorBegin(mctx android.ImageInterfaceContext) {
MutateImage(mctx, m)
}
@@ -273,7 +270,7 @@
m.Properties.VendorVariantNeeded = b
}
-func (m *Module) SnapshotVersion(mctx android.BaseModuleContext) string {
+func (m *Module) SnapshotVersion(mctx android.ImageInterfaceContext) string {
if snapshot, ok := m.linker.(SnapshotInterface); ok {
return snapshot.Version()
} else {
@@ -291,7 +288,7 @@
}
// MutateImage handles common image mutations for ImageMutatableModule interfaces.
-func MutateImage(mctx android.BaseModuleContext, m ImageMutatableModule) {
+func MutateImage(mctx android.ImageInterfaceContext, m ImageMutatableModule) {
// Validation check
vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
productSpecific := mctx.ProductSpecific()
@@ -370,7 +367,7 @@
if m.HasProductVariant() {
productVariantNeeded = true
}
- } else if vendorSpecific && m.SdkVersion() == "" {
+ } else if vendorSpecific {
// This will be available in /vendor (or /odm) only
vendorVariantNeeded = true
} else {
@@ -380,7 +377,7 @@
coreVariantNeeded = true
}
- if coreVariantNeeded && productSpecific && m.SdkVersion() == "" {
+ if coreVariantNeeded && productSpecific {
// The module has "product_specific: true" that does not create core variant.
coreVariantNeeded = false
productVariantNeeded = true
@@ -431,35 +428,35 @@
}
}
-func (c *Module) VendorVariantNeeded(ctx android.BaseModuleContext) bool {
+func (c *Module) VendorVariantNeeded(ctx android.ImageInterfaceContext) bool {
return c.Properties.VendorVariantNeeded
}
-func (c *Module) ProductVariantNeeded(ctx android.BaseModuleContext) bool {
+func (c *Module) ProductVariantNeeded(ctx android.ImageInterfaceContext) bool {
return c.Properties.ProductVariantNeeded
}
-func (c *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+func (c *Module) CoreVariantNeeded(ctx android.ImageInterfaceContext) bool {
return c.Properties.CoreVariantNeeded
}
-func (c *Module) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (c *Module) RamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return c.Properties.RamdiskVariantNeeded
}
-func (c *Module) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (c *Module) VendorRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return c.Properties.VendorRamdiskVariantNeeded
}
-func (c *Module) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (c *Module) DebugRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return false
}
-func (c *Module) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
+func (c *Module) RecoveryVariantNeeded(ctx android.ImageInterfaceContext) bool {
return c.Properties.RecoveryVariantNeeded
}
-func (c *Module) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+func (c *Module) ExtraImageVariations(ctx android.ImageInterfaceContext) []string {
return c.Properties.ExtraVersionedImageVariations
}
@@ -513,7 +510,7 @@
}
}
-func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string) {
+func (c *Module) SetImageVariation(ctx android.ImageInterfaceContext, variant string) {
if variant == android.RamdiskVariation {
c.MakeAsPlatform()
squashRamdiskSrcs(c)
diff --git a/cc/libbuildversion/Android.bp b/cc/libbuildversion/Android.bp
index b105a30..c1f2c10 100644
--- a/cc/libbuildversion/Android.bp
+++ b/cc/libbuildversion/Android.bp
@@ -20,4 +20,5 @@
"//apex_available:anyapex",
],
vendor_available: true,
+ visibility: ["//visibility:public"],
}
diff --git a/cc/library.go b/cc/library.go
index 6017848..950ea91 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -25,14 +25,18 @@
"sync"
"android/soong/android"
+ "android/soong/cc/config"
"github.com/google/blueprint"
+ "github.com/google/blueprint/depset"
"github.com/google/blueprint/pathtools"
"github.com/google/blueprint/proptools"
)
// LibraryProperties is a collection of properties shared by cc library rules/cc.
type LibraryProperties struct {
+ // local file name to pass to the linker as -exported_symbols_list
+ Exported_symbols_list *string `android:"path,arch_variant"`
// local file name to pass to the linker as -unexported_symbols_list
Unexported_symbols_list *string `android:"path,arch_variant"`
// local file name to pass to the linker as -force_symbols_not_weak_list
@@ -61,21 +65,7 @@
Static_ndk_lib *bool
// Generate stubs to make this library accessible to APEXes.
- Stubs struct {
- // Relative path to the symbol map. The symbol map provides the list of
- // symbols that are exported for stubs variant of this library.
- Symbol_file *string `android:"path,arch_variant"`
-
- // List versions to generate stubs libs for. The version name "current" is always
- // implicitly added.
- Versions []string
-
- // Whether to not require the implementation of the library to be installed if a
- // client of the stubs is installed. Defaults to true; set to false if the
- // implementation is made available by some other means, e.g. in a Microdroid
- // virtual machine.
- Implementation_installable *bool
- } `android:"arch_variant"`
+ Stubs StubsProperties `android:"arch_variant"`
// set the name of the output
Stem *string `android:"arch_variant"`
@@ -124,6 +114,22 @@
Vendor_public_library vendorPublicLibraryProperties
}
+type StubsProperties struct {
+ // Relative path to the symbol map. The symbol map provides the list of
+ // symbols that are exported for stubs variant of this library.
+ Symbol_file *string `android:"path,arch_variant"`
+
+ // List versions to generate stubs libs for. The version name "current" is always
+ // implicitly added.
+ Versions []string
+
+ // Whether to not require the implementation of the library to be installed if a
+ // client of the stubs is installed. Defaults to true; set to false if the
+ // implementation is made available by some other means, e.g. in a Microdroid
+ // virtual machine.
+ Implementation_installable *bool
+}
+
// StaticProperties is a properties stanza to affect only attributes of the "static" variants of a
// library module.
type StaticProperties struct {
@@ -454,11 +460,15 @@
return props
}
-// linkerFlags takes a Flags struct and augments it to contain linker flags that are defined by this
-// library, or that are implied by attributes of this library (such as whether this library is a
-// shared library).
-func (library *libraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
- flags = library.baseLinker.linkerFlags(ctx, flags)
+func CommonLibraryLinkerFlags(ctx android.ModuleContext, flags Flags,
+ toolchain config.Toolchain, libName string) Flags {
+
+ mod, ok := ctx.Module().(LinkableInterface)
+
+ if !ok {
+ ctx.ModuleErrorf("trying to add linker flags to a non-LinkableInterface module.")
+ return flags
+ }
// MinGW spits out warnings about -fPIC even for -fpie?!) being ignored because
// all code is position independent, and then those warnings get promoted to
@@ -466,27 +476,18 @@
if !ctx.Windows() {
flags.Global.CFlags = append(flags.Global.CFlags, "-fPIC")
}
-
- if library.static() {
- flags.Local.CFlags = append(flags.Local.CFlags, library.StaticProperties.Static.Cflags.GetOrDefault(ctx, nil)...)
- } else if library.shared() {
- flags.Local.CFlags = append(flags.Local.CFlags, library.SharedProperties.Shared.Cflags.GetOrDefault(ctx, nil)...)
- }
-
- if library.shared() {
- libName := library.getLibName(ctx)
+ if mod.Shared() {
var f []string
- if ctx.toolchain().Bionic() {
+ if toolchain.Bionic() {
f = append(f,
"-nostdlib",
"-Wl,--gc-sections",
)
}
-
if ctx.Darwin() {
f = append(f,
"-dynamiclib",
- "-install_name @rpath/"+libName+flags.Toolchain.ShlibSuffix(),
+ "-install_name @rpath/"+libName+toolchain.ShlibSuffix(),
)
if ctx.Arch().ArchType == android.X86 {
f = append(f,
@@ -496,16 +497,30 @@
} else {
f = append(f, "-shared")
if !ctx.Windows() {
- f = append(f, "-Wl,-soname,"+libName+flags.Toolchain.ShlibSuffix())
+ f = append(f, "-Wl,-soname,"+libName+toolchain.ShlibSuffix())
}
}
-
flags.Global.LdFlags = append(flags.Global.LdFlags, f...)
}
return flags
}
+// linkerFlags takes a Flags struct and augments it to contain linker flags that are defined by this
+// library, or that are implied by attributes of this library (such as whether this library is a
+// shared library).
+func (library *libraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
+ flags = library.baseLinker.linkerFlags(ctx, flags)
+ flags = CommonLibraryLinkerFlags(ctx, flags, ctx.toolchain(), library.getLibName(ctx))
+ if library.static() {
+ flags.Local.CFlags = append(flags.Local.CFlags, library.StaticProperties.Static.Cflags.GetOrDefault(ctx, nil)...)
+ } else if library.shared() {
+ flags.Local.CFlags = append(flags.Local.CFlags, library.SharedProperties.Shared.Cflags.GetOrDefault(ctx, nil)...)
+ }
+
+ return flags
+}
+
// compilerFlags takes a Flags and augments it to contain compile flags from global values,
// per-target values, module type values, per-module Blueprints properties, extra flags from
// `flags`, and generated sources from `deps`.
@@ -524,7 +539,7 @@
// Wipe all the module-local properties, leaving only the global properties.
flags.Local = LocalOrGlobalFlags{}
}
- if library.buildStubs() {
+ if library.BuildStubs() {
// Remove -include <file> when compiling stubs. Otherwise, the force included
// headers might cause conflicting types error with the symbols in the
// generated stubs source code. e.g.
@@ -543,13 +558,12 @@
flags.Local.CommonFlags = removeInclude(flags.Local.CommonFlags)
flags.Local.CFlags = removeInclude(flags.Local.CFlags)
- flags = addStubLibraryCompilerFlags(flags)
+ flags = AddStubLibraryCompilerFlags(flags)
}
return flags
}
-func (library *libraryDecorator) getHeaderAbiCheckerProperties(ctx android.BaseModuleContext) headerAbiCheckerProperties {
- m := ctx.Module().(*Module)
+func (library *libraryDecorator) getHeaderAbiCheckerProperties(m *Module) headerAbiCheckerProperties {
variantProps := &library.Properties.Target.Platform.Header_abi_checker
if m.InVendor() {
variantProps = &library.Properties.Target.Vendor.Header_abi_checker
@@ -559,78 +573,44 @@
props := library.Properties.Header_abi_checker
err := proptools.AppendProperties(&props, variantProps, nil)
if err != nil {
- ctx.ModuleErrorf("Cannot merge headerAbiCheckerProperties: %s", err.Error())
+ panic(fmt.Errorf("Cannot merge headerAbiCheckerProperties: %s", err.Error()))
}
return props
}
func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
+ sharedFlags := ctx.getSharedFlags()
+
if ctx.IsLlndk() {
- vendorApiLevel := ctx.Config().VendorApiLevel()
- if vendorApiLevel == "" {
- // TODO(b/321892570): Some tests relying on old fixtures which
- // doesn't set vendorApiLevel. Needs to fix them.
- vendorApiLevel = ctx.Config().PlatformSdkVersion().String()
+ // Get the matching SDK version for the vendor API level.
+ version, err := android.GetSdkVersionForVendorApiLevel(ctx.Config().VendorApiLevel())
+ if err != nil {
+ panic(err)
}
+
// This is the vendor variant of an LLNDK library, build the LLNDK stubs.
- nativeAbiResult := parseNativeAbiDefinition(ctx,
+ nativeAbiResult := ParseNativeAbiDefinition(ctx,
String(library.Properties.Llndk.Symbol_file),
- android.ApiLevelOrPanic(ctx, vendorApiLevel), "--llndk")
- objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
+ nativeClampedApiLevel(ctx, version), "--llndk")
+ objs := CompileStubLibrary(ctx, flags, nativeAbiResult.StubSrc, sharedFlags)
if !Bool(library.Properties.Llndk.Unversioned) {
library.versionScriptPath = android.OptionalPathForPath(
- nativeAbiResult.versionScript)
+ nativeAbiResult.VersionScript)
}
return objs
}
if ctx.IsVendorPublicLibrary() {
- nativeAbiResult := parseNativeAbiDefinition(ctx,
+ nativeAbiResult := ParseNativeAbiDefinition(ctx,
String(library.Properties.Vendor_public_library.Symbol_file),
android.FutureApiLevel, "")
- objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
+ objs := CompileStubLibrary(ctx, flags, nativeAbiResult.StubSrc, sharedFlags)
if !Bool(library.Properties.Vendor_public_library.Unversioned) {
- library.versionScriptPath = android.OptionalPathForPath(nativeAbiResult.versionScript)
+ library.versionScriptPath = android.OptionalPathForPath(nativeAbiResult.VersionScript)
}
return objs
}
- if library.buildStubs() {
- symbolFile := String(library.Properties.Stubs.Symbol_file)
- if symbolFile != "" && !strings.HasSuffix(symbolFile, ".map.txt") {
- ctx.PropertyErrorf("symbol_file", "%q doesn't have .map.txt suffix", symbolFile)
- return Objects{}
- }
- library.stubsSymbolFilePath = android.PathForModuleSrc(ctx, symbolFile)
- // b/239274367 --apex and --systemapi filters symbols tagged with # apex and #
- // systemapi, respectively. The former is for symbols defined in platform libraries
- // and the latter is for symbols defined in APEXes.
- // A single library can contain either # apex or # systemapi, but not both.
- // The stub generator (ndkstubgen) is additive, so passing _both_ of these to it should be a no-op.
- // However, having this distinction helps guard accidental
- // promotion or demotion of API and also helps the API review process b/191371676
- var flag string
- if ctx.Module().(android.ApexModule).NotInPlatform() {
- flag = "--apex"
- } else {
- flag = "--systemapi"
- }
- // b/184712170, unless the lib is an NDK library, exclude all public symbols from
- // the stub so that it is mandated that all symbols are explicitly marked with
- // either apex or systemapi.
- if !ctx.Module().(*Module).IsNdk(ctx.Config()) {
- flag = flag + " --no-ndk"
- }
- nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile,
- android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), flag)
- objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
- library.versionScriptPath = android.OptionalPathForPath(
- nativeAbiResult.versionScript)
-
- // Parse symbol file to get API list for coverage
- if library.stubsVersion() == "current" && ctx.PrimaryArch() && !ctx.inRecovery() && !ctx.inProduct() && !ctx.inVendor() {
- library.apiListCoverageXmlPath = parseSymbolFileForAPICoverage(ctx, symbolFile)
- }
-
- return objs
+ if library.BuildStubs() {
+ return library.compileModuleLibApiStubs(ctx, flags, deps)
}
srcs := library.baseCompiler.Properties.Srcs.GetOrDefault(ctx, nil)
@@ -669,20 +649,100 @@
objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceStaticLibrary, srcs,
android.PathsForModuleSrc(ctx, library.StaticProperties.Static.Tidy_disabled_srcs),
android.PathsForModuleSrc(ctx, library.StaticProperties.Static.Tidy_timeout_srcs),
- library.baseCompiler.pathDeps, library.baseCompiler.cFlagsDeps))
+ library.baseCompiler.pathDeps, library.baseCompiler.cFlagsDeps, sharedFlags))
} else if library.shared() {
srcs := android.PathsForModuleSrc(ctx, sharedSrcs)
objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceSharedLibrary, srcs,
android.PathsForModuleSrc(ctx, library.SharedProperties.Shared.Tidy_disabled_srcs),
android.PathsForModuleSrc(ctx, library.SharedProperties.Shared.Tidy_timeout_srcs),
- library.baseCompiler.pathDeps, library.baseCompiler.cFlagsDeps))
+ library.baseCompiler.pathDeps, library.baseCompiler.cFlagsDeps, sharedFlags))
+ }
+
+ return objs
+}
+
+type ApiStubsParams struct {
+ NotInPlatform bool
+ IsNdk bool
+ BaseModuleName string
+ ModuleName string
+}
+
+// GetApiStubsFlags calculates the genstubFlags string to pass to ParseNativeAbiDefinition
+func GetApiStubsFlags(api ApiStubsParams) string {
+ var flag string
+
+ // b/239274367 --apex and --systemapi filters symbols tagged with # apex and #
+ // systemapi, respectively. The former is for symbols defined in platform libraries
+ // and the latter is for symbols defined in APEXes.
+ // A single library can contain either # apex or # systemapi, but not both.
+ // The stub generator (ndkstubgen) is additive, so passing _both_ of these to it should be a no-op.
+ // However, having this distinction helps guard accidental
+ // promotion or demotion of API and also helps the API review process b/191371676
+ if api.NotInPlatform {
+ flag = "--apex"
+ } else {
+ flag = "--systemapi"
+ }
+
+ // b/184712170, unless the lib is an NDK library, exclude all public symbols from
+ // the stub so that it is mandated that all symbols are explicitly marked with
+ // either apex or systemapi.
+ if !api.IsNdk &&
+ // the symbol files of libclang libs are autogenerated and do not contain systemapi tags
+ // TODO (spandandas): Update mapfile.py to include #systemapi tag on all symbols
+ !strings.Contains(api.ModuleName, "libclang_rt") {
+ flag = flag + " --no-ndk"
+ }
+
+ // TODO(b/361303067): Remove this special case if bionic/ projects are added to ART development branches.
+ if isBionic(api.BaseModuleName) {
+ // set the flags explicitly for bionic libs.
+ // this is necessary for development in minimal branches which does not contain bionic/*.
+ // In such minimal branches, e.g. on the prebuilt libc stubs
+ // 1. IsNdk will return false (since the ndk_library definition for libc does not exist)
+ // 2. NotInPlatform will return true (since the source com.android.runtime does not exist)
+ flag = "--apex"
+ }
+
+ return flag
+}
+
+// Compile stubs for the API surface between platform and apex
+// This method will be used by source and prebuilt cc module types.
+func (library *libraryDecorator) compileModuleLibApiStubs(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
+ // TODO (b/275273834): Make this a hard error when the symbol files have been added to module sdk.
+ if library.Properties.Stubs.Symbol_file == nil {
+ return Objects{}
+ }
+
+ symbolFile := String(library.Properties.Stubs.Symbol_file)
+ library.stubsSymbolFilePath = android.PathForModuleSrc(ctx, symbolFile)
+
+ apiParams := ApiStubsParams{
+ NotInPlatform: ctx.notInPlatform(),
+ IsNdk: ctx.Module().(*Module).IsNdk(ctx.Config()),
+ BaseModuleName: ctx.baseModuleName(),
+ ModuleName: ctx.ModuleName(),
+ }
+ flag := GetApiStubsFlags(apiParams)
+
+ nativeAbiResult := ParseNativeAbiDefinition(ctx, symbolFile,
+ android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), flag)
+ objs := CompileStubLibrary(ctx, flags, nativeAbiResult.StubSrc, ctx.getSharedFlags())
+
+ library.versionScriptPath = android.OptionalPathForPath(
+ nativeAbiResult.VersionScript)
+ // Parse symbol file to get API list for coverage
+ if library.StubsVersion() == "current" && ctx.PrimaryArch() && !ctx.inRecovery() && !ctx.inProduct() && !ctx.inVendor() {
+ library.apiListCoverageXmlPath = ParseSymbolFileForAPICoverage(ctx, symbolFile)
}
return objs
}
type libraryInterface interface {
- versionedInterface
+ VersionedInterface
static() bool
shared() bool
@@ -699,38 +759,56 @@
setShared()
// Gets the ABI properties for vendor, product, or platform variant
- getHeaderAbiCheckerProperties(ctx android.BaseModuleContext) headerAbiCheckerProperties
+ getHeaderAbiCheckerProperties(m *Module) headerAbiCheckerProperties
// Write LOCAL_ADDITIONAL_DEPENDENCIES for ABI diff
androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer)
- availableFor(string) bool
+ apexAvailable() []string
- getAPIListCoverageXMLPath() android.ModuleOutPath
+ setAPIListCoverageXMLPath(out android.ModuleOutPath)
+ symbolsFile() *string
+ setSymbolFilePath(path android.Path)
+ setVersionScriptPath(path android.OptionalPath)
installable() *bool
}
-type versionedInterface interface {
- buildStubs() bool
- setBuildStubs(isLatest bool)
- hasStubsVariants() bool
- isStubsImplementationRequired() bool
- setStubsVersion(string)
- stubsVersion() string
+func (library *libraryDecorator) symbolsFile() *string {
+ return library.Properties.Stubs.Symbol_file
+}
- stubsVersions(ctx android.BaseModuleContext) []string
- setAllStubsVersions([]string)
- allStubsVersions() []string
+func (library *libraryDecorator) setSymbolFilePath(path android.Path) {
+ library.stubsSymbolFilePath = path
+}
- implementationModuleName(name string) string
- hasLLNDKStubs() bool
- hasLLNDKHeaders() bool
- hasVendorPublicLibrary() bool
+func (library *libraryDecorator) setVersionScriptPath(path android.OptionalPath) {
+ library.versionScriptPath = path
+}
+
+type VersionedInterface interface {
+ BuildStubs() bool
+ SetBuildStubs(isLatest bool)
+ HasStubsVariants() bool
+ IsStubsImplementationRequired() bool
+ SetStubsVersion(string)
+ StubsVersion() string
+
+ StubsVersions(ctx android.BaseModuleContext) []string
+ SetAllStubsVersions([]string)
+ AllStubsVersions() []string
+
+ ImplementationModuleName(name string) string
+ HasLLNDKStubs() bool
+ HasLLNDKHeaders() bool
+ HasVendorPublicLibrary() bool
+ IsLLNDKMovedToApex() bool
+
+ GetAPIListCoverageXMLPath() android.ModuleOutPath
}
var _ libraryInterface = (*libraryDecorator)(nil)
-var _ versionedInterface = (*libraryDecorator)(nil)
+var _ VersionedInterface = (*libraryDecorator)(nil)
func (library *libraryDecorator) getLibNameHelper(baseModuleName string, inVendor bool, inProduct bool) string {
name := library.libName
@@ -779,9 +857,9 @@
library.baseLinker.linkerInit(ctx)
// Let baseLinker know whether this variant is for stubs or not, so that
// it can omit things that are not required for linking stubs.
- library.baseLinker.dynamicProperties.BuildStubs = library.buildStubs()
+ library.baseLinker.dynamicProperties.BuildStubs = library.BuildStubs()
- if library.buildStubs() {
+ if library.BuildStubs() {
macroNames := versioningMacroNamesList(ctx.Config())
myName := versioningMacroName(ctx.ModuleName())
versioningMacroNamesListMutex.Lock()
@@ -900,7 +978,7 @@
return deps
}
-func (library *libraryDecorator) linkerSpecifiedDeps(ctx android.ConfigAndErrorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps {
+func (library *libraryDecorator) linkerSpecifiedDeps(ctx android.ConfigurableEvaluatorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps {
specifiedDeps = library.baseLinker.linkerSpecifiedDeps(ctx, module, specifiedDeps)
var properties StaticOrSharedProperties
if library.static() {
@@ -940,8 +1018,8 @@
moduleInfoJSON.Uninstallable = true
}
- if library.buildStubs() && library.stubsVersion() != "" {
- moduleInfoJSON.SubName += "." + library.stubsVersion()
+ if library.BuildStubs() && library.StubsVersion() != "" {
+ moduleInfoJSON.SubName += "." + library.StubsVersion()
}
// If a library providing a stub is included in an APEX, the private APIs of the library
@@ -952,10 +1030,10 @@
// very early stage in the boot process).
if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.notInPlatform() &&
!ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() && !ctx.useVndk() && !ctx.static() {
- if library.buildStubs() && library.isLatestStubVersion() {
+ if library.BuildStubs() && library.isLatestStubVersion() {
moduleInfoJSON.SubName = ""
}
- if !library.buildStubs() {
+ if !library.BuildStubs() {
moduleInfoJSON.SubName = ".bootstrap"
}
}
@@ -999,7 +1077,7 @@
Objects: library.objects,
WholeStaticLibsFromPrebuilts: library.wholeStaticLibsFromPrebuilts,
- TransitiveStaticLibrariesForOrdering: android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).
+ TransitiveStaticLibrariesForOrdering: depset.NewBuilder[android.Path](depset.TOPOLOGICAL).
Direct(outputFile).
Transitive(deps.TranstiveStaticLibrariesForOrdering).
Build(),
@@ -1029,10 +1107,14 @@
linkerDeps = append(linkerDeps, flags.LdFlagsDeps...)
linkerDeps = append(linkerDeps, ndkSharedLibDeps(ctx)...)
+ exportedSymbols := ctx.ExpandOptionalSource(library.Properties.Exported_symbols_list, "exported_symbols_list")
unexportedSymbols := ctx.ExpandOptionalSource(library.Properties.Unexported_symbols_list, "unexported_symbols_list")
forceNotWeakSymbols := ctx.ExpandOptionalSource(library.Properties.Force_symbols_not_weak_list, "force_symbols_not_weak_list")
forceWeakSymbols := ctx.ExpandOptionalSource(library.Properties.Force_symbols_weak_list, "force_symbols_weak_list")
if !ctx.Darwin() {
+ if exportedSymbols.Valid() {
+ ctx.PropertyErrorf("exported_symbols_list", "Only supported on Darwin")
+ }
if unexportedSymbols.Valid() {
ctx.PropertyErrorf("unexported_symbols_list", "Only supported on Darwin")
}
@@ -1043,6 +1125,10 @@
ctx.PropertyErrorf("force_symbols_weak_list", "Only supported on Darwin")
}
} else {
+ if exportedSymbols.Valid() {
+ flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-exported_symbols_list,"+exportedSymbols.String())
+ linkerDeps = append(linkerDeps, exportedSymbols.Path())
+ }
if unexportedSymbols.Valid() {
flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-unexported_symbols_list,"+unexportedSymbols.String())
linkerDeps = append(linkerDeps, unexportedSymbols.Path())
@@ -1090,7 +1176,7 @@
stripFlags := flagsToStripFlags(flags)
needsStrip := library.stripper.NeedsStrip(ctx)
- if library.buildStubs() {
+ if library.BuildStubs() {
// No need to strip stubs libraries
needsStrip = false
}
@@ -1144,7 +1230,7 @@
linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
- if generatedLib := generateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil && !library.buildStubs() {
+ if generatedLib := generateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil && !library.BuildStubs() {
if ctx.Module().(*Module).WholeRustStaticlib {
deps.WholeStaticLibs = append(deps.WholeStaticLibs, generatedLib)
} else {
@@ -1164,8 +1250,8 @@
library.coverageOutputFile = transformCoverageFilesToZip(ctx, objs, library.getLibName(ctx))
library.linkSAbiDumpFiles(ctx, deps, objs, fileName, unstrippedOutputFile)
- var transitiveStaticLibrariesForOrdering *android.DepSet[android.Path]
- if static := ctx.GetDirectDepsWithTag(staticVariantTag); len(static) > 0 {
+ var transitiveStaticLibrariesForOrdering depset.DepSet[android.Path]
+ if static := ctx.GetDirectDepsProxyWithTag(staticVariantTag); len(static) > 0 {
s, _ := android.OtherModuleProvider(ctx, static[0], StaticLibraryInfoProvider)
transitiveStaticLibrariesForOrdering = s.TransitiveStaticLibrariesForOrdering
}
@@ -1175,31 +1261,44 @@
SharedLibrary: unstrippedOutputFile,
TransitiveStaticLibrariesForOrdering: transitiveStaticLibrariesForOrdering,
Target: ctx.Target(),
+ IsStubs: library.BuildStubs(),
})
- addStubDependencyProviders(ctx)
+ AddStubDependencyProviders(ctx)
return unstrippedOutputFile
}
-func addStubDependencyProviders(ctx ModuleContext) {
- stubs := ctx.GetDirectDepsWithTag(stubImplDepTag)
+// Visits the stub variants of the library and returns a struct containing the stub .so paths
+func AddStubDependencyProviders(ctx android.BaseModuleContext) []SharedStubLibrary {
+ stubsInfo := []SharedStubLibrary{}
+ stubs := ctx.GetDirectDepsProxyWithTag(StubImplDepTag)
if len(stubs) > 0 {
- var stubsInfo []SharedStubLibrary
for _, stub := range stubs {
- stubInfo, _ := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider)
+ stubInfo, ok := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider)
+ // TODO (b/275273834): Make this a hard error when the symbol files have been added to module sdk.
+ if !ok {
+ continue
+ }
flagInfo, _ := android.OtherModuleProvider(ctx, stub, FlagExporterInfoProvider)
+ if _, ok = android.OtherModuleProvider(ctx, stub, CcInfoProvider); !ok {
+ panic(fmt.Errorf("stub is not a cc module %s", stub))
+ }
stubsInfo = append(stubsInfo, SharedStubLibrary{
- Version: moduleLibraryInterface(stub).stubsVersion(),
+ Version: android.OtherModuleProviderOrDefault(ctx, stub, LinkableInfoProvider).StubsVersion,
SharedLibraryInfo: stubInfo,
FlagExporterInfo: flagInfo,
})
}
- android.SetProvider(ctx, SharedLibraryStubsProvider, SharedLibraryStubsInfo{
- SharedStubLibraries: stubsInfo,
- IsLLNDK: ctx.IsLlndk(),
- })
+ if len(stubsInfo) > 0 {
+ android.SetProvider(ctx, SharedLibraryStubsProvider, SharedLibraryStubsInfo{
+ SharedStubLibraries: stubsInfo,
+ IsLLNDK: ctx.Module().(LinkableInterface).IsLlndk(),
+ })
+ }
}
+
+ return stubsInfo
}
func (library *libraryDecorator) unstrippedOutputFilePath() android.Path {
@@ -1215,7 +1314,7 @@
}
func (library *libraryDecorator) nativeCoverage() bool {
- if library.header() || library.buildStubs() {
+ if library.header() || library.BuildStubs() {
return false
}
return true
@@ -1237,14 +1336,6 @@
func (library *libraryDecorator) llndkIncludeDirsForAbiCheck(ctx ModuleContext, deps PathDeps) []string {
var includeDirs, systemIncludeDirs []string
- // The ABI checker does not need the preprocess which adds macro guards to function declarations.
- preprocessedDirs := android.PathsForModuleSrc(ctx, library.Properties.Llndk.Export_preprocessed_headers).Strings()
- if Bool(library.Properties.Llndk.Export_headers_as_system) {
- systemIncludeDirs = append(systemIncludeDirs, preprocessedDirs...)
- } else {
- includeDirs = append(includeDirs, preprocessedDirs...)
- }
-
if library.Properties.Llndk.Override_export_include_dirs != nil {
includeDirs = append(includeDirs, android.PathsForModuleSrc(
ctx, library.Properties.Llndk.Override_export_include_dirs).Strings()...)
@@ -1270,15 +1361,14 @@
func (library *libraryDecorator) linkLlndkSAbiDumpFiles(ctx ModuleContext,
deps PathDeps, sAbiDumpFiles android.Paths, soFile android.Path, libFileName string,
excludeSymbolVersions, excludeSymbolTags []string,
- vendorApiLevel string) android.Path {
- // NDK symbols in version 34 are LLNDK symbols. Those in version 35 are not.
+ sdkVersionForVendorApiLevel string) android.Path {
return transformDumpToLinkedDump(ctx,
sAbiDumpFiles, soFile, libFileName+".llndk",
library.llndkIncludeDirsForAbiCheck(ctx, deps),
android.OptionalPathForModuleSrc(ctx, library.Properties.Llndk.Symbol_file),
append([]string{"*_PLATFORM", "*_PRIVATE"}, excludeSymbolVersions...),
append([]string{"platform-only"}, excludeSymbolTags...),
- []string{"llndk=" + vendorApiLevel}, "34", true /* isLlndk */)
+ []string{"llndk"}, sdkVersionForVendorApiLevel)
}
func (library *libraryDecorator) linkApexSAbiDumpFiles(ctx ModuleContext,
@@ -1291,7 +1381,7 @@
android.OptionalPathForModuleSrc(ctx, library.Properties.Stubs.Symbol_file),
append([]string{"*_PLATFORM", "*_PRIVATE"}, excludeSymbolVersions...),
append([]string{"platform-only"}, excludeSymbolTags...),
- []string{"apex", "systemapi"}, sdkVersion, false /* isLlndk */)
+ []string{"apex", "systemapi"}, sdkVersion)
}
func getRefAbiDumpFile(ctx android.ModuleInstallPathContext,
@@ -1346,13 +1436,18 @@
sourceVersion, errorMessage string) {
extraFlags := []string{"-target-version", sourceVersion}
- headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx)
+ headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx.Module().(*Module))
if Bool(headerAbiChecker.Check_all_apis) {
extraFlags = append(extraFlags, "-check-all-apis")
} else {
extraFlags = append(extraFlags,
"-allow-unreferenced-changes",
"-allow-unreferenced-elf-symbol-changes")
+ // The functions in standard libraries are not always declared in the headers.
+ // Allow them to be added or removed without changing the symbols.
+ if isBionic(ctx.ModuleName()) {
+ extraFlags = append(extraFlags, "-allow-adding-removing-referenced-apis")
+ }
}
if isLlndk {
extraFlags = append(extraFlags, "-consider-opaque-types-different")
@@ -1418,7 +1513,7 @@
func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, deps PathDeps, objs Objects, fileName string, soFile android.Path) {
if library.sabi.shouldCreateSourceAbiDump() {
exportedIncludeDirs := library.exportedIncludeDirsForAbiCheck(ctx)
- headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx)
+ headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx.Module().(*Module))
currSdkVersion := currRefAbiDumpSdkVersion(ctx)
currVendorVersion := ctx.Config().VendorApiLevel()
@@ -1429,22 +1524,27 @@
android.OptionalPathForModuleSrc(ctx, library.symbolFileForAbiCheck(ctx)),
headerAbiChecker.Exclude_symbol_versions,
headerAbiChecker.Exclude_symbol_tags,
- []string{} /* includeSymbolTags */, currSdkVersion, false /* isLlndk */)
+ []string{} /* includeSymbolTags */, currSdkVersion)
var llndkDump, apexVariantDump android.Path
- tags := classifySourceAbiDump(ctx)
+ tags := classifySourceAbiDump(ctx.Module().(*Module))
optInTags := []lsdumpTag{}
for _, tag := range tags {
if tag == llndkLsdumpTag && currVendorVersion != "" {
if llndkDump == nil {
+ sdkVersion, err := android.GetSdkVersionForVendorApiLevel(currVendorVersion)
+ if err != nil {
+ ctx.ModuleErrorf("Cannot create %s llndk dump: %s", fileName, err)
+ return
+ }
// TODO(b/323447559): Evaluate if replacing sAbiDumpFiles with implDump is faster
llndkDump = library.linkLlndkSAbiDumpFiles(ctx,
deps, objs.sAbiDumpFiles, soFile, fileName,
headerAbiChecker.Exclude_symbol_versions,
headerAbiChecker.Exclude_symbol_tags,
- currVendorVersion)
+ nativeClampedApiLevel(ctx, sdkVersion).String())
}
- addLsdumpPath(string(tag) + ":" + llndkDump.String())
+ addLsdumpPath(ctx.Config(), string(tag)+":"+llndkDump.String())
} else if tag == apexLsdumpTag {
if apexVariantDump == nil {
apexVariantDump = library.linkApexSAbiDumpFiles(ctx,
@@ -1453,12 +1553,12 @@
headerAbiChecker.Exclude_symbol_tags,
currSdkVersion)
}
- addLsdumpPath(string(tag) + ":" + apexVariantDump.String())
+ addLsdumpPath(ctx.Config(), string(tag)+":"+apexVariantDump.String())
} else {
if tag.dirName() == "" {
optInTags = append(optInTags, tag)
}
- addLsdumpPath(string(tag) + ":" + implDump.String())
+ addLsdumpPath(ctx.Config(), string(tag)+":"+implDump.String())
}
}
@@ -1552,25 +1652,6 @@
}
}
-func processLLNDKHeaders(ctx ModuleContext, srcHeaderDir string, outDir android.ModuleGenPath) (timestamp android.Path, installPaths android.WritablePaths) {
- srcDir := android.PathForModuleSrc(ctx, srcHeaderDir)
- srcFiles := ctx.GlobFiles(filepath.Join(srcDir.String(), "**/*.h"), nil)
-
- for _, header := range srcFiles {
- headerDir := filepath.Dir(header.String())
- relHeaderDir, err := filepath.Rel(srcDir.String(), headerDir)
- if err != nil {
- ctx.ModuleErrorf("filepath.Rel(%q, %q) failed: %s",
- srcDir.String(), headerDir, err)
- continue
- }
-
- installPaths = append(installPaths, outDir.Join(ctx, relHeaderDir, header.Base()))
- }
-
- return processHeadersWithVersioner(ctx, srcDir, outDir, srcFiles, installPaths), installPaths
-}
-
// link registers actions to link this library, and sets various fields
// on this library to reflect information that should be exported up the build
// tree (for example, exported flags and include paths).
@@ -1578,26 +1659,6 @@
flags Flags, deps PathDeps, objs Objects) android.Path {
if ctx.IsLlndk() {
- if len(library.Properties.Llndk.Export_preprocessed_headers) > 0 {
- // This is the vendor variant of an LLNDK library with preprocessed headers.
- genHeaderOutDir := android.PathForModuleGen(ctx, "include")
-
- var timestampFiles android.Paths
- for _, dir := range library.Properties.Llndk.Export_preprocessed_headers {
- timestampFile, installPaths := processLLNDKHeaders(ctx, dir, genHeaderOutDir)
- timestampFiles = append(timestampFiles, timestampFile)
- library.addExportedGeneratedHeaders(installPaths.Paths()...)
- }
-
- if Bool(library.Properties.Llndk.Export_headers_as_system) {
- library.reexportSystemDirs(genHeaderOutDir)
- } else {
- library.reexportDirs(genHeaderOutDir)
- }
-
- library.reexportDeps(timestampFiles...)
- }
-
// override the module's export_include_dirs with llndk.override_export_include_dirs
// if it is set.
if override := library.Properties.Llndk.Override_export_include_dirs; override != nil {
@@ -1722,9 +1783,9 @@
}
func (library *libraryDecorator) exportVersioningMacroIfNeeded(ctx android.BaseModuleContext) {
- if library.buildStubs() && library.stubsVersion() != "" && !library.skipAPIDefine {
+ if library.BuildStubs() && library.StubsVersion() != "" && !library.skipAPIDefine {
name := versioningMacroName(ctx.Module().(*Module).ImplementationModuleName(ctx))
- apiLevel, err := android.ApiLevelFromUser(ctx, library.stubsVersion())
+ apiLevel, err := android.ApiLevelFromUser(ctx, library.StubsVersion())
if err != nil {
ctx.ModuleErrorf("Can't export version macro: %s", err.Error())
}
@@ -1775,21 +1836,17 @@
func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) {
if library.shared() {
- if library.hasStubsVariants() && !ctx.Host() && ctx.directlyInAnyApex() {
+ translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
+ if library.HasStubsVariants() && !ctx.Host() && !ctx.isSdkVariant() &&
+ InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.BuildStubs() &&
+ !translatedArch && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() {
// Bionic libraries (e.g. libc.so) is installed to the bootstrap subdirectory.
// The original path becomes a symlink to the corresponding file in the
// runtime APEX.
- translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
- if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.buildStubs() &&
- !translatedArch && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() {
- if ctx.Device() {
- library.installSymlinkToRuntimeApex(ctx, file)
- }
- library.baseInstaller.subDir = "bootstrap"
+ if ctx.Device() {
+ library.installSymlinkToRuntimeApex(ctx, file)
}
- } else if ctx.directlyInAnyApex() && ctx.IsLlndk() && !isBionic(ctx.baseModuleName()) {
- // Skip installing LLNDK (non-bionic) libraries moved to APEX.
- ctx.Module().HideFromMake()
+ library.baseInstaller.subDir = "bootstrap"
}
library.baseInstaller.install(ctx, file)
@@ -1798,7 +1855,7 @@
if Bool(library.Properties.Static_ndk_lib) && library.static() &&
!ctx.InVendorOrProduct() && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() && ctx.Device() &&
library.baseLinker.sanitize.isUnsanitizedVariant() &&
- ctx.isForPlatform() && !ctx.isPreventInstall() {
+ CtxIsForPlatform(ctx) && !ctx.isPreventInstall() {
installPath := getUnversionedLibraryInstallPath(ctx).Join(ctx, file.Base())
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
@@ -1818,12 +1875,17 @@
return library.shared() || library.static()
}
-// static returns true if this library is for a "static' variant.
+// static returns true if this library is for a "static" variant.
func (library *libraryDecorator) static() bool {
return library.MutatedProperties.VariantIsStatic
}
-// shared returns true if this library is for a "shared' variant.
+// staticLibrary returns true if this library is for a "static"" variant.
+func (library *libraryDecorator) staticLibrary() bool {
+ return library.static()
+}
+
+// shared returns true if this library is for a "shared" variant.
func (library *libraryDecorator) shared() bool {
return library.MutatedProperties.VariantIsShared
}
@@ -1863,35 +1925,40 @@
library.MutatedProperties.BuildStatic = false
}
-// hasLLNDKStubs returns true if this cc_library module has a variant that will build LLNDK stubs.
-func (library *libraryDecorator) hasLLNDKStubs() bool {
+// HasLLNDKStubs returns true if this cc_library module has a variant that will build LLNDK stubs.
+func (library *libraryDecorator) HasLLNDKStubs() bool {
return String(library.Properties.Llndk.Symbol_file) != ""
}
// hasLLNDKStubs returns true if this cc_library module has a variant that will build LLNDK stubs.
-func (library *libraryDecorator) hasLLNDKHeaders() bool {
+func (library *libraryDecorator) HasLLNDKHeaders() bool {
return Bool(library.Properties.Llndk.Llndk_headers)
}
-// hasVendorPublicLibrary returns true if this cc_library module has a variant that will build
+// IsLLNDKMovedToApex returns true if this cc_library module sets the llndk.moved_to_apex property.
+func (library *libraryDecorator) IsLLNDKMovedToApex() bool {
+ return Bool(library.Properties.Llndk.Moved_to_apex)
+}
+
+// HasVendorPublicLibrary returns true if this cc_library module has a variant that will build
// vendor public library stubs.
-func (library *libraryDecorator) hasVendorPublicLibrary() bool {
+func (library *libraryDecorator) HasVendorPublicLibrary() bool {
return String(library.Properties.Vendor_public_library.Symbol_file) != ""
}
-func (library *libraryDecorator) implementationModuleName(name string) string {
+func (library *libraryDecorator) ImplementationModuleName(name string) string {
return name
}
-func (library *libraryDecorator) buildStubs() bool {
+func (library *libraryDecorator) BuildStubs() bool {
return library.MutatedProperties.BuildStubs
}
func (library *libraryDecorator) symbolFileForAbiCheck(ctx ModuleContext) *string {
- if props := library.getHeaderAbiCheckerProperties(ctx); props.Symbol_file != nil {
+ if props := library.getHeaderAbiCheckerProperties(ctx.Module().(*Module)); props.Symbol_file != nil {
return props.Symbol_file
}
- if library.hasStubsVariants() && library.Properties.Stubs.Symbol_file != nil {
+ if library.HasStubsVariants() && library.Properties.Stubs.Symbol_file != nil {
return library.Properties.Stubs.Symbol_file
}
// TODO(b/309880485): Distinguish platform, NDK, LLNDK, and APEX version scripts.
@@ -1901,35 +1968,35 @@
return nil
}
-func (library *libraryDecorator) hasStubsVariants() bool {
+func (library *libraryDecorator) HasStubsVariants() bool {
// Just having stubs.symbol_file is enough to create a stub variant. In that case
// the stub for the future API level is created.
return library.Properties.Stubs.Symbol_file != nil ||
len(library.Properties.Stubs.Versions) > 0
}
-func (library *libraryDecorator) isStubsImplementationRequired() bool {
+func (library *libraryDecorator) IsStubsImplementationRequired() bool {
return BoolDefault(library.Properties.Stubs.Implementation_installable, true)
}
-func (library *libraryDecorator) stubsVersions(ctx android.BaseModuleContext) []string {
- if !library.hasStubsVariants() {
+func (library *libraryDecorator) StubsVersions(ctx android.BaseModuleContext) []string {
+ if !library.HasStubsVariants() {
return nil
}
- if library.hasLLNDKStubs() && ctx.Module().(*Module).InVendorOrProduct() {
+ if library.HasLLNDKStubs() && ctx.Module().(*Module).InVendorOrProduct() {
// LLNDK libraries only need a single stubs variant (""), which is
// added automatically in createVersionVariations().
return nil
}
// Future API level is implicitly added if there isn't
- versions := addCurrentVersionIfNotPresent(library.Properties.Stubs.Versions)
- normalizeVersions(ctx, versions)
+ versions := AddCurrentVersionIfNotPresent(library.Properties.Stubs.Versions)
+ NormalizeVersions(ctx, versions)
return versions
}
-func addCurrentVersionIfNotPresent(vers []string) []string {
+func AddCurrentVersionIfNotPresent(vers []string) []string {
if inList(android.FutureApiLevel.String(), vers) {
return vers
}
@@ -1942,24 +2009,24 @@
return append(vers, android.FutureApiLevel.String())
}
-func (library *libraryDecorator) setStubsVersion(version string) {
+func (library *libraryDecorator) SetStubsVersion(version string) {
library.MutatedProperties.StubsVersion = version
}
-func (library *libraryDecorator) stubsVersion() string {
+func (library *libraryDecorator) StubsVersion() string {
return library.MutatedProperties.StubsVersion
}
-func (library *libraryDecorator) setBuildStubs(isLatest bool) {
+func (library *libraryDecorator) SetBuildStubs(isLatest bool) {
library.MutatedProperties.BuildStubs = true
library.MutatedProperties.IsLatestVersion = isLatest
}
-func (library *libraryDecorator) setAllStubsVersions(versions []string) {
+func (library *libraryDecorator) SetAllStubsVersions(versions []string) {
library.MutatedProperties.AllStubsVersions = versions
}
-func (library *libraryDecorator) allStubsVersions() []string {
+func (library *libraryDecorator) AllStubsVersions() []string {
return library.MutatedProperties.AllStubsVersions
}
@@ -1967,17 +2034,15 @@
return library.MutatedProperties.IsLatestVersion
}
-func (library *libraryDecorator) availableFor(what string) bool {
+func (library *libraryDecorator) apexAvailable() []string {
var list []string
if library.static() {
list = library.StaticProperties.Static.Apex_available
} else if library.shared() {
list = library.SharedProperties.Shared.Apex_available
}
- if len(list) == 0 {
- return false
- }
- return android.CheckAvailableForApex(what, list)
+
+ return list
}
func (library *libraryDecorator) installable() *bool {
@@ -1990,7 +2055,7 @@
}
func (library *libraryDecorator) makeUninstallable(mod *Module) {
- if library.static() && library.buildStatic() && !library.buildStubs() {
+ if library.static() && library.buildStatic() && !library.BuildStubs() {
// If we're asked to make a static library uninstallable we don't do
// anything since AndroidMkEntries always sets LOCAL_UNINSTALLABLE_MODULE
// for these entries. This is done to still get the make targets for NOTICE
@@ -2004,10 +2069,14 @@
return library.path.Partition()
}
-func (library *libraryDecorator) getAPIListCoverageXMLPath() android.ModuleOutPath {
+func (library *libraryDecorator) GetAPIListCoverageXMLPath() android.ModuleOutPath {
return library.apiListCoverageXmlPath
}
+func (library *libraryDecorator) setAPIListCoverageXMLPath(xml android.ModuleOutPath) {
+ library.apiListCoverageXmlPath = xml
+}
+
func (library *libraryDecorator) overriddenModules() []string {
return library.Properties.Overrides
}
@@ -2091,12 +2160,7 @@
sharedCompiler.StaticProperties.Static.System_shared_libs == nil &&
sharedCompiler.SharedProperties.Shared.System_shared_libs == nil {
- // TODO: namespaces?
ctx.AddVariationDependencies([]blueprint.Variation{{"link", "static"}}, reuseObjTag, ctx.ModuleName())
- sharedCompiler.baseCompiler.Properties.OriginalSrcs =
- sharedCompiler.baseCompiler.Properties.Srcs
- sharedCompiler.baseCompiler.Properties.Srcs = proptools.NewConfigurable[[]string](nil, nil)
- sharedCompiler.baseCompiler.Properties.Generated_sources = nil
}
// This dep is just to reference static variant from shared variant
@@ -2127,7 +2191,7 @@
} else {
// Header only
}
- } else if library, ok := ctx.Module().(LinkableInterface); ok && (library.CcLibraryInterface() || library.RustLibraryInterface()) {
+ } else if library, ok := ctx.Module().(LinkableInterface); ok && (library.CcLibraryInterface()) {
// Non-cc.Modules may need an empty variant for their mutators.
variations := []string{}
if library.NonCcVariants() {
@@ -2182,7 +2246,7 @@
}
buildStatic := library.BuildStaticVariant() && !isLLNDK
buildShared := library.BuildSharedVariant()
- if library.BuildRlibVariant() && library.IsRustFFI() && !buildStatic && (incomingVariation == "static" || incomingVariation == "") {
+ if library.BuildRlibVariant() && !buildStatic && (incomingVariation == "static" || incomingVariation == "") {
// Rust modules do not build static libs, but rlibs are used as if they
// were via `static_libs`. Thus we need to alias the BuildRlibVariant
// to "static" for Rust FFI libraries.
@@ -2239,10 +2303,10 @@
}
}
-// normalizeVersions modifies `versions` in place, so that each raw version
+// NormalizeVersions modifies `versions` in place, so that each raw version
// string becomes its normalized canonical form.
// Validates that the versions in `versions` are specified in least to greatest order.
-func normalizeVersions(ctx android.BaseModuleContext, versions []string) {
+func NormalizeVersions(ctx android.BaseModuleContext, versions []string) {
var previous android.ApiLevel
for i, v := range versions {
ver, err := android.ApiLevelFromUser(ctx, v)
@@ -2259,7 +2323,7 @@
}
func perApiVersionVariations(mctx android.BaseModuleContext, minSdkVersion string) []string {
- from, err := nativeApiLevelFromUser(mctx, minSdkVersion)
+ from, err := NativeApiLevelFromUser(mctx, minSdkVersion)
if err != nil {
mctx.PropertyErrorf("min_sdk_version", err.Error())
return []string{""}
@@ -2287,25 +2351,25 @@
module.CcLibraryInterface() && module.Shared()
}
-func moduleLibraryInterface(module blueprint.Module) libraryInterface {
- if m, ok := module.(*Module); ok {
- return m.library
+func moduleVersionedInterface(module blueprint.Module) VersionedInterface {
+ if m, ok := module.(VersionedLinkableInterface); ok {
+ return m.VersionedInterface()
}
return nil
}
// setStubsVersions normalizes the versions in the Stubs.Versions property into MutatedProperties.AllStubsVersions.
-func setStubsVersions(mctx android.BaseModuleContext, library libraryInterface, module *Module) {
- if !library.buildShared() || !canBeVersionVariant(module) {
+func setStubsVersions(mctx android.BaseModuleContext, module VersionedLinkableInterface) {
+ if !module.BuildSharedVariant() || !canBeVersionVariant(module) {
return
}
- versions := library.stubsVersions(mctx)
+ versions := module.VersionedInterface().StubsVersions(mctx)
if mctx.Failed() {
return
}
// Set the versions on the pre-mutated module so they can be read by any llndk modules that
// depend on the implementation library and haven't been mutated yet.
- library.setAllStubsVersions(versions)
+ module.VersionedInterface().SetAllStubsVersions(versions)
}
// versionTransitionMutator splits a module into the mandatory non-stubs variant
@@ -2316,14 +2380,13 @@
if ctx.Os() != android.Android {
return []string{""}
}
-
- m, ok := ctx.Module().(*Module)
- if library := moduleLibraryInterface(ctx.Module()); library != nil && canBeVersionVariant(m) {
- setStubsVersions(ctx, library, m)
-
- return append(slices.Clone(library.allStubsVersions()), "")
- } else if ok && m.SplitPerApiLevel() && m.IsSdkVariant() {
- return perApiVersionVariations(ctx, m.MinSdkVersion())
+ if m, ok := ctx.Module().(VersionedLinkableInterface); ok {
+ if m.CcLibraryInterface() && canBeVersionVariant(m) {
+ setStubsVersions(ctx, m)
+ return append(slices.Clone(m.VersionedInterface().AllStubsVersions()), "")
+ } else if m.SplitPerApiLevel() && m.IsSdkVariant() {
+ return perApiVersionVariations(ctx, m.MinSdkVersion())
+ }
}
return []string{""}
@@ -2337,11 +2400,11 @@
if ctx.Os() != android.Android {
return ""
}
- m, ok := ctx.Module().(*Module)
- if library := moduleLibraryInterface(ctx.Module()); library != nil && canBeVersionVariant(m) {
+ m, ok := ctx.Module().(VersionedLinkableInterface)
+ if library := moduleVersionedInterface(ctx.Module()); library != nil && canBeVersionVariant(m) {
if incomingVariation == "latest" {
latestVersion := ""
- versions := library.allStubsVersions()
+ versions := library.AllStubsVersions()
if len(versions) > 0 {
latestVersion = versions[len(versions)-1]
}
@@ -2366,40 +2429,39 @@
return
}
- m, ok := ctx.Module().(*Module)
- if library := moduleLibraryInterface(ctx.Module()); library != nil && canBeVersionVariant(m) {
+ m, ok := ctx.Module().(VersionedLinkableInterface)
+ if library := moduleVersionedInterface(ctx.Module()); library != nil && canBeVersionVariant(m) {
isLLNDK := m.IsLlndk()
isVendorPublicLibrary := m.IsVendorPublicLibrary()
- isImportedApiLibrary := m.isImportedApiLibrary()
- if variation != "" || isLLNDK || isVendorPublicLibrary || isImportedApiLibrary {
+ if variation != "" || isLLNDK || isVendorPublicLibrary {
// A stubs or LLNDK stubs variant.
- if m.sanitize != nil {
- m.sanitize.Properties.ForceDisable = true
+ if sm, ok := ctx.Module().(PlatformSanitizeable); ok && sm.SanitizePropDefined() {
+ sm.ForceDisableSanitizers()
}
- if m.stl != nil {
- m.stl.Properties.Stl = StringPtr("none")
- }
- m.Properties.PreventInstall = true
- lib := moduleLibraryInterface(m)
- allStubsVersions := library.allStubsVersions()
+ m.SetStl("none")
+ m.SetPreventInstall()
+ allStubsVersions := m.VersionedInterface().AllStubsVersions()
isLatest := len(allStubsVersions) > 0 && variation == allStubsVersions[len(allStubsVersions)-1]
- lib.setBuildStubs(isLatest)
+ m.VersionedInterface().SetBuildStubs(isLatest)
}
if variation != "" {
// A non-LLNDK stubs module is hidden from make
- library.setStubsVersion(variation)
- m.Properties.HideFromMake = true
+ m.VersionedInterface().SetStubsVersion(variation)
+ m.SetHideFromMake()
} else {
// A non-LLNDK implementation module has a dependency to all stubs versions
- for _, version := range library.allStubsVersions() {
- ctx.AddVariationDependencies([]blueprint.Variation{{"version", version}},
- stubImplDepTag, ctx.ModuleName())
+ for _, version := range m.VersionedInterface().AllStubsVersions() {
+ ctx.AddVariationDependencies(
+ []blueprint.Variation{
+ {Mutator: "version", Variation: version},
+ {Mutator: "link", Variation: "shared"}},
+ StubImplDepTag, ctx.ModuleName())
}
}
} else if ok && m.SplitPerApiLevel() && m.IsSdkVariant() {
- m.Properties.Sdk_version = StringPtr(variation)
- m.Properties.Min_sdk_version = StringPtr(variation)
+ m.SetSdkVersion(variation)
+ m.SetMinSdkVersion(variation)
}
}
@@ -2411,13 +2473,12 @@
inject *bool, fileName string) android.ModuleOutPath {
// TODO(b/137267623): Remove this in favor of a cc_genrule when they support operating on shared libraries.
injectBoringSSLHash := Bool(inject)
- ctx.VisitDirectDeps(func(dep android.Module) {
+ ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) {
if tag, ok := ctx.OtherModuleDependencyTag(dep).(libraryDependencyTag); ok && tag.static() {
- if cc, ok := dep.(*Module); ok {
- if library, ok := cc.linker.(*libraryDecorator); ok {
- if Bool(library.Properties.Inject_bssl_hash) {
- injectBoringSSLHash = true
- }
+ if ccInfo, ok := android.OtherModuleProvider(ctx, dep, CcInfoProvider); ok &&
+ ccInfo.LinkerInfo != nil && ccInfo.LinkerInfo.LibraryDecoratorInfo != nil {
+ if ccInfo.LinkerInfo.LibraryDecoratorInfo.InjectBsslHash {
+ injectBoringSSLHash = true
}
}
}
diff --git a/cc/library_headers_test.go b/cc/library_headers_test.go
index 1924b2f..5a45767 100644
--- a/cc/library_headers_test.go
+++ b/cc/library_headers_test.go
@@ -46,7 +46,7 @@
// Test that there's a valid AndroidMk entry.
headers := ctx.ModuleForTests("headers", "android_arm64_armv8-a").Module()
- e := android.AndroidMkEntriesForTest(t, ctx, headers)[0]
+ e := android.AndroidMkInfoForTest(t, ctx, headers).PrimaryInfo
// This duplicates the tests done in AndroidMkEntries.write. It would be
// better to test its output, but there are no test functions that capture that.
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 053c460..d1440ea 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -543,10 +543,10 @@
p.ExportedFlags = exportedInfo.Flags
if ccModule.linker != nil {
specifiedDeps := specifiedDeps{}
- specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx, ccModule, specifiedDeps)
+ specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx.SdkModuleContext(), ccModule, specifiedDeps)
if lib := ccModule.library; lib != nil {
- if !lib.hasStubsVariants() {
+ if !lib.HasStubsVariants() {
// Propagate dynamic dependencies for implementation libs, but not stubs.
p.SharedLibs = specifiedDeps.sharedLibs
} else {
@@ -554,8 +554,8 @@
// ccModule.StubsVersion()) if the module is versioned. 2. Ensure that all
// the versioned stub libs are retained in the prebuilt tree; currently only
// the stub corresponding to ccModule.StubsVersion() is.
- p.StubsVersions = lib.allStubsVersions()
- if lib.buildStubs() && ccModule.stubsSymbolFilePath() == nil {
+ p.StubsVersions = lib.AllStubsVersions()
+ if lib.BuildStubs() && ccModule.stubsSymbolFilePath() == nil {
ctx.ModuleErrorf("Could not determine symbol_file")
} else {
p.StubsSymbolFilePath = ccModule.stubsSymbolFilePath()
diff --git a/cc/library_stub.go b/cc/library_stub.go
deleted file mode 100644
index 6367825..0000000
--- a/cc/library_stub.go
+++ /dev/null
@@ -1,512 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cc
-
-import (
- "regexp"
- "strings"
-
- "android/soong/android"
- "android/soong/multitree"
-
- "github.com/google/blueprint/proptools"
-)
-
-var (
- ndkVariantRegex = regexp.MustCompile("ndk\\.([a-zA-Z0-9]+)")
- stubVariantRegex = regexp.MustCompile("apex\\.([a-zA-Z0-9]+)")
-)
-
-func init() {
- RegisterLibraryStubBuildComponents(android.InitRegistrationContext)
-}
-
-func RegisterLibraryStubBuildComponents(ctx android.RegistrationContext) {
- ctx.RegisterModuleType("cc_api_library", CcApiLibraryFactory)
- ctx.RegisterModuleType("cc_api_headers", CcApiHeadersFactory)
- ctx.RegisterModuleType("cc_api_variant", CcApiVariantFactory)
-}
-
-func updateImportedLibraryDependency(ctx android.BottomUpMutatorContext) {
- m, ok := ctx.Module().(*Module)
- if !ok {
- return
- }
-
- apiLibrary, ok := m.linker.(*apiLibraryDecorator)
- if !ok {
- return
- }
-
- if m.InVendorOrProduct() && apiLibrary.hasLLNDKStubs() {
- // Add LLNDK variant dependency
- if inList("llndk", apiLibrary.properties.Variants) {
- variantName := BuildApiVariantName(m.BaseModuleName(), "llndk", "")
- ctx.AddDependency(m, nil, variantName)
- }
- } else if m.IsSdkVariant() {
- // Add NDK variant dependencies
- targetVariant := "ndk." + m.StubsVersion()
- if inList(targetVariant, apiLibrary.properties.Variants) {
- variantName := BuildApiVariantName(m.BaseModuleName(), targetVariant, "")
- ctx.AddDependency(m, nil, variantName)
- }
- } else if m.IsStubs() {
- targetVariant := "apex." + m.StubsVersion()
- if inList(targetVariant, apiLibrary.properties.Variants) {
- variantName := BuildApiVariantName(m.BaseModuleName(), targetVariant, "")
- ctx.AddDependency(m, nil, variantName)
- }
- }
-}
-
-// 'cc_api_library' is a module type which is from the exported API surface
-// with C shared library type. The module will replace original module, and
-// offer a link to the module that generates shared library object from the
-// map file.
-type apiLibraryProperties struct {
- Src *string `android:"arch_variant"`
- Variants []string
-}
-
-type apiLibraryDecorator struct {
- *libraryDecorator
- properties apiLibraryProperties
-}
-
-func CcApiLibraryFactory() android.Module {
- module, decorator := NewLibrary(android.DeviceSupported)
- apiLibraryDecorator := &apiLibraryDecorator{
- libraryDecorator: decorator,
- }
- apiLibraryDecorator.BuildOnlyShared()
-
- module.stl = nil
- module.sanitize = nil
- decorator.disableStripping()
-
- module.compiler = nil
- module.linker = apiLibraryDecorator
- module.installer = nil
- module.library = apiLibraryDecorator
- module.AddProperties(&module.Properties, &apiLibraryDecorator.properties)
-
- // Prevent default system libs (libc, libm, and libdl) from being linked
- if apiLibraryDecorator.baseLinker.Properties.System_shared_libs == nil {
- apiLibraryDecorator.baseLinker.Properties.System_shared_libs = []string{}
- }
-
- apiLibraryDecorator.baseLinker.Properties.No_libcrt = BoolPtr(true)
- apiLibraryDecorator.baseLinker.Properties.Nocrt = BoolPtr(true)
-
- module.Init()
-
- return module
-}
-
-func (d *apiLibraryDecorator) Name(basename string) string {
- return basename + multitree.GetApiImportSuffix()
-}
-
-// Export include dirs without checking for existence.
-// The directories are not guaranteed to exist during Soong analysis.
-func (d *apiLibraryDecorator) exportIncludes(ctx ModuleContext) {
- exporterProps := d.flagExporter.Properties
- for _, dir := range exporterProps.Export_include_dirs.GetOrDefault(ctx, nil) {
- d.dirs = append(d.dirs, android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), dir))
- }
- // system headers
- for _, dir := range exporterProps.Export_system_include_dirs {
- d.systemDirs = append(d.systemDirs, android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), dir))
- }
-}
-
-func (d *apiLibraryDecorator) linkerInit(ctx BaseModuleContext) {
- d.baseLinker.linkerInit(ctx)
-
- if d.hasNDKStubs() {
- // Set SDK version of module as current
- ctx.Module().(*Module).Properties.Sdk_version = StringPtr("current")
-
- // Add NDK stub as NDK known libs
- name := ctx.ModuleName()
-
- ndkKnownLibsLock.Lock()
- ndkKnownLibs := getNDKKnownLibs(ctx.Config())
- if !inList(name, *ndkKnownLibs) {
- *ndkKnownLibs = append(*ndkKnownLibs, name)
- }
- ndkKnownLibsLock.Unlock()
- }
-}
-
-func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objects Objects) android.Path {
- m, _ := ctx.Module().(*Module)
-
- var in android.Path
-
- // src might not exist during the beginning of soong analysis in Multi-tree
- if src := String(d.properties.Src); src != "" {
- in = android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), src)
- }
-
- libName := m.BaseModuleName() + multitree.GetApiImportSuffix()
-
- load_cc_variant := func(apiVariantModule string) {
- var mod android.Module
-
- ctx.VisitDirectDeps(func(depMod android.Module) {
- if depMod.Name() == apiVariantModule {
- mod = depMod
- libName = apiVariantModule
- }
- })
-
- if mod != nil {
- variantMod, ok := mod.(*CcApiVariant)
- if ok {
- in = variantMod.Src()
-
- // Copy LLDNK properties to cc_api_library module
- exportIncludeDirs := append(d.libraryDecorator.flagExporter.Properties.Export_include_dirs.GetOrDefault(ctx, nil),
- variantMod.exportProperties.Export_include_dirs...)
- d.libraryDecorator.flagExporter.Properties.Export_include_dirs = proptools.NewConfigurable[[]string](
- nil,
- []proptools.ConfigurableCase[[]string]{
- proptools.NewConfigurableCase[[]string](nil, &exportIncludeDirs),
- },
- )
-
- // Export headers as system include dirs if specified. Mostly for libc
- if Bool(variantMod.exportProperties.Export_headers_as_system) {
- d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs = append(
- d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs,
- d.libraryDecorator.flagExporter.Properties.Export_include_dirs.GetOrDefault(ctx, nil)...)
- d.libraryDecorator.flagExporter.Properties.Export_include_dirs = proptools.NewConfigurable[[]string](nil, nil)
- }
- }
- }
- }
-
- if m.InVendorOrProduct() && d.hasLLNDKStubs() {
- // LLNDK variant
- load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "llndk", ""))
- } else if m.IsSdkVariant() {
- // NDK Variant
- load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "ndk", m.StubsVersion()))
- } else if m.IsStubs() {
- // APEX Variant
- load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "apex", m.StubsVersion()))
- }
-
- // Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
- d.exportIncludes(ctx)
- d.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
- d.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
- d.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
- d.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
- d.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
-
- if in == nil {
- ctx.PropertyErrorf("src", "Unable to locate source property")
- return nil
- }
-
- // Make the _compilation_ of rdeps have an order-only dep on cc_api_library.src (an .so file)
- // The .so file itself has an order-only dependency on the headers contributed by this library.
- // Creating this dependency ensures that the headers are assembled before compilation of rdeps begins.
- d.libraryDecorator.reexportDeps(in)
- d.libraryDecorator.flagExporter.setProvider(ctx)
-
- d.unstrippedOutputFile = in
- libName += flags.Toolchain.ShlibSuffix()
-
- tocFile := android.PathForModuleOut(ctx, libName+".toc")
- d.tocFile = android.OptionalPathForPath(tocFile)
- TransformSharedObjectToToc(ctx, in, tocFile)
-
- outputFile := android.PathForModuleOut(ctx, libName)
-
- // TODO(b/270485584) This copies with a new name, just to avoid conflict with prebuilts.
- // We can just use original input if there is any way to avoid name conflict without copy.
- ctx.Build(pctx, android.BuildParams{
- Rule: android.Cp,
- Description: "API surface imported library",
- Input: in,
- Output: outputFile,
- Args: map[string]string{
- "cpFlags": "-L",
- },
- })
-
- android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
- SharedLibrary: outputFile,
- Target: ctx.Target(),
-
- TableOfContents: d.tocFile,
- })
-
- d.shareStubs(ctx)
-
- return outputFile
-}
-
-// Share additional information about stub libraries with provider
-func (d *apiLibraryDecorator) shareStubs(ctx ModuleContext) {
- stubs := ctx.GetDirectDepsWithTag(stubImplDepTag)
- if len(stubs) > 0 {
- var stubsInfo []SharedStubLibrary
- for _, stub := range stubs {
- stubInfo, _ := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider)
- flagInfo, _ := android.OtherModuleProvider(ctx, stub, FlagExporterInfoProvider)
- stubsInfo = append(stubsInfo, SharedStubLibrary{
- Version: moduleLibraryInterface(stub).stubsVersion(),
- SharedLibraryInfo: stubInfo,
- FlagExporterInfo: flagInfo,
- })
- }
- android.SetProvider(ctx, SharedLibraryStubsProvider, SharedLibraryStubsInfo{
- SharedStubLibraries: stubsInfo,
-
- IsLLNDK: ctx.IsLlndk(),
- })
- }
-}
-
-func (d *apiLibraryDecorator) availableFor(what string) bool {
- // Stub from API surface should be available for any APEX.
- return true
-}
-
-func (d *apiLibraryDecorator) hasApexStubs() bool {
- for _, variant := range d.properties.Variants {
- if strings.HasPrefix(variant, "apex") {
- return true
- }
- }
- return false
-}
-
-func (d *apiLibraryDecorator) hasStubsVariants() bool {
- return d.hasApexStubs()
-}
-
-func (d *apiLibraryDecorator) stubsVersions(ctx android.BaseModuleContext) []string {
- m, ok := ctx.Module().(*Module)
-
- if !ok {
- return nil
- }
-
- // TODO(b/244244438) Create more version information for NDK and APEX variations
- // NDK variants
- if m.IsSdkVariant() {
- // TODO(b/249193999) Do not check if module has NDK stubs once all NDK cc_api_library contains ndk variant of cc_api_variant.
- if d.hasNDKStubs() {
- return d.getNdkVersions()
- }
- }
-
- if d.hasLLNDKStubs() && m.InVendorOrProduct() {
- // LLNDK libraries only need a single stubs variant.
- return []string{android.FutureApiLevel.String()}
- }
-
- stubsVersions := d.getStubVersions()
-
- if len(stubsVersions) != 0 {
- return stubsVersions
- }
-
- if m.MinSdkVersion() == "" {
- return nil
- }
-
- firstVersion, err := nativeApiLevelFromUser(ctx,
- m.MinSdkVersion())
-
- if err != nil {
- return nil
- }
-
- return ndkLibraryVersions(ctx, firstVersion)
-}
-
-func (d *apiLibraryDecorator) hasLLNDKStubs() bool {
- return inList("llndk", d.properties.Variants)
-}
-
-func (d *apiLibraryDecorator) hasNDKStubs() bool {
- for _, variant := range d.properties.Variants {
- if ndkVariantRegex.MatchString(variant) {
- return true
- }
- }
- return false
-}
-
-func (d *apiLibraryDecorator) getNdkVersions() []string {
- ndkVersions := []string{}
-
- for _, variant := range d.properties.Variants {
- if match := ndkVariantRegex.FindStringSubmatch(variant); len(match) == 2 {
- ndkVersions = append(ndkVersions, match[1])
- }
- }
-
- return ndkVersions
-}
-
-func (d *apiLibraryDecorator) getStubVersions() []string {
- stubVersions := []string{}
-
- for _, variant := range d.properties.Variants {
- if match := stubVariantRegex.FindStringSubmatch(variant); len(match) == 2 {
- stubVersions = append(stubVersions, match[1])
- }
- }
-
- return stubVersions
-}
-
-// 'cc_api_headers' is similar with 'cc_api_library', but which replaces
-// header libraries. The module will replace any dependencies to existing
-// original header libraries.
-type apiHeadersDecorator struct {
- *libraryDecorator
-}
-
-func CcApiHeadersFactory() android.Module {
- module, decorator := NewLibrary(android.DeviceSupported)
- apiHeadersDecorator := &apiHeadersDecorator{
- libraryDecorator: decorator,
- }
- apiHeadersDecorator.HeaderOnly()
-
- module.stl = nil
- module.sanitize = nil
- decorator.disableStripping()
-
- module.compiler = nil
- module.linker = apiHeadersDecorator
- module.installer = nil
-
- // Prevent default system libs (libc, libm, and libdl) from being linked
- if apiHeadersDecorator.baseLinker.Properties.System_shared_libs == nil {
- apiHeadersDecorator.baseLinker.Properties.System_shared_libs = []string{}
- }
-
- apiHeadersDecorator.baseLinker.Properties.No_libcrt = BoolPtr(true)
- apiHeadersDecorator.baseLinker.Properties.Nocrt = BoolPtr(true)
-
- module.Init()
-
- return module
-}
-
-func (d *apiHeadersDecorator) Name(basename string) string {
- return basename + multitree.GetApiImportSuffix()
-}
-
-func (d *apiHeadersDecorator) availableFor(what string) bool {
- // Stub from API surface should be available for any APEX.
- return true
-}
-
-type ccApiexportProperties struct {
- Src *string `android:"arch_variant"`
- Variant *string
- Version *string
-}
-
-type variantExporterProperties struct {
- // Header directory to export
- Export_include_dirs []string `android:"arch_variant"`
-
- // Export all headers as system include
- Export_headers_as_system *bool
-}
-
-type CcApiVariant struct {
- android.ModuleBase
-
- properties ccApiexportProperties
- exportProperties variantExporterProperties
-
- src android.Path
-}
-
-var _ android.Module = (*CcApiVariant)(nil)
-var _ android.ImageInterface = (*CcApiVariant)(nil)
-
-func CcApiVariantFactory() android.Module {
- module := &CcApiVariant{}
-
- module.AddProperties(&module.properties)
- module.AddProperties(&module.exportProperties)
-
- android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
- return module
-}
-
-func (v *CcApiVariant) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- // No need to build
-
- if String(v.properties.Src) == "" {
- ctx.PropertyErrorf("src", "src is a required property")
- }
-
- // Skip the existence check of the stub prebuilt file.
- // The file is not guaranteed to exist during Soong analysis.
- // Build orchestrator will be responsible for creating a connected ninja graph.
- v.src = android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), String(v.properties.Src))
-}
-
-func (v *CcApiVariant) Name() string {
- version := String(v.properties.Version)
- return BuildApiVariantName(v.BaseModuleName(), *v.properties.Variant, version)
-}
-
-func (v *CcApiVariant) Src() android.Path {
- return v.src
-}
-
-func BuildApiVariantName(baseName string, variant string, version string) string {
- names := []string{baseName, variant}
- if version != "" {
- names = append(names, version)
- }
-
- return strings.Join(names[:], ".") + multitree.GetApiImportSuffix()
-}
-
-// Implement ImageInterface to generate image variants
-func (v *CcApiVariant) ImageMutatorBegin(ctx android.BaseModuleContext) {}
-func (v *CcApiVariant) VendorVariantNeeded(ctx android.BaseModuleContext) bool {
- return String(v.properties.Variant) == "llndk"
-}
-func (v *CcApiVariant) ProductVariantNeeded(ctx android.BaseModuleContext) bool {
- return String(v.properties.Variant) == "llndk"
-}
-func (v *CcApiVariant) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
- return inList(String(v.properties.Variant), []string{"ndk", "apex"})
-}
-func (v *CcApiVariant) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false }
-func (v *CcApiVariant) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false }
-func (v *CcApiVariant) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false }
-func (v *CcApiVariant) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { return false }
-func (v *CcApiVariant) ExtraImageVariations(ctx android.BaseModuleContext) []string { return nil }
-func (v *CcApiVariant) SetImageVariation(ctx android.BaseModuleContext, variation string) {
-}
diff --git a/cc/linkable.go b/cc/linkable.go
index 1672366..337b459 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -5,6 +5,7 @@
"android/soong/fuzz"
"github.com/google/blueprint"
+ "github.com/google/blueprint/depset"
)
// PlatformSanitizeable is an interface for sanitizing platform modules.
@@ -52,6 +53,9 @@
// SanitizableDepTagChecker returns a SantizableDependencyTagChecker function type.
SanitizableDepTagChecker() SantizableDependencyTagChecker
+
+ // ForceDisableSanitizers sets the ForceDisable sanitize property
+ ForceDisableSanitizers()
}
// SantizableDependencyTagChecker functions check whether or not a dependency
@@ -62,6 +66,30 @@
// implementation should handle tags from both.
type SantizableDependencyTagChecker func(tag blueprint.DependencyTag) bool
+type VersionedLinkableInterface interface {
+ LinkableInterface
+ android.ApexModule
+
+ // VersionedInterface returns the VersionedInterface for this module
+ // (e.g. c.library), or nil if this is module is not a VersionedInterface.
+ VersionedInterface() VersionedInterface
+
+ // HasStubsVariants true if this module is a stub or has a sibling variant
+ // that is a stub.
+ HasStubsVariants() bool
+
+ // SetStl sets the stl property for CC modules. Does not panic if for other module types.
+ SetStl(string)
+ SetSdkVersion(string)
+ SetMinSdkVersion(version string)
+ ApexSdkVersion() android.ApiLevel
+ ImplementationModuleNameForMake(ctx android.BaseModuleContext) string
+
+ // RustApexExclude returns ApexExclude() for Rust modules; always returns false for all non-Rust modules.
+ // TODO(b/362509506): remove this once all apex_exclude uses are switched to stubs.
+ RustApexExclude() bool
+}
+
// LinkableInterface is an interface for a type of module that is linkable in a C++ library.
type LinkableInterface interface {
android.Module
@@ -101,9 +129,6 @@
IsPrebuilt() bool
Toc() android.OptionalPath
- // IsRustFFI returns true if this is a Rust FFI library.
- IsRustFFI() bool
-
// IsFuzzModule returns true if this a *_fuzz module.
IsFuzzModule() bool
@@ -140,18 +165,12 @@
// IsLlndk returns true for both LLNDK (public) and LLNDK-private libs.
IsLlndk() bool
- // HasLlndkStubs returns true if this library has a variant that will build LLNDK stubs.
- HasLlndkStubs() bool
-
// NeedsLlndkVariants returns true if this module has LLNDK stubs or provides LLNDK headers.
NeedsLlndkVariants() bool
// NeedsVendorPublicLibraryVariants returns true if this module has vendor public library stubs.
NeedsVendorPublicLibraryVariants() bool
- //StubsVersion returns the stubs version for this module.
- StubsVersion() string
-
// UseVndk returns true if the module is using VNDK libraries instead of the libraries in /system/lib or /system/lib64.
// "product" and "vendor" variant modules return true for this function.
// When BOARD_VNDK_VERSION is set, vendor variants of "vendor_available: true", "vendor: true",
@@ -180,6 +199,7 @@
MinSdkVersion() string
AlwaysSdk() bool
IsSdkVariant() bool
+ Multilib() string
SplitPerApiLevel() bool
@@ -248,6 +268,7 @@
// FuzzModule returns the fuzz.FuzzModule associated with the module.
FuzzModuleStruct() fuzz.FuzzModule
+ IsCrt() bool
}
var (
@@ -316,10 +337,12 @@
SharedLibrary android.Path
Target android.Target
- TableOfContents android.OptionalPath
+ TableOfContents android.OptionalPath
+ IsStubs bool
+ ImplementationDeps depset.DepSet[string]
// should be obtained from static analogue
- TransitiveStaticLibrariesForOrdering *android.DepSet[android.Path]
+ TransitiveStaticLibrariesForOrdering depset.DepSet[android.Path]
}
var SharedLibraryInfoProvider = blueprint.NewProvider[SharedLibraryInfo]()
@@ -361,7 +384,7 @@
// This isn't the actual transitive DepSet, shared library dependencies have been
// converted into static library analogues. It is only used to order the static
// library dependencies that were specified for the current module.
- TransitiveStaticLibrariesForOrdering *android.DepSet[android.Path]
+ TransitiveStaticLibrariesForOrdering depset.DepSet[android.Path]
}
var StaticLibraryInfoProvider = blueprint.NewProvider[StaticLibraryInfo]()
@@ -385,3 +408,9 @@
}
var FlagExporterInfoProvider = blueprint.NewProvider[FlagExporterInfo]()
+
+var ImplementationDepInfoProvider = blueprint.NewProvider[*ImplementationDepInfo]()
+
+type ImplementationDepInfo struct {
+ ImplementationDeps depset.DepSet[android.Path]
+}
diff --git a/cc/linker.go b/cc/linker.go
index 0056817..f854937 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -85,7 +85,7 @@
// list of header libraries to re-export include directories from. Entries must be
// present in header_libs.
- Export_header_lib_headers []string `android:"arch_variant"`
+ Export_header_lib_headers proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"`
// list of generated headers to re-export include directories from. Entries must be
// present in generated_headers.
@@ -235,13 +235,16 @@
// Generate compact dynamic relocation table, default true.
Pack_relocations *bool `android:"arch_variant"`
- // local file name to pass to the linker as --version-script
+ // local file name to pass to the linker as --version-script. Not supported on darwin, and will fail to build
+ // if provided to the darwin variant of a module.
Version_script *string `android:"path,arch_variant"`
- // local file name to pass to the linker as --dynamic-list
+ // local file name to pass to the linker as --dynamic-list. Not supported on darwin, and will fail to build
+ // if provided to the darwin variant of a module.
Dynamic_list *string `android:"path,arch_variant"`
- // local files to pass to the linker as --script
+ // local files to pass to the linker as --script. Not supported on darwin or windows, and will fail to build
+ // if provided to the darwin or windows variant of a module.
Linker_scripts []string `android:"path,arch_variant"`
// list of static libs that should not be used to build this module
@@ -302,7 +305,7 @@
deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Shared_libs.GetOrDefault(ctx, nil)...)
deps.RuntimeLibs = append(deps.RuntimeLibs, linker.Properties.Runtime_libs...)
- deps.ReexportHeaderLibHeaders = append(deps.ReexportHeaderLibHeaders, linker.Properties.Export_header_lib_headers...)
+ deps.ReexportHeaderLibHeaders = append(deps.ReexportHeaderLibHeaders, linker.Properties.Export_header_lib_headers.GetOrDefault(ctx, nil)...)
deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, linker.Properties.Export_static_lib_headers...)
deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, linker.Properties.Export_shared_lib_headers...)
deps.ReexportGeneratedHeaders = append(deps.ReexportGeneratedHeaders, linker.Properties.Export_generated_headers...)
@@ -454,7 +457,7 @@
if ctx.minSdkVersion() == "current" {
return true
}
- parsedSdkVersion, err := nativeApiLevelFromUser(ctx, ctx.minSdkVersion())
+ parsedSdkVersion, err := NativeApiLevelFromUser(ctx, ctx.minSdkVersion())
if err != nil {
ctx.PropertyErrorf("min_sdk_version",
"Invalid min_sdk_version value (must be int or current): %q",
@@ -468,16 +471,77 @@
// ModuleContext extends BaseModuleContext
// BaseModuleContext should know if LLD is used?
-func (linker *baseLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags {
- toolchain := ctx.toolchain()
-
+func CommonLinkerFlags(ctx android.ModuleContext, flags Flags, useClangLld bool,
+ toolchain config.Toolchain, allow_undefined_symbols bool) Flags {
hod := "Host"
if ctx.Os().Class == android.Device {
hod = "Device"
}
- if linker.useClangLld(ctx) {
+ mod, ok := ctx.Module().(LinkableInterface)
+ if !ok {
+ ctx.ModuleErrorf("trying to add CommonLinkerFlags to non-LinkableInterface module.")
+ return flags
+ }
+ if useClangLld {
flags.Global.LdFlags = append(flags.Global.LdFlags, fmt.Sprintf("${config.%sGlobalLldflags}", hod))
+ } else {
+ flags.Global.LdFlags = append(flags.Global.LdFlags, fmt.Sprintf("${config.%sGlobalLdflags}", hod))
+ }
+
+ if allow_undefined_symbols {
+ if ctx.Darwin() {
+ // darwin defaults to treating undefined symbols as errors
+ flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,-undefined,dynamic_lookup")
+ }
+ } else if !ctx.Darwin() && !ctx.Windows() {
+ flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--no-undefined")
+ }
+
+ if useClangLld {
+ flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.Lldflags())
+ } else {
+ flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.Ldflags())
+ }
+
+ if !toolchain.Bionic() && ctx.Os() != android.LinuxMusl {
+ if !ctx.Windows() {
+ // Add -ldl, -lpthread, -lm and -lrt to host builds to match the default behavior of device
+ // builds
+ flags.Global.LdFlags = append(flags.Global.LdFlags,
+ "-ldl",
+ "-lpthread",
+ "-lm",
+ )
+ if !ctx.Darwin() {
+ flags.Global.LdFlags = append(flags.Global.LdFlags, "-lrt")
+ }
+ }
+ }
+ staticLib := mod.CcLibraryInterface() && mod.Static()
+ if ctx.Host() && !ctx.Windows() && !staticLib {
+ flags.Global.LdFlags = append(flags.Global.LdFlags, RpathFlags(ctx)...)
+ }
+
+ flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.ToolchainLdflags())
+ return flags
+}
+
+func (linker *baseLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags {
+ toolchain := ctx.toolchain()
+ allow_undefined_symbols := Bool(linker.Properties.Allow_undefined_symbols)
+
+ flags = CommonLinkerFlags(ctx, flags, linker.useClangLld(ctx), toolchain,
+ allow_undefined_symbols)
+
+ if !toolchain.Bionic() && ctx.Os() != android.LinuxMusl {
+ CheckBadHostLdlibs(ctx, "host_ldlibs", linker.Properties.Host_ldlibs)
+ flags.Local.LdFlags = append(flags.Local.LdFlags, linker.Properties.Host_ldlibs...)
+ }
+
+ CheckBadLinkerFlags(ctx, "ldflags", linker.Properties.Ldflags)
+
+ if linker.useClangLld(ctx) {
if !BoolDefault(linker.Properties.Pack_relocations, packRelocationsDefault) {
flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=none")
} else if ctx.Device() {
@@ -495,53 +559,10 @@
flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=android")
}
}
- } else {
- flags.Global.LdFlags = append(flags.Global.LdFlags, fmt.Sprintf("${config.%sGlobalLdflags}", hod))
}
- if Bool(linker.Properties.Allow_undefined_symbols) {
- if ctx.Darwin() {
- // darwin defaults to treating undefined symbols as errors
- flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,-undefined,dynamic_lookup")
- }
- } else if !ctx.Darwin() && !ctx.Windows() {
- flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--no-undefined")
- }
-
- if linker.useClangLld(ctx) {
- flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.Lldflags())
- } else {
- flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.Ldflags())
- }
-
- if !ctx.toolchain().Bionic() && ctx.Os() != android.LinuxMusl {
- CheckBadHostLdlibs(ctx, "host_ldlibs", linker.Properties.Host_ldlibs)
-
- flags.Local.LdFlags = append(flags.Local.LdFlags, linker.Properties.Host_ldlibs...)
-
- if !ctx.Windows() {
- // Add -ldl, -lpthread, -lm and -lrt to host builds to match the default behavior of device
- // builds
- flags.Global.LdFlags = append(flags.Global.LdFlags,
- "-ldl",
- "-lpthread",
- "-lm",
- )
- if !ctx.Darwin() {
- flags.Global.LdFlags = append(flags.Global.LdFlags, "-lrt")
- }
- }
- }
-
- CheckBadLinkerFlags(ctx, "ldflags", linker.Properties.Ldflags)
flags.Local.LdFlags = append(flags.Local.LdFlags, proptools.NinjaAndShellEscapeList(linker.Properties.Ldflags)...)
- if ctx.Host() && !ctx.Windows() && !ctx.static() {
- flags.Global.LdFlags = append(flags.Global.LdFlags, RpathFlags(ctx)...)
- }
-
- flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.ToolchainLdflags())
-
// Version_script is not needed when linking stubs lib where the version
// script is created from the symbol map file.
if !linker.dynamicProperties.BuildStubs {
@@ -560,7 +581,7 @@
if versionScript.Valid() {
if ctx.Darwin() {
- ctx.PropertyErrorf("version_script", "Not supported on Darwin")
+ ctx.AddMissingDependencies([]string{"version_script_not_supported_on_darwin"})
} else {
flags.Local.LdFlags = append(flags.Local.LdFlags,
config.VersionScriptFlagPrefix+versionScript.String())
@@ -578,7 +599,7 @@
dynamicList := android.OptionalPathForModuleSrc(ctx, linker.Properties.Dynamic_list)
if dynamicList.Valid() {
if ctx.Darwin() {
- ctx.PropertyErrorf("dynamic_list", "Not supported on Darwin")
+ ctx.AddMissingDependencies([]string{"dynamic_list_not_supported_on_darwin"})
} else {
flags.Local.LdFlags = append(flags.Local.LdFlags,
"-Wl,--dynamic-list,"+dynamicList.String())
@@ -587,13 +608,17 @@
}
linkerScriptPaths := android.PathsForModuleSrc(ctx, linker.Properties.Linker_scripts)
- if len(linkerScriptPaths) > 0 && (ctx.Darwin() || ctx.Windows()) {
- ctx.PropertyErrorf("linker_scripts", "Only supported for ELF files")
- } else {
- for _, linkerScriptPath := range linkerScriptPaths {
- flags.Local.LdFlags = append(flags.Local.LdFlags,
- "-Wl,--script,"+linkerScriptPath.String())
- flags.LdFlagsDeps = append(flags.LdFlagsDeps, linkerScriptPath)
+ if len(linkerScriptPaths) > 0 {
+ if ctx.Darwin() {
+ ctx.AddMissingDependencies([]string{"linker_scripts_not_supported_on_darwin"})
+ } else if ctx.Windows() {
+ ctx.PropertyErrorf("linker_scripts", "Only supported for ELF files")
+ } else {
+ for _, linkerScriptPath := range linkerScriptPaths {
+ flags.Local.LdFlags = append(flags.Local.LdFlags,
+ "-Wl,--script,"+linkerScriptPath.String())
+ flags.LdFlagsDeps = append(flags.LdFlagsDeps, linkerScriptPath)
+ }
}
}
}
@@ -645,7 +670,7 @@
panic(fmt.Errorf("baseLinker doesn't know how to link"))
}
-func (linker *baseLinker) linkerSpecifiedDeps(ctx android.ConfigAndErrorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps {
+func (linker *baseLinker) linkerSpecifiedDeps(ctx android.ConfigurableEvaluatorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps {
eval := module.ConfigurableEvaluator(ctx)
specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, linker.Properties.Shared_libs.GetOrDefault(eval, nil)...)
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 5ece78a..5586576 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -36,10 +36,6 @@
// bionic/libc.
Export_headers_as_system *bool
- // Which headers to process with versioner. This really only handles
- // bionic/libc/include right now.
- Export_preprocessed_headers []string
-
// Whether the system library uses symbol versions.
Unversioned *bool
@@ -61,28 +57,58 @@
// if true, make this module available to provide headers to other modules that set
// llndk.symbol_file.
Llndk_headers *bool
+
+ // moved_to_apex marks this module has having been distributed through an apex module.
+ Moved_to_apex *bool
}
func makeLlndkVars(ctx android.MakeVarsContext) {
- // Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to avoid installing libraries on /system if
- // they been moved to an apex.
- movedToApexLlndkLibraries := make(map[string]bool)
- ctx.VisitAllModules(func(module android.Module) {
- if library := moduleLibraryInterface(module); library != nil && library.hasLLNDKStubs() {
- // Skip bionic libs, they are handled in different manner
- name := library.implementationModuleName(module.(*Module).BaseModuleName())
- if module.(android.ApexModule).DirectlyInAnyApex() && !isBionic(name) {
- movedToApexLlndkLibraries[name] = true
- }
- }
- })
- ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES",
- strings.Join(android.SortedKeys(movedToApexLlndkLibraries), " "))
}
func init() {
RegisterLlndkLibraryTxtType(android.InitRegistrationContext)
+ android.RegisterParallelSingletonType("movedToApexLlndkLibraries", movedToApexLlndkLibrariesFactory)
+}
+
+func movedToApexLlndkLibrariesFactory() android.Singleton {
+ return &movedToApexLlndkLibraries{}
+}
+
+type movedToApexLlndkLibraries struct {
+ movedToApexLlndkLibraries []string
+}
+
+func (s *movedToApexLlndkLibraries) GenerateBuildActions(ctx android.SingletonContext) {
+ // Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to generate the linker config.
+ movedToApexLlndkLibrariesMap := make(map[string]bool)
+ ctx.VisitAllModules(func(module android.Module) {
+ if library := moduleVersionedInterface(module); library != nil && library.HasLLNDKStubs() {
+ if library.IsLLNDKMovedToApex() {
+ name := library.ImplementationModuleName(module.(*Module).BaseModuleName())
+ movedToApexLlndkLibrariesMap[name] = true
+ }
+ }
+ })
+ s.movedToApexLlndkLibraries = android.SortedKeys(movedToApexLlndkLibrariesMap)
+
+ var sb strings.Builder
+ for i, l := range s.movedToApexLlndkLibraries {
+ if i > 0 {
+ sb.WriteRune(' ')
+ }
+ sb.WriteString(l)
+ sb.WriteString(".so")
+ }
+ android.WriteFileRule(ctx, MovedToApexLlndkLibrariesFile(ctx), sb.String())
+}
+
+func MovedToApexLlndkLibrariesFile(ctx android.PathContext) android.WritablePath {
+ return android.PathForIntermediates(ctx, "moved_to_apex_llndk_libraries.txt")
+}
+
+func (s *movedToApexLlndkLibraries) MakeVars(ctx android.MakeVarsContext) {
+ ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES", strings.Join(s.movedToApexLlndkLibraries, " "))
}
func RegisterLlndkLibraryTxtType(ctx android.RegistrationContext) {
@@ -197,10 +223,10 @@
lib, isLib := m.linker.(*libraryDecorator)
prebuiltLib, isPrebuiltLib := m.linker.(*prebuiltLibraryLinker)
- if m.InVendorOrProduct() && isLib && lib.hasLLNDKStubs() {
+ if m.InVendorOrProduct() && isLib && lib.HasLLNDKStubs() {
m.VendorProperties.IsLLNDK = true
}
- if m.InVendorOrProduct() && isPrebuiltLib && prebuiltLib.hasLLNDKStubs() {
+ if m.InVendorOrProduct() && isPrebuiltLib && prebuiltLib.HasLLNDKStubs() {
m.VendorProperties.IsLLNDK = true
}
diff --git a/cc/lto.go b/cc/lto.go
index f3af7d2..4444152 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -110,7 +110,7 @@
var ltoLdFlags []string
// Do not perform costly LTO optimizations for Eng builds.
- if Bool(lto.Properties.Lto_O0) || ctx.optimizeForSize() || ctx.Config().Eng() {
+ if Bool(lto.Properties.Lto_O0) || ctx.Config().Eng() {
ltoLdFlags = append(ltoLdFlags, "-Wl,--lto-O0")
}
diff --git a/cc/makevars.go b/cc/makevars.go
index c9352a4..ca97b76 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -25,10 +25,7 @@
)
var (
- modulesWarningsAllowedKey = android.NewOnceKey("ModulesWarningsAllowed")
- modulesUsingWnoErrorKey = android.NewOnceKey("ModulesUsingWnoError")
- modulesMissingProfileFileKey = android.NewOnceKey("ModulesMissingProfileFile")
- sanitizerVariables = map[string]string{
+ sanitizerVariables = map[string]string{
"ADDRESS_SANITIZER_RUNTIME_LIBRARY": config.AddressSanitizerRuntimeLibrary(),
"HWADDRESS_SANITIZER_RUNTIME_LIBRARY": config.HWAddressSanitizerRuntimeLibrary(),
"HWADDRESS_SANITIZER_STATIC_LIBRARY": config.HWAddressSanitizerStaticLibrary(),
@@ -50,15 +47,9 @@
}).(*sync.Map)
}
-func makeStringOfKeys(ctx android.MakeVarsContext, key android.OnceKey) string {
- set := getNamedMapForConfig(ctx.Config(), key)
- keys := []string{}
- set.Range(func(key interface{}, value interface{}) bool {
- keys = append(keys, key.(string))
- return true
- })
- sort.Strings(keys)
- return strings.Join(keys, " ")
+func makeVarsString(items []string) string {
+ items = android.SortedUniqueStrings(items)
+ return strings.Join(items, " ")
}
func makeStringOfWarningAllowedProjects() string {
@@ -108,27 +99,33 @@
ctx.Strict("GLOBAL_CLANG_EXTERNAL_CFLAGS_NO_OVERRIDE", "${config.NoOverrideExternalGlobalCflags}")
// Filter vendor_public_library that are exported to make
- exportedVendorPublicLibraries := []string{}
+ var exportedVendorPublicLibraries []string
+ var warningsAllowed []string
+ var usingWnoErrors []string
+ var missingProfiles []string
ctx.VisitAllModules(func(module android.Module) {
+ if v, ok := android.OtherModuleProvider(ctx, module, CcMakeVarsInfoProvider); ok {
+ warningsAllowed = android.AppendIfNotZero(warningsAllowed, v.WarningsAllowed)
+ usingWnoErrors = android.AppendIfNotZero(usingWnoErrors, v.UsingWnoError)
+ missingProfiles = android.AppendIfNotZero(missingProfiles, v.MissingProfile)
+ }
if ccModule, ok := module.(*Module); ok {
baseName := ccModule.BaseModuleName()
if ccModule.IsVendorPublicLibrary() && module.ExportedToMake() {
- if !inList(baseName, exportedVendorPublicLibraries) {
- exportedVendorPublicLibraries = append(exportedVendorPublicLibraries, baseName)
- }
+ exportedVendorPublicLibraries = append(exportedVendorPublicLibraries, baseName)
}
}
})
- sort.Strings(exportedVendorPublicLibraries)
- ctx.Strict("VENDOR_PUBLIC_LIBRARIES", strings.Join(exportedVendorPublicLibraries, " "))
+ ctx.Strict("VENDOR_PUBLIC_LIBRARIES", makeVarsString(exportedVendorPublicLibraries))
+ lsdumpPaths := *lsdumpPaths(ctx.Config())
sort.Strings(lsdumpPaths)
ctx.Strict("LSDUMP_PATHS", strings.Join(lsdumpPaths, " "))
ctx.Strict("ANDROID_WARNING_ALLOWED_PROJECTS", makeStringOfWarningAllowedProjects())
- ctx.Strict("SOONG_MODULES_WARNINGS_ALLOWED", makeStringOfKeys(ctx, modulesWarningsAllowedKey))
- ctx.Strict("SOONG_MODULES_USING_WNO_ERROR", makeStringOfKeys(ctx, modulesUsingWnoErrorKey))
- ctx.Strict("SOONG_MODULES_MISSING_PGO_PROFILE_FILE", makeStringOfKeys(ctx, modulesMissingProfileFileKey))
+ ctx.Strict("SOONG_MODULES_WARNINGS_ALLOWED", makeVarsString(warningsAllowed))
+ ctx.Strict("SOONG_MODULES_USING_WNO_ERROR", makeVarsString(usingWnoErrors))
+ ctx.Strict("SOONG_MODULES_MISSING_PGO_PROFILE_FILE", makeVarsString(missingProfiles))
ctx.Strict("CLANG_COVERAGE_CONFIG_CFLAGS", strings.Join(clangCoverageCFlags, " "))
ctx.Strict("CLANG_COVERAGE_CONFIG_COMMFLAGS", strings.Join(clangCoverageCommonFlags, " "))
@@ -189,8 +186,6 @@
if len(deviceTargets) > 1 {
makeVarsToolchain(ctx, "2ND_", deviceTargets[1])
}
-
- makeLlndkVars(ctx)
}
func makeVarsToolchain(ctx android.MakeVarsContext, secondPrefix string,
diff --git a/cc/ndk_abi.go b/cc/ndk_abi.go
index 8202cc0..2706261 100644
--- a/cc/ndk_abi.go
+++ b/cc/ndk_abi.go
@@ -46,7 +46,7 @@
if m, ok := module.(*Module); ok {
if installer, ok := m.installer.(*stubDecorator); ok {
- if canDumpAbi(ctx.Config(), ctx.ModuleDir(module)) {
+ if installer.hasAbiDump {
depPaths = append(depPaths, installer.abiDumpPath)
}
}
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index e002931..7481954 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -23,15 +23,6 @@
)
var (
- versionBionicHeaders = pctx.AndroidStaticRule("versionBionicHeaders",
- blueprint.RuleParams{
- // The `&& touch $out` isn't really necessary, but Blueprint won't
- // let us have only implicit outputs.
- Command: "$versionerCmd -o $outDir $srcDir $depsPath && touch $out",
- CommandDeps: []string{"$versionerCmd"},
- },
- "depsPath", "srcDir", "outDir")
-
preprocessNdkHeader = pctx.AndroidStaticRule("preprocessNdkHeader",
blueprint.RuleParams{
Command: "$preprocessor -o $out $in",
@@ -40,10 +31,6 @@
"preprocessor")
)
-func init() {
- pctx.SourcePathVariable("versionerCmd", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/versioner")
-}
-
// Returns the NDK base include path for use with sdk_version current. Usable with -I.
func getCurrentIncludePath(ctx android.PathContext) android.OutputPath {
return getNdkSysrootBase(ctx).Join(ctx, "usr/include")
@@ -167,126 +154,6 @@
return module
}
-type versionedHeaderProperties struct {
- // Base directory of the headers being installed. As an example:
- //
- // versioned_ndk_headers {
- // name: "foo",
- // from: "include",
- // to: "",
- // }
- //
- // Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead
- // "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h.
- From *string
-
- // Install path within the sysroot. This is relative to usr/include.
- To *string
-
- // Path to the NOTICE file associated with the headers.
- License *string
-}
-
-// Like ndk_headers, but preprocesses the headers with the bionic versioner:
-// https://android.googlesource.com/platform/bionic/+/main/tools/versioner/README.md.
-//
-// Unlike ndk_headers, we don't operate on a list of sources but rather a whole directory, the
-// module does not have the srcs property, and operates on a full directory (the `from` property).
-//
-// Note that this is really only built to handle bionic/libc/include.
-type versionedHeaderModule struct {
- android.ModuleBase
-
- properties versionedHeaderProperties
-
- srcPaths android.Paths
- installPaths android.Paths
- licensePath android.Path
-}
-
-// Return the glob pattern to find all .h files beneath `dir`
-func headerGlobPattern(dir string) string {
- return filepath.Join(dir, "**", "*.h")
-}
-
-func (m *versionedHeaderModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- if String(m.properties.License) == "" {
- ctx.PropertyErrorf("license", "field is required")
- }
-
- m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
-
- fromSrcPath := android.PathForModuleSrc(ctx, String(m.properties.From))
- toOutputPath := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
- m.srcPaths = ctx.GlobFiles(headerGlobPattern(fromSrcPath.String()), nil)
- var installPaths []android.WritablePath
- for _, header := range m.srcPaths {
- installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To))
- installPath := installDir.Join(ctx, header.Base())
- installPaths = append(installPaths, installPath)
- m.installPaths = append(m.installPaths, installPath)
- }
-
- if len(m.installPaths) == 0 {
- ctx.ModuleErrorf("glob %q matched zero files", String(m.properties.From))
- }
-
- processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, m.srcPaths, installPaths)
-}
-
-func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path,
- srcPaths android.Paths, installPaths []android.WritablePath) android.Path {
- // The versioner depends on a dependencies directory to simplify determining include paths
- // when parsing headers. This directory contains architecture specific directories as well
- // as a common directory, each of which contains symlinks to the actually directories to
- // be included.
- //
- // ctx.Glob doesn't follow symlinks, so we need to do this ourselves so we correctly
- // depend on these headers.
- // TODO(http://b/35673191): Update the versioner to use a --sysroot.
- depsPath := android.PathForSource(ctx, "bionic/libc/versioner-dependencies")
- depsGlob := ctx.Glob(filepath.Join(depsPath.String(), "**/*"), nil)
- for i, path := range depsGlob {
- if ctx.IsSymlink(path) {
- dest := ctx.Readlink(path)
- // Additional .. to account for the symlink itself.
- depsGlob[i] = android.PathForSource(
- ctx, filepath.Clean(filepath.Join(path.String(), "..", dest)))
- }
- }
-
- timestampFile := android.PathForModuleOut(ctx, "versioner.timestamp")
- ctx.Build(pctx, android.BuildParams{
- Rule: versionBionicHeaders,
- Description: "versioner preprocess " + srcDir.Rel(),
- Output: timestampFile,
- Implicits: append(srcPaths, depsGlob...),
- ImplicitOutputs: installPaths,
- Args: map[string]string{
- "depsPath": depsPath.String(),
- "srcDir": srcDir.String(),
- "outDir": outDir.String(),
- },
- })
-
- return timestampFile
-}
-
-// versioned_ndk_headers preprocesses the headers with the bionic versioner:
-// https://android.googlesource.com/platform/bionic/+/main/tools/versioner/README.md.
-// Unlike the ndk_headers soong module, versioned_ndk_headers operates on a
-// directory level specified in `from` property. This is only used to process
-// the bionic/libc/include directory.
-func VersionedNdkHeadersFactory() android.Module {
- module := &versionedHeaderModule{}
-
- module.AddProperties(&module.properties)
-
- android.InitAndroidModule(module)
-
- return module
-}
-
// preprocessed_ndk_header {
//
// name: "foo",
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 3e35ef5..1f0fc07 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -103,8 +103,17 @@
// https://github.com/android-ndk/ndk/issues/265.
Unversioned_until *string
- // Headers presented by this library to the Public API Surface
+ // DO NOT USE THIS
+ // NDK libraries should not export their headers. Headers belonging to NDK
+ // libraries should be added to the NDK with an ndk_headers module.
Export_header_libs []string
+
+ // Do not add other export_* properties without consulting with danalbert@.
+ // Consumers of ndk_library modules should emulate the typical NDK build
+ // behavior as closely as possible (that is, all NDK APIs are exposed to
+ // builds via --sysroot). Export behaviors used in Soong will not be present
+ // for app developers as they don't use Soong, and reliance on these export
+ // behaviors can mask issues with the NDK sysroot.
}
type stubDecorator struct {
@@ -116,6 +125,7 @@
parsedCoverageXmlPath android.ModuleOutPath
installPath android.Path
abiDumpPath android.OutputPath
+ hasAbiDump bool
abiDiffPaths android.Paths
apiLevel android.ApiLevel
@@ -123,22 +133,20 @@
unversionedUntil android.ApiLevel
}
-var _ versionedInterface = (*stubDecorator)(nil)
+var _ VersionedInterface = (*stubDecorator)(nil)
func shouldUseVersionScript(ctx BaseModuleContext, stub *stubDecorator) bool {
return stub.apiLevel.GreaterThanOrEqualTo(stub.unversionedUntil)
}
-func (stub *stubDecorator) implementationModuleName(name string) string {
+func (stub *stubDecorator) ImplementationModuleName(name string) string {
return strings.TrimSuffix(name, ndkLibrarySuffix)
}
func ndkLibraryVersions(ctx android.BaseModuleContext, from android.ApiLevel) []string {
- var versions []android.ApiLevel
versionStrs := []string{}
- for _, version := range ctx.Config().AllSupportedApiLevels() {
+ for _, version := range ctx.Config().FinalApiLevels() {
if version.GreaterThanOrEqualTo(from) {
- versions = append(versions, version)
versionStrs = append(versionStrs, version.String())
}
}
@@ -147,7 +155,7 @@
return versionStrs
}
-func (this *stubDecorator) stubsVersions(ctx android.BaseModuleContext) []string {
+func (this *stubDecorator) StubsVersions(ctx android.BaseModuleContext) []string {
if !ctx.Module().Enabled(ctx) {
return nil
}
@@ -155,7 +163,7 @@
ctx.Module().Disable()
return nil
}
- firstVersion, err := nativeApiLevelFromUser(ctx,
+ firstVersion, err := NativeApiLevelFromUser(ctx,
String(this.properties.First_version))
if err != nil {
ctx.PropertyErrorf("first_version", err.Error())
@@ -165,10 +173,10 @@
}
func (this *stubDecorator) initializeProperties(ctx BaseModuleContext) bool {
- this.apiLevel = nativeApiLevelOrPanic(ctx, this.stubsVersion())
+ this.apiLevel = nativeApiLevelOrPanic(ctx, this.StubsVersion())
var err error
- this.firstVersion, err = nativeApiLevelFromUser(ctx,
+ this.firstVersion, err = NativeApiLevelFromUser(ctx,
String(this.properties.First_version))
if err != nil {
ctx.PropertyErrorf("first_version", err.Error())
@@ -176,7 +184,7 @@
}
str := proptools.StringDefault(this.properties.Unversioned_until, "minimum")
- this.unversionedUntil, err = nativeApiLevelFromUser(ctx, str)
+ this.unversionedUntil, err = NativeApiLevelFromUser(ctx, str)
if err != nil {
ctx.PropertyErrorf("unversioned_until", err.Error())
return false
@@ -228,7 +236,7 @@
pctx.StaticVariable("StubLibraryCompilerFlags", strings.Join(stubLibraryCompilerFlags, " "))
}
-func addStubLibraryCompilerFlags(flags Flags) Flags {
+func AddStubLibraryCompilerFlags(flags Flags) Flags {
flags.Global.CFlags = append(flags.Global.CFlags, stubLibraryCompilerFlags...)
// All symbols in the stubs library should be visible.
if inList("-fvisibility=hidden", flags.Local.CFlags) {
@@ -239,17 +247,17 @@
func (stub *stubDecorator) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
flags = stub.baseCompiler.compilerFlags(ctx, flags, deps)
- return addStubLibraryCompilerFlags(flags)
+ return AddStubLibraryCompilerFlags(flags)
}
-type ndkApiOutputs struct {
- stubSrc android.ModuleGenPath
- versionScript android.ModuleGenPath
+type NdkApiOutputs struct {
+ StubSrc android.ModuleGenPath
+ VersionScript android.ModuleGenPath
symbolList android.ModuleGenPath
}
-func parseNativeAbiDefinition(ctx ModuleContext, symbolFile string,
- apiLevel android.ApiLevel, genstubFlags string) ndkApiOutputs {
+func ParseNativeAbiDefinition(ctx android.ModuleContext, symbolFile string,
+ apiLevel android.ApiLevel, genstubFlags string) NdkApiOutputs {
stubSrcPath := android.PathForModuleGen(ctx, "stub.c")
versionScriptPath := android.PathForModuleGen(ctx, "stub.map")
@@ -271,37 +279,36 @@
},
})
- return ndkApiOutputs{
- stubSrc: stubSrcPath,
- versionScript: versionScriptPath,
+ return NdkApiOutputs{
+ StubSrc: stubSrcPath,
+ VersionScript: versionScriptPath,
symbolList: symbolListPath,
}
}
-func compileStubLibrary(ctx ModuleContext, flags Flags, src android.Path) Objects {
+func CompileStubLibrary(ctx android.ModuleContext, flags Flags, src android.Path, sharedFlags *SharedFlags) Objects {
// libc/libm stubs libraries end up mismatching with clang's internal definition of these
// functions (which have noreturn attributes and other things). Because we just want to create a
// stub with symbol definitions, and types aren't important in C, ignore the mismatch.
flags.Local.ConlyFlags = append(flags.Local.ConlyFlags, "-fno-builtin")
return compileObjs(ctx, flagsToBuilderFlags(flags), "",
- android.Paths{src}, nil, nil, nil, nil)
+ android.Paths{src}, nil, nil, nil, nil, sharedFlags)
}
func (this *stubDecorator) findImplementationLibrary(ctx ModuleContext) android.Path {
- dep := ctx.GetDirectDepWithTag(strings.TrimSuffix(ctx.ModuleName(), ndkLibrarySuffix),
+ dep := ctx.GetDirectDepProxyWithTag(strings.TrimSuffix(ctx.ModuleName(), ndkLibrarySuffix),
stubImplementation)
if dep == nil {
- ctx.ModuleErrorf("Could not find implementation for stub")
+ ctx.ModuleErrorf("Could not find implementation for stub: ")
return nil
}
- impl, ok := dep.(*Module)
- if !ok {
+ if _, ok := android.OtherModuleProvider(ctx, *dep, CcInfoProvider); !ok {
ctx.ModuleErrorf("Implementation for stub is not correct module type")
return nil
}
- output := impl.UnstrippedOutputFile()
+ output := android.OtherModuleProviderOrDefault(ctx, *dep, LinkableInfoProvider).UnstrippedOutputFile
if output == nil {
- ctx.ModuleErrorf("implementation module (%s) has no output", impl)
+ ctx.ModuleErrorf("implementation module (%s) has no output", *dep)
return nil
}
@@ -320,12 +327,18 @@
return android.ExistentPathForSource(ctx, subpath)
}
+func (this *stubDecorator) builtAbiDumpLocation(ctx ModuleContext, apiLevel android.ApiLevel) android.OutputPath {
+ return getNdkAbiDumpInstallBase(ctx).Join(ctx,
+ apiLevel.String(), ctx.Arch().ArchType.String(),
+ this.libraryName(ctx), "abi.stg")
+}
+
// Feature flag.
-func canDumpAbi(config android.Config, moduleDir string) bool {
+func (this *stubDecorator) canDumpAbi(ctx ModuleContext) bool {
if runtime.GOOS == "darwin" {
return false
}
- if strings.HasPrefix(moduleDir, "bionic/") {
+ if strings.HasPrefix(ctx.ModuleDir(), "bionic/") {
// Bionic has enough uncommon implementation details like ifuncs and asm
// code that the ABI tracking here has a ton of false positives. That's
// causing pretty extreme friction for development there, so disabling
@@ -334,20 +347,26 @@
// http://b/358653811
return false
}
+
// http://b/156513478
- return config.ReleaseNdkAbiMonitored()
+ return ctx.Config().ReleaseNdkAbiMonitored()
}
// Feature flag to disable diffing against prebuilts.
-func canDiffAbi(config android.Config) bool {
+func (this *stubDecorator) canDiffAbi(config android.Config) bool {
+ if this.apiLevel.IsCurrent() {
+ // Diffs are performed from this to next, and there's nothing after
+ // current.
+ return false
+ }
+
return config.ReleaseNdkAbiMonitored()
}
func (this *stubDecorator) dumpAbi(ctx ModuleContext, symbolList android.Path) {
implementationLibrary := this.findImplementationLibrary(ctx)
- this.abiDumpPath = getNdkAbiDumpInstallBase(ctx).Join(ctx,
- this.apiLevel.String(), ctx.Arch().ArchType.String(),
- this.libraryName(ctx), "abi.stg")
+ this.abiDumpPath = this.builtAbiDumpLocation(ctx, this.apiLevel)
+ this.hasAbiDump = true
headersList := getNdkABIHeadersFile(ctx)
ctx.Build(pctx, android.BuildParams{
Rule: stg,
@@ -366,7 +385,7 @@
}
func findNextApiLevel(ctx ModuleContext, apiLevel android.ApiLevel) *android.ApiLevel {
- apiLevels := append(ctx.Config().AllSupportedApiLevels(),
+ apiLevels := append(ctx.Config().FinalApiLevels(),
android.FutureApiLevel)
for _, api := range apiLevels {
if api.GreaterThan(apiLevel) {
@@ -412,19 +431,34 @@
// Also ensure that the ABI of the next API level (if there is one) matches
// this API level. *New* ABI is allowed, but any changes to APIs that exist
// in this API level are disallowed.
- if !this.apiLevel.IsCurrent() && prebuiltAbiDump.Valid() {
+ if prebuiltAbiDump.Valid() {
nextApiLevel := findNextApiLevel(ctx, this.apiLevel)
if nextApiLevel == nil {
panic(fmt.Errorf("could not determine which API level follows "+
"non-current API level %s", this.apiLevel))
}
+
+ // Preview ABI levels are not recorded in prebuilts. ABI compatibility
+ // for preview APIs is still monitored via "current" so we have early
+ // warning rather than learning about an ABI break during finalization,
+ // but is only checked against the "current" API dumps in the out
+ // directory.
nextAbiDiffPath := android.PathForModuleOut(ctx,
"abidiff_next.timestamp")
- nextAbiDump := this.findPrebuiltAbiDump(ctx, *nextApiLevel)
- missingNextPrebuiltError := fmt.Sprintf(
- missingPrebuiltErrorTemplate, this.libraryName(ctx),
- nextAbiDump.InvalidReason())
+
+ var nextAbiDump android.OptionalPath
+ if nextApiLevel.IsCurrent() {
+ nextAbiDump = android.OptionalPathForPath(
+ this.builtAbiDumpLocation(ctx, *nextApiLevel),
+ )
+ } else {
+ nextAbiDump = this.findPrebuiltAbiDump(ctx, *nextApiLevel)
+ }
+
if !nextAbiDump.Valid() {
+ missingNextPrebuiltError := fmt.Sprintf(
+ missingPrebuiltErrorTemplate, this.libraryName(ctx),
+ nextAbiDump.InvalidReason())
ctx.Build(pctx, android.BuildParams{
Rule: android.ErrorRule,
Output: nextAbiDiffPath,
@@ -455,7 +489,7 @@
ctx.PropertyErrorf("symbol_file", "must end with .map.txt")
}
- if !c.buildStubs() {
+ if !c.BuildStubs() {
// NDK libraries have no implementation variant, nothing to do
return Objects{}
}
@@ -466,17 +500,17 @@
}
symbolFile := String(c.properties.Symbol_file)
- nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile, c.apiLevel, "")
- objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
- c.versionScriptPath = nativeAbiResult.versionScript
- if canDumpAbi(ctx.Config(), ctx.ModuleDir()) {
+ nativeAbiResult := ParseNativeAbiDefinition(ctx, symbolFile, c.apiLevel, "")
+ objs := CompileStubLibrary(ctx, flags, nativeAbiResult.StubSrc, ctx.getSharedFlags())
+ c.versionScriptPath = nativeAbiResult.VersionScript
+ if c.canDumpAbi(ctx) {
c.dumpAbi(ctx, nativeAbiResult.symbolList)
- if canDiffAbi(ctx.Config()) {
+ if c.canDiffAbi(ctx.Config()) {
c.diffAbi(ctx)
}
}
if c.apiLevel.IsCurrent() && ctx.PrimaryArch() {
- c.parsedCoverageXmlPath = parseSymbolFileForAPICoverage(ctx, symbolFile)
+ c.parsedCoverageXmlPath = ParseSymbolFileForAPICoverage(ctx, symbolFile)
}
return objs
}
@@ -484,7 +518,8 @@
// Add a dependency on the header modules of this ndk_library
func (linker *stubDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
return Deps{
- HeaderLibs: linker.properties.Export_header_libs,
+ ReexportHeaderLibHeaders: linker.properties.Export_header_libs,
+ HeaderLibs: linker.properties.Export_header_libs,
}
}
@@ -506,7 +541,7 @@
func (stub *stubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps,
objs Objects) android.Path {
- if !stub.buildStubs() {
+ if !stub.BuildStubs() {
// NDK libraries have no implementation variant, nothing to do
return nil
}
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index f571523..a5f014b 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -79,7 +79,6 @@
func RegisterNdkModuleTypes(ctx android.RegistrationContext) {
ctx.RegisterModuleType("ndk_headers", NdkHeadersFactory)
ctx.RegisterModuleType("ndk_library", NdkLibraryFactory)
- ctx.RegisterModuleType("versioned_ndk_headers", VersionedNdkHeadersFactory)
ctx.RegisterModuleType("preprocessed_ndk_headers", preprocessedNdkHeadersFactory)
ctx.RegisterParallelSingletonType("ndk", NdkSingleton)
}
@@ -230,17 +229,6 @@
licensePaths = append(licensePaths, m.licensePath)
}
- if m, ok := module.(*versionedHeaderModule); ok {
- headerSrcPaths = append(headerSrcPaths, m.srcPaths...)
- headerInstallPaths = append(headerInstallPaths, m.installPaths...)
- // Verification intentionally not done for headers that go through
- // versioner. It'd be nice to have, but the only user is bionic, and
- // that one module would also need to use skip_verification, so it
- // wouldn't help at all.
- installPaths = append(installPaths, m.installPaths...)
- licensePaths = append(licensePaths, m.licensePath)
- }
-
if m, ok := module.(*preprocessedHeadersModule); ok {
headerSrcPaths = append(headerSrcPaths, m.srcPaths...)
headerInstallPaths = append(headerInstallPaths, m.installPaths...)
@@ -257,7 +245,7 @@
}
if m, ok := module.(*Module); ok {
- if installer, ok := m.installer.(*stubDecorator); ok && m.library.buildStubs() {
+ if installer, ok := m.installer.(*stubDecorator); ok && m.library.BuildStubs() {
installPaths = append(installPaths, installer.installPath)
}
diff --git a/cc/ndkstubgen/test_ndkstubgen.py b/cc/ndkstubgen/test_ndkstubgen.py
index 22f31d9..6c24b4f 100755
--- a/cc/ndkstubgen/test_ndkstubgen.py
+++ b/cc/ndkstubgen/test_ndkstubgen.py
@@ -473,16 +473,17 @@
VERSION_35 { # introduced=35
global:
wiggle;
- waggle;
- waggle; # llndk=202404
- bubble; # llndk=202404
- duddle;
- duddle; # llndk=202504
+ waggle; # llndk
} VERSION_34;
+ VERSION_36 { # introduced=36
+ global:
+ abc;
+ xyz; # llndk
+ } VERSION_35;
"""))
f = copy(self.filter)
f.llndk = True
- f.api = 202404
+ f.api = 35
parser = symbolfile.SymbolFileParser(input_file, {}, f)
versions = parser.parse()
@@ -497,8 +498,8 @@
expected_src = textwrap.dedent("""\
void foo() {}
void bar() {}
+ void wiggle() {}
void waggle() {}
- void bubble() {}
""")
self.assertEqual(expected_src, src_file.getvalue())
@@ -510,8 +511,8 @@
};
VERSION_35 {
global:
+ wiggle;
waggle;
- bubble;
} VERSION_34;
""")
self.assertEqual(expected_version, version_file.getvalue())
@@ -521,15 +522,15 @@
LIBANDROID {
global:
foo; # introduced=34
- bar; # introduced=35
- bar; # llndk=202404
- baz; # introduced=35
+ bar; # introduced=35 llndk
+ baz; # introduced=V
+ qux; # introduced=36
};
"""))
f = copy(self.filter)
f.llndk = True
- f.api = 202404
- parser = symbolfile.SymbolFileParser(input_file, {}, f)
+ f.api = 35
+ parser = symbolfile.SymbolFileParser(input_file, {'V': 35}, f)
versions = parser.parse()
src_file = io.StringIO()
@@ -543,6 +544,7 @@
expected_src = textwrap.dedent("""\
void foo() {}
void bar() {}
+ void baz() {}
""")
self.assertEqual(expected_src, src_file.getvalue())
@@ -551,6 +553,7 @@
global:
foo;
bar;
+ baz;
};
""")
self.assertEqual(expected_version, version_file.getvalue())
diff --git a/cc/object.go b/cc/object.go
index a4f4c84..bbfca94 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -159,7 +159,7 @@
// isForPlatform is terribly named and actually means isNotApex.
if Bool(object.Properties.Crt) &&
!Bool(object.Properties.Exclude_from_ndk_sysroot) && ctx.useSdk() &&
- ctx.isSdkVariant() && ctx.isForPlatform() {
+ ctx.isSdkVariant() && CtxIsForPlatform(ctx) {
output = getVersionedLibraryInstallPath(ctx,
nativeApiLevelOrPanic(ctx, ctx.sdkVersion())).Join(ctx, outputName)
@@ -203,7 +203,7 @@
return outputFile
}
-func (object *objectLinker) linkerSpecifiedDeps(ctx android.ConfigAndErrorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps {
+func (object *objectLinker) linkerSpecifiedDeps(ctx android.ConfigurableEvaluatorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps {
eval := module.ConfigurableEvaluator(ctx)
specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, object.Properties.Shared_libs.GetOrDefault(eval, nil)...)
diff --git a/cc/orderfile.go b/cc/orderfile.go
index 38b8905..c07a098 100644
--- a/cc/orderfile.go
+++ b/cc/orderfile.go
@@ -54,10 +54,6 @@
})
}
-func recordMissingOrderfile(ctx BaseModuleContext, missing string) {
- getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
-}
-
type OrderfileProperties struct {
Orderfile struct {
Instrumentation *bool
@@ -117,7 +113,7 @@
// Record that this module's order file is absent
missing := *props.Orderfile.Order_file_path + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
- recordMissingOrderfile(ctx, missing)
+ ctx.getOrCreateMakeVarsInfo().MissingProfile = missing
return android.OptionalPath{}
}
@@ -157,7 +153,7 @@
}
// Currently, we are not enabling orderfiles to begin from static libraries
- if ctx.static() && !ctx.staticBinary() {
+ if ctx.staticLibrary() {
return
}
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index fb151d8..70ee5e3 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -17,6 +17,7 @@
import (
"path/filepath"
+ "github.com/google/blueprint/depset"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -95,10 +96,6 @@
return p.libraryDecorator.linkerDeps(ctx, deps)
}
-func (p *prebuiltLibraryLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags {
- return flags
-}
-
func (p *prebuiltLibraryLinker) linkerProps() []interface{} {
return p.libraryDecorator.linkerProps()
}
@@ -117,6 +114,14 @@
// TODO(ccross): verify shared library dependencies
srcs := p.prebuiltSrcs(ctx)
+ stubInfo := AddStubDependencyProviders(ctx)
+
+ // Stub variants will create a stub .so file from stub .c files
+ if p.BuildStubs() && objs.objFiles != nil {
+ // TODO (b/275273834): Make objs.objFiles == nil a hard error when the symbol files have been added to module sdk.
+ return p.linkShared(ctx, flags, deps, objs)
+ }
+
if len(srcs) > 0 {
if len(srcs) > 1 {
ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
@@ -135,7 +140,7 @@
}
if p.static() {
- depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(in).Build()
+ depSet := depset.NewBuilder[android.Path](depset.TOPOLOGICAL).Direct(in).Build()
android.SetProvider(ctx, StaticLibraryInfoProvider, StaticLibraryInfo{
StaticLibrary: in,
@@ -199,10 +204,22 @@
Target: ctx.Target(),
TableOfContents: p.tocFile,
+ IsStubs: p.BuildStubs(),
})
return outputFile
}
+ } else if p.shared() && len(stubInfo) > 0 {
+ // This is a prebuilt which does not have any implementation (nil `srcs`), but provides APIs.
+ // Provide the latest (i.e. `current`) stubs to reverse dependencies.
+ latestStub := stubInfo[len(stubInfo)-1].SharedLibraryInfo.SharedLibrary
+ android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
+ SharedLibrary: latestStub,
+ Target: ctx.Target(),
+ IsStubs: true,
+ })
+
+ return latestStub
}
if p.header() {
@@ -251,17 +268,17 @@
}
// Implements versionedInterface
-func (p *prebuiltLibraryLinker) implementationModuleName(name string) string {
+func (p *prebuiltLibraryLinker) ImplementationModuleName(name string) string {
return android.RemoveOptionalPrebuiltPrefix(name)
}
func NewPrebuiltLibrary(hod android.HostOrDeviceSupported, srcsProperty string) (*Module, *libraryDecorator) {
module, library := NewLibrary(hod)
- module.compiler = nil
prebuilt := &prebuiltLibraryLinker{
libraryDecorator: library,
}
+ module.compiler = prebuilt
module.linker = prebuilt
module.library = prebuilt
@@ -280,6 +297,13 @@
return module, library
}
+func (p *prebuiltLibraryLinker) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
+ if p.BuildStubs() && p.StubsVersion() != "" {
+ return p.compileModuleLibApiStubs(ctx, flags, deps)
+ }
+ return Objects{}
+}
+
// cc_prebuilt_library installs a precompiled shared library that are
// listed in the srcs property in the device's directory.
func PrebuiltLibraryFactory() android.Module {
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index acbbabc..3214fb4 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -50,6 +50,7 @@
cc_prebuilt_library_shared {
name: "liba",
srcs: ["liba.so"],
+ prefer: true,
}
cc_library {
@@ -59,6 +60,7 @@
cc_prebuilt_library_static {
name: "libb",
srcs: ["libb.a"],
+ prefer: true,
}
cc_library_shared {
@@ -169,9 +171,9 @@
t.Errorf("crtx missing dependency on prebuilt_crtx")
}
- entries := android.AndroidMkEntriesForTest(t, ctx, prebuiltLiba)[0]
+ entries := android.AndroidMkInfoForTest(t, ctx, prebuiltLiba).PrimaryInfo
android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_prebuilt_library_shared", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
- entries = android.AndroidMkEntriesForTest(t, ctx, prebuiltLibb)[0]
+ entries = android.AndroidMkInfoForTest(t, ctx, prebuiltLibb).PrimaryInfo
android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_prebuilt_library_static", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
}
@@ -486,7 +488,7 @@
expectedDependency := ctx.ModuleForTests(tc.expectedDependencyName, "android_arm64_armv8-a_shared").Module()
android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", libfoo.Name(), tc.expectedDependencyName), true, hasDep(ctx, libfoo, expectedDependency))
// check that LOCAL_SHARED_LIBRARIES contains libbar and not libbar.v<N>
- entries := android.AndroidMkEntriesForTest(t, ctx, libfoo)[0]
+ entries := android.AndroidMkInfoForTest(t, ctx, libfoo).PrimaryInfo
android.AssertStringListContains(t, "Version should not be present in LOCAL_SHARED_LIBRARIES", entries.EntryMap["LOCAL_SHARED_LIBRARIES"], "libbar")
// check installation rules
@@ -496,7 +498,7 @@
// check LOCAL_MODULE of the selected module name
// the prebuilt should have the same LOCAL_MODULE when exported to make
- entries = android.AndroidMkEntriesForTest(t, ctx, libbar)[0]
+ entries = android.AndroidMkInfoForTest(t, ctx, libbar).PrimaryInfo
android.AssertStringEquals(t, "unexpected LOCAL_MODULE", "libbar", entries.EntryMap["LOCAL_MODULE"][0])
}
}
diff --git a/cc/sabi.go b/cc/sabi.go
index 64eab41..06ab6ec 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -22,10 +22,16 @@
)
var (
- lsdumpPaths []string
lsdumpPathsLock sync.Mutex
+ lsdumpKey = android.NewOnceKey("lsdump")
)
+func lsdumpPaths(config android.Config) *[]string {
+ return config.Once(lsdumpKey, func() any {
+ return &[]string{}
+ }).(*[]string)
+}
+
type lsdumpTag string
const (
@@ -84,8 +90,8 @@
type SAbiProperties struct {
// Whether ABI dump should be created for this module.
- // Set by `sabiDepsMutator` if this module is a shared library that needs ABI check, or a static
- // library that is depended on by an ABI checked library.
+ // Set by `sabiTransitionMutator` if this module is a shared library that needs ABI check,
+ // or a static library that is depended on by an ABI checked library.
ShouldCreateSourceAbiDump bool `blueprint:"mutated"`
// Include directories that may contain ABI information exported by a library.
@@ -121,10 +127,9 @@
}
// Returns a slice of strings that represent the ABI dumps generated for this module.
-func classifySourceAbiDump(ctx android.BaseModuleContext) []lsdumpTag {
+func classifySourceAbiDump(m *Module) []lsdumpTag {
result := []lsdumpTag{}
- m := ctx.Module().(*Module)
- headerAbiChecker := m.library.getHeaderAbiCheckerProperties(ctx)
+ headerAbiChecker := m.library.getHeaderAbiCheckerProperties(m)
if headerAbiChecker.explicitlyDisabled() {
return result
}
@@ -132,7 +137,7 @@
if m.isImplementationForLLNDKPublic() {
result = append(result, llndkLsdumpTag)
}
- if m.library.hasStubsVariants() {
+ if m.library.HasStubsVariants() {
result = append(result, apexLsdumpTag)
}
if headerAbiChecker.enabled() {
@@ -149,24 +154,37 @@
return result
}
-// Called from sabiDepsMutator to check whether ABI dumps should be created for this module.
+type shouldCreateAbiDumpContext interface {
+ android.ModuleProviderContext
+ Module() android.Module
+ Config() android.Config
+}
+
+var _ shouldCreateAbiDumpContext = android.ModuleContext(nil)
+var _ shouldCreateAbiDumpContext = android.OutgoingTransitionContext(nil)
+
+// Called from sabiTransitionMutator to check whether ABI dumps should be created for this module.
// ctx should be wrapping a native library type module.
-func shouldCreateSourceAbiDumpForLibrary(ctx android.BaseModuleContext) bool {
- // Only generate ABI dump for device modules.
- if !ctx.Device() {
+func shouldCreateSourceAbiDumpForLibrary(ctx shouldCreateAbiDumpContext) bool {
+ m, ok := ctx.Module().(*Module)
+ if !ok {
return false
}
- m := ctx.Module().(*Module)
+ // Only generate ABI dump for device modules.
+ if !m.Device() {
+ return false
+ }
// Only create ABI dump for native library module types.
if m.library == nil {
return false
}
- // Create ABI dump for static libraries only if they are dependencies of ABI checked libraries.
+ // Don't create ABI dump for static libraries
+ // The sabi variant will be propagated to dependencies of ABI checked libraries.
if m.library.static() {
- return m.sabi.shouldCreateSourceAbiDump()
+ return false
}
// Module is shared library type.
@@ -215,39 +233,73 @@
return false
}
}
- return len(classifySourceAbiDump(ctx)) > 0
+ return len(classifySourceAbiDump(m)) > 0
}
// Mark the direct and transitive dependencies of libraries that need ABI check, so that ABI dumps
// of their dependencies would be generated.
-func sabiDepsMutator(mctx android.TopDownMutatorContext) {
+type sabiTransitionMutator struct{}
+
+func (s *sabiTransitionMutator) Split(ctx android.BaseModuleContext) []string {
+ return []string{""}
+}
+
+func (s *sabiTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
// Escape hatch to not check any ABI dump.
- if mctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") {
- return
+ if ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") {
+ return ""
}
+
// Only create ABI dump for native shared libraries and their static library dependencies.
- if m, ok := mctx.Module().(*Module); ok && m.sabi != nil {
- if shouldCreateSourceAbiDumpForLibrary(mctx) {
- // Mark this module so that .sdump / .lsdump for this library can be generated.
+ if m, ok := ctx.Module().(*Module); ok && m.sabi != nil {
+ if shouldCreateSourceAbiDumpForLibrary(ctx) {
+ if IsStaticDepTag(ctx.DepTag()) || ctx.DepTag() == reuseObjTag {
+ return "sabi"
+ }
+ } else if sourceVariation == "sabi" {
+ if IsWholeStaticLib(ctx.DepTag()) || ctx.DepTag() == reuseObjTag {
+ return "sabi"
+ }
+ }
+ }
+
+ return ""
+}
+
+func (s *sabiTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+ if incomingVariation == "" {
+ return ""
+ }
+
+ if incomingVariation == "sabi" {
+ if m, ok := ctx.Module().(*Module); ok && m.sabi != nil {
+ return "sabi"
+ }
+ }
+
+ return ""
+}
+
+func (s *sabiTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
+ if m, ok := ctx.Module().(*Module); ok && m.sabi != nil {
+ if variation == "sabi" {
m.sabi.Properties.ShouldCreateSourceAbiDump = true
- // Mark all of its static library dependencies.
- mctx.VisitDirectDeps(func(child android.Module) {
- depTag := mctx.OtherModuleDependencyTag(child)
- if IsStaticDepTag(depTag) || depTag == reuseObjTag {
- if c, ok := child.(*Module); ok && c.sabi != nil {
- // Mark this module so that .sdump for this static library can be generated.
- c.sabi.Properties.ShouldCreateSourceAbiDump = true
- }
- }
- })
+ m.HideFromMake()
+ m.Properties.PreventInstall = true
+ } else if shouldCreateSourceAbiDumpForLibrary(ctx) {
+ // Escape hatch to not check any ABI dump.
+ if !ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") {
+ m.sabi.Properties.ShouldCreateSourceAbiDump = true
+ }
}
}
}
// Add an entry to the global list of lsdump. The list is exported to a Make variable by
// `cc.makeVarsProvider`.
-func addLsdumpPath(lsdumpPath string) {
+func addLsdumpPath(config android.Config, lsdumpPath string) {
+ lsdumpPaths := lsdumpPaths(config)
lsdumpPathsLock.Lock()
defer lsdumpPathsLock.Unlock()
- lsdumpPaths = append(lsdumpPaths, lsdumpPath)
+ *lsdumpPaths = append(*lsdumpPaths, lsdumpPath)
}
diff --git a/cc/sabi_test.go b/cc/sabi_test.go
new file mode 100644
index 0000000..6b8cc17
--- /dev/null
+++ b/cc/sabi_test.go
@@ -0,0 +1,66 @@
+// 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 cc
+
+import (
+ "android/soong/android"
+ "testing"
+)
+
+func TestSabi(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "libsabi",
+ srcs: ["sabi.cpp"],
+ static_libs: ["libdirect"],
+ header_abi_checker: {
+ enabled: true,
+ symbol_file: "libsabi.map.txt",
+ ref_dump_dirs: ["abi-dumps"],
+ },
+ }
+
+ cc_library {
+ name: "libdirect",
+ srcs: ["direct.cpp"],
+ whole_static_libs: ["libtransitive"],
+ }
+
+ cc_library {
+ name: "libtransitive",
+ srcs: ["transitive.cpp"],
+ }
+ `
+
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithCcDefaultModules,
+ ).RunTestWithBp(t, bp)
+
+ libsabiStatic := result.ModuleForTests("libsabi", "android_arm64_armv8-a_static_sabi")
+ sabiObjSDump := libsabiStatic.Output("obj/sabi.sdump")
+
+ libDirect := result.ModuleForTests("libdirect", "android_arm64_armv8-a_static_sabi")
+ directObjSDump := libDirect.Output("obj/direct.sdump")
+
+ libTransitive := result.ModuleForTests("libtransitive", "android_arm64_armv8-a_static_sabi")
+ transitiveObjSDump := libTransitive.Output("obj/transitive.sdump")
+
+ libsabiShared := result.ModuleForTests("libsabi", "android_arm64_armv8-a_shared")
+ sabiLink := libsabiShared.Rule("sAbiLink")
+
+ android.AssertStringListContains(t, "sabi link inputs", sabiLink.Inputs.Strings(), sabiObjSDump.Output.String())
+ android.AssertStringListContains(t, "sabi link inputs", sabiLink.Inputs.Strings(), directObjSDump.Output.String())
+ android.AssertStringListContains(t, "sabi link inputs", sabiLink.Inputs.Strings(), transitiveObjSDump.Output.String())
+}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 7b0652c..d8d8c7a 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -176,7 +176,7 @@
switch t {
case cfi, Hwasan, Asan, tsan, Fuzzer, scs, Memtag_stack:
sanitizer := &sanitizerSplitMutator{t}
- ctx.TopDown(t.variationName()+"_markapexes", sanitizer.markSanitizableApexesMutator)
+ ctx.BottomUp(t.variationName()+"_markapexes", sanitizer.markSanitizableApexesMutator)
ctx.Transition(t.variationName(), sanitizer)
case Memtag_heap, Memtag_globals, intOverflow:
// do nothing
@@ -992,7 +992,7 @@
return flags
}
-func (s *sanitize) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+func (s *sanitize) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
// Add a suffix for cfi/hwasan/scs-enabled static/header libraries to allow surfacing
// both the sanitized and non-sanitized variants to make without a name conflict.
if entries.Class == "STATIC_LIBRARIES" || entries.Class == "HEADER_LIBRARIES" {
@@ -1153,7 +1153,7 @@
// If an APEX is sanitized or not depends on whether it contains at least one
// sanitized module. Transition mutators cannot propagate information up the
// dependency graph this way, so we need an auxiliary mutator to do so.
-func (s *sanitizerSplitMutator) markSanitizableApexesMutator(ctx android.TopDownMutatorContext) {
+func (s *sanitizerSplitMutator) markSanitizableApexesMutator(ctx android.BottomUpMutatorContext) {
if sanitizeable, ok := ctx.Module().(Sanitizeable); ok {
enabled := sanitizeable.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
ctx.VisitDirectDeps(func(dep android.Module) {
@@ -1355,7 +1355,7 @@
}
// Propagate the ubsan minimal runtime dependency when there are integer overflow sanitized static dependencies.
-func sanitizerRuntimeDepsMutator(mctx android.TopDownMutatorContext) {
+func sanitizerRuntimeDepsMutator(mctx android.BottomUpMutatorContext) {
// Change this to PlatformSanitizable when/if non-cc modules support ubsan sanitizers.
if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil {
if c.sanitize.Properties.ForceDisable {
@@ -1437,11 +1437,11 @@
//"null",
//"shift-base",
//"signed-integer-overflow",
- // TODO(danalbert): Fix UB in libc++'s __tree so we can turn this on.
- // https://llvm.org/PR19302
- // http://reviews.llvm.org/D6974
- // "object-size",
)
+
+ if mctx.Config().ReleaseBuildObjectSizeSanitizer() {
+ sanitizers = append(sanitizers, "object-size")
+ }
}
sanitizers = append(sanitizers, sanProps.Misc_undefined...)
}
@@ -1504,9 +1504,6 @@
if Bool(sanProps.Memtag_globals) {
sanitizers = append(sanitizers, "memtag-globals")
- // TODO(mitchp): For now, enable memtag-heap with memtag-globals because the linker
- // isn't new enough (https://reviews.llvm.org/differential/changeset/?ref=4243566).
- sanitizers = append(sanitizers, "memtag-heap")
}
if Bool(sanProps.Fuzzer) {
@@ -1813,7 +1810,7 @@
type sanitizerLibrariesTxtModule struct {
android.ModuleBase
- outputFile android.OutputPath
+ outputFile android.Path
}
var _ etc.PrebuiltEtcModule = (*sanitizerLibrariesTxtModule)(nil)
@@ -1830,10 +1827,7 @@
type sanitizerLibraryDependencyTag struct {
blueprint.BaseDependencyTag
-}
-
-func (t sanitizerLibraryDependencyTag) AllowDisabledModuleDependency(target android.Module) bool {
- return true
+ android.AlwaysAllowDisabledModuleDependencyTag
}
var _ android.AllowDisabledModuleDependency = (*sanitizerLibraryDependencyTag)(nil)
@@ -1899,20 +1893,23 @@
func (txt *sanitizerLibrariesTxtModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
filename := txt.Name()
- txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath
- android.WriteFileRule(ctx, txt.outputFile, txt.getSanitizerLibs(ctx))
+ outputFile := android.PathForModuleOut(ctx, filename)
+ android.WriteFileRule(ctx, outputFile, txt.getSanitizerLibs(ctx))
installPath := android.PathForModuleInstall(ctx, "etc")
- ctx.InstallFile(installPath, filename, txt.outputFile)
+ ctx.InstallFile(installPath, filename, outputFile)
- ctx.SetOutputFiles(android.Paths{txt.outputFile}, "")
+ ctx.SetOutputFiles(android.Paths{outputFile}, "")
+ txt.outputFile = outputFile
}
-func (txt *sanitizerLibrariesTxtModule) AndroidMkEntries() []android.AndroidMkEntries {
- return []android.AndroidMkEntries{{
- Class: "ETC",
- OutputFile: android.OptionalPathForPath(txt.outputFile),
- }}
+func (txt *sanitizerLibrariesTxtModule) PrepareAndroidMKProviderInfo(config android.Config) *android.AndroidMkProviderInfo {
+ return &android.AndroidMkProviderInfo{
+ PrimaryInfo: android.AndroidMkInfo{
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(txt.outputFile),
+ },
+ }
}
// PrebuiltEtcModule interface
diff --git a/cc/sdk.go b/cc/sdk.go
index dc1261d..5dd44d8 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -51,13 +51,6 @@
return []string{""}
}
}
- case *CcApiVariant:
- ccApiVariant, _ := ctx.Module().(*CcApiVariant)
- if String(ccApiVariant.properties.Variant) == "ndk" {
- return []string{"sdk"}
- } else {
- return []string{""}
- }
}
return []string{""}
@@ -84,11 +77,6 @@
return incomingVariation
}
}
- case *CcApiVariant:
- ccApiVariant, _ := ctx.Module().(*CcApiVariant)
- if String(ccApiVariant.properties.Variant) == "ndk" {
- return "sdk"
- }
}
if ctx.IsAddingDependency() {
diff --git a/cc/strip.go b/cc/strip.go
index b1f34bb..36c0c48 100644
--- a/cc/strip.go
+++ b/cc/strip.go
@@ -52,11 +52,7 @@
// NeedsStrip determines if stripping is required for a module.
func (stripper *Stripper) NeedsStrip(actx android.ModuleContext) bool {
forceDisable := Bool(stripper.StripProperties.Strip.None)
- defaultEnable := (!actx.Config().KatiEnabled() || actx.Device())
- forceEnable := Bool(stripper.StripProperties.Strip.All) ||
- Bool(stripper.StripProperties.Strip.Keep_symbols) ||
- Bool(stripper.StripProperties.Strip.Keep_symbols_and_debug_frame)
- return !forceDisable && (forceEnable || defaultEnable)
+ return !forceDisable
}
func (stripper *Stripper) strip(actx android.ModuleContext, in android.Path, out android.ModuleOutPath,
diff --git a/cc/stub_library.go b/cc/stub_library.go
index e746a33..9d7b5bc 100644
--- a/cc/stub_library.go
+++ b/cc/stub_library.go
@@ -26,20 +26,24 @@
android.RegisterParallelSingletonType("stublibraries", stubLibrariesSingleton)
}
+func stubLibrariesSingleton() android.Singleton {
+ return &stubLibraries{}
+}
+
type stubLibraries struct {
- stubLibraryMap map[string]bool
- stubVendorLibraryMap map[string]bool
+ stubLibraries []string
+ vendorStubLibraries []string
apiListCoverageXmlPaths []string
}
// Check if the module defines stub, or itself is stub
-func IsStubTarget(m *Module) bool {
- return m.IsStubs() || m.HasStubsVariants()
+func IsStubTarget(info *LinkableInfo) bool {
+ return info != nil && (info.IsStubs || info.HasStubsVariants)
}
// Get target file name to be installed from this module
-func getInstalledFileName(ctx android.SingletonContext, m *Module) string {
+func getInstalledFileName(ctx android.SingletonContext, m LinkableInterface) string {
for _, ps := range android.OtherModuleProviderOrDefault(
ctx, m.Module(), android.InstallFilesProvider).PackagingSpecs {
if name := ps.FileName(); name != "" {
@@ -51,36 +55,39 @@
func (s *stubLibraries) GenerateBuildActions(ctx android.SingletonContext) {
// Visit all generated soong modules and store stub library file names.
+ stubLibraryMap := make(map[string]bool)
+ vendorStubLibraryMap := make(map[string]bool)
ctx.VisitAllModules(func(module android.Module) {
- if m, ok := module.(*Module); ok {
- if IsStubTarget(m) {
+ if m, ok := module.(VersionedLinkableInterface); ok {
+ if IsStubTarget(android.OtherModuleProviderOrDefault(ctx, m, LinkableInfoProvider)) {
if name := getInstalledFileName(ctx, m); name != "" {
- s.stubLibraryMap[name] = true
+ stubLibraryMap[name] = true
if m.InVendor() {
- s.stubVendorLibraryMap[name] = true
+ vendorStubLibraryMap[name] = true
}
}
}
- if m.library != nil && android.IsModulePreferred(m) {
- if p := m.library.getAPIListCoverageXMLPath().String(); p != "" {
+ if m.CcLibraryInterface() && android.IsModulePreferred(m) {
+ if p := m.VersionedInterface().GetAPIListCoverageXMLPath().String(); p != "" {
s.apiListCoverageXmlPaths = append(s.apiListCoverageXmlPaths, p)
}
}
}
})
+ s.stubLibraries = android.SortedKeys(stubLibraryMap)
+ s.vendorStubLibraries = android.SortedKeys(vendorStubLibraryMap)
+
+ android.WriteFileRule(ctx, StubLibrariesFile(ctx), strings.Join(s.stubLibraries, " "))
}
-func stubLibrariesSingleton() android.Singleton {
- return &stubLibraries{
- stubLibraryMap: make(map[string]bool),
- stubVendorLibraryMap: make(map[string]bool),
- }
+func StubLibrariesFile(ctx android.PathContext) android.WritablePath {
+ return android.PathForIntermediates(ctx, "stub_libraries.txt")
}
func (s *stubLibraries) MakeVars(ctx android.MakeVarsContext) {
// Convert stub library file names into Makefile variable.
- ctx.Strict("STUB_LIBRARIES", strings.Join(android.SortedKeys(s.stubLibraryMap), " "))
- ctx.Strict("SOONG_STUB_VENDOR_LIBRARIES", strings.Join(android.SortedKeys(s.stubVendorLibraryMap), " "))
+ ctx.Strict("STUB_LIBRARIES", strings.Join(s.stubLibraries, " "))
+ ctx.Strict("SOONG_STUB_VENDOR_LIBRARIES", strings.Join(s.vendorStubLibraries, " "))
// Export the list of API XML files to Make.
sort.Strings(s.apiListCoverageXmlPaths)
diff --git a/cc/symbolfile/__init__.py b/cc/symbolfile/__init__.py
index 4553616..f2bd186 100644
--- a/cc/symbolfile/__init__.py
+++ b/cc/symbolfile/__init__.py
@@ -103,24 +103,13 @@
@property
def has_llndk_tags(self) -> bool:
"""Returns True if any LL-NDK tags are set."""
- for tag in self.tags:
- if tag == 'llndk' or tag.startswith('llndk='):
- return True
- return False
+ return 'llndk' in self.tags
@property
def has_platform_only_tags(self) -> bool:
"""Returns True if any platform-only tags are set."""
return 'platform-only' in self.tags
- def copy_introduced_from(self, tags: Tags) -> None:
- """Copies introduced= or introduced-*= tags."""
- for tag in tags:
- if tag.startswith('introduced=') or tag.startswith('introduced-'):
- name, _ = split_tag(tag)
- if not any(self_tag.startswith(name + '=') for self_tag in self.tags):
- self.tags += (tag,)
-
@dataclass
class Symbol:
@@ -158,8 +147,6 @@
"""Returns true if this tag has an API level that may need decoding."""
if tag.startswith('llndk-deprecated='):
return True
- if tag.startswith('llndk='):
- return True
if tag.startswith('introduced='):
return True
if tag.startswith('introduced-'):
@@ -245,21 +232,19 @@
self.systemapi = systemapi
self.ndk = ndk
+ def _symbol_in_arch_api(self, tags: Tags) -> bool:
+ if not symbol_in_arch(tags, self.arch):
+ return True
+ if not symbol_in_api(tags, self.arch, self.api):
+ return True
+ return False
+
def _should_omit_tags(self, tags: Tags) -> bool:
"""Returns True if the tagged object should be omitted.
This defines the rules shared between version tagging and symbol tagging.
"""
- # LLNDK mode/tags follow the similar filtering except that API level checking
- # is based llndk= instead of introduced=.
- if self.llndk:
- if tags.has_mode_tags and not tags.has_llndk_tags:
- return True
- if not symbol_in_arch(tags, self.arch):
- return True
- if not symbol_in_llndk_api(tags, self.arch, self.api):
- return True
- return False
+ # The apex and llndk tags will only exclude APIs from other modes. If in
# APEX or LLNDK mode and neither tag is provided, we fall back to the
# default behavior because all NDK symbols are implicitly available to
# APEX and LLNDK.
@@ -268,12 +253,10 @@
return False
if self.systemapi and tags.has_systemapi_tags:
return False
+ if self.llndk and tags.has_llndk_tags:
+ return self._symbol_in_arch_api(tags)
return True
- if not symbol_in_arch(tags, self.arch):
- return True
- if not symbol_in_api(tags, self.arch, self.api):
- return True
- return False
+ return self._symbol_in_arch_api(tags)
def should_omit_version(self, version: Version) -> bool:
"""Returns True if the version section should be omitted.
@@ -286,10 +269,6 @@
return True
if version.tags.has_platform_only_tags:
return True
- # Include all versions when targeting LLNDK because LLNDK symbols are self-versioned.
- # Empty version block will be handled separately.
- if self.llndk:
- return False
return self._should_omit_tags(version.tags)
def should_omit_symbol(self, symbol: Symbol) -> bool:
@@ -302,6 +281,7 @@
return self._should_omit_tags(symbol.tags)
+
def symbol_in_arch(tags: Tags, arch: Arch) -> bool:
"""Returns true if the symbol is present for the given architecture."""
has_arch_tags = False
@@ -316,14 +296,6 @@
# for the tagged architectures.
return not has_arch_tags
-def symbol_in_llndk_api(tags: Iterable[Tag], arch: Arch, api: int) -> bool:
- """Returns true if the symbol is present for the given LLNDK API level."""
- # Check llndk= first.
- for tag in tags:
- if tag.startswith('llndk='):
- return api >= int(get_tag_value(tag))
- # If not, we keep old behavior: NDK symbols in <= 34 are LLNDK symbols.
- return symbol_in_api(tags, arch, 34)
def symbol_in_api(tags: Iterable[Tag], arch: Arch, api: int) -> bool:
"""Returns true if the symbol is present for the given API level."""
@@ -400,7 +372,6 @@
f'Unexpected contents at top level: {self.current_line}')
self.check_no_duplicate_symbols(versions)
- self.check_llndk_introduced(versions)
return versions
def check_no_duplicate_symbols(self, versions: Iterable[Version]) -> None:
@@ -429,31 +400,6 @@
raise MultiplyDefinedSymbolError(
sorted(list(multiply_defined_symbols)))
- def check_llndk_introduced(self, versions: Iterable[Version]) -> None:
- """Raises errors when llndk= is missing for new llndk symbols."""
- if not self.filter.llndk:
- return
-
- def assert_llndk_with_version(tags: Tags, name: str) -> None:
- has_llndk_introduced = False
- for tag in tags:
- if tag.startswith('llndk='):
- has_llndk_introduced = True
- break
- if not has_llndk_introduced:
- raise ParseError(f'{name}: missing version. `llndk=yyyymm`')
-
- arch = self.filter.arch
- for version in versions:
- # llndk symbols >= introduced=35 should be tagged
- # explicitly with llndk=yyyymm.
- for symbol in version.symbols:
- if not symbol.tags.has_llndk_tags:
- continue
- if symbol_in_api(symbol.tags, arch, 34):
- continue
- assert_llndk_with_version(symbol.tags, symbol.name)
-
def parse_version(self) -> Version:
"""Parses a single version section and returns a Version object."""
assert self.current_line is not None
@@ -487,9 +433,7 @@
else:
raise ParseError('Unknown visiblity label: ' + visibility)
elif global_scope and not cpp_symbols:
- symbol = self.parse_symbol()
- symbol.tags.copy_introduced_from(tags)
- symbols.append(symbol)
+ symbols.append(self.parse_symbol())
else:
# We're in a hidden scope or in 'extern "C++"' block. Ignore
# everything.
diff --git a/cc/symbolfile/test_symbolfile.py b/cc/symbolfile/test_symbolfile.py
index 8b412b9..14bb737 100644
--- a/cc/symbolfile/test_symbolfile.py
+++ b/cc/symbolfile/test_symbolfile.py
@@ -344,45 +344,6 @@
self.assertInclude(f_llndk, s_none)
self.assertInclude(f_llndk, s_llndk)
- def test_omit_llndk_versioned(self) -> None:
- f_ndk = self.filter
- f_ndk.api = 35
-
- f_llndk = copy(f_ndk)
- f_llndk.llndk = True
- f_llndk.api = 202404
-
- s = Symbol('foo', Tags())
- s_llndk = Symbol('foo', Tags.from_strs(['llndk']))
- s_llndk_202404 = Symbol('foo', Tags.from_strs(['llndk=202404']))
- s_34 = Symbol('foo', Tags.from_strs(['introduced=34']))
- s_34_llndk = Symbol('foo', Tags.from_strs(['introduced=34', 'llndk']))
- s_35 = Symbol('foo', Tags.from_strs(['introduced=35']))
- s_35_llndk_202404 = Symbol('foo', Tags.from_strs(['introduced=35', 'llndk=202404']))
- s_35_llndk_202504 = Symbol('foo', Tags.from_strs(['introduced=35', 'llndk=202504']))
-
- # When targeting NDK, omit LLNDK tags
- self.assertInclude(f_ndk, s)
- self.assertOmit(f_ndk, s_llndk)
- self.assertOmit(f_ndk, s_llndk_202404)
- self.assertInclude(f_ndk, s_34)
- self.assertOmit(f_ndk, s_34_llndk)
- self.assertInclude(f_ndk, s_35)
- self.assertOmit(f_ndk, s_35_llndk_202404)
- self.assertOmit(f_ndk, s_35_llndk_202504)
-
- # When targeting LLNDK, old symbols without any mode tags are included as LLNDK
- self.assertInclude(f_llndk, s)
- # When targeting LLNDK, old symbols with #llndk are included as LLNDK
- self.assertInclude(f_llndk, s_llndk)
- self.assertInclude(f_llndk, s_llndk_202404)
- self.assertInclude(f_llndk, s_34)
- self.assertInclude(f_llndk, s_34_llndk)
- # When targeting LLNDK, new symbols(>=35) should be tagged with llndk-introduced=.
- self.assertOmit(f_llndk, s_35)
- self.assertInclude(f_llndk, s_35_llndk_202404)
- self.assertOmit(f_llndk, s_35_llndk_202504)
-
def test_omit_apex(self) -> None:
f_none = self.filter
f_apex = copy(f_none)
@@ -494,8 +455,8 @@
# should_omit_tags() can differently based on introduced API level when treating
# LLNDK-available symbols.
expected_symbols = [
- Symbol('baz', Tags.from_strs(['introduced=35'])),
- Symbol('qux', Tags.from_strs(['apex', 'llndk', 'introduced=35'])),
+ Symbol('baz', Tags()),
+ Symbol('qux', Tags.from_strs(['apex', 'llndk'])),
]
self.assertEqual(expected_symbols, version.symbols)
@@ -643,19 +604,6 @@
]
self.assertEqual(expected_symbols, version.symbols)
- def test_parse_llndk_version_is_missing(self) -> None:
- input_file = io.StringIO(textwrap.dedent("""\
- VERSION_1 { # introduced=35
- foo;
- bar; # llndk
- };
- """))
- f = copy(self.filter)
- f.llndk = True
- parser = symbolfile.SymbolFileParser(input_file, {}, f)
- with self.assertRaises(symbolfile.ParseError):
- parser.parse()
-
def main() -> None:
suite = unittest.TestLoader().loadTestsFromName(__name__)
diff --git a/cc/test.go b/cc/test.go
index f5bb761..dad4afa 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -15,10 +15,11 @@
package cc
import (
- "github.com/google/blueprint/proptools"
"path/filepath"
"strconv"
+ "github.com/google/blueprint/proptools"
+
"android/soong/android"
"android/soong/tradefed"
)
@@ -28,8 +29,8 @@
// if set, build against the gtest library. Defaults to true.
Gtest *bool
- // if set, use the isolated gtest runner. Defaults to true if gtest is also true and the arch is Windows, false
- // otherwise.
+ // if set, use the isolated gtest runner. Defaults to false.
+ // Isolation is not supported on Windows.
Isolated *bool
}
@@ -82,6 +83,16 @@
// the test
Data []string `android:"path,arch_variant"`
+ // Same as data, but adds dependencies on modules using the device's os variant, and common
+ // architecture's variant. Can be useful to add device-built apps to the data of a host
+ // test.
+ Device_common_data []string `android:"path_device_common"`
+
+ // Same as data, but adds dependencies on modules using the device's os variant, and the
+ // device's first architecture's variant. Can be useful to add device-built apps to the data
+ // of a host test.
+ Device_first_data []string `android:"path_device_first"`
+
// list of shared library modules that should be installed alongside the test
Data_libs []string `android:"arch_variant"`
@@ -187,8 +198,8 @@
return BoolDefault(test.LinkerProperties.Gtest, true)
}
-func (test *testDecorator) isolated(ctx android.EarlyModuleContext) bool {
- return BoolDefault(test.LinkerProperties.Isolated, false)
+func (test *testDecorator) isolated(ctx android.BaseModuleContext) bool {
+ return BoolDefault(test.LinkerProperties.Isolated, false) && !ctx.Windows()
}
// NOTE: Keep this in sync with cc/cc_test.bzl#gtest_copts
@@ -324,33 +335,35 @@
func (test *testBinary) install(ctx ModuleContext, file android.Path) {
dataSrcPaths := android.PathsForModuleSrc(ctx, test.Properties.Data)
+ dataSrcPaths = append(dataSrcPaths, android.PathsForModuleSrc(ctx, test.Properties.Device_common_data)...)
+ dataSrcPaths = append(dataSrcPaths, android.PathsForModuleSrc(ctx, test.Properties.Device_first_data)...)
for _, dataSrcPath := range dataSrcPaths {
test.data = append(test.data, android.DataPath{SrcPath: dataSrcPath})
}
- ctx.VisitDirectDepsWithTag(dataLibDepTag, func(dep android.Module) {
+ ctx.VisitDirectDepsProxyWithTag(dataLibDepTag, func(dep android.ModuleProxy) {
depName := ctx.OtherModuleName(dep)
- linkableDep, ok := dep.(LinkableInterface)
+ linkableDep, ok := android.OtherModuleProvider(ctx, dep, LinkableInfoProvider)
if !ok {
ctx.ModuleErrorf("data_lib %q is not a LinkableInterface module", depName)
}
- if linkableDep.OutputFile().Valid() {
+ if linkableDep.OutputFile.Valid() {
test.data = append(test.data,
- android.DataPath{SrcPath: linkableDep.OutputFile().Path(),
- RelativeInstallPath: linkableDep.RelativeInstallPath()})
+ android.DataPath{SrcPath: linkableDep.OutputFile.Path(),
+ RelativeInstallPath: linkableDep.RelativeInstallPath})
}
})
- ctx.VisitDirectDepsWithTag(dataBinDepTag, func(dep android.Module) {
+ ctx.VisitDirectDepsProxyWithTag(dataBinDepTag, func(dep android.ModuleProxy) {
depName := ctx.OtherModuleName(dep)
- linkableDep, ok := dep.(LinkableInterface)
+ linkableDep, ok := android.OtherModuleProvider(ctx, dep, LinkableInfoProvider)
if !ok {
ctx.ModuleErrorf("data_bin %q is not a LinkableInterface module", depName)
}
- if linkableDep.OutputFile().Valid() {
+ if linkableDep.OutputFile.Valid() {
test.data = append(test.data,
- android.DataPath{SrcPath: linkableDep.OutputFile().Path(),
- RelativeInstallPath: linkableDep.RelativeInstallPath()})
+ android.DataPath{SrcPath: linkableDep.OutputFile.Path(),
+ RelativeInstallPath: linkableDep.RelativeInstallPath})
}
})
@@ -384,6 +397,28 @@
test.Properties.Test_options.Unit_test = proptools.BoolPtr(true)
}
+ if !ctx.Config().KatiEnabled() { // TODO(spandandas): Remove the special case for kati
+ // Install the test config in testcases/ directory for atest.
+ c, ok := ctx.Module().(*Module)
+ if !ok {
+ ctx.ModuleErrorf("Not a cc_test module")
+ }
+ // Install configs in the root of $PRODUCT_OUT/testcases/$module
+ testCases := android.PathForModuleInPartitionInstall(ctx, "testcases", ctx.ModuleName()+c.SubName())
+ if ctx.PrimaryArch() {
+ if test.testConfig != nil {
+ ctx.InstallFile(testCases, ctx.ModuleName()+".config", test.testConfig)
+ }
+ for _, extraTestConfig := range test.extraTestConfigs {
+ ctx.InstallFile(testCases, extraTestConfig.Base(), extraTestConfig)
+ }
+ }
+ // Install tests and data in arch specific subdir $PRODUCT_OUT/testcases/$module/$arch
+ testCases = testCases.Join(ctx, ctx.Target().Arch.ArchType.String())
+ ctx.InstallTestData(testCases, test.data)
+ ctx.InstallFile(testCases, file.Base(), file)
+ }
+
test.binaryDecorator.baseInstaller.installTestData(ctx, test.data)
test.binaryDecorator.baseInstaller.install(ctx, file)
}
diff --git a/cc/testing.go b/cc/testing.go
index 159f86c..14a6b7a 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -20,7 +20,6 @@
"android/soong/android"
"android/soong/genrule"
- "android/soong/multitree"
)
func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) {
@@ -29,9 +28,6 @@
RegisterBinaryBuildComponents(ctx)
RegisterLibraryBuildComponents(ctx)
RegisterLibraryHeadersBuildComponents(ctx)
- RegisterLibraryStubBuildComponents(ctx)
-
- multitree.RegisterApiImportsModule(ctx)
ctx.RegisterModuleType("prebuilt_build_tool", android.NewPrebuiltBuildTool)
ctx.RegisterModuleType("cc_benchmark", BenchmarkFactory)
diff --git a/cc/tidy.go b/cc/tidy.go
index ec1e8a2..2373658 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -219,15 +219,11 @@
subsetTidyFileGroups := make(map[string]android.Paths) // subset group name => tidy file Paths
// (1) Collect all obj/tidy files into OS-specific groups.
- ctx.VisitAllModuleVariants(module, func(variant android.Module) {
- if ctx.Config().KatiEnabled() && android.ShouldSkipAndroidMkProcessing(ctx, variant) {
- return
- }
- if m, ok := variant.(*Module); ok {
- osName := variant.Target().Os.Name
- addToOSGroup(osName, m.objFiles, allObjFileGroups, subsetObjFileGroups)
- addToOSGroup(osName, m.tidyFiles, allTidyFileGroups, subsetTidyFileGroups)
- }
+ ctx.VisitAllModuleVariantProxies(module, func(variant android.ModuleProxy) {
+ osName := android.OtherModuleProviderOrDefault(ctx, variant, android.CommonModuleInfoKey).Target.Os.Name
+ info := android.OtherModuleProviderOrDefault(ctx, variant, CcObjectInfoProvider)
+ addToOSGroup(osName, info.ObjFiles, allObjFileGroups, subsetObjFileGroups)
+ addToOSGroup(osName, info.TidyFiles, allTidyFileGroups, subsetTidyFileGroups)
})
// (2) Add an all-OS group, with "" or "subset" name, to include all os-specific phony targets.
@@ -258,7 +254,7 @@
// Collect tidy/obj targets from the 'final' modules.
ctx.VisitAllModules(func(module android.Module) {
- if module == ctx.FinalModule(module) {
+ if ctx.IsFinalModule(module) {
collectTidyObjModuleTargets(ctx, module, tidyModulesInDirGroup, objModulesInDirGroup)
}
})
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index e7dff40..4a2adf0 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -166,6 +166,7 @@
Target: ctx.Target(),
TableOfContents: p.tocFile,
+ IsStubs: false,
})
p.libraryDecorator.flagExporter.setProvider(ctx)
diff --git a/cmd/extract_apks/bundle_proto/Android.bp b/cmd/extract_apks/bundle_proto/Android.bp
index e56c0fb..0abf1e2 100644
--- a/cmd/extract_apks/bundle_proto/Android.bp
+++ b/cmd/extract_apks/bundle_proto/Android.bp
@@ -10,4 +10,8 @@
proto: {
canonical_path_from_root: false,
},
+ visibility: [
+ "//build/soong:__subpackages__",
+ "//tools/mainline:__subpackages__",
+ ],
}
diff --git a/cmd/find_input_delta/find_input_delta/Android.bp b/cmd/find_input_delta/find_input_delta/Android.bp
new file mode 100644
index 0000000..93a7708
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta/Android.bp
@@ -0,0 +1,18 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+blueprint_go_binary {
+ name: "find_input_delta",
+ deps: [
+ "golang-protobuf-encoding-prototext",
+ "golang-protobuf-reflect-protoreflect",
+ "golang-protobuf-runtime-protoimpl",
+ "soong-cmd-find_input_delta-lib",
+ "soong-cmd-find_input_delta-proto",
+ "soong-cmd-find_input_delta-proto_internal",
+ ],
+ srcs: [
+ "main.go",
+ ],
+}
diff --git a/cmd/find_input_delta/find_input_delta/main.go b/cmd/find_input_delta/find_input_delta/main.go
new file mode 100644
index 0000000..65ef881
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta/main.go
@@ -0,0 +1,100 @@
+// 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 main
+
+import (
+ "flag"
+ "os"
+ "regexp"
+
+ fid_lib "android/soong/cmd/find_input_delta/find_input_delta_lib"
+)
+
+var fileSepRegex = regexp.MustCompile("[^[:space:]]+")
+
+func main() {
+ var top string
+ var prior_state_file string
+ var new_state_file string
+ var target string
+ var inputs_file string
+ var template string
+ var inputs []string
+ var inspect bool
+ var err error
+
+ flag.StringVar(&top, "top", ".", "path to top of workspace")
+ flag.StringVar(&prior_state_file, "prior_state", "", "prior internal state file")
+ flag.StringVar(&new_state_file, "new_state", "", "new internal state file")
+ flag.StringVar(&target, "target", "", "name of ninja output file for build action")
+ flag.StringVar(&inputs_file, "inputs_file", "", "file containing list of input files")
+ flag.StringVar(&template, "template", fid_lib.DefaultTemplate, "output template for FileList")
+ flag.BoolVar(&inspect, "inspect", false, "whether to inspect file contents")
+
+ flag.Parse()
+
+ if target == "" {
+ panic("must specify --target")
+ }
+ // Drop any extra file names that arrived in `target`.
+ target = fileSepRegex.FindString(target)
+ if prior_state_file == "" {
+ prior_state_file = target + ".pc_state"
+ }
+ if new_state_file == "" {
+ new_state_file = prior_state_file + ".new"
+ }
+
+ if err = os.Chdir(top); err != nil {
+ panic(err)
+ }
+
+ inputs = flag.Args()
+ if inputs_file != "" {
+ data, err := os.ReadFile(inputs_file)
+ if err != nil {
+ panic(err)
+ }
+ inputs = append(inputs, fileSepRegex.FindAllString(string(data), -1)...)
+ }
+
+ // Read the prior state
+ prior_state, err := fid_lib.LoadState(prior_state_file, fid_lib.OsFs)
+ if err != nil {
+ panic(err)
+ }
+ // Create the new state
+ new_state, err := fid_lib.CreateState(inputs, inspect, fid_lib.OsFs)
+ if err != nil {
+ panic(err)
+ }
+ if err = fid_lib.WriteState(new_state, new_state_file); err != nil {
+ panic(err)
+ }
+
+ file_list := fid_lib.CompareInternalState(prior_state, new_state, target)
+
+ if err = file_list.Format(os.Stdout, template); err != nil {
+ panic(err)
+ }
+
+ metrics_dir := os.Getenv("SOONG_METRICS_AGGREGATION_DIR")
+ out_dir := os.Getenv("OUT_DIR")
+ if metrics_dir != "" {
+ if err = file_list.WriteMetrics(metrics_dir, out_dir); err != nil {
+ panic(err)
+ }
+ }
+}
diff --git a/testing/code_metadata_proto/Android.bp b/cmd/find_input_delta/find_input_delta_lib/Android.bp
similarity index 63%
rename from testing/code_metadata_proto/Android.bp
rename to cmd/find_input_delta/find_input_delta_lib/Android.bp
index f07efff..ef9c65b 100644
--- a/testing/code_metadata_proto/Android.bp
+++ b/cmd/find_input_delta/find_input_delta_lib/Android.bp
@@ -1,4 +1,4 @@
-// Copyright 2022 Google Inc. All rights reserved.
+// 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.
@@ -17,27 +17,20 @@
}
bootstrap_go_package {
- name: "soong-testing-code_metadata_proto",
- pkgPath: "android/soong/testing/code_metadata_proto",
+ name: "soong-cmd-find_input_delta-lib",
+ pkgPath: "android/soong/cmd/find_input_delta/find_input_delta_lib",
deps: [
+ "golang-protobuf-encoding-prototext",
"golang-protobuf-reflect-protoreflect",
"golang-protobuf-runtime-protoimpl",
+ "soong-cmd-find_input_delta-proto",
+ "soong-cmd-find_input_delta-proto_internal",
+ "android-archive-zip",
+ "blueprint-pathtools",
],
srcs: [
- "code_metadata.pb.go",
+ "fs.go",
+ "file_list.go",
+ "internal_state.go",
],
}
-
-python_library_host {
- name: "code-metadata-proto-py",
- pkg_path: "code_metadata",
- srcs: [
- "code_metadata.proto",
- ],
- libs: [
- "libprotobuf-python",
- ],
- proto: {
- canonical_path_from_root: false,
- },
-}
diff --git a/cmd/find_input_delta/find_input_delta_lib/file_list.go b/cmd/find_input_delta/find_input_delta_lib/file_list.go
new file mode 100644
index 0000000..f1d588b
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_lib/file_list.go
@@ -0,0 +1,184 @@
+// 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 find_input_delta_lib
+
+import (
+ "fmt"
+ "hash/fnv"
+ "io"
+ "os"
+ "path/filepath"
+ "strings"
+ "text/template"
+
+ fid_exp "android/soong/cmd/find_input_delta/find_input_delta_proto"
+ "google.golang.org/protobuf/encoding/protowire"
+ "google.golang.org/protobuf/proto"
+)
+
+var DefaultTemplate = `
+ {{- define "contents"}}
+ {{- range .Deletions}}-{{.}} {{end}}
+ {{- range .Additions}}+{{.}} {{end}}
+ {{- range .Changes}}+{{- .Name}} {{end}}
+ {{- range .Changes}}
+ {{- if or .Additions .Deletions .Changes}}--file {{.Name}} {{template "contents" .}}--endfile {{end}}
+ {{- end}}
+ {{- end}}
+ {{- template "contents" .}}`
+
+type FileList struct {
+ // The name of the parent for the list of file differences.
+ // For the outermost FileList, this is the name of the ninja target.
+ // Under `Changes`, it is the name of the changed file.
+ Name string
+
+ // The added files
+ Additions []string
+
+ // The deleted files
+ Deletions []string
+
+ // The modified files
+ Changes []FileList
+
+ // Map of file_extension:counts
+ ExtCountMap map[string]*FileCounts
+
+ // Total number of added/changed/deleted files.
+ TotalDelta uint32
+}
+
+// The maximum number of files that will be recorded by name.
+var MaxFilesRecorded uint32 = 50
+
+type FileCounts struct {
+ Additions uint32
+ Deletions uint32
+ Changes uint32
+}
+
+func FileListFactory(name string) *FileList {
+ return &FileList{
+ Name: name,
+ ExtCountMap: make(map[string]*FileCounts),
+ }
+}
+
+func (fl *FileList) addFile(name string) {
+ fl.Additions = append(fl.Additions, name)
+ fl.TotalDelta += 1
+ ext := filepath.Ext(name)
+ if _, ok := fl.ExtCountMap[ext]; !ok {
+ fl.ExtCountMap[ext] = &FileCounts{}
+ }
+ fl.ExtCountMap[ext].Additions += 1
+}
+
+func (fl *FileList) deleteFile(name string) {
+ fl.Deletions = append(fl.Deletions, name)
+ fl.TotalDelta += 1
+ ext := filepath.Ext(name)
+ if _, ok := fl.ExtCountMap[ext]; !ok {
+ fl.ExtCountMap[ext] = &FileCounts{}
+ }
+ fl.ExtCountMap[ext].Deletions += 1
+}
+
+func (fl *FileList) changeFile(name string, ch *FileList) {
+ fl.Changes = append(fl.Changes, *ch)
+ fl.TotalDelta += 1
+ ext := filepath.Ext(name)
+ if _, ok := fl.ExtCountMap[ext]; !ok {
+ fl.ExtCountMap[ext] = &FileCounts{}
+ }
+ fl.ExtCountMap[ext].Changes += 1
+}
+
+// Write a SoongExecutionMetrics FileList proto to `dir`.
+//
+// Path
+// Prune any paths that
+// begin with `pruneDir` (usually ${OUT_DIR}). The file is only written if any
+// non-pruned changes are present.
+func (fl *FileList) WriteMetrics(dir, pruneDir string) (err error) {
+ if dir == "" {
+ return fmt.Errorf("No directory given")
+ }
+ var needed bool
+
+ if !strings.HasSuffix(pruneDir, "/") {
+ pruneDir += "/"
+ }
+
+ // Hash the dir and `fl.Name` to simplify scanning the metrics
+ // aggregation directory.
+ h := fnv.New128()
+ h.Write([]byte(dir + " " + fl.Name + ".FileList"))
+ path := fmt.Sprintf("%x.pb", h.Sum([]byte{}))
+ path = filepath.Join(dir, path[0:2], path[2:])
+
+ var msg = &fid_exp.FileList{Name: proto.String(fl.Name)}
+ for _, a := range fl.Additions {
+ if strings.HasPrefix(a, pruneDir) {
+ continue
+ }
+ msg.Additions = append(msg.Additions, a)
+ needed = true
+ }
+ for _, ch := range fl.Changes {
+ if strings.HasPrefix(ch.Name, pruneDir) {
+ continue
+ }
+ msg.Changes = append(msg.Changes, ch.Name)
+ needed = true
+ }
+ for _, d := range fl.Deletions {
+ if strings.HasPrefix(d, pruneDir) {
+ continue
+ }
+ msg.Deletions = append(msg.Deletions, d)
+ needed = true
+ }
+ if !needed {
+ return nil
+ }
+ data := protowire.AppendVarint(
+ []byte{},
+ protowire.EncodeTag(
+ protowire.Number(fid_exp.FieldNumbers_FIELD_NUMBERS_FILE_LIST),
+ protowire.BytesType))
+ size := uint64(proto.Size(msg))
+ data = protowire.AppendVarint(data, size)
+ data, err = proto.MarshalOptions{UseCachedSize: true}.MarshalAppend(data, msg)
+ if err != nil {
+ return err
+ }
+
+ err = os.MkdirAll(filepath.Dir(path), 0777)
+ if err != nil {
+ return err
+ }
+
+ return os.WriteFile(path, data, 0644)
+}
+
+func (fl *FileList) Format(wr io.Writer, format string) error {
+ tmpl, err := template.New("filelist").Parse(format)
+ if err != nil {
+ return err
+ }
+ return tmpl.Execute(wr, fl)
+}
diff --git a/cmd/find_input_delta/find_input_delta_lib/file_list_test.go b/cmd/find_input_delta/find_input_delta_lib/file_list_test.go
new file mode 100644
index 0000000..2459f1e
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_lib/file_list_test.go
@@ -0,0 +1,131 @@
+// 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 find_input_delta_lib
+
+import (
+ "bytes"
+ "slices"
+ "testing"
+
+ // For Assert*.
+ "android/soong/android"
+)
+
+func (fl *FileList) Equal(other *FileList) bool {
+ if fl.Name != other.Name {
+ return false
+ }
+ if !slices.Equal(fl.Additions, other.Additions) {
+ return false
+ }
+ if !slices.Equal(fl.Deletions, other.Deletions) {
+ return false
+ }
+ if len(fl.Changes) != len(other.Changes) {
+ return false
+ }
+ for idx, ch := range fl.Changes {
+ if !ch.Equal(&other.Changes[idx]) {
+ return false
+ }
+ }
+ return true
+}
+
+func TestFormat(t *testing.T) {
+ testCases := []struct {
+ Name string
+ Template string
+ Input FileList
+ Expected string
+ Err error
+ }{
+ {
+ Name: "no contents",
+ Template: DefaultTemplate,
+ Input: FileList{
+ Name: "target",
+ Additions: []string{"add1", "add2"},
+ Deletions: []string{"del1", "del2"},
+ Changes: []FileList{
+ FileList{Name: "mod1"},
+ FileList{Name: "mod2"},
+ },
+ },
+ Expected: "-del1 -del2 +add1 +add2 +mod1 +mod2 ",
+ Err: nil,
+ },
+ {
+ Name: "adds",
+ Template: DefaultTemplate,
+ Input: FileList{
+ Name: "target",
+ Additions: []string{"add1", "add2"},
+ },
+ Expected: "+add1 +add2 ",
+ Err: nil,
+ },
+ {
+ Name: "deletes",
+ Template: DefaultTemplate,
+ Input: FileList{
+ Name: "target",
+ Deletions: []string{"del1", "del2"},
+ },
+ Expected: "-del1 -del2 ",
+ Err: nil,
+ },
+ {
+ Name: "changes",
+ Template: DefaultTemplate,
+ Input: FileList{
+ Name: "target",
+ Changes: []FileList{
+ FileList{Name: "mod1"},
+ FileList{Name: "mod2"},
+ },
+ },
+ Expected: "+mod1 +mod2 ",
+ Err: nil,
+ },
+ {
+ Name: "with contents",
+ Template: DefaultTemplate,
+ Input: FileList{
+ Name: "target",
+ Additions: []string{"add1", "add2"},
+ Deletions: []string{"del1", "del2"},
+ Changes: []FileList{
+ FileList{
+ Name: "mod1",
+ },
+ FileList{
+ Name: "mod2",
+ Additions: []string{"a1"},
+ Deletions: []string{"d1"},
+ },
+ },
+ },
+ Expected: "-del1 -del2 +add1 +add2 +mod1 +mod2 --file mod2 -d1 +a1 --endfile ",
+ Err: nil,
+ },
+ }
+ for _, tc := range testCases {
+ buf := bytes.NewBuffer([]byte{})
+ err := tc.Input.Format(buf, tc.Template)
+ android.AssertSame(t, tc.Name, tc.Err, err)
+ android.AssertSame(t, tc.Name, tc.Expected, buf.String())
+ }
+}
diff --git a/cmd/find_input_delta/find_input_delta_lib/fs.go b/cmd/find_input_delta/find_input_delta_lib/fs.go
new file mode 100644
index 0000000..09a8aa6
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_lib/fs.go
@@ -0,0 +1,37 @@
+// 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 find_input_delta_lib
+
+import (
+ "io/fs"
+ "os"
+)
+
+// OsFs provides a minimal implementation so that we can use testing/fstest for
+// unit tests.
+var OsFs fileSystem = osFS{}
+
+type fileSystem interface {
+ Open(path string) (fs.File, error)
+ Stat(path string) (os.FileInfo, error)
+ ReadFile(path string) ([]byte, error)
+}
+
+// osFS implements fileSystem using the local disk.
+type osFS struct{}
+
+func (osFS) Open(path string) (fs.File, error) { return os.Open(path) }
+func (osFS) Stat(path string) (os.FileInfo, error) { return os.Stat(path) }
+func (osFS) ReadFile(path string) ([]byte, error) { return os.ReadFile(path) }
diff --git a/cmd/find_input_delta/find_input_delta_lib/internal_state.go b/cmd/find_input_delta/find_input_delta_lib/internal_state.go
new file mode 100644
index 0000000..bf4f866
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_lib/internal_state.go
@@ -0,0 +1,148 @@
+// 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 find_input_delta_lib
+
+import (
+ "errors"
+ "fmt"
+ "io/fs"
+ "regexp"
+ "slices"
+
+ fid_proto "android/soong/cmd/find_input_delta/find_input_delta_proto_internal"
+ "android/soong/third_party/zip"
+ "github.com/google/blueprint/pathtools"
+ "google.golang.org/protobuf/proto"
+)
+
+// Load the internal state from a file.
+// If the file does not exist, an empty state is returned.
+func LoadState(filename string, fsys fs.ReadFileFS) (*fid_proto.PartialCompileInputs, error) {
+ var message = &fid_proto.PartialCompileInputs{}
+ data, err := fsys.ReadFile(filename)
+ if err != nil && !errors.Is(err, fs.ErrNotExist) {
+ return message, err
+ }
+ proto.Unmarshal(data, message)
+ return message, nil
+}
+
+type StatReadFileFS interface {
+ fs.StatFS
+ fs.ReadFileFS
+}
+
+// Create the internal state by examining the inputs.
+func CreateState(inputs []string, inspect_contents bool, fsys StatReadFileFS) (*fid_proto.PartialCompileInputs, error) {
+ ret := &fid_proto.PartialCompileInputs{}
+ slices.Sort(inputs)
+ for _, input := range inputs {
+ stat, err := fs.Stat(fsys, input)
+ if err != nil {
+ if errors.Is(err, fs.ErrNotExist) {
+ continue
+ }
+ return ret, err
+ }
+ pci := &fid_proto.PartialCompileInput{
+ Name: proto.String(input),
+ MtimeNsec: proto.Int64(stat.ModTime().UnixNano()),
+ // If we ever have an easy hash, assign it here.
+ }
+ if inspect_contents {
+ // NOTE: When we find it useful, we can parallelize the file inspection for speed.
+ contents, err := InspectFileContents(input)
+ if err != nil {
+ return ret, err
+ }
+ if contents != nil {
+ pci.Contents = contents
+ }
+ }
+ ret.InputFiles = append(ret.InputFiles, pci)
+ }
+ return ret, nil
+}
+
+// We ignore any suffix digit caused by sharding.
+var InspectExtsZipRegexp = regexp.MustCompile("\\.(jar|apex|apk)[0-9]*$")
+
+// Inspect the file and extract the state of the elements in the archive.
+// If this is not an archive of some sort, nil is returned.
+func InspectFileContents(name string) ([]*fid_proto.PartialCompileInput, error) {
+ if InspectExtsZipRegexp.Match([]byte(name)) {
+ return inspectZipFileContents(name)
+ }
+ return nil, nil
+}
+
+func inspectZipFileContents(name string) ([]*fid_proto.PartialCompileInput, error) {
+ rc, err := zip.OpenReader(name)
+ if err != nil {
+ return nil, err
+ }
+ ret := []*fid_proto.PartialCompileInput{}
+ for _, v := range rc.File {
+ pci := &fid_proto.PartialCompileInput{
+ Name: proto.String(v.Name),
+ MtimeNsec: proto.Int64(v.ModTime().UnixNano()),
+ Hash: proto.String(fmt.Sprintf("%08x", v.CRC32)),
+ }
+ ret = append(ret, pci)
+ // We do not support nested inspection.
+ }
+ return ret, nil
+}
+
+func WriteState(s *fid_proto.PartialCompileInputs, path string) error {
+ data, err := proto.Marshal(s)
+ if err != nil {
+ return err
+ }
+ return pathtools.WriteFileIfChanged(path, data, 0644)
+}
+
+func CompareInternalState(prior, other *fid_proto.PartialCompileInputs, target string) *FileList {
+ return CompareInputFiles(prior.GetInputFiles(), other.GetInputFiles(), target)
+}
+
+func CompareInputFiles(prior, other []*fid_proto.PartialCompileInput, name string) *FileList {
+ fl := FileListFactory(name)
+ PriorMap := make(map[string]*fid_proto.PartialCompileInput, len(prior))
+ // We know that the lists are properly sorted, so we can simply compare them.
+ for _, v := range prior {
+ PriorMap[v.GetName()] = v
+ }
+ otherMap := make(map[string]*fid_proto.PartialCompileInput, len(other))
+ for _, v := range other {
+ name = v.GetName()
+ otherMap[name] = v
+ if _, ok := PriorMap[name]; !ok {
+ // Added file
+ fl.addFile(name)
+ } else if !proto.Equal(PriorMap[name], v) {
+ // Changed file
+ fl.changeFile(name, CompareInputFiles(PriorMap[name].GetContents(), v.GetContents(), name))
+ }
+ }
+ for _, v := range prior {
+ name := v.GetName()
+ if _, ok := otherMap[name]; !ok {
+ // Deleted file
+ fl.deleteFile(name)
+ }
+ }
+ return fl
+}
diff --git a/cmd/find_input_delta/find_input_delta_lib/internal_state_test.go b/cmd/find_input_delta/find_input_delta_lib/internal_state_test.go
new file mode 100644
index 0000000..c168d5a
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_lib/internal_state_test.go
@@ -0,0 +1,283 @@
+// 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 find_input_delta_lib
+
+import (
+ "errors"
+ "io/fs"
+ "testing"
+ "testing/fstest"
+ "time"
+
+ // For Assert*.
+ "android/soong/android"
+
+ fid_proto "android/soong/cmd/find_input_delta/find_input_delta_proto_internal"
+ "google.golang.org/protobuf/proto"
+)
+
+// Various state files
+
+func marshalProto(t *testing.T, message proto.Message) []byte {
+ data, err := proto.Marshal(message)
+ if err != nil {
+ t.Errorf("%v", err)
+ }
+ return data
+}
+
+func protoFile(name string, mtime_nsec int64, hash string, contents []*fid_proto.PartialCompileInput) (pci *fid_proto.PartialCompileInput) {
+ pci = &fid_proto.PartialCompileInput{
+ Name: proto.String(name),
+ }
+ if mtime_nsec != 0 {
+ pci.MtimeNsec = proto.Int64(mtime_nsec)
+ }
+ if len(hash) > 0 {
+ pci.Hash = proto.String(hash)
+ }
+ if contents != nil {
+ pci.Contents = contents
+ }
+ return
+}
+
+func TestLoadState(t *testing.T) {
+ testCases := []struct {
+ Name string
+ Filename string
+ Mapfs fs.ReadFileFS
+ Expected *fid_proto.PartialCompileInputs
+ Err error
+ }{
+ {
+ Name: "missing file",
+ Filename: "missing",
+ Mapfs: fstest.MapFS{},
+ Expected: &fid_proto.PartialCompileInputs{},
+ Err: nil,
+ },
+ {
+ Name: "bad file",
+ Filename: ".",
+ Mapfs: OsFs,
+ Expected: &fid_proto.PartialCompileInputs{},
+ Err: errors.New("read failed"),
+ },
+ {
+ Name: "file with mtime",
+ Filename: "state.old",
+ Mapfs: fstest.MapFS{
+ "state.old": &fstest.MapFile{
+ Data: marshalProto(t, &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ protoFile("input1", 100, "", nil),
+ },
+ }),
+ },
+ },
+ Expected: &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ protoFile("input1", 100, "", nil),
+ },
+ },
+ Err: nil,
+ },
+ {
+ Name: "file with mtime and hash",
+ Filename: "state.old",
+ Mapfs: fstest.MapFS{
+ "state.old": &fstest.MapFile{
+ Data: marshalProto(t, &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ protoFile("input1", 100, "crc:crc_value", nil),
+ },
+ }),
+ },
+ },
+ Expected: &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ protoFile("input1", 100, "crc:crc_value", nil),
+ },
+ },
+ Err: nil,
+ },
+ }
+ for _, tc := range testCases {
+ actual, err := LoadState(tc.Filename, tc.Mapfs)
+ if tc.Err == nil {
+ android.AssertSame(t, tc.Name, tc.Err, err)
+ } else if err == nil {
+ t.Errorf("%s: expected error, did not get one", tc.Name)
+ }
+ if !proto.Equal(tc.Expected, actual) {
+ t.Errorf("%s: expected %v, actual %v", tc.Name, tc.Expected, actual)
+ }
+ }
+}
+
+func TestCreateState(t *testing.T) {
+ testCases := []struct {
+ Name string
+ Inputs []string
+ Inspect bool
+ Mapfs StatReadFileFS
+ Expected *fid_proto.PartialCompileInputs
+ Err error
+ }{
+ {
+ Name: "no inputs",
+ Inputs: []string{},
+ Mapfs: fstest.MapFS{},
+ Expected: &fid_proto.PartialCompileInputs{},
+ Err: nil,
+ },
+ {
+ Name: "files found",
+ Inputs: []string{"baz", "foo", "bar"},
+ Mapfs: fstest.MapFS{
+ "foo": &fstest.MapFile{ModTime: time.Unix(0, 100).UTC()},
+ "baz": &fstest.MapFile{ModTime: time.Unix(0, 300).UTC()},
+ "bar": &fstest.MapFile{ModTime: time.Unix(0, 200).UTC()},
+ },
+ Expected: &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ // Files are always sorted.
+ protoFile("bar", 200, "", nil),
+ protoFile("baz", 300, "", nil),
+ protoFile("foo", 100, "", nil),
+ },
+ },
+ Err: nil,
+ },
+ }
+ for _, tc := range testCases {
+ actual, err := CreateState(tc.Inputs, tc.Inspect, tc.Mapfs)
+ if tc.Err == nil {
+ android.AssertSame(t, tc.Name, tc.Err, err)
+ } else if err == nil {
+ t.Errorf("%s: expected error, did not get one", tc.Name)
+ }
+ if !proto.Equal(tc.Expected, actual) {
+ t.Errorf("%s: expected %v, actual %v", tc.Name, tc.Expected, actual)
+ }
+ }
+}
+
+func TestCompareInternalState(t *testing.T) {
+ testCases := []struct {
+ Name string
+ Target string
+ Prior *fid_proto.PartialCompileInputs
+ New *fid_proto.PartialCompileInputs
+ Expected *FileList
+ }{
+ {
+ Name: "prior is empty",
+ Target: "foo",
+ Prior: &fid_proto.PartialCompileInputs{},
+ New: &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ protoFile("file1", 100, "", nil),
+ },
+ },
+ Expected: &FileList{
+ Name: "foo",
+ Additions: []string{"file1"},
+ },
+ },
+ {
+ Name: "one each add modify delete",
+ Target: "foo",
+ Prior: &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ protoFile("file0", 100, "", nil),
+ protoFile("file1", 100, "", nil),
+ protoFile("file2", 200, "", nil),
+ },
+ },
+ New: &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ protoFile("file0", 100, "", nil),
+ protoFile("file1", 200, "", nil),
+ protoFile("file3", 300, "", nil),
+ },
+ },
+ Expected: &FileList{
+ Name: "foo",
+ Additions: []string{"file3"},
+ Changes: []FileList{FileList{Name: "file1"}},
+ Deletions: []string{"file2"},
+ },
+ },
+ {
+ Name: "interior one each add modify delete",
+ Target: "bar",
+ Prior: &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ protoFile("file1", 405, "", []*fid_proto.PartialCompileInput{
+ protoFile("innerC", 400, "crc32:11111111", nil),
+ protoFile("innerD", 400, "crc32:44444444", nil),
+ }),
+ },
+ },
+ New: &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ protoFile("file1", 505, "", []*fid_proto.PartialCompileInput{
+ protoFile("innerA", 400, "crc32:55555555", nil),
+ protoFile("innerC", 500, "crc32:66666666", nil),
+ }),
+ },
+ },
+ Expected: &FileList{
+ Name: "bar",
+ Changes: []FileList{FileList{
+ Name: "file1",
+ Additions: []string{"innerA"},
+ Changes: []FileList{FileList{Name: "innerC"}},
+ Deletions: []string{"innerD"},
+ }},
+ },
+ },
+ }
+ for _, tc := range testCases {
+ actual := CompareInternalState(tc.Prior, tc.New, tc.Target)
+ if !tc.Expected.Equal(actual) {
+ t.Errorf("%s: expected %v, actual %v", tc.Name, tc.Expected, actual)
+ }
+ }
+}
+
+func TestCompareInspectExtsZipRegexp(t *testing.T) {
+ testCases := []struct {
+ Name string
+ Expected bool
+ }{
+ {Name: ".jar", Expected: true},
+ {Name: ".jar5", Expected: true},
+ {Name: ".apex", Expected: true},
+ {Name: ".apex9", Expected: true},
+ {Name: ".apexx", Expected: false},
+ {Name: ".apk", Expected: true},
+ {Name: ".apk3", Expected: true},
+ {Name: ".go", Expected: false},
+ }
+ for _, tc := range testCases {
+ actual := InspectExtsZipRegexp.Match([]byte(tc.Name))
+ if tc.Expected != actual {
+ t.Errorf("%s: expected %v, actual %v", tc.Name, tc.Expected, actual)
+ }
+ }
+}
diff --git a/testing/code_metadata_internal_proto/Android.bp b/cmd/find_input_delta/find_input_delta_proto/Android.bp
similarity index 67%
copy from testing/code_metadata_internal_proto/Android.bp
copy to cmd/find_input_delta/find_input_delta_proto/Android.bp
index a534cc2..1a05b9e 100644
--- a/testing/code_metadata_internal_proto/Android.bp
+++ b/cmd/find_input_delta/find_input_delta_proto/Android.bp
@@ -1,4 +1,4 @@
-// Copyright 2022 Google Inc. All rights reserved.
+// 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.
@@ -17,13 +17,13 @@
}
bootstrap_go_package {
- name: "soong-testing-code_metadata_internal_proto",
- pkgPath: "android/soong/testing/code_metadata_internal_proto",
+ name: "soong-cmd-find_input_delta-proto",
+ pkgPath: "android/soong/cmd/find_input_delta/find_input_delta_proto",
deps: [
- "golang-protobuf-reflect-protoreflect",
- "golang-protobuf-runtime-protoimpl",
- ],
+ "golang-protobuf-reflect-protoreflect",
+ "golang-protobuf-runtime-protoimpl",
+ ],
srcs: [
- "code_metadata_internal.pb.go",
+ "file_list.pb.go",
],
}
diff --git a/cmd/find_input_delta/find_input_delta_proto/file_list.pb.go b/cmd/find_input_delta/find_input_delta_proto/file_list.pb.go
new file mode 100644
index 0000000..b6adc45
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_proto/file_list.pb.go
@@ -0,0 +1,257 @@
+//
+// Copyright (C) 2024 The Android Open-Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.33.0
+// protoc v3.21.12
+// source: file_list.proto
+
+package find_input_delta_proto
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type FieldNumbers int32
+
+const (
+ FieldNumbers_FIELD_NUMBERS_UNSPECIFIED FieldNumbers = 0
+ FieldNumbers_FIELD_NUMBERS_FILE_LIST FieldNumbers = 1
+)
+
+// Enum value maps for FieldNumbers.
+var (
+ FieldNumbers_name = map[int32]string{
+ 0: "FIELD_NUMBERS_UNSPECIFIED",
+ 1: "FIELD_NUMBERS_FILE_LIST",
+ }
+ FieldNumbers_value = map[string]int32{
+ "FIELD_NUMBERS_UNSPECIFIED": 0,
+ "FIELD_NUMBERS_FILE_LIST": 1,
+ }
+)
+
+func (x FieldNumbers) Enum() *FieldNumbers {
+ p := new(FieldNumbers)
+ *p = x
+ return p
+}
+
+func (x FieldNumbers) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (FieldNumbers) Descriptor() protoreflect.EnumDescriptor {
+ return file_file_list_proto_enumTypes[0].Descriptor()
+}
+
+func (FieldNumbers) Type() protoreflect.EnumType {
+ return &file_file_list_proto_enumTypes[0]
+}
+
+func (x FieldNumbers) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *FieldNumbers) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = FieldNumbers(num)
+ return nil
+}
+
+// Deprecated: Use FieldNumbers.Descriptor instead.
+func (FieldNumbers) EnumDescriptor() ([]byte, []int) {
+ return file_file_list_proto_rawDescGZIP(), []int{0}
+}
+
+type FileList struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of the output file (Ninja target).
+ Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+ // The added files.
+ Additions []string `protobuf:"bytes,2,rep,name=additions" json:"additions,omitempty"`
+ // The changed files.
+ Changes []string `protobuf:"bytes,3,rep,name=changes" json:"changes,omitempty"`
+ // The deleted files.
+ Deletions []string `protobuf:"bytes,4,rep,name=deletions" json:"deletions,omitempty"`
+}
+
+func (x *FileList) Reset() {
+ *x = FileList{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_file_list_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *FileList) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FileList) ProtoMessage() {}
+
+func (x *FileList) ProtoReflect() protoreflect.Message {
+ mi := &file_file_list_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use FileList.ProtoReflect.Descriptor instead.
+func (*FileList) Descriptor() ([]byte, []int) {
+ return file_file_list_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *FileList) GetName() string {
+ if x != nil && x.Name != nil {
+ return *x.Name
+ }
+ return ""
+}
+
+func (x *FileList) GetAdditions() []string {
+ if x != nil {
+ return x.Additions
+ }
+ return nil
+}
+
+func (x *FileList) GetChanges() []string {
+ if x != nil {
+ return x.Changes
+ }
+ return nil
+}
+
+func (x *FileList) GetDeletions() []string {
+ if x != nil {
+ return x.Deletions
+ }
+ return nil
+}
+
+var File_file_list_proto protoreflect.FileDescriptor
+
+var file_file_list_proto_rawDesc = []byte{
+ 0x0a, 0x0f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x12, 0x1e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x5f,
+ 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x22, 0x74, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x12, 0x0a,
+ 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
+ 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02,
+ 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12,
+ 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09,
+ 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x6c,
+ 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65,
+ 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2a, 0x4a, 0x0a, 0x0c, 0x46, 0x69, 0x65, 0x6c, 0x64,
+ 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x19, 0x46, 0x49, 0x45, 0x4c, 0x44,
+ 0x5f, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49,
+ 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f,
+ 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x4c, 0x49, 0x53,
+ 0x54, 0x10, 0x01, 0x42, 0x3b, 0x5a, 0x39, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73,
+ 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e,
+ 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69,
+ 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+}
+
+var (
+ file_file_list_proto_rawDescOnce sync.Once
+ file_file_list_proto_rawDescData = file_file_list_proto_rawDesc
+)
+
+func file_file_list_proto_rawDescGZIP() []byte {
+ file_file_list_proto_rawDescOnce.Do(func() {
+ file_file_list_proto_rawDescData = protoimpl.X.CompressGZIP(file_file_list_proto_rawDescData)
+ })
+ return file_file_list_proto_rawDescData
+}
+
+var file_file_list_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_file_list_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_file_list_proto_goTypes = []interface{}{
+ (FieldNumbers)(0), // 0: android.find_input_delta_proto.FieldNumbers
+ (*FileList)(nil), // 1: android.find_input_delta_proto.FileList
+}
+var file_file_list_proto_depIdxs = []int32{
+ 0, // [0:0] is the sub-list for method output_type
+ 0, // [0:0] is the sub-list for method input_type
+ 0, // [0:0] is the sub-list for extension type_name
+ 0, // [0:0] is the sub-list for extension extendee
+ 0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_file_list_proto_init() }
+func file_file_list_proto_init() {
+ if File_file_list_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_file_list_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*FileList); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_file_list_proto_rawDesc,
+ NumEnums: 1,
+ NumMessages: 1,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_file_list_proto_goTypes,
+ DependencyIndexes: file_file_list_proto_depIdxs,
+ EnumInfos: file_file_list_proto_enumTypes,
+ MessageInfos: file_file_list_proto_msgTypes,
+ }.Build()
+ File_file_list_proto = out.File
+ file_file_list_proto_rawDesc = nil
+ file_file_list_proto_goTypes = nil
+ file_file_list_proto_depIdxs = nil
+}
diff --git a/cmd/find_input_delta/find_input_delta_proto/file_list.proto b/cmd/find_input_delta/find_input_delta_proto/file_list.proto
new file mode 100644
index 0000000..5309d66
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_proto/file_list.proto
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2024 The Android Open-Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto2";
+package android.find_input_delta_proto;
+option go_package = "android/soong/cmd/find_input_delta/find_input_delta_proto";
+
+enum FieldNumbers {
+ FIELD_NUMBERS_UNSPECIFIED = 0;
+ FIELD_NUMBERS_FILE_LIST = 1;
+}
+
+message FileList {
+ // The name of the output file (Ninja target).
+ optional string name = 1;
+
+ // The added files.
+ repeated string additions = 2;
+
+ // The changed files.
+ repeated string changes = 3;
+
+ // The deleted files.
+ repeated string deletions = 4;
+}
diff --git a/cmd/find_input_delta/find_input_delta_proto/regen.sh b/cmd/find_input_delta/find_input_delta_proto/regen.sh
new file mode 100755
index 0000000..d773659
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_proto/regen.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+aprotoc --go_out=paths=source_relative:. file_list.proto
diff --git a/testing/code_metadata_internal_proto/Android.bp b/cmd/find_input_delta/find_input_delta_proto_internal/Android.bp
similarity index 67%
rename from testing/code_metadata_internal_proto/Android.bp
rename to cmd/find_input_delta/find_input_delta_proto_internal/Android.bp
index a534cc2..00ba9ff 100644
--- a/testing/code_metadata_internal_proto/Android.bp
+++ b/cmd/find_input_delta/find_input_delta_proto_internal/Android.bp
@@ -1,4 +1,4 @@
-// Copyright 2022 Google Inc. All rights reserved.
+// 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.
@@ -17,13 +17,13 @@
}
bootstrap_go_package {
- name: "soong-testing-code_metadata_internal_proto",
- pkgPath: "android/soong/testing/code_metadata_internal_proto",
+ name: "soong-cmd-find_input_delta-proto_internal",
+ pkgPath: "android/soong/cmd/find_input_delta/find_input_delta_proto_internal",
deps: [
- "golang-protobuf-reflect-protoreflect",
- "golang-protobuf-runtime-protoimpl",
- ],
+ "golang-protobuf-reflect-protoreflect",
+ "golang-protobuf-runtime-protoimpl",
+ ],
srcs: [
- "code_metadata_internal.pb.go",
+ "internal_state.pb.go",
],
}
diff --git a/cmd/find_input_delta/find_input_delta_proto_internal/internal_state.pb.go b/cmd/find_input_delta/find_input_delta_proto_internal/internal_state.pb.go
new file mode 100644
index 0000000..c5b048b
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_proto_internal/internal_state.pb.go
@@ -0,0 +1,272 @@
+//
+// Copyright (C) 2024 The Android Open-Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.33.0
+// protoc v3.21.12
+// source: internal_state.proto
+
+package find_input_delta_proto_internal
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// The state of all inputs.
+type PartialCompileInputs struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The status of each file.
+ InputFiles []*PartialCompileInput `protobuf:"bytes,1,rep,name=input_files,json=inputFiles" json:"input_files,omitempty"`
+}
+
+func (x *PartialCompileInputs) Reset() {
+ *x = PartialCompileInputs{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_internal_state_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *PartialCompileInputs) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PartialCompileInputs) ProtoMessage() {}
+
+func (x *PartialCompileInputs) ProtoReflect() protoreflect.Message {
+ mi := &file_internal_state_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use PartialCompileInputs.ProtoReflect.Descriptor instead.
+func (*PartialCompileInputs) Descriptor() ([]byte, []int) {
+ return file_internal_state_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *PartialCompileInputs) GetInputFiles() []*PartialCompileInput {
+ if x != nil {
+ return x.InputFiles
+ }
+ return nil
+}
+
+// The state of one input.
+type PartialCompileInput struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of the file.
+ Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+ // The timestamp of the file in (Unix) nanoseconds.
+ MtimeNsec *int64 `protobuf:"varint,2,opt,name=mtime_nsec,json=mtimeNsec" json:"mtime_nsec,omitempty"`
+ // The hash of the file. For crc32 hashes, this will be 8 hex digits.
+ Hash *string `protobuf:"bytes,3,opt,name=hash" json:"hash,omitempty"`
+ // Contents of the file, if the file was inspected (such as jar files, etc).
+ Contents []*PartialCompileInput `protobuf:"bytes,4,rep,name=contents" json:"contents,omitempty"`
+}
+
+func (x *PartialCompileInput) Reset() {
+ *x = PartialCompileInput{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_internal_state_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *PartialCompileInput) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PartialCompileInput) ProtoMessage() {}
+
+func (x *PartialCompileInput) ProtoReflect() protoreflect.Message {
+ mi := &file_internal_state_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use PartialCompileInput.ProtoReflect.Descriptor instead.
+func (*PartialCompileInput) Descriptor() ([]byte, []int) {
+ return file_internal_state_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *PartialCompileInput) GetName() string {
+ if x != nil && x.Name != nil {
+ return *x.Name
+ }
+ return ""
+}
+
+func (x *PartialCompileInput) GetMtimeNsec() int64 {
+ if x != nil && x.MtimeNsec != nil {
+ return *x.MtimeNsec
+ }
+ return 0
+}
+
+func (x *PartialCompileInput) GetHash() string {
+ if x != nil && x.Hash != nil {
+ return *x.Hash
+ }
+ return ""
+}
+
+func (x *PartialCompileInput) GetContents() []*PartialCompileInput {
+ if x != nil {
+ return x.Contents
+ }
+ return nil
+}
+
+var File_internal_state_proto protoreflect.FileDescriptor
+
+var file_internal_state_proto_rawDesc = []byte{
+ 0x0a, 0x14, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x27, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e,
+ 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61,
+ 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x22,
+ 0x75, 0x0a, 0x14, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c,
+ 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x5d, 0x0a, 0x0b, 0x69, 0x6e, 0x70, 0x75, 0x74,
+ 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x61,
+ 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75,
+ 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, 0x69, 0x6e,
+ 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x43, 0x6f,
+ 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x0a, 0x69, 0x6e, 0x70, 0x75,
+ 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x22, 0xb6, 0x01, 0x0a, 0x13, 0x50, 0x61, 0x72, 0x74, 0x69,
+ 0x61, 0x6c, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x12,
+ 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
+ 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6e, 0x73, 0x65, 0x63,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x6d, 0x74, 0x69, 0x6d, 0x65, 0x4e, 0x73, 0x65,
+ 0x63, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x58, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
+ 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+ 0x64, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c,
+ 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
+ 0x6c, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65,
+ 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42,
+ 0x40, 0x5a, 0x3e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67,
+ 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74,
+ 0x61, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c,
+ 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
+ 0x6c,
+}
+
+var (
+ file_internal_state_proto_rawDescOnce sync.Once
+ file_internal_state_proto_rawDescData = file_internal_state_proto_rawDesc
+)
+
+func file_internal_state_proto_rawDescGZIP() []byte {
+ file_internal_state_proto_rawDescOnce.Do(func() {
+ file_internal_state_proto_rawDescData = protoimpl.X.CompressGZIP(file_internal_state_proto_rawDescData)
+ })
+ return file_internal_state_proto_rawDescData
+}
+
+var file_internal_state_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_internal_state_proto_goTypes = []interface{}{
+ (*PartialCompileInputs)(nil), // 0: android.find_input_delta_proto_internal.PartialCompileInputs
+ (*PartialCompileInput)(nil), // 1: android.find_input_delta_proto_internal.PartialCompileInput
+}
+var file_internal_state_proto_depIdxs = []int32{
+ 1, // 0: android.find_input_delta_proto_internal.PartialCompileInputs.input_files:type_name -> android.find_input_delta_proto_internal.PartialCompileInput
+ 1, // 1: android.find_input_delta_proto_internal.PartialCompileInput.contents:type_name -> android.find_input_delta_proto_internal.PartialCompileInput
+ 2, // [2:2] is the sub-list for method output_type
+ 2, // [2:2] is the sub-list for method input_type
+ 2, // [2:2] is the sub-list for extension type_name
+ 2, // [2:2] is the sub-list for extension extendee
+ 0, // [0:2] is the sub-list for field type_name
+}
+
+func init() { file_internal_state_proto_init() }
+func file_internal_state_proto_init() {
+ if File_internal_state_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_internal_state_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*PartialCompileInputs); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_internal_state_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*PartialCompileInput); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_internal_state_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 2,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_internal_state_proto_goTypes,
+ DependencyIndexes: file_internal_state_proto_depIdxs,
+ MessageInfos: file_internal_state_proto_msgTypes,
+ }.Build()
+ File_internal_state_proto = out.File
+ file_internal_state_proto_rawDesc = nil
+ file_internal_state_proto_goTypes = nil
+ file_internal_state_proto_depIdxs = nil
+}
diff --git a/cmd/find_input_delta/find_input_delta_proto_internal/internal_state.proto b/cmd/find_input_delta/find_input_delta_proto_internal/internal_state.proto
new file mode 100644
index 0000000..54c90cc
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_proto_internal/internal_state.proto
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2024 The Android Open-Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto2";
+package android.find_input_delta_proto_internal;
+option go_package = "android/soong/find_input_delta/find_input_delta_proto_internal";
+
+// The state of all inputs.
+message PartialCompileInputs {
+ // The status of each file.
+ repeated PartialCompileInput input_files = 1;
+}
+
+// The state of one input.
+message PartialCompileInput {
+ // The name of the file.
+ optional string name = 1;
+
+ // The timestamp of the file in (Unix) nanoseconds.
+ optional int64 mtime_nsec = 2;
+
+ // The hash of the file. For crc32 hashes, this will be 8 hex digits.
+ optional string hash = 3;
+
+ // Contents of the file, if the file was inspected (such as jar files, etc).
+ repeated PartialCompileInput contents = 4;
+}
diff --git a/cmd/find_input_delta/find_input_delta_proto_internal/regen.sh b/cmd/find_input_delta/find_input_delta_proto_internal/regen.sh
new file mode 100755
index 0000000..cbaf7d0
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_proto_internal/regen.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+aprotoc --go_out=paths=source_relative:. internal_state.proto
diff --git a/cmd/kotlinc_incremental/Android.bp b/cmd/kotlinc_incremental/Android.bp
new file mode 100644
index 0000000..7816553
--- /dev/null
+++ b/cmd/kotlinc_incremental/Android.bp
@@ -0,0 +1,65 @@
+//
+// Copyright (C) 2025 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ "Kotlin_Incremental_license",
+ ],
+}
+
+license {
+ name: "Kotlin_Incremental_license",
+ visibility: [":__subpackages__"],
+ license_kinds: ["legacy_proprietary"],
+}
+
+java_library_host {
+ name: "kotlin-incremental-client-lib",
+ srcs: [
+ "src/com/**/*.kt",
+ ],
+ static_libs: [
+ "kotlin-compiler-embeddable",
+ "kotlin-compiler-runner",
+ "kotlin-daemon-client",
+ ],
+
+ plugins: [],
+
+ kotlincflags: [
+ "-Werror",
+ ],
+}
+
+java_binary_host {
+ name: "kotlin-incremental-client",
+ manifest: "kotlin-incremental-client.mf",
+ static_libs: ["kotlin-incremental-client-lib"],
+}
+
+java_test_host {
+ name: "kotlin-incremental-client-tests",
+ srcs: [
+ "tests/src/com/**/*.kt",
+ ],
+ static_libs: [
+ "kotlin-incremental-client-lib",
+ "junit",
+ "truth",
+ ],
+}
diff --git a/cmd/kotlinc_incremental/kotlin-incremental-client.mf b/cmd/kotlinc_incremental/kotlin-incremental-client.mf
new file mode 100644
index 0000000..b84c86a
--- /dev/null
+++ b/cmd/kotlinc_incremental/kotlin-incremental-client.mf
@@ -0,0 +1 @@
+Main-Class: com.android.kotlin.compiler.client.MainKt
diff --git a/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/Main.kt b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/Main.kt
new file mode 100644
index 0000000..4938641
--- /dev/null
+++ b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/Main.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.kotlin.compiler.client
+
+fun main(args: Array<String>) {
+ println("compiling")
+}
diff --git a/cmd/kotlinc_incremental/tests/src/com/android/kotlin/compiler/client/MainTest.kt b/cmd/kotlinc_incremental/tests/src/com/android/kotlin/compiler/client/MainTest.kt
new file mode 100644
index 0000000..3354aa4
--- /dev/null
+++ b/cmd/kotlinc_incremental/tests/src/com/android/kotlin/compiler/client/MainTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.kotlin.compiler.client
+
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class MainTest {
+ @Test
+ fun testMain() {
+ assertThat(true).isTrue()
+ }
+}
\ No newline at end of file
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
deleted file mode 100644
index c3b0381..0000000
--- a/cmd/multiproduct_kati/main.go
+++ /dev/null
@@ -1,598 +0,0 @@
-// Copyright 2017 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package main
-
-import (
- "bufio"
- "context"
- "flag"
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "os"
- "os/exec"
- "path/filepath"
- "regexp"
- "runtime"
- "strings"
- "sync"
- "syscall"
- "time"
-
- "android/soong/ui/logger"
- "android/soong/ui/signal"
- "android/soong/ui/status"
- "android/soong/ui/terminal"
- "android/soong/ui/tracer"
- "android/soong/zip"
-)
-
-var numJobs = flag.Int("j", 0, "number of parallel jobs [0=autodetect]")
-
-var keepArtifacts = flag.Bool("keep", false, "keep archives of artifacts")
-var incremental = flag.Bool("incremental", false, "run in incremental mode (saving intermediates)")
-
-var outDir = flag.String("out", "", "path to store output directories (defaults to tmpdir under $OUT when empty)")
-var alternateResultDir = flag.Bool("dist", false, "write select results to $DIST_DIR (or <out>/dist when empty)")
-
-var bazelMode = flag.Bool("bazel-mode", false, "use bazel for analysis of certain modules")
-var bazelModeStaging = flag.Bool("bazel-mode-staging", false, "use bazel for analysis of certain near-ready modules")
-
-var onlyConfig = flag.Bool("only-config", false, "Only run product config (not Soong or Kati)")
-var onlySoong = flag.Bool("only-soong", false, "Only run product config and Soong (not Kati)")
-
-var buildVariant = flag.String("variant", "eng", "build variant to use")
-
-var shardCount = flag.Int("shard-count", 1, "split the products into multiple shards (to spread the build onto multiple machines, etc)")
-var shard = flag.Int("shard", 1, "1-indexed shard to execute")
-
-var skipProducts multipleStringArg
-var includeProducts multipleStringArg
-
-func init() {
- flag.Var(&skipProducts, "skip-products", "comma-separated list of products to skip (known failures, etc)")
- flag.Var(&includeProducts, "products", "comma-separated list of products to build")
-}
-
-// multipleStringArg is a flag.Value that takes comma separated lists and converts them to a
-// []string. The argument can be passed multiple times to append more values.
-type multipleStringArg []string
-
-func (m *multipleStringArg) String() string {
- return strings.Join(*m, `, `)
-}
-
-func (m *multipleStringArg) Set(s string) error {
- *m = append(*m, strings.Split(s, ",")...)
- return nil
-}
-
-const errorLeadingLines = 20
-const errorTrailingLines = 20
-
-func errMsgFromLog(filename string) string {
- if filename == "" {
- return ""
- }
-
- data, err := ioutil.ReadFile(filename)
- if err != nil {
- return ""
- }
-
- lines := strings.Split(strings.TrimSpace(string(data)), "\n")
- if len(lines) > errorLeadingLines+errorTrailingLines+1 {
- lines[errorLeadingLines] = fmt.Sprintf("... skipping %d lines ...",
- len(lines)-errorLeadingLines-errorTrailingLines)
-
- lines = append(lines[:errorLeadingLines+1],
- lines[len(lines)-errorTrailingLines:]...)
- }
- var buf strings.Builder
- for _, line := range lines {
- buf.WriteString("> ")
- buf.WriteString(line)
- buf.WriteString("\n")
- }
- return buf.String()
-}
-
-// TODO(b/70370883): This tool uses a lot of open files -- over the default
-// soft limit of 1024 on some systems. So bump up to the hard limit until I fix
-// the algorithm.
-func setMaxFiles(log logger.Logger) {
- var limits syscall.Rlimit
-
- err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limits)
- if err != nil {
- log.Println("Failed to get file limit:", err)
- return
- }
-
- log.Verbosef("Current file limits: %d soft, %d hard", limits.Cur, limits.Max)
- if limits.Cur == limits.Max {
- return
- }
-
- limits.Cur = limits.Max
- err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limits)
- if err != nil {
- log.Println("Failed to increase file limit:", err)
- }
-}
-
-func inList(str string, list []string) bool {
- for _, other := range list {
- if str == other {
- return true
- }
- }
- return false
-}
-
-func copyFile(from, to string) error {
- fromFile, err := os.Open(from)
- if err != nil {
- return err
- }
- defer fromFile.Close()
-
- toFile, err := os.Create(to)
- if err != nil {
- return err
- }
- defer toFile.Close()
-
- _, err = io.Copy(toFile, fromFile)
- return err
-}
-
-type mpContext struct {
- Logger logger.Logger
- Status status.ToolStatus
-
- SoongUi string
- MainOutDir string
- MainLogsDir string
-}
-
-func findNamedProducts(soongUi string, log logger.Logger) []string {
- cmd := exec.Command(soongUi, "--dumpvars-mode", "--vars=all_named_products")
- output, err := cmd.Output()
- if err != nil {
- log.Fatalf("Cannot determine named products: %v", err)
- }
-
- rx := regexp.MustCompile(`^all_named_products='(.*)'$`)
- match := rx.FindStringSubmatch(strings.TrimSpace(string(output)))
- return strings.Fields(match[1])
-}
-
-// ensureEmptyFileExists ensures that the containing directory exists, and the
-// specified file exists. If it doesn't exist, it will write an empty file.
-func ensureEmptyFileExists(file string, log logger.Logger) {
- if _, err := os.Stat(file); os.IsNotExist(err) {
- f, err := os.Create(file)
- if err != nil {
- log.Fatalf("Error creating %s: %q\n", file, err)
- }
- f.Close()
- } else if err != nil {
- log.Fatalf("Error checking %s: %q\n", file, err)
- }
-}
-
-func outDirBase() string {
- outDirBase := os.Getenv("OUT_DIR")
- if outDirBase == "" {
- return "out"
- } else {
- return outDirBase
- }
-}
-
-func distDir(outDir string) string {
- if distDir := os.Getenv("DIST_DIR"); distDir != "" {
- return filepath.Clean(distDir)
- } else {
- return filepath.Join(outDir, "dist")
- }
-}
-
-func forceAnsiOutput() bool {
- value := os.Getenv("SOONG_UI_ANSI_OUTPUT")
- return value == "1" || value == "y" || value == "yes" || value == "on" || value == "true"
-}
-
-func getBazelArg() string {
- count := 0
- str := ""
- if *bazelMode {
- count++
- str = "--bazel-mode"
- }
- if *bazelModeStaging {
- count++
- str = "--bazel-mode-staging"
- }
-
- if count > 1 {
- // Can't set more than one
- fmt.Errorf("Only one bazel mode is permitted to be set.")
- os.Exit(1)
- }
-
- return str
-}
-
-func main() {
- stdio := terminal.StdioImpl{}
-
- output := terminal.NewStatusOutput(stdio.Stdout(), "", false, false,
- forceAnsiOutput())
- log := logger.New(output)
- defer log.Cleanup()
-
- for _, v := range os.Environ() {
- log.Println("Environment: " + v)
- }
-
- log.Printf("Argv: %v\n", os.Args)
-
- flag.Parse()
-
- _, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- trace := tracer.New(log)
- defer trace.Close()
-
- stat := &status.Status{}
- defer stat.Finish()
- stat.AddOutput(output)
-
- var failures failureCount
- stat.AddOutput(&failures)
-
- signal.SetupSignals(log, cancel, func() {
- trace.Close()
- log.Cleanup()
- stat.Finish()
- })
-
- soongUi := "build/soong/soong_ui.bash"
-
- var outputDir string
- if *outDir != "" {
- outputDir = *outDir
- } else {
- name := "multiproduct"
- if !*incremental {
- name += "-" + time.Now().Format("20060102150405")
- }
- outputDir = filepath.Join(outDirBase(), name)
- }
-
- log.Println("Output directory:", outputDir)
-
- // The ninja_build file is used by our buildbots to understand that the output
- // can be parsed as ninja output.
- if err := os.MkdirAll(outputDir, 0777); err != nil {
- log.Fatalf("Failed to create output directory: %v", err)
- }
- ensureEmptyFileExists(filepath.Join(outputDir, "ninja_build"), log)
-
- logsDir := filepath.Join(outputDir, "logs")
- os.MkdirAll(logsDir, 0777)
-
- var configLogsDir string
- if *alternateResultDir {
- configLogsDir = filepath.Join(distDir(outDirBase()), "logs")
- } else {
- configLogsDir = outputDir
- }
-
- log.Println("Logs dir: " + configLogsDir)
-
- os.MkdirAll(configLogsDir, 0777)
- log.SetOutput(filepath.Join(configLogsDir, "soong.log"))
- trace.SetOutput(filepath.Join(configLogsDir, "build.trace"))
-
- var jobs = *numJobs
- if jobs < 1 {
- jobs = runtime.NumCPU() / 4
-
- ramGb := int(detectTotalRAM() / (1024 * 1024 * 1024))
- if ramJobs := ramGb / 40; ramGb > 0 && jobs > ramJobs {
- jobs = ramJobs
- }
-
- if jobs < 1 {
- jobs = 1
- }
- }
- log.Verbosef("Using %d parallel jobs", jobs)
-
- setMaxFiles(log)
-
- allProducts := findNamedProducts(soongUi, log)
- var productsList []string
-
- if len(includeProducts) > 0 {
- var missingProducts []string
- for _, product := range includeProducts {
- if inList(product, allProducts) {
- productsList = append(productsList, product)
- } else {
- missingProducts = append(missingProducts, product)
- }
- }
- if len(missingProducts) > 0 {
- log.Fatalf("Products don't exist: %s\n", missingProducts)
- }
- } else {
- productsList = allProducts
- }
-
- finalProductsList := make([]string, 0, len(productsList))
- skipProduct := func(p string) bool {
- for _, s := range skipProducts {
- if p == s {
- return true
- }
- }
- return false
- }
- for _, product := range productsList {
- if !skipProduct(product) {
- finalProductsList = append(finalProductsList, product)
- } else {
- log.Verbose("Skipping: ", product)
- }
- }
-
- if *shard < 1 {
- log.Fatalf("--shard value must be >= 1, not %d\n", *shard)
- } else if *shardCount < 1 {
- log.Fatalf("--shard-count value must be >= 1, not %d\n", *shardCount)
- } else if *shard > *shardCount {
- log.Fatalf("--shard (%d) must not be greater than --shard-count (%d)\n", *shard,
- *shardCount)
- } else if *shardCount > 1 {
- finalProductsList = splitList(finalProductsList, *shardCount)[*shard-1]
- }
-
- log.Verbose("Got product list: ", finalProductsList)
-
- s := stat.StartTool()
- s.SetTotalActions(len(finalProductsList))
-
- mpCtx := &mpContext{
- Logger: log,
- Status: s,
- SoongUi: soongUi,
- MainOutDir: outputDir,
- MainLogsDir: logsDir,
- }
-
- products := make(chan string, len(productsList))
- go func() {
- defer close(products)
- for _, product := range finalProductsList {
- products <- product
- }
- }()
-
- var wg sync.WaitGroup
- for i := 0; i < jobs; i++ {
- wg.Add(1)
- // To smooth out the spikes in memory usage, skew the
- // initial starting time of the jobs by a small amount.
- time.Sleep(15 * time.Second)
- go func() {
- defer wg.Done()
- for {
- select {
- case product := <-products:
- if product == "" {
- return
- }
- runSoongUiForProduct(mpCtx, product)
- }
- }
- }()
- }
- wg.Wait()
-
- if *alternateResultDir {
- args := zip.ZipArgs{
- FileArgs: []zip.FileArg{
- {GlobDir: logsDir, SourcePrefixToStrip: logsDir},
- },
- OutputFilePath: filepath.Join(distDir(outDirBase()), "logs.zip"),
- NumParallelJobs: runtime.NumCPU(),
- CompressionLevel: 5,
- }
- log.Printf("Logs zip: %v\n", args.OutputFilePath)
- if err := zip.Zip(args); err != nil {
- log.Fatalf("Error zipping logs: %v", err)
- }
- }
-
- s.Finish()
-
- if failures.count == 1 {
- log.Fatal("1 failure")
- } else if failures.count > 1 {
- log.Fatalf("%d failures %q", failures.count, failures.fails)
- } else {
- fmt.Fprintln(output, "Success")
- }
-}
-
-func cleanupAfterProduct(outDir, productZip string) {
- if *keepArtifacts {
- args := zip.ZipArgs{
- FileArgs: []zip.FileArg{
- {
- GlobDir: outDir,
- SourcePrefixToStrip: outDir,
- },
- },
- OutputFilePath: productZip,
- NumParallelJobs: runtime.NumCPU(),
- CompressionLevel: 5,
- }
- if err := zip.Zip(args); err != nil {
- log.Fatalf("Error zipping artifacts: %v", err)
- }
- }
- if !*incremental {
- os.RemoveAll(outDir)
- }
-}
-
-func runSoongUiForProduct(mpctx *mpContext, product string) {
- outDir := filepath.Join(mpctx.MainOutDir, product)
- logsDir := filepath.Join(mpctx.MainLogsDir, product)
- productZip := filepath.Join(mpctx.MainOutDir, product+".zip")
- consoleLogPath := filepath.Join(logsDir, "std.log")
-
- if err := os.MkdirAll(outDir, 0777); err != nil {
- mpctx.Logger.Fatalf("Error creating out directory: %v", err)
- }
- if err := os.MkdirAll(logsDir, 0777); err != nil {
- mpctx.Logger.Fatalf("Error creating log directory: %v", err)
- }
-
- consoleLogFile, err := os.Create(consoleLogPath)
- if err != nil {
- mpctx.Logger.Fatalf("Error creating console log file: %v", err)
- }
- defer consoleLogFile.Close()
-
- consoleLogWriter := bufio.NewWriter(consoleLogFile)
- defer consoleLogWriter.Flush()
-
- args := []string{"--make-mode", "--skip-soong-tests", "--skip-ninja"}
-
- if !*keepArtifacts {
- args = append(args, "--empty-ninja-file")
- }
-
- if *onlyConfig {
- args = append(args, "--config-only")
- } else if *onlySoong {
- args = append(args, "--soong-only")
- }
-
- bazelStr := getBazelArg()
- if bazelStr != "" {
- args = append(args, bazelStr)
- }
-
- cmd := exec.Command(mpctx.SoongUi, args...)
- cmd.Stdout = consoleLogWriter
- cmd.Stderr = consoleLogWriter
- cmd.Env = append(os.Environ(),
- "OUT_DIR="+outDir,
- "TARGET_PRODUCT="+product,
- "TARGET_BUILD_VARIANT="+*buildVariant,
- "TARGET_BUILD_TYPE=release",
- "TARGET_BUILD_APPS=",
- "TARGET_BUILD_UNBUNDLED=",
- "USE_RBE=false") // Disabling RBE saves ~10 secs per product
-
- if *alternateResultDir {
- cmd.Env = append(cmd.Env,
- "DIST_DIR="+filepath.Join(distDir(outDirBase()), "products/"+product))
- }
-
- action := &status.Action{
- Description: product,
- Outputs: []string{product},
- }
-
- mpctx.Status.StartAction(action)
- defer cleanupAfterProduct(outDir, productZip)
-
- before := time.Now()
- err = cmd.Run()
-
- if !*onlyConfig && !*onlySoong {
- katiBuildNinjaFile := filepath.Join(outDir, "build-"+product+".ninja")
- if after, err := os.Stat(katiBuildNinjaFile); err == nil && after.ModTime().After(before) {
- err := copyFile(consoleLogPath, filepath.Join(filepath.Dir(consoleLogPath), "std_full.log"))
- if err != nil {
- log.Fatalf("Error copying log file: %s", err)
- }
- }
- }
- var errOutput string
- if err == nil {
- errOutput = ""
- } else {
- errOutput = errMsgFromLog(consoleLogPath)
- }
-
- mpctx.Status.FinishAction(status.ActionResult{
- Action: action,
- Error: err,
- Output: errOutput,
- })
-}
-
-type failureCount struct {
- count int
- fails []string
-}
-
-func (f *failureCount) StartAction(action *status.Action, counts status.Counts) {}
-
-func (f *failureCount) FinishAction(result status.ActionResult, counts status.Counts) {
- if result.Error != nil {
- f.count += 1
- f.fails = append(f.fails, result.Action.Description)
- }
-}
-
-func (f *failureCount) Message(level status.MsgLevel, message string) {
- if level >= status.ErrorLvl {
- f.count += 1
- }
-}
-
-func (f *failureCount) Flush() {}
-
-func (f *failureCount) Write(p []byte) (int, error) {
- // discard writes
- return len(p), nil
-}
-
-func splitList(list []string, shardCount int) (ret [][]string) {
- each := len(list) / shardCount
- extra := len(list) % shardCount
- for i := 0; i < shardCount; i++ {
- count := each
- if extra > 0 {
- count += 1
- extra -= 1
- }
- ret = append(ret, list[:count])
- list = list[count:]
- }
- return
-}
diff --git a/cmd/multiproduct_kati/main_darwin.go b/cmd/multiproduct_kati/main_darwin.go
deleted file mode 100644
index 3d1b12a..0000000
--- a/cmd/multiproduct_kati/main_darwin.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2017 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package main
-
-func detectTotalRAM() uint64 {
- // unimplemented stub on darwin
- return 0
-}
diff --git a/cmd/multiproduct_kati/main_test.go b/cmd/multiproduct_kati/main_test.go
deleted file mode 100644
index 263a124..0000000
--- a/cmd/multiproduct_kati/main_test.go
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2019 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package main
-
-import (
- "fmt"
- "reflect"
- "testing"
-)
-
-func TestSplitList(t *testing.T) {
- testcases := []struct {
- inputCount int
- shardCount int
- want [][]string
- }{
- {
- inputCount: 1,
- shardCount: 1,
- want: [][]string{{"1"}},
- },
- {
- inputCount: 1,
- shardCount: 2,
- want: [][]string{{"1"}, {}},
- },
- {
- inputCount: 4,
- shardCount: 2,
- want: [][]string{{"1", "2"}, {"3", "4"}},
- },
- {
- inputCount: 19,
- shardCount: 10,
- want: [][]string{
- {"1", "2"},
- {"3", "4"},
- {"5", "6"},
- {"7", "8"},
- {"9", "10"},
- {"11", "12"},
- {"13", "14"},
- {"15", "16"},
- {"17", "18"},
- {"19"},
- },
- },
- {
- inputCount: 15,
- shardCount: 10,
- want: [][]string{
- {"1", "2"},
- {"3", "4"},
- {"5", "6"},
- {"7", "8"},
- {"9", "10"},
- {"11"},
- {"12"},
- {"13"},
- {"14"},
- {"15"},
- },
- },
- }
-
- for _, tc := range testcases {
- t.Run(fmt.Sprintf("%d/%d", tc.inputCount, tc.shardCount), func(t *testing.T) {
- input := []string{}
- for i := 1; i <= tc.inputCount; i++ {
- input = append(input, fmt.Sprintf("%d", i))
- }
-
- got := splitList(input, tc.shardCount)
-
- if !reflect.DeepEqual(got, tc.want) {
- t.Errorf("unexpected result for splitList([]string{...%d...}, %d):\nwant: %v\n got: %v\n",
- tc.inputCount, tc.shardCount, tc.want, got)
- }
- })
- }
-}
diff --git a/cmd/release_config/build_flag/main.go b/cmd/release_config/build_flag/main.go
index 5d183ee..5d103cc 100644
--- a/cmd/release_config/build_flag/main.go
+++ b/cmd/release_config/build_flag/main.go
@@ -90,6 +90,9 @@
if !ok {
return "", fmt.Errorf("%s not found in %s", name, config.Name)
}
+ if fa.Redacted {
+ return "==REDACTED==", nil
+ }
return rc_lib.MarshalValue(fa.Value), nil
}
@@ -329,7 +332,7 @@
return err
}
updatedFiles = append(updatedFiles, flagPath)
- fmt.Printf("Added/Updated: %s\n", strings.Join(updatedFiles, " "))
+ fmt.Printf("\033[1mAdded/Updated: %s\033[0m\n", strings.Join(updatedFiles, " "))
return nil
}
diff --git a/cmd/release_config/release_config/main.go b/cmd/release_config/release_config/main.go
index d06b2b7..7013d6b 100644
--- a/cmd/release_config/release_config/main.go
+++ b/cmd/release_config/release_config/main.go
@@ -95,7 +95,7 @@
if allMake {
// Write one makefile per release config, using the canonical release name.
for _, c := range configs.GetSortedReleaseConfigs() {
- if c.Name != targetRelease {
+ if c.Name != targetRelease && !c.DisallowLunchUse {
makefilePath = filepath.Join(outputDir, fmt.Sprintf("release_config-%s-%s.varmk", product, c.Name))
err = config.WriteMakefile(makefilePath, c.Name, configs)
if err != nil {
diff --git a/cmd/release_config/release_config_contributions/Android.bp b/cmd/release_config/release_config_contributions/Android.bp
new file mode 100644
index 0000000..6882ea2
--- /dev/null
+++ b/cmd/release_config/release_config_contributions/Android.bp
@@ -0,0 +1,32 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+blueprint_go_binary {
+ name: "release-config-contributions",
+ deps: [
+ "golang-protobuf-encoding-prototext",
+ "golang-protobuf-reflect-protoreflect",
+ "golang-protobuf-runtime-protoimpl",
+ "soong-cmd-release_config-proto",
+ "soong-cmd-release_config-lib",
+ ],
+ srcs: [
+ "main.go",
+ ],
+}
+
+bootstrap_go_package {
+ name: "soong-cmd-release_config-release_config_contributions",
+ pkgPath: "android/soong/cmd/release_config/release_config_contributions",
+ deps: [
+ "golang-protobuf-encoding-prototext",
+ "golang-protobuf-reflect-protoreflect",
+ "golang-protobuf-runtime-protoimpl",
+ "soong-cmd-release_config-proto",
+ "soong-cmd-release_config-lib",
+ ],
+ srcs: [
+ "main.go",
+ ],
+}
diff --git a/cmd/release_config/release_config_contributions/main.go b/cmd/release_config/release_config_contributions/main.go
new file mode 100644
index 0000000..a954cf1
--- /dev/null
+++ b/cmd/release_config/release_config_contributions/main.go
@@ -0,0 +1,130 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "slices"
+ "strings"
+
+ rc_lib "android/soong/cmd/release_config/release_config_lib"
+ rc_proto "android/soong/cmd/release_config/release_config_proto"
+)
+
+type Flags struct {
+ // The path to the top of the workspace. Default: ".".
+ top string
+
+ // Output file.
+ output string
+
+ // Format for output file
+ format string
+
+ // List of release config directories to process.
+ dirs rc_lib.StringList
+
+ // Disable warning messages
+ quiet bool
+
+ // Panic on errors.
+ debug bool
+}
+
+func sortDirectories(dirList []string) {
+ order := func(dir string) int {
+ switch {
+ // These three are always in this order.
+ case dir == "build/release":
+ return 1
+ case dir == "vendor/google_shared/build/release":
+ return 2
+ case dir == "vendor/google/release":
+ return 3
+ // Keep their subdirs in the same order.
+ case strings.HasPrefix(dir, "build/release/"):
+ return 21
+ case strings.HasPrefix(dir, "vendor/google_shared/build/release/"):
+ return 22
+ case strings.HasPrefix(dir, "vendor/google/release/"):
+ return 23
+ // Everything else sorts by directory path.
+ default:
+ return 99
+ }
+ }
+
+ slices.SortFunc(dirList, func(a, b string) int {
+ aOrder, bOrder := order(a), order(b)
+ if aOrder != bOrder {
+ return aOrder - bOrder
+ }
+ return strings.Compare(a, b)
+ })
+}
+
+func main() {
+ var flags Flags
+ topDir, err := rc_lib.GetTopDir()
+
+ // Handle the common arguments
+ flag.StringVar(&flags.top, "top", topDir, "path to top of workspace")
+ flag.Var(&flags.dirs, "dir", "path to a release config contribution directory. May be repeated")
+ flag.StringVar(&flags.format, "format", "pb", "output file format")
+ flag.StringVar(&flags.output, "output", "release_config_contributions.pb", "output file")
+ flag.BoolVar(&flags.debug, "debug", false, "turn on debugging output for errors")
+ flag.BoolVar(&flags.quiet, "quiet", false, "disable warning messages")
+ flag.Parse()
+
+ errorExit := func(err error) {
+ if flags.debug {
+ panic(err)
+ }
+ fmt.Fprintf(os.Stderr, "%s\n", err)
+ os.Exit(1)
+ }
+
+ if flags.quiet {
+ rc_lib.DisableWarnings()
+ }
+
+ if err = os.Chdir(flags.top); err != nil {
+ errorExit(err)
+ }
+
+ contributingDirsMap := make(map[string][]string)
+ for _, dir := range flags.dirs {
+ contributions, err := rc_lib.EnumerateReleaseConfigs(dir)
+ if err != nil {
+ errorExit(err)
+ }
+ for _, name := range contributions {
+ contributingDirsMap[name] = append(contributingDirsMap[name], dir)
+ }
+ }
+
+ releaseConfigNames := []string{}
+ for name := range contributingDirsMap {
+ releaseConfigNames = append(releaseConfigNames, name)
+ }
+ slices.Sort(releaseConfigNames)
+
+ message := &rc_proto.ReleaseConfigContributionsArtifacts{
+ ReleaseConfigContributionsArtifactList: []*rc_proto.ReleaseConfigContributionsArtifact{},
+ }
+ for _, name := range releaseConfigNames {
+ dirs := contributingDirsMap[name]
+ sortDirectories(dirs)
+ message.ReleaseConfigContributionsArtifactList = append(
+ message.ReleaseConfigContributionsArtifactList,
+ &rc_proto.ReleaseConfigContributionsArtifact{
+ Name: &name,
+ ContributingDirectories: dirs,
+ })
+ }
+
+ err = rc_lib.WriteFormattedMessage(flags.output, flags.format, message)
+ if err != nil {
+ errorExit(err)
+ }
+}
diff --git a/cmd/release_config/release_config_lib/flag_artifact.go b/cmd/release_config/release_config_lib/flag_artifact.go
index 93c50cd..f493e1e 100644
--- a/cmd/release_config/release_config_lib/flag_artifact.go
+++ b/cmd/release_config/release_config_lib/flag_artifact.go
@@ -84,8 +84,10 @@
func (fas *FlagArtifacts) SortedFlagNames() []string {
var names []string
- for k, _ := range *fas {
- names = append(names, k)
+ for k, v := range *fas {
+ if !v.Redacted {
+ names = append(names, k)
+ }
}
slices.Sort(names)
return names
@@ -99,10 +101,13 @@
if namespace := fa.FlagDeclaration.GetNamespace(); namespace != "" {
ret.Namespace = proto.String(namespace)
}
+ if bugs := fa.FlagDeclaration.GetBugs(); bugs != nil {
+ ret.Bugs = bugs
+ }
if description := fa.FlagDeclaration.GetDescription(); description != "" {
ret.Description = proto.String(description)
}
- if workflow := fa.FlagDeclaration.GetWorkflow(); workflow != rc_proto.Workflow_Workflow_Unspecified {
+ if workflow := fa.FlagDeclaration.GetWorkflow(); workflow != rc_proto.Workflow_WORKFLOW_UNSPECIFIED {
ret.Workflow = &workflow
}
if containers := fa.FlagDeclaration.GetContainers(); containers != nil {
@@ -180,15 +185,20 @@
// error: any error encountered
func (fa *FlagArtifact) UpdateValue(flagValue FlagValue) error {
name := *flagValue.proto.Name
- fa.Traces = append(fa.Traces, &rc_proto.Tracepoint{Source: proto.String(flagValue.path), Value: flagValue.proto.Value})
- if flagValue.proto.GetRedacted() {
- fa.Redacted = true
- fmt.Printf("Redacting flag %s in %s\n", name, flagValue.path)
- return nil
+ redacted := flagValue.proto.GetRedacted()
+ if redacted {
+ fa.Redact()
+ flagValue.proto.Value = fa.Value
+ warnf("Redacting flag %s in %s\n", name, flagValue.path)
+ } else {
+ // If we are assigning a value, then the flag is no longer redacted.
+ fa.Redacted = false
}
+ fa.Traces = append(fa.Traces, &rc_proto.Tracepoint{Source: proto.String(flagValue.path), Value: flagValue.proto.Value})
if fa.Value.GetObsolete() {
return fmt.Errorf("Attempting to set obsolete flag %s. Trace=%v", name, fa.Traces)
}
+
var newValue *rc_proto.Value
switch val := flagValue.proto.Value.Val.(type) {
case *rc_proto.Value_StringValue:
@@ -210,6 +220,11 @@
return nil
}
+func (fa *FlagArtifact) Redact() {
+ fa.Redacted = true
+ fa.Value = &rc_proto.Value{Val: &rc_proto.Value_StringValue{StringValue: "*REDACTED*"}}
+}
+
// Marshal the FlagArtifact into a flag_artifact message.
func (fa *FlagArtifact) Marshal() (*rc_proto.FlagArtifact, error) {
if fa.Redacted {
diff --git a/cmd/release_config/release_config_lib/release_config.go b/cmd/release_config/release_config_lib/release_config.go
index adf0e62..873f2fc 100644
--- a/cmd/release_config/release_config_lib/release_config.go
+++ b/cmd/release_config/release_config_lib/release_config.go
@@ -21,7 +21,6 @@
"path/filepath"
"regexp"
"slices"
- "sort"
"strings"
rc_proto "android/soong/cmd/release_config/release_config_proto"
@@ -68,6 +67,9 @@
// overrides. Build flag value overrides are an error.
AconfigFlagsOnly bool
+ // True if this release config is not allowed as TARGET_RELEASE.
+ DisallowLunchUse bool
+
// Unmarshalled flag artifacts
FlagArtifacts FlagArtifacts
@@ -86,6 +88,31 @@
// Prior stage(s) for flag advancement (during development).
// Once a flag has met criteria in a prior stage, it can advance to this one.
PriorStagesMap map[string]bool
+
+ // What type of release config is this? This should never be
+ // ReleaseConfigType_CONFIG_TYPE_UNSPECIFIED.
+ ReleaseConfigType rc_proto.ReleaseConfigType
+}
+
+// If true, this is a proper release config that can be used in "lunch".
+func (config *ReleaseConfig) isConfigListable() bool {
+ // Do not list disallowed release configs.
+ if config.DisallowLunchUse {
+ return false
+ }
+ // Logic based on ReleaseConfigType.
+ switch config.ReleaseConfigType {
+ case rc_proto.ReleaseConfigType_RELEASE_CONFIG:
+ return true
+ }
+
+ return false
+}
+
+// If true, this ReleaseConfigType may only inherit from a ReleaseConfig of the
+// same ReleaseConfigType.
+var ReleaseConfigInheritanceDenyMap = map[rc_proto.ReleaseConfigType]bool{
+ rc_proto.ReleaseConfigType_BUILD_VARIANT: true,
}
func ReleaseConfigFactory(name string, index int) (c *ReleaseConfig) {
@@ -98,6 +125,10 @@
}
func (config *ReleaseConfig) InheritConfig(iConfig *ReleaseConfig) error {
+ if config.ReleaseConfigType != iConfig.ReleaseConfigType && ReleaseConfigInheritanceDenyMap[config.ReleaseConfigType] {
+ return fmt.Errorf("Release config %s (type '%s') cannot inherit from %s (type '%s')",
+ config.Name, config.ReleaseConfigType, iConfig.Name, iConfig.ReleaseConfigType)
+ }
for f := range iConfig.FilesUsedMap {
config.FilesUsedMap[f] = true
}
@@ -107,6 +138,9 @@
if !ok {
return fmt.Errorf("Could not inherit flag %s from %s", name, iConfig.Name)
}
+ if fa.Redacted {
+ myFa.Redact()
+ }
if name == "RELEASE_ACONFIG_VALUE_SETS" {
// If there is a value assigned, add the trace.
if len(fa.Value.GetStringValue()) > 0 {
@@ -152,10 +186,10 @@
contributionsToApply := []*ReleaseConfigContribution{}
myInherits := []string{}
myInheritsSet := make(map[string]bool)
- // If there is a "root" release config, it is the start of every inheritance chain.
- _, err = configs.GetReleaseConfig("root")
- if err == nil && !isRoot {
- config.InheritNames = append([]string{"root"}, config.InheritNames...)
+ if config.ReleaseConfigType == rc_proto.ReleaseConfigType_RELEASE_CONFIG {
+ if _, err = configs.GetReleaseConfigStrict("root"); err == nil {
+ config.InheritNames = append([]string{"root"}, config.InheritNames...)
+ }
}
for _, inherit := range config.InheritNames {
if _, ok := myInheritsSet[inherit]; ok {
@@ -166,6 +200,13 @@
}
myInherits = append(myInherits, inherit)
myInheritsSet[inherit] = true
+ // TODO: there are some configs that rely on vgsbr being
+ // present on branches where it isn't. Once the broken configs
+ // are fixed, we can be more strict. In the meantime, they
+ // will wind up inheriting `trunk_stable` instead of the
+ // non-existent (alias) that they reference today. Once fixed,
+ // this becomes:
+ // iConfig, err := configs.GetReleaseConfigStrict(inherit)
iConfig, err := configs.GetReleaseConfig(inherit)
if err != nil {
return err
@@ -261,11 +302,38 @@
if err := fa.UpdateValue(*value); err != nil {
return err
}
- if fa.Redacted {
- delete(config.FlagArtifacts, name)
+ }
+ }
+
+ if config.ReleaseConfigType == rc_proto.ReleaseConfigType_RELEASE_CONFIG {
+ inheritBuildVariant := func() error {
+ build_variant := os.Getenv("TARGET_BUILD_VARIANT")
+ if build_variant == "" || config.Name == build_variant {
+ return nil
+ }
+ variant, err := configs.GetReleaseConfigStrict(build_variant)
+ if err != nil {
+ // Failure to find the build-variant release config is
+ // not an error.
+ return nil
+ }
+ if variant.ReleaseConfigType != rc_proto.ReleaseConfigType_BUILD_VARIANT {
+ return nil
+ }
+ if err = variant.GenerateReleaseConfig(configs); err != nil {
+ return err
+ }
+ return config.InheritConfig(variant)
+ }
+
+ useVariant, ok := config.FlagArtifacts["RELEASE_BUILD_USE_VARIANT_FLAGS"]
+ if ok && MarshalValue(useVariant.Value) != "" {
+ if err = inheritBuildVariant(); err != nil {
+ return err
}
}
}
+
// Now remove any duplicates from the actual value of RELEASE_ACONFIG_VALUE_SETS
myAconfigValueSets := []string{}
myAconfigValueSetsMap := map[string]bool{}
@@ -280,11 +348,28 @@
directories := []string{}
valueDirectories := []string{}
+ // These path prefixes are exclusive for a release config.
+ // "A release config shall exist in at most one of these."
+ // If we find a benefit to generalizing this, we can do so at that time.
+ exclusiveDirPrefixes := []string{
+ "build/release",
+ "vendor/google_shared/build/release",
+ }
+ var exclusiveDir string
for idx, confDir := range configs.configDirs {
if _, ok := myDirsMap[idx]; ok {
directories = append(directories, confDir)
}
if _, ok := myValueDirsMap[idx]; ok {
+ for _, dir := range exclusiveDirPrefixes {
+ if strings.HasPrefix(confDir, dir) {
+ if exclusiveDir != "" && !strings.HasPrefix(exclusiveDir, dir) {
+ return fmt.Errorf("%s is declared in both %s and %s",
+ config.Name, exclusiveDir, confDir)
+ }
+ exclusiveDir = confDir
+ }
+ }
valueDirectories = append(valueDirectories, confDir)
}
}
@@ -296,6 +381,10 @@
if err != nil {
return err
}
+ // Redacted flags return nil when rendered.
+ if artifact == nil {
+ continue
+ }
for _, container := range v.FlagDeclaration.Containers {
if _, ok := config.PartitionBuildFlags[container]; !ok {
config.PartitionBuildFlags[container] = &rc_proto.FlagArtifacts{}
@@ -308,12 +397,7 @@
OtherNames: config.OtherNames,
Flags: func() []*rc_proto.FlagArtifact {
ret := []*rc_proto.FlagArtifact{}
- flagNames := []string{}
- for k := range config.FlagArtifacts {
- flagNames = append(flagNames, k)
- }
- sort.Strings(flagNames)
- for _, flagName := range flagNames {
+ for _, flagName := range config.FlagArtifacts.SortedFlagNames() {
flag := config.FlagArtifacts[flagName]
ret = append(ret, &rc_proto.FlagArtifact{
FlagDeclaration: flag.FlagDeclaration,
@@ -323,11 +407,13 @@
}
return ret
}(),
- AconfigValueSets: myAconfigValueSets,
- Inherits: myInherits,
- Directories: directories,
- ValueDirectories: valueDirectories,
- PriorStages: SortedMapKeys(config.PriorStagesMap),
+ AconfigValueSets: myAconfigValueSets,
+ Inherits: myInherits,
+ Directories: directories,
+ ValueDirectories: valueDirectories,
+ PriorStages: SortedMapKeys(config.PriorStagesMap),
+ ReleaseConfigType: config.ReleaseConfigType.Enum(),
+ DisallowLunchUse: proto.Bool(config.DisallowLunchUse),
}
config.compileInProgress = false
@@ -348,7 +434,7 @@
}
}
for _, rcName := range extraAconfigReleaseConfigs {
- rc, err := configs.GetReleaseConfig(rcName)
+ rc, err := configs.GetReleaseConfigStrict(rcName)
if err != nil {
return err
}
@@ -404,6 +490,9 @@
}
// As it stands this list is not per-product, but conceptually it is, and will be.
data += fmt.Sprintf("ALL_RELEASE_CONFIGS_FOR_PRODUCT :=$= %s\n", strings.Join(configs.GetAllReleaseNames(), " "))
+ if config.DisallowLunchUse {
+ data += fmt.Sprintf("_disallow_lunch_use :=$= true\n")
+ }
data += fmt.Sprintf("_used_files := %s\n", strings.Join(config.GetSortedFileList(), " "))
data += fmt.Sprintf("_ALL_RELEASE_FLAGS :=$= %s\n", strings.Join(names, " "))
for _, pName := range pNames {
diff --git a/cmd/release_config/release_config_lib/release_configs.go b/cmd/release_config/release_config_lib/release_configs.go
index 97eb8f1..b0f8cb7 100644
--- a/cmd/release_config/release_config_lib/release_configs.go
+++ b/cmd/release_config/release_config_lib/release_configs.go
@@ -248,6 +248,18 @@
return configs.configDirs[index], nil
}
+// Return the (unsorted) release configs contributed to by `dir`.
+func EnumerateReleaseConfigs(dir string) ([]string, error) {
+ var ret []string
+ err := WalkTextprotoFiles(dir, "release_configs", func(path string, d fs.DirEntry, err error) error {
+ // Strip off the trailing `.textproto` from the name.
+ name := filepath.Base(path)
+ ret = append(ret, name[:len(name)-10])
+ return err
+ })
+ return ret, err
+}
+
func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex int) error {
if _, err := os.Stat(path); err != nil {
return fmt.Errorf("%s does not exist\n", path)
@@ -349,11 +361,24 @@
if fmt.Sprintf("%s.textproto", name) != filepath.Base(path) {
return fmt.Errorf("%s incorrectly declares release config %s", path, name)
}
+ releaseConfigType := releaseConfigContribution.proto.ReleaseConfigType
+ if releaseConfigType == nil {
+ if name == "root" {
+ releaseConfigType = rc_proto.ReleaseConfigType_EXPLICIT_INHERITANCE_CONFIG.Enum()
+ } else {
+ releaseConfigType = rc_proto.ReleaseConfigType_RELEASE_CONFIG.Enum()
+ }
+ }
if _, ok := configs.ReleaseConfigs[name]; !ok {
configs.ReleaseConfigs[name] = ReleaseConfigFactory(name, ConfigDirIndex)
+ configs.ReleaseConfigs[name].ReleaseConfigType = *releaseConfigType
}
config := configs.ReleaseConfigs[name]
+ if config.ReleaseConfigType != *releaseConfigType {
+ return fmt.Errorf("%s mismatching ReleaseConfigType value %s", path, *releaseConfigType)
+ }
config.FilesUsedMap[path] = true
+ config.DisallowLunchUse = config.DisallowLunchUse || releaseConfigContribution.proto.GetDisallowLunchUse()
inheritNames := make(map[string]bool)
for _, inh := range config.InheritNames {
inheritNames[inh] = true
@@ -398,6 +423,14 @@
}
func (configs *ReleaseConfigs) GetReleaseConfig(name string) (*ReleaseConfig, error) {
+ return configs.getReleaseConfig(name, configs.allowMissing)
+}
+
+func (configs *ReleaseConfigs) GetReleaseConfigStrict(name string) (*ReleaseConfig, error) {
+ return configs.getReleaseConfig(name, false)
+}
+
+func (configs *ReleaseConfigs) getReleaseConfig(name string, allow_missing bool) (*ReleaseConfig, error) {
trace := []string{name}
for target, ok := configs.Aliases[name]; ok; target, ok = configs.Aliases[name] {
name = *target
@@ -406,7 +439,7 @@
if config, ok := configs.ReleaseConfigs[name]; ok {
return config, nil
}
- if configs.allowMissing {
+ if allow_missing {
if config, ok := configs.ReleaseConfigs["trunk_staging"]; ok {
return config, nil
}
@@ -417,8 +450,10 @@
func (configs *ReleaseConfigs) GetAllReleaseNames() []string {
var allReleaseNames []string
for _, v := range configs.ReleaseConfigs {
- allReleaseNames = append(allReleaseNames, v.Name)
- allReleaseNames = append(allReleaseNames, v.OtherNames...)
+ if v.isConfigListable() {
+ allReleaseNames = append(allReleaseNames, v.Name)
+ allReleaseNames = append(allReleaseNames, v.OtherNames...)
+ }
}
slices.Sort(allReleaseNames)
return allReleaseNames
@@ -455,7 +490,7 @@
dirName := filepath.Dir(contrib.path)
for k, names := range contrib.FlagValueDirs {
for _, rcName := range names {
- if config, err := configs.GetReleaseConfig(rcName); err == nil {
+ if config, err := configs.getReleaseConfig(rcName, false); err == nil {
rcPath := filepath.Join(dirName, "release_configs", fmt.Sprintf("%s.textproto", config.Name))
if _, err := os.Stat(rcPath); err != nil {
errors = append(errors, fmt.Sprintf("%s exists but %s does not contribute to %s",
diff --git a/cmd/release_config/release_config_proto/Android.bp b/cmd/release_config/release_config_proto/Android.bp
index c34d203..c6869b1 100644
--- a/cmd/release_config/release_config_proto/Android.bp
+++ b/cmd/release_config/release_config_proto/Android.bp
@@ -28,5 +28,6 @@
"build_flags_declarations.pb.go",
"build_flags_src.pb.go",
"build_flags_out.pb.go",
+ "release_configs_contributions.pb.go",
],
}
diff --git a/cmd/release_config/release_config_proto/build_flags_common.pb.go b/cmd/release_config/release_config_proto/build_flags_common.pb.go
index 82fbcfa..7b52b07 100644
--- a/cmd/release_config/release_config_proto/build_flags_common.pb.go
+++ b/cmd/release_config/release_config_proto/build_flags_common.pb.go
@@ -15,7 +15,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.33.0
+// protoc-gen-go v1.30.0
// protoc v3.21.12
// source: build_flags_common.proto
@@ -38,6 +38,8 @@
type Workflow int32
const (
+ Workflow_WORKFLOW_UNSPECIFIED Workflow = 0
+ // Deprecated. Use WORKFLOW_UNSPECIFIED instead.
Workflow_Workflow_Unspecified Workflow = 0
// Boolean value flags that progress from false to true.
Workflow_LAUNCH Workflow = 1
@@ -52,12 +54,14 @@
// Enum value maps for Workflow.
var (
Workflow_name = map[int32]string{
- 0: "Workflow_Unspecified",
+ 0: "WORKFLOW_UNSPECIFIED",
+ // Duplicate value: 0: "Workflow_Unspecified",
1: "LAUNCH",
2: "PREBUILT",
3: "MANUAL",
}
Workflow_value = map[string]int32{
+ "WORKFLOW_UNSPECIFIED": 0,
"Workflow_Unspecified": 0,
"LAUNCH": 1,
"PREBUILT": 2,
@@ -108,15 +112,17 @@
0x0a, 0x18, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x5f, 0x63, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x61, 0x6e, 0x64, 0x72,
0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66,
- 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2a, 0x4a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b,
- 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x18, 0x0a, 0x14, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
- 0x5f, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x10, 0x00, 0x12, 0x0a,
- 0x0a, 0x06, 0x4c, 0x41, 0x55, 0x4e, 0x43, 0x48, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x52,
- 0x45, 0x42, 0x55, 0x49, 0x4c, 0x54, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x41, 0x4e, 0x55,
- 0x41, 0x4c, 0x10, 0x03, 0x42, 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f,
- 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f,
- 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e,
- 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2a, 0x68, 0x0a, 0x08, 0x57, 0x6f, 0x72, 0x6b,
+ 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x18, 0x0a, 0x14, 0x57, 0x4f, 0x52, 0x4b, 0x46, 0x4c, 0x4f, 0x57,
+ 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18,
+ 0x0a, 0x14, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x55, 0x6e, 0x73, 0x70, 0x65,
+ 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x41, 0x55, 0x4e,
+ 0x43, 0x48, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x52, 0x45, 0x42, 0x55, 0x49, 0x4c, 0x54,
+ 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x41, 0x4e, 0x55, 0x41, 0x4c, 0x10, 0x03, 0x1a, 0x02,
+ 0x10, 0x01, 0x42, 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f,
+ 0x6f, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
+ 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
}
var (
@@ -133,7 +139,7 @@
var file_build_flags_common_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_build_flags_common_proto_goTypes = []interface{}{
- (Workflow)(0), // 0: android.release_config_proto.workflow
+ (Workflow)(0), // 0: android.release_config_proto.Workflow
}
var file_build_flags_common_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
diff --git a/cmd/release_config/release_config_proto/build_flags_common.proto b/cmd/release_config/release_config_proto/build_flags_common.proto
index d5d6101..cd9f1e0 100644
--- a/cmd/release_config/release_config_proto/build_flags_common.proto
+++ b/cmd/release_config/release_config_proto/build_flags_common.proto
@@ -20,7 +20,11 @@
// This protobuf file defines common messages used in the rest of the build flag
// protos.
-enum workflow {
+enum Workflow {
+ option allow_alias = true;
+ WORKFLOW_UNSPECIFIED = 0;
+
+ // Deprecated. Use WORKFLOW_UNSPECIFIED instead.
Workflow_Unspecified = 0;
// Boolean value flags that progress from false to true.
diff --git a/cmd/release_config/release_config_proto/build_flags_declarations.pb.go b/cmd/release_config/release_config_proto/build_flags_declarations.pb.go
index d2de89a..0029f99 100644
--- a/cmd/release_config/release_config_proto/build_flags_declarations.pb.go
+++ b/cmd/release_config/release_config_proto/build_flags_declarations.pb.go
@@ -15,7 +15,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.33.0
+// protoc-gen-go v1.30.0
// protoc v3.21.12
// source: build_flags_declarations.proto
@@ -48,6 +48,8 @@
Namespace *string `protobuf:"bytes,2,opt,name=namespace" json:"namespace,omitempty"`
// Text description of the flag's purpose.
Description *string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"`
+ // The bug number associated with the flag.
+ Bugs []string `protobuf:"bytes,4,rep,name=bugs" json:"bugs,omitempty"`
// Where the flag was declared.
DeclarationPath *string `protobuf:"bytes,5,opt,name=declaration_path,json=declarationPath" json:"declaration_path,omitempty"`
// Workflow for this flag.
@@ -110,6 +112,13 @@
return ""
}
+func (x *FlagDeclarationArtifact) GetBugs() []string {
+ if x != nil {
+ return x.Bugs
+ }
+ return nil
+}
+
func (x *FlagDeclarationArtifact) GetDeclarationPath() string {
if x != nil && x.DeclarationPath != nil {
return *x.DeclarationPath
@@ -121,7 +130,7 @@
if x != nil && x.Workflow != nil {
return *x.Workflow
}
- return Workflow_Workflow_Unspecified
+ return Workflow_WORKFLOW_UNSPECIFIED
}
func (x *FlagDeclarationArtifact) GetContainers() []string {
@@ -187,37 +196,38 @@
0x12, 0x1c, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73,
0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18,
0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x6d,
- 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8e, 0x02, 0x0a, 0x19, 0x66, 0x6c, 0x61,
- 0x67, 0x5f, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x72,
- 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61,
- 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e,
- 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63,
- 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64,
- 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x65,
- 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05,
- 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x50, 0x61, 0x74, 0x68, 0x12, 0x43, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
- 0x77, 0x18, 0xcd, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f,
- 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
- 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
- 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x1f, 0x0a, 0x0a, 0x63, 0x6f,
- 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0xce, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52,
- 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x4a, 0x04, 0x08, 0x04, 0x10,
- 0x05, 0x4a, 0x06, 0x08, 0xcf, 0x01, 0x10, 0xd0, 0x01, 0x22, 0x9a, 0x01, 0x0a, 0x1a, 0x66, 0x6c,
- 0x61, 0x67, 0x5f, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61,
- 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x12, 0x7c, 0x0a, 0x1e, 0x66, 0x6c, 0x61, 0x67,
- 0x5f, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x72, 0x74,
- 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
- 0x32, 0x37, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61,
- 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
- 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x1b, 0x66, 0x6c, 0x61, 0x67, 0x44,
- 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61,
- 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
- 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f,
- 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63,
- 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9a, 0x02, 0x0a, 0x17, 0x46, 0x6c, 0x61,
+ 0x67, 0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x72, 0x74, 0x69,
+ 0x66, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65,
+ 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d,
+ 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,
+ 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73,
+ 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x75, 0x67, 0x73,
+ 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x62, 0x75, 0x67, 0x73, 0x12, 0x29, 0x0a, 0x10,
+ 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68,
+ 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x12, 0x43, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66,
+ 0x6c, 0x6f, 0x77, 0x18, 0xcd, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x61, 0x6e, 0x64,
+ 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e,
+ 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
+ 0x6f, 0x77, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x1f, 0x0a, 0x0a,
+ 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0xce, 0x01, 0x20, 0x03, 0x28,
+ 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x4a, 0x06, 0x08,
+ 0xcf, 0x01, 0x10, 0xd0, 0x01, 0x22, 0x96, 0x01, 0x0a, 0x18, 0x46, 0x6c, 0x61, 0x67, 0x44, 0x65,
+ 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63,
+ 0x74, 0x73, 0x12, 0x7a, 0x0a, 0x1e, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x64, 0x65, 0x63, 0x6c, 0x61,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f,
+ 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x61, 0x6e, 0x64,
+ 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e,
+ 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x6c, 0x61, 0x67, 0x44, 0x65,
+ 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63,
+ 0x74, 0x52, 0x1b, 0x66, 0x6c, 0x61, 0x67, 0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x33,
+ 0x5a, 0x31, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f,
+ 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72,
+ 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f,
}
var (
@@ -234,13 +244,13 @@
var file_build_flags_declarations_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_build_flags_declarations_proto_goTypes = []interface{}{
- (*FlagDeclarationArtifact)(nil), // 0: android.release_config_proto.flag_declaration_artifact
- (*FlagDeclarationArtifacts)(nil), // 1: android.release_config_proto.flag_declaration_artifacts
- (Workflow)(0), // 2: android.release_config_proto.workflow
+ (*FlagDeclarationArtifact)(nil), // 0: android.release_config_proto.FlagDeclarationArtifact
+ (*FlagDeclarationArtifacts)(nil), // 1: android.release_config_proto.FlagDeclarationArtifacts
+ (Workflow)(0), // 2: android.release_config_proto.Workflow
}
var file_build_flags_declarations_proto_depIdxs = []int32{
- 2, // 0: android.release_config_proto.flag_declaration_artifact.workflow:type_name -> android.release_config_proto.workflow
- 0, // 1: android.release_config_proto.flag_declaration_artifacts.flag_declaration_artifact_list:type_name -> android.release_config_proto.flag_declaration_artifact
+ 2, // 0: android.release_config_proto.FlagDeclarationArtifact.workflow:type_name -> android.release_config_proto.Workflow
+ 0, // 1: android.release_config_proto.FlagDeclarationArtifacts.flag_declaration_artifact_list:type_name -> android.release_config_proto.FlagDeclarationArtifact
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
diff --git a/cmd/release_config/release_config_proto/build_flags_declarations.proto b/cmd/release_config/release_config_proto/build_flags_declarations.proto
index 233158e..ccdccfb 100644
--- a/cmd/release_config/release_config_proto/build_flags_declarations.proto
+++ b/cmd/release_config/release_config_proto/build_flags_declarations.proto
@@ -39,7 +39,7 @@
// com.android.mypackage is a valid name while com.android.myPackage,
// com.android.1mypackage are invalid
-message flag_declaration_artifact {
+message FlagDeclarationArtifact {
// The name of the flag.
// See # name for format detail
optional string name = 1;
@@ -51,14 +51,14 @@
// Text description of the flag's purpose.
optional string description = 3;
- // reserve this for bug, if needed.
- reserved 4;
+ // The bug number associated with the flag.
+ repeated string bugs = 4;
// Where the flag was declared.
optional string declaration_path = 5;
// Workflow for this flag.
- optional workflow workflow = 205;
+ optional Workflow workflow = 205;
// The container for this flag. This overrides any default container given
// in the release_config_map message.
@@ -69,7 +69,7 @@
reserved 207;
}
-message flag_declaration_artifacts {
+message FlagDeclarationArtifacts {
// The artifacts
- repeated flag_declaration_artifact flag_declaration_artifact_list = 1;
+ repeated FlagDeclarationArtifact flag_declaration_artifact_list = 1;
}
diff --git a/cmd/release_config/release_config_proto/build_flags_out.pb.go b/cmd/release_config/release_config_proto/build_flags_out.pb.go
index c63ea26..21a37a9 100644
--- a/cmd/release_config/release_config_proto/build_flags_out.pb.go
+++ b/cmd/release_config/release_config_proto/build_flags_out.pb.go
@@ -15,7 +15,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.33.0
+// protoc-gen-go v1.30.0
// protoc v3.21.12
// source: build_flags_out.proto
@@ -235,6 +235,12 @@
// config. The listed directories contain at least a `release_config` message
// for this release config.
ValueDirectories []string `protobuf:"bytes,8,rep,name=value_directories,json=valueDirectories" json:"value_directories,omitempty"`
+ // The ReleaseConfigType of this release config.
+ ReleaseConfigType *ReleaseConfigType `protobuf:"varint,9,opt,name=release_config_type,json=releaseConfigType,enum=android.release_config_proto.ReleaseConfigType" json:"release_config_type,omitempty"`
+ // Whether to disallow this release config as TARGET_RELEASE.
+ // If true, this release config can only be inherited, it cannot be used
+ // directly in a build.
+ DisallowLunchUse *bool `protobuf:"varint,10,opt,name=disallow_lunch_use,json=disallowLunchUse" json:"disallow_lunch_use,omitempty"`
}
func (x *ReleaseConfigArtifact) Reset() {
@@ -325,6 +331,20 @@
return nil
}
+func (x *ReleaseConfigArtifact) GetReleaseConfigType() ReleaseConfigType {
+ if x != nil && x.ReleaseConfigType != nil {
+ return *x.ReleaseConfigType
+ }
+ return ReleaseConfigType_CONFIG_TYPE_UNSPECIFIED
+}
+
+func (x *ReleaseConfigArtifact) GetDisallowLunchUse() bool {
+ if x != nil && x.DisallowLunchUse != nil {
+ return *x.DisallowLunchUse
+ }
+ return false
+}
+
type ReleaseConfigsArtifact struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -399,89 +419,97 @@
0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x61,
0x67, 0x73, 0x5f, 0x73, 0x72, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x60, 0x0a, 0x0a,
- 0x74, 0x72, 0x61, 0x63, 0x65, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f,
+ 0x54, 0x72, 0x61, 0x63, 0x65, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f,
0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72,
0x63, 0x65, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0xc9, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c,
0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xe8,
- 0x01, 0x0a, 0x0d, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74,
- 0x12, 0x59, 0x0a, 0x10, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x61, 0x6e, 0x64,
- 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e,
- 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x64,
- 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x66, 0x6c, 0x61, 0x67,
- 0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x05, 0x76,
- 0x61, 0x6c, 0x75, 0x65, 0x18, 0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e,
- 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f,
- 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65,
- 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x40, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65,
- 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+ 0x6f, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xe6,
+ 0x01, 0x0a, 0x0c, 0x46, 0x6c, 0x61, 0x67, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12,
+ 0x58, 0x0a, 0x10, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x6e, 0x64, 0x72,
+ 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x6c, 0x61, 0x67, 0x44, 0x65, 0x63,
+ 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x66, 0x6c, 0x61, 0x67, 0x44, 0x65,
+ 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c,
+ 0x75, 0x65, 0x18, 0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e, 0x64, 0x72,
+ 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05,
+ 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x40, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x18,
+ 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e,
+ 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52,
+ 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x22, 0x61, 0x0a, 0x0d, 0x46, 0x6c, 0x61, 0x67, 0x41,
+ 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x12, 0x40, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67,
+ 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
- 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x70, 0x6f, 0x69, 0x6e,
- 0x74, 0x52, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x22, 0x63, 0x0a, 0x0e, 0x66, 0x6c, 0x61,
- 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x12, 0x41, 0x0a, 0x05, 0x66,
- 0x6c, 0x61, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x6e, 0x64,
- 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e,
- 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61,
- 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x52, 0x0e,
- 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x22, 0xdd,
- 0x02, 0x0a, 0x17, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
- 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
- 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f,
- 0x0a, 0x0b, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20,
- 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12,
- 0x41, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b,
- 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65,
- 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x66, 0x6c,
- 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x05, 0x66, 0x6c, 0x61,
- 0x67, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x76, 0x61,
- 0x6c, 0x75, 0x65, 0x5f, 0x73, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10,
- 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x65, 0x74, 0x73,
- 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03,
- 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x12, 0x20, 0x0a, 0x0b,
- 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28,
- 0x09, 0x52, 0x0b, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x12, 0x21,
- 0x0a, 0x0c, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x67, 0x65, 0x73, 0x18, 0x07,
- 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x67, 0x65,
- 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63,
- 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x76, 0x61,
- 0x6c, 0x75, 0x65, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x52, 0x0e,
- 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x22, 0xe8,
- 0x03, 0x0a, 0x18, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
- 0x67, 0x73, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x5c, 0x0a, 0x0e, 0x72,
- 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65,
- 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
- 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x0d, 0x72, 0x65, 0x6c, 0x65,
- 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x69, 0x0a, 0x15, 0x6f, 0x74, 0x68,
- 0x65, 0x72, 0x5f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
- 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f,
+ 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x6c, 0x61, 0x67, 0x41, 0x72, 0x74, 0x69, 0x66,
+ 0x61, 0x63, 0x74, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x52, 0x0e, 0x66, 0x6c, 0x61, 0x67,
+ 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x22, 0xe9, 0x03, 0x0a, 0x15, 0x52,
+ 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x41, 0x72, 0x74, 0x69,
+ 0x66, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x74, 0x68, 0x65,
+ 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6f,
+ 0x74, 0x68, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x05, 0x66, 0x6c, 0x61,
+ 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f,
0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
- 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f,
- 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52,
- 0x13, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e,
- 0x66, 0x69, 0x67, 0x73, 0x12, 0x87, 0x01, 0x0a, 0x17, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65,
- 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61, 0x70, 0x73, 0x5f, 0x6d, 0x61, 0x70,
- 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x50, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
- 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f,
- 0x6e, 0x66, 0x69, 0x67, 0x73, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x2e, 0x52,
+ 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x6c, 0x61, 0x67, 0x41, 0x72, 0x74, 0x69,
+ 0x66, 0x61, 0x63, 0x74, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x61,
+ 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x73, 0x65, 0x74,
+ 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+ 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x65, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x68,
+ 0x65, 0x72, 0x69, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x68,
+ 0x65, 0x72, 0x69, 0x74, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f,
+ 0x72, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x72, 0x65,
+ 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x69, 0x6f, 0x72,
+ 0x5f, 0x73, 0x74, 0x61, 0x67, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x70,
+ 0x72, 0x69, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x67, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18,
+ 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x44, 0x69, 0x72, 0x65,
+ 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x12, 0x5f, 0x0a, 0x13, 0x72, 0x65, 0x6c, 0x65, 0x61,
+ 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x09,
+ 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72,
+ 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+ 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f,
+ 0x6e, 0x66, 0x69, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x64, 0x69, 0x73, 0x61,
+ 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x6c, 0x75, 0x6e, 0x63, 0x68, 0x5f, 0x75, 0x73, 0x65, 0x18, 0x0a,
+ 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x64, 0x69, 0x73, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x75,
+ 0x6e, 0x63, 0x68, 0x55, 0x73, 0x65, 0x52, 0x0e, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74,
+ 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x22, 0xde, 0x03, 0x0a, 0x16, 0x52, 0x65, 0x6c, 0x65, 0x61,
+ 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63,
+ 0x74, 0x12, 0x5a, 0x0a, 0x0e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e,
+ 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x61, 0x6e, 0x64, 0x72,
+ 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65,
+ 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x0d,
+ 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x67, 0x0a,
+ 0x15, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x61,
+ 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65,
+ 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63,
+ 0x74, 0x52, 0x13, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x85, 0x01, 0x0a, 0x17, 0x72, 0x65, 0x6c, 0x65, 0x61,
+ 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61, 0x70, 0x73, 0x5f, 0x6d,
+ 0x61, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x4e, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f,
+ 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
+ 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x2e, 0x52,
0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x73,
0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73,
- 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x73, 0x4d, 0x61, 0x70, 0x1a, 0x79,
+ 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x73, 0x4d, 0x61, 0x70, 0x1a, 0x77,
0x0a, 0x19, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d,
0x61, 0x70, 0x73, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
- 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x46, 0x0a,
- 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x61,
+ 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x44, 0x0a,
+ 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x61,
0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63,
- 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x6c, 0x65,
- 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61, 0x70, 0x52, 0x05,
- 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64,
- 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61,
- 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73,
- 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65,
+ 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x52, 0x05, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64, 0x72, 0x6f,
+ 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65,
+ 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f,
+ 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
}
var (
@@ -498,32 +526,34 @@
var file_build_flags_out_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_build_flags_out_proto_goTypes = []interface{}{
- (*Tracepoint)(nil), // 0: android.release_config_proto.tracepoint
- (*FlagArtifact)(nil), // 1: android.release_config_proto.flag_artifact
- (*FlagArtifacts)(nil), // 2: android.release_config_proto.flag_artifacts
- (*ReleaseConfigArtifact)(nil), // 3: android.release_config_proto.release_config_artifact
- (*ReleaseConfigsArtifact)(nil), // 4: android.release_config_proto.release_configs_artifact
- nil, // 5: android.release_config_proto.release_configs_artifact.ReleaseConfigMapsMapEntry
- (*Value)(nil), // 6: android.release_config_proto.value
- (*FlagDeclaration)(nil), // 7: android.release_config_proto.flag_declaration
- (*ReleaseConfigMap)(nil), // 8: android.release_config_proto.release_config_map
+ (*Tracepoint)(nil), // 0: android.release_config_proto.Tracepoint
+ (*FlagArtifact)(nil), // 1: android.release_config_proto.FlagArtifact
+ (*FlagArtifacts)(nil), // 2: android.release_config_proto.FlagArtifacts
+ (*ReleaseConfigArtifact)(nil), // 3: android.release_config_proto.ReleaseConfigArtifact
+ (*ReleaseConfigsArtifact)(nil), // 4: android.release_config_proto.ReleaseConfigsArtifact
+ nil, // 5: android.release_config_proto.ReleaseConfigsArtifact.ReleaseConfigMapsMapEntry
+ (*Value)(nil), // 6: android.release_config_proto.Value
+ (*FlagDeclaration)(nil), // 7: android.release_config_proto.FlagDeclaration
+ (ReleaseConfigType)(0), // 8: android.release_config_proto.ReleaseConfigType
+ (*ReleaseConfigMap)(nil), // 9: android.release_config_proto.ReleaseConfigMap
}
var file_build_flags_out_proto_depIdxs = []int32{
- 6, // 0: android.release_config_proto.tracepoint.value:type_name -> android.release_config_proto.value
- 7, // 1: android.release_config_proto.flag_artifact.flag_declaration:type_name -> android.release_config_proto.flag_declaration
- 6, // 2: android.release_config_proto.flag_artifact.value:type_name -> android.release_config_proto.value
- 0, // 3: android.release_config_proto.flag_artifact.traces:type_name -> android.release_config_proto.tracepoint
- 1, // 4: android.release_config_proto.flag_artifacts.flags:type_name -> android.release_config_proto.flag_artifact
- 1, // 5: android.release_config_proto.release_config_artifact.flags:type_name -> android.release_config_proto.flag_artifact
- 3, // 6: android.release_config_proto.release_configs_artifact.release_config:type_name -> android.release_config_proto.release_config_artifact
- 3, // 7: android.release_config_proto.release_configs_artifact.other_release_configs:type_name -> android.release_config_proto.release_config_artifact
- 5, // 8: android.release_config_proto.release_configs_artifact.release_config_maps_map:type_name -> android.release_config_proto.release_configs_artifact.ReleaseConfigMapsMapEntry
- 8, // 9: android.release_config_proto.release_configs_artifact.ReleaseConfigMapsMapEntry.value:type_name -> android.release_config_proto.release_config_map
- 10, // [10:10] is the sub-list for method output_type
- 10, // [10:10] is the sub-list for method input_type
- 10, // [10:10] is the sub-list for extension type_name
- 10, // [10:10] is the sub-list for extension extendee
- 0, // [0:10] is the sub-list for field type_name
+ 6, // 0: android.release_config_proto.Tracepoint.value:type_name -> android.release_config_proto.Value
+ 7, // 1: android.release_config_proto.FlagArtifact.flag_declaration:type_name -> android.release_config_proto.FlagDeclaration
+ 6, // 2: android.release_config_proto.FlagArtifact.value:type_name -> android.release_config_proto.Value
+ 0, // 3: android.release_config_proto.FlagArtifact.traces:type_name -> android.release_config_proto.Tracepoint
+ 1, // 4: android.release_config_proto.FlagArtifacts.flags:type_name -> android.release_config_proto.FlagArtifact
+ 1, // 5: android.release_config_proto.ReleaseConfigArtifact.flags:type_name -> android.release_config_proto.FlagArtifact
+ 8, // 6: android.release_config_proto.ReleaseConfigArtifact.release_config_type:type_name -> android.release_config_proto.ReleaseConfigType
+ 3, // 7: android.release_config_proto.ReleaseConfigsArtifact.release_config:type_name -> android.release_config_proto.ReleaseConfigArtifact
+ 3, // 8: android.release_config_proto.ReleaseConfigsArtifact.other_release_configs:type_name -> android.release_config_proto.ReleaseConfigArtifact
+ 5, // 9: android.release_config_proto.ReleaseConfigsArtifact.release_config_maps_map:type_name -> android.release_config_proto.ReleaseConfigsArtifact.ReleaseConfigMapsMapEntry
+ 9, // 10: android.release_config_proto.ReleaseConfigsArtifact.ReleaseConfigMapsMapEntry.value:type_name -> android.release_config_proto.ReleaseConfigMap
+ 11, // [11:11] is the sub-list for method output_type
+ 11, // [11:11] is the sub-list for method input_type
+ 11, // [11:11] is the sub-list for extension type_name
+ 11, // [11:11] is the sub-list for extension extendee
+ 0, // [0:11] is the sub-list for field type_name
}
func init() { file_build_flags_out_proto_init() }
diff --git a/cmd/release_config/release_config_proto/build_flags_out.proto b/cmd/release_config/release_config_proto/build_flags_out.proto
index 4dc84e9..8b53464 100644
--- a/cmd/release_config/release_config_proto/build_flags_out.proto
+++ b/cmd/release_config/release_config_proto/build_flags_out.proto
@@ -39,30 +39,30 @@
// com.android.mypackage is a valid name while com.android.myPackage,
// com.android.1mypackage are invalid
-message tracepoint {
+message Tracepoint {
// Path to declaration or value file relative to $TOP
optional string source = 1;
- optional value value = 201;
+ optional Value value = 201;
}
-message flag_artifact {
+message FlagArtifact {
// The original declaration
- optional flag_declaration flag_declaration = 1;
+ optional FlagDeclaration flag_declaration = 1;
// Value for the flag
- optional value value = 201;
+ optional Value value = 201;
// Trace of where the flag value was assigned.
- repeated tracepoint traces = 8;
+ repeated Tracepoint traces = 8;
}
-message flag_artifacts {
+message FlagArtifacts {
// The artifacts
- repeated flag_artifact flags = 1;
+ repeated FlagArtifact flags = 1;
reserved "flag_artifacts";
}
-message release_config_artifact {
+message ReleaseConfigArtifact {
// The name of the release config.
// See # name for format detail
optional string name = 1;
@@ -72,7 +72,7 @@
// The complete set of build flags in this release config, after all
// inheritance and other processing is complete.
- repeated flag_artifact flags = 3;
+ repeated FlagArtifact flags = 3;
reserved "flag_artifacts";
// The (complete) list of aconfig_value_sets Soong modules to use.
@@ -96,16 +96,24 @@
// config. The listed directories contain at least a `release_config` message
// for this release config.
repeated string value_directories = 8;
+
+ // The ReleaseConfigType of this release config.
+ optional ReleaseConfigType release_config_type = 9;
+
+ // Whether to disallow this release config as TARGET_RELEASE.
+ // If true, this release config can only be inherited, it cannot be used
+ // directly in a build.
+ optional bool disallow_lunch_use = 10;
}
-message release_configs_artifact {
+message ReleaseConfigsArtifact {
// The active release config for this build.
- optional release_config_artifact release_config = 1;
+ optional ReleaseConfigArtifact release_config = 1;
// All other release configs defined for this TARGET_PRODUCT.
- repeated release_config_artifact other_release_configs = 2;
+ repeated ReleaseConfigArtifact other_release_configs = 2;
// Map of release_config_artifact.directories to release_config_map message.
- map<string, release_config_map> release_config_maps_map = 3;
+ map<string, ReleaseConfigMap> release_config_maps_map = 3;
}
diff --git a/cmd/release_config/release_config_proto/build_flags_src.pb.go b/cmd/release_config/release_config_proto/build_flags_src.pb.go
index bc5f5c0..9fc4ea4 100644
--- a/cmd/release_config/release_config_proto/build_flags_src.pb.go
+++ b/cmd/release_config/release_config_proto/build_flags_src.pb.go
@@ -15,7 +15,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.33.0
+// protoc-gen-go v1.30.0
// protoc v3.21.12
// source: build_flags_src.proto
@@ -35,6 +35,76 @@
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
+type ReleaseConfigType int32
+
+const (
+ // This is treated as `RELEASE_CONFIG`.
+ ReleaseConfigType_CONFIG_TYPE_UNSPECIFIED ReleaseConfigType = 0
+ // This is a normal release config. This is the only ReleaseConfigType with
+ // implicit inheritance.
+ ReleaseConfigType_RELEASE_CONFIG ReleaseConfigType = 1
+ // Same as RELEASE_CONFIG, except no implicit inheritance happens.
+ // This is the "root" release config.
+ ReleaseConfigType_EXPLICIT_INHERITANCE_CONFIG ReleaseConfigType = 2
+ // This is a release config applied based on the TARGET_BUILD_VARIANT
+ // environment variable, if the build flag RELEASE_BUILD_USE_VARIANT_FLAGS is
+ // enabled.
+ ReleaseConfigType_BUILD_VARIANT ReleaseConfigType = 3
+)
+
+// Enum value maps for ReleaseConfigType.
+var (
+ ReleaseConfigType_name = map[int32]string{
+ 0: "CONFIG_TYPE_UNSPECIFIED",
+ 1: "RELEASE_CONFIG",
+ 2: "EXPLICIT_INHERITANCE_CONFIG",
+ 3: "BUILD_VARIANT",
+ }
+ ReleaseConfigType_value = map[string]int32{
+ "CONFIG_TYPE_UNSPECIFIED": 0,
+ "RELEASE_CONFIG": 1,
+ "EXPLICIT_INHERITANCE_CONFIG": 2,
+ "BUILD_VARIANT": 3,
+ }
+)
+
+func (x ReleaseConfigType) Enum() *ReleaseConfigType {
+ p := new(ReleaseConfigType)
+ *p = x
+ return p
+}
+
+func (x ReleaseConfigType) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ReleaseConfigType) Descriptor() protoreflect.EnumDescriptor {
+ return file_build_flags_src_proto_enumTypes[0].Descriptor()
+}
+
+func (ReleaseConfigType) Type() protoreflect.EnumType {
+ return &file_build_flags_src_proto_enumTypes[0]
+}
+
+func (x ReleaseConfigType) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *ReleaseConfigType) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = ReleaseConfigType(num)
+ return nil
+}
+
+// Deprecated: Use ReleaseConfigType.Descriptor instead.
+func (ReleaseConfigType) EnumDescriptor() ([]byte, []int) {
+ return file_build_flags_src_proto_rawDescGZIP(), []int{0}
+}
+
type Value struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -159,6 +229,8 @@
Namespace *string `protobuf:"bytes,2,opt,name=namespace" json:"namespace,omitempty"`
// Text description of the flag's purpose.
Description *string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"`
+ // The bug number associated with the flag.
+ Bugs []string `protobuf:"bytes,4,rep,name=bugs" json:"bugs,omitempty"`
// Value for the flag
Value *Value `protobuf:"bytes,201,opt,name=value" json:"value,omitempty"`
// Workflow for this flag.
@@ -221,6 +293,13 @@
return ""
}
+func (x *FlagDeclaration) GetBugs() []string {
+ if x != nil {
+ return x.Bugs
+ }
+ return nil
+}
+
func (x *FlagDeclaration) GetValue() *Value {
if x != nil {
return x.Value
@@ -232,7 +311,7 @@
if x != nil && x.Workflow != nil {
return *x.Workflow
}
- return Workflow_Workflow_Unspecified
+ return Workflow_WORKFLOW_UNSPECIFIED
}
func (x *FlagDeclaration) GetContainers() []string {
@@ -329,6 +408,12 @@
// Prior stage(s) for flag advancement (during development).
// Once a flag has met criteria in a prior stage, it can advance to this one.
PriorStages []string `protobuf:"bytes,5,rep,name=prior_stages,json=priorStages" json:"prior_stages,omitempty"`
+ // The ReleaseConfigType of this release config.
+ ReleaseConfigType *ReleaseConfigType `protobuf:"varint,6,opt,name=release_config_type,json=releaseConfigType,enum=android.release_config_proto.ReleaseConfigType" json:"release_config_type,omitempty"`
+ // Whether to disallow this release config as TARGET_RELEASE.
+ // If true, this release config can only be inherited, it cannot be used
+ // directly in a build.
+ DisallowLunchUse *bool `protobuf:"varint,7,opt,name=disallow_lunch_use,json=disallowLunchUse" json:"disallow_lunch_use,omitempty"`
}
func (x *ReleaseConfig) Reset() {
@@ -398,6 +483,20 @@
return nil
}
+func (x *ReleaseConfig) GetReleaseConfigType() ReleaseConfigType {
+ if x != nil && x.ReleaseConfigType != nil {
+ return *x.ReleaseConfigType
+ }
+ return ReleaseConfigType_CONFIG_TYPE_UNSPECIFIED
+}
+
+func (x *ReleaseConfig) GetDisallowLunchUse() bool {
+ if x != nil && x.DisallowLunchUse != nil {
+ return *x.DisallowLunchUse
+ }
+ return false
+}
+
// Any aliases. These are used for continuous integration builder config.
type ReleaseAlias struct {
state protoimpl.MessageState
@@ -531,7 +630,7 @@
0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x61,
0x67, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
- 0xa5, 0x01, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2e, 0x0a, 0x11, 0x75, 0x6e, 0x73,
+ 0xa5, 0x01, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2e, 0x0a, 0x11, 0x75, 0x6e, 0x73,
0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0xc8,
0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x10, 0x75, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x69,
0x66, 0x69, 0x65, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x24, 0x0a, 0x0c, 0x73, 0x74, 0x72,
@@ -541,59 +640,76 @@
0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75,
0x65, 0x12, 0x1d, 0x0a, 0x08, 0x6f, 0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x18, 0xcb, 0x01,
0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x08, 0x6f, 0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65,
- 0x42, 0x05, 0x0a, 0x03, 0x76, 0x61, 0x6c, 0x22, 0x96, 0x02, 0x0a, 0x10, 0x66, 0x6c, 0x61, 0x67,
- 0x5f, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04,
- 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
- 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x20,
- 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20,
+ 0x42, 0x05, 0x0a, 0x03, 0x76, 0x61, 0x6c, 0x22, 0xa3, 0x02, 0x0a, 0x0f, 0x46, 0x6c, 0x61, 0x67,
+ 0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e,
+ 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
+ 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a,
+ 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12,
+ 0x12, 0x0a, 0x04, 0x62, 0x75, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x62,
+ 0x75, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0xc9, 0x01, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65,
+ 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12,
+ 0x43, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0xcd, 0x01, 0x20, 0x01,
+ 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c,
+ 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b,
+ 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x1f, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
+ 0x72, 0x73, 0x18, 0xce, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61,
+ 0x69, 0x6e, 0x65, 0x72, 0x73, 0x4a, 0x06, 0x08, 0xcf, 0x01, 0x10, 0xd0, 0x01, 0x22, 0x78, 0x0a,
+ 0x09, 0x46, 0x6c, 0x61, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
+ 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a,
+ 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23,
+ 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65,
+ 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x61,
+ 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1b, 0x0a, 0x08, 0x72, 0x65,
+ 0x64, 0x61, 0x63, 0x74, 0x65, 0x64, 0x18, 0xca, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72,
+ 0x65, 0x64, 0x61, 0x63, 0x74, 0x65, 0x64, 0x22, 0xcd, 0x02, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x65,
+ 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
+ 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a,
+ 0x08, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
+ 0x08, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x61, 0x63, 0x6f,
+ 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x73, 0x65, 0x74, 0x73, 0x18,
+ 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x61,
+ 0x6c, 0x75, 0x65, 0x53, 0x65, 0x74, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x61, 0x63, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x04, 0x20,
+ 0x01, 0x28, 0x08, 0x52, 0x10, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x6c, 0x61, 0x67,
+ 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x5f, 0x73,
+ 0x74, 0x61, 0x67, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x69,
+ 0x6f, 0x72, 0x53, 0x74, 0x61, 0x67, 0x65, 0x73, 0x12, 0x5f, 0x0a, 0x13, 0x72, 0x65, 0x6c, 0x65,
+ 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
+ 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e,
+ 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x64, 0x69, 0x73,
+ 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x6c, 0x75, 0x6e, 0x63, 0x68, 0x5f, 0x75, 0x73, 0x65, 0x18,
+ 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x64, 0x69, 0x73, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x4c,
+ 0x75, 0x6e, 0x63, 0x68, 0x55, 0x73, 0x65, 0x22, 0x3a, 0x0a, 0x0c, 0x52, 0x65, 0x6c, 0x65, 0x61,
+ 0x73, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74,
+ 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72,
+ 0x67, 0x65, 0x74, 0x22, 0xa9, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x12, 0x44, 0x0a, 0x07, 0x61, 0x6c, 0x69, 0x61,
+ 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x6e, 0x64, 0x72,
+ 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65,
+ 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0x20,
+ 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
- 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x23, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61,
- 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
- 0x76, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x43, 0x0a, 0x08,
- 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0xcd, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,
- 0x26, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73,
- 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x77,
- 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
- 0x77, 0x12, 0x1f, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18,
- 0xce, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
- 0x72, 0x73, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x06, 0x08, 0xcf, 0x01, 0x10, 0xd0, 0x01,
- 0x22, 0x79, 0x0a, 0x0a, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12,
- 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
- 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0xc9, 0x01, 0x20, 0x01,
- 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c,
- 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1b,
- 0x0a, 0x08, 0x72, 0x65, 0x64, 0x61, 0x63, 0x74, 0x65, 0x64, 0x18, 0xca, 0x01, 0x20, 0x01, 0x28,
- 0x08, 0x52, 0x08, 0x72, 0x65, 0x64, 0x61, 0x63, 0x74, 0x65, 0x64, 0x22, 0xbf, 0x01, 0x0a, 0x0e,
- 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12,
- 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
- 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x18, 0x02,
- 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x12, 0x2c,
- 0x0a, 0x12, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f,
- 0x73, 0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x61, 0x63, 0x6f, 0x6e,
- 0x66, 0x69, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x65, 0x74, 0x73, 0x12, 0x2c, 0x0a, 0x12,
- 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x5f, 0x6f, 0x6e,
- 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69,
- 0x67, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72,
- 0x69, 0x6f, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x67, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09,
- 0x52, 0x0b, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x67, 0x65, 0x73, 0x22, 0x3b, 0x0a,
- 0x0d, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x12,
- 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
- 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0xac, 0x01, 0x0a, 0x12, 0x72,
- 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61,
- 0x70, 0x12, 0x45, 0x0a, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03,
- 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c,
- 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x52,
- 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63,
- 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64,
- 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x12, 0x64, 0x65,
- 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73,
- 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43,
- 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x42, 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64,
+ 0x12, 0x2d, 0x0a, 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74,
+ 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x64, 0x65,
+ 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2a,
+ 0x78, 0x0a, 0x11, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+ 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x54,
+ 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10,
+ 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x5f, 0x43, 0x4f, 0x4e,
+ 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x1f, 0x0a, 0x1b, 0x45, 0x58, 0x50, 0x4c, 0x49, 0x43, 0x49,
+ 0x54, 0x5f, 0x49, 0x4e, 0x48, 0x45, 0x52, 0x49, 0x54, 0x41, 0x4e, 0x43, 0x45, 0x5f, 0x43, 0x4f,
+ 0x4e, 0x46, 0x49, 0x47, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x42, 0x55, 0x49, 0x4c, 0x44, 0x5f,
+ 0x56, 0x41, 0x52, 0x49, 0x41, 0x4e, 0x54, 0x10, 0x03, 0x42, 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64,
0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61,
0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73,
0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
@@ -611,26 +727,29 @@
return file_build_flags_src_proto_rawDescData
}
+var file_build_flags_src_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_build_flags_src_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_build_flags_src_proto_goTypes = []interface{}{
- (*Value)(nil), // 0: android.release_config_proto.value
- (*FlagDeclaration)(nil), // 1: android.release_config_proto.flag_declaration
- (*FlagValue)(nil), // 2: android.release_config_proto.flag_value
- (*ReleaseConfig)(nil), // 3: android.release_config_proto.release_config
- (*ReleaseAlias)(nil), // 4: android.release_config_proto.release_alias
- (*ReleaseConfigMap)(nil), // 5: android.release_config_proto.release_config_map
- (Workflow)(0), // 6: android.release_config_proto.workflow
+ (ReleaseConfigType)(0), // 0: android.release_config_proto.ReleaseConfigType
+ (*Value)(nil), // 1: android.release_config_proto.Value
+ (*FlagDeclaration)(nil), // 2: android.release_config_proto.FlagDeclaration
+ (*FlagValue)(nil), // 3: android.release_config_proto.FlagValue
+ (*ReleaseConfig)(nil), // 4: android.release_config_proto.ReleaseConfig
+ (*ReleaseAlias)(nil), // 5: android.release_config_proto.ReleaseAlias
+ (*ReleaseConfigMap)(nil), // 6: android.release_config_proto.ReleaseConfigMap
+ (Workflow)(0), // 7: android.release_config_proto.Workflow
}
var file_build_flags_src_proto_depIdxs = []int32{
- 0, // 0: android.release_config_proto.flag_declaration.value:type_name -> android.release_config_proto.value
- 6, // 1: android.release_config_proto.flag_declaration.workflow:type_name -> android.release_config_proto.workflow
- 0, // 2: android.release_config_proto.flag_value.value:type_name -> android.release_config_proto.value
- 4, // 3: android.release_config_proto.release_config_map.aliases:type_name -> android.release_config_proto.release_alias
- 4, // [4:4] is the sub-list for method output_type
- 4, // [4:4] is the sub-list for method input_type
- 4, // [4:4] is the sub-list for extension type_name
- 4, // [4:4] is the sub-list for extension extendee
- 0, // [0:4] is the sub-list for field type_name
+ 1, // 0: android.release_config_proto.FlagDeclaration.value:type_name -> android.release_config_proto.Value
+ 7, // 1: android.release_config_proto.FlagDeclaration.workflow:type_name -> android.release_config_proto.Workflow
+ 1, // 2: android.release_config_proto.FlagValue.value:type_name -> android.release_config_proto.Value
+ 0, // 3: android.release_config_proto.ReleaseConfig.release_config_type:type_name -> android.release_config_proto.ReleaseConfigType
+ 5, // 4: android.release_config_proto.ReleaseConfigMap.aliases:type_name -> android.release_config_proto.ReleaseAlias
+ 5, // [5:5] is the sub-list for method output_type
+ 5, // [5:5] is the sub-list for method input_type
+ 5, // [5:5] is the sub-list for extension type_name
+ 5, // [5:5] is the sub-list for extension extendee
+ 0, // [0:5] is the sub-list for field type_name
}
func init() { file_build_flags_src_proto_init() }
@@ -724,13 +843,14 @@
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_build_flags_src_proto_rawDesc,
- NumEnums: 0,
+ NumEnums: 1,
NumMessages: 6,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_build_flags_src_proto_goTypes,
DependencyIndexes: file_build_flags_src_proto_depIdxs,
+ EnumInfos: file_build_flags_src_proto_enumTypes,
MessageInfos: file_build_flags_src_proto_msgTypes,
}.Build()
File_build_flags_src_proto = out.File
diff --git a/cmd/release_config/release_config_proto/build_flags_src.proto b/cmd/release_config/release_config_proto/build_flags_src.proto
index 4fad478..2cc1a84 100644
--- a/cmd/release_config/release_config_proto/build_flags_src.proto
+++ b/cmd/release_config/release_config_proto/build_flags_src.proto
@@ -44,7 +44,7 @@
// com.android.mypackage is a valid name while com.android.myPackage,
// com.android.1mypackage are invalid
-message value {
+message Value {
oneof val {
bool unspecified_value = 200;
string string_value = 201;
@@ -55,7 +55,7 @@
}
// The proto used in the source tree.
-message flag_declaration {
+message FlagDeclaration {
// The name of the flag.
// See # name for format detail
optional string name = 1;
@@ -67,14 +67,14 @@
// Text description of the flag's purpose.
optional string description = 3;
- // reserve this for bug, if needed.
- reserved 4;
+ // The bug number associated with the flag.
+ repeated string bugs = 4;
// Value for the flag
- optional value value = 201;
+ optional Value value = 201;
// Workflow for this flag.
- optional workflow workflow = 205;
+ optional Workflow workflow = 205;
// The container for this flag. This overrides any default container given
// in the release_config_map message.
@@ -85,21 +85,39 @@
reserved 207;
}
-message flag_value {
+message FlagValue {
// Name of the flag.
// See # name for format detail
optional string name = 2;
// Value for the flag
- optional value value = 201;
+ optional Value value = 201;
// If true, the flag is completely removed from the release config as if
// never declared.
optional bool redacted = 202;
}
+enum ReleaseConfigType {
+ // This is treated as `RELEASE_CONFIG`.
+ CONFIG_TYPE_UNSPECIFIED = 0;
+
+ // This is a normal release config. This is the only ReleaseConfigType with
+ // implicit inheritance.
+ RELEASE_CONFIG = 1;
+
+ // Same as RELEASE_CONFIG, except no implicit inheritance happens.
+ // This is the "root" release config.
+ EXPLICIT_INHERITANCE_CONFIG = 2;
+
+ // This is a release config applied based on the TARGET_BUILD_VARIANT
+ // environment variable, if the build flag RELEASE_BUILD_USE_VARIANT_FLAGS is
+ // enabled.
+ BUILD_VARIANT = 3;
+}
+
// This replaces $(call declare-release-config).
-message release_config {
+message ReleaseConfig {
// The name of the release config.
// See # name for format detail
optional string name = 1;
@@ -117,10 +135,18 @@
// Prior stage(s) for flag advancement (during development).
// Once a flag has met criteria in a prior stage, it can advance to this one.
repeated string prior_stages = 5;
+
+ // The ReleaseConfigType of this release config.
+ optional ReleaseConfigType release_config_type = 6;
+
+ // Whether to disallow this release config as TARGET_RELEASE.
+ // If true, this release config can only be inherited, it cannot be used
+ // directly in a build.
+ optional bool disallow_lunch_use = 7;
}
// Any aliases. These are used for continuous integration builder config.
-message release_alias {
+message ReleaseAlias {
// The name of the alias.
optional string name = 1;
@@ -129,9 +155,9 @@
}
// This provides the data from release_config_map.mk
-message release_config_map {
+message ReleaseConfigMap {
// Any aliases.
- repeated release_alias aliases = 1;
+ repeated ReleaseAlias aliases = 1;
// Description of this map and its intended use.
optional string description = 2;
diff --git a/cmd/release_config/release_config_proto/regen.sh b/cmd/release_config/release_config_proto/regen.sh
old mode 100644
new mode 100755
index 23e3115..a92bfc0
--- a/cmd/release_config/release_config_proto/regen.sh
+++ b/cmd/release_config/release_config_proto/regen.sh
@@ -1,3 +1,3 @@
#!/bin/bash
-aprotoc --go_out=paths=source_relative:. build_flags_src.proto build_flags_out.proto build_flags_common.proto build_flags_declarations.proto
+aprotoc --go_out=paths=source_relative:. build_flags_src.proto build_flags_out.proto build_flags_common.proto build_flags_declarations.proto release_configs_contributions.proto
diff --git a/cmd/release_config/release_config_proto/release_configs_contributions.pb.go b/cmd/release_config/release_config_proto/release_configs_contributions.pb.go
new file mode 100644
index 0000000..339e4ba
--- /dev/null
+++ b/cmd/release_config/release_config_proto/release_configs_contributions.pb.go
@@ -0,0 +1,252 @@
+//
+// Copyright (C) 2025 The Android Open-Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.30.0
+// protoc v3.21.12
+// source: release_configs_contributions.proto
+
+package release_config_proto
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type ReleaseConfigContributionsArtifact struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of the release config.
+ Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+ // The release config contribution directories that may contribute to this
+ // release config.
+ ContributingDirectories []string `protobuf:"bytes,2,rep,name=contributing_directories,json=contributingDirectories" json:"contributing_directories,omitempty"`
+}
+
+func (x *ReleaseConfigContributionsArtifact) Reset() {
+ *x = ReleaseConfigContributionsArtifact{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_release_configs_contributions_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ReleaseConfigContributionsArtifact) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReleaseConfigContributionsArtifact) ProtoMessage() {}
+
+func (x *ReleaseConfigContributionsArtifact) ProtoReflect() protoreflect.Message {
+ mi := &file_release_configs_contributions_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReleaseConfigContributionsArtifact.ProtoReflect.Descriptor instead.
+func (*ReleaseConfigContributionsArtifact) Descriptor() ([]byte, []int) {
+ return file_release_configs_contributions_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *ReleaseConfigContributionsArtifact) GetName() string {
+ if x != nil && x.Name != nil {
+ return *x.Name
+ }
+ return ""
+}
+
+func (x *ReleaseConfigContributionsArtifact) GetContributingDirectories() []string {
+ if x != nil {
+ return x.ContributingDirectories
+ }
+ return nil
+}
+
+type ReleaseConfigContributionsArtifacts struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The artifacts
+ ReleaseConfigContributionsArtifactList []*ReleaseConfigContributionsArtifact `protobuf:"bytes,1,rep,name=release_config_contributions_artifact_list,json=releaseConfigContributionsArtifactList" json:"release_config_contributions_artifact_list,omitempty"`
+}
+
+func (x *ReleaseConfigContributionsArtifacts) Reset() {
+ *x = ReleaseConfigContributionsArtifacts{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_release_configs_contributions_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ReleaseConfigContributionsArtifacts) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReleaseConfigContributionsArtifacts) ProtoMessage() {}
+
+func (x *ReleaseConfigContributionsArtifacts) ProtoReflect() protoreflect.Message {
+ mi := &file_release_configs_contributions_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReleaseConfigContributionsArtifacts.ProtoReflect.Descriptor instead.
+func (*ReleaseConfigContributionsArtifacts) Descriptor() ([]byte, []int) {
+ return file_release_configs_contributions_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *ReleaseConfigContributionsArtifacts) GetReleaseConfigContributionsArtifactList() []*ReleaseConfigContributionsArtifact {
+ if x != nil {
+ return x.ReleaseConfigContributionsArtifactList
+ }
+ return nil
+}
+
+var File_release_configs_contributions_proto protoreflect.FileDescriptor
+
+var file_release_configs_contributions_proto_rawDesc = []byte{
+ 0x0a, 0x23, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+ 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72,
+ 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x22, 0x73, 0x0a, 0x22, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f,
+ 0x6e, 0x66, 0x69, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
+ 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x39, 0x0a,
+ 0x18, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x69,
+ 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
+ 0x17, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x72,
+ 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x22, 0xc4, 0x01, 0x0a, 0x23, 0x52, 0x65, 0x6c,
+ 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x69,
+ 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73,
+ 0x12, 0x9c, 0x01, 0x0a, 0x2a, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e,
+ 0x66, 0x69, 0x67, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18,
+ 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e,
+ 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x41,
+ 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x26, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65,
+ 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x42,
+ 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67,
+ 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f,
+ 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f,
+}
+
+var (
+ file_release_configs_contributions_proto_rawDescOnce sync.Once
+ file_release_configs_contributions_proto_rawDescData = file_release_configs_contributions_proto_rawDesc
+)
+
+func file_release_configs_contributions_proto_rawDescGZIP() []byte {
+ file_release_configs_contributions_proto_rawDescOnce.Do(func() {
+ file_release_configs_contributions_proto_rawDescData = protoimpl.X.CompressGZIP(file_release_configs_contributions_proto_rawDescData)
+ })
+ return file_release_configs_contributions_proto_rawDescData
+}
+
+var file_release_configs_contributions_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_release_configs_contributions_proto_goTypes = []interface{}{
+ (*ReleaseConfigContributionsArtifact)(nil), // 0: android.release_config_proto.ReleaseConfigContributionsArtifact
+ (*ReleaseConfigContributionsArtifacts)(nil), // 1: android.release_config_proto.ReleaseConfigContributionsArtifacts
+}
+var file_release_configs_contributions_proto_depIdxs = []int32{
+ 0, // 0: android.release_config_proto.ReleaseConfigContributionsArtifacts.release_config_contributions_artifact_list:type_name -> android.release_config_proto.ReleaseConfigContributionsArtifact
+ 1, // [1:1] is the sub-list for method output_type
+ 1, // [1:1] is the sub-list for method input_type
+ 1, // [1:1] is the sub-list for extension type_name
+ 1, // [1:1] is the sub-list for extension extendee
+ 0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_release_configs_contributions_proto_init() }
+func file_release_configs_contributions_proto_init() {
+ if File_release_configs_contributions_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_release_configs_contributions_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ReleaseConfigContributionsArtifact); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_release_configs_contributions_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ReleaseConfigContributionsArtifacts); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_release_configs_contributions_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 2,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_release_configs_contributions_proto_goTypes,
+ DependencyIndexes: file_release_configs_contributions_proto_depIdxs,
+ MessageInfos: file_release_configs_contributions_proto_msgTypes,
+ }.Build()
+ File_release_configs_contributions_proto = out.File
+ file_release_configs_contributions_proto_rawDesc = nil
+ file_release_configs_contributions_proto_goTypes = nil
+ file_release_configs_contributions_proto_depIdxs = nil
+}
diff --git a/cmd/release_config/release_config_proto/release_configs_contributions.proto b/cmd/release_config/release_config_proto/release_configs_contributions.proto
new file mode 100644
index 0000000..bc7aeda
--- /dev/null
+++ b/cmd/release_config/release_config_proto/release_configs_contributions.proto
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2025 The Android Open-Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto2";
+package android.release_config_proto;
+option go_package = "android/soong/release_config/release_config_proto";
+
+message ReleaseConfigContributionsArtifact {
+ // The name of the release config.
+ optional string name = 1;
+
+ // The release config contribution directories that may contribute to this
+ // release config.
+ repeated string contributing_directories = 2;
+}
+
+message ReleaseConfigContributionsArtifacts {
+ // The artifacts
+ repeated ReleaseConfigContributionsArtifact release_config_contributions_artifact_list = 1;
+}
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index e69a930..f3931a4 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -27,6 +27,7 @@
"os"
"os/exec"
"path/filepath"
+ "regexp"
"strconv"
"strings"
"time"
@@ -51,6 +52,8 @@
sandboxDirPlaceholder = "__SBOX_SANDBOX_DIR__"
)
+var envVarNameRegex = regexp.MustCompile("^[a-zA-Z0-9_-]+$")
+
func init() {
flag.StringVar(&sandboxesRoot, "sandbox-path", "",
"root of temp directory to put the sandbox into")
@@ -238,6 +241,51 @@
return &manifest, nil
}
+func createEnv(command *sbox_proto.Command) ([]string, error) {
+ env := []string{}
+ if command.DontInheritEnv == nil || !*command.DontInheritEnv {
+ env = os.Environ()
+ }
+ for _, envVar := range command.Env {
+ if envVar.Name == nil || !envVarNameRegex.MatchString(*envVar.Name) {
+ name := "nil"
+ if envVar.Name != nil {
+ name = *envVar.Name
+ }
+ return nil, fmt.Errorf("Invalid environment variable name: %q", name)
+ }
+ if envVar.State == nil {
+ return nil, fmt.Errorf("Must set state")
+ }
+ switch state := envVar.State.(type) {
+ case *sbox_proto.EnvironmentVariable_Value:
+ env = append(env, *envVar.Name+"="+state.Value)
+ case *sbox_proto.EnvironmentVariable_Unset:
+ if !state.Unset {
+ return nil, fmt.Errorf("Can't have unset set to false")
+ }
+ prefix := *envVar.Name + "="
+ for i := 0; i < len(env); i++ {
+ if strings.HasPrefix(env[i], prefix) {
+ env = append(env[:i], env[i+1:]...)
+ i--
+ }
+ }
+ case *sbox_proto.EnvironmentVariable_Inherit:
+ if !state.Inherit {
+ return nil, fmt.Errorf("Can't have inherit set to false")
+ }
+ val, ok := os.LookupEnv(*envVar.Name)
+ if ok {
+ env = append(env, *envVar.Name+"="+val)
+ }
+ default:
+ return nil, fmt.Errorf("Unhandled state type")
+ }
+ }
+ return env, nil
+}
+
// runCommand runs a single command from a manifest. If the command references the
// __SBOX_DEPFILE__ placeholder it returns the name of the depfile that was used.
func runCommand(command *sbox_proto.Command, tempDir string, commandIndex int) (depFile string, err error) {
@@ -313,6 +361,12 @@
return "", fmt.Errorf("Failed to update PATH: %w", err)
}
}
+
+ cmd.Env, err = createEnv(command)
+ if err != nil {
+ return "", err
+ }
+
err = cmd.Run()
if err != nil {
diff --git a/cmd/sbox/sbox_proto/sbox.pb.go b/cmd/sbox/sbox_proto/sbox.pb.go
index 7c84f2c..271039c 100644
--- a/cmd/sbox/sbox_proto/sbox.pb.go
+++ b/cmd/sbox/sbox_proto/sbox.pb.go
@@ -14,8 +14,8 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.26.0
-// protoc v3.9.1
+// protoc-gen-go v1.33.0
+// protoc v3.21.12
// source: sbox.proto
package sbox_proto
@@ -116,6 +116,13 @@
// A list of files that will be copied before the sandboxed command, and whose contents should be
// copied as if they were listed in copy_before.
RspFiles []*RspFile `protobuf:"bytes,6,rep,name=rsp_files,json=rspFiles" json:"rsp_files,omitempty"`
+ // The environment variables that will be set or unset while running the command.
+ // Also see dont_inherit_env.
+ Env []*EnvironmentVariable `protobuf:"bytes,7,rep,name=env" json:"env,omitempty"`
+ // By default, all environment variables are inherited from the calling process, but may be
+ // replaced or unset by env. If dont_inherit_env is set, no environment variables will be
+ // inherited, and instead only the variables in env will be defined.
+ DontInheritEnv *bool `protobuf:"varint,8,opt,name=dont_inherit_env,json=dontInheritEnv" json:"dont_inherit_env,omitempty"`
}
func (x *Command) Reset() {
@@ -192,6 +199,129 @@
return nil
}
+func (x *Command) GetEnv() []*EnvironmentVariable {
+ if x != nil {
+ return x.Env
+ }
+ return nil
+}
+
+func (x *Command) GetDontInheritEnv() bool {
+ if x != nil && x.DontInheritEnv != nil {
+ return *x.DontInheritEnv
+ }
+ return false
+}
+
+type EnvironmentVariable struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of the environment variable
+ Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"`
+ // Types that are assignable to State:
+ //
+ // *EnvironmentVariable_Value
+ // *EnvironmentVariable_Unset
+ // *EnvironmentVariable_Inherit
+ State isEnvironmentVariable_State `protobuf_oneof:"state"`
+}
+
+func (x *EnvironmentVariable) Reset() {
+ *x = EnvironmentVariable{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_sbox_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *EnvironmentVariable) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EnvironmentVariable) ProtoMessage() {}
+
+func (x *EnvironmentVariable) ProtoReflect() protoreflect.Message {
+ mi := &file_sbox_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use EnvironmentVariable.ProtoReflect.Descriptor instead.
+func (*EnvironmentVariable) Descriptor() ([]byte, []int) {
+ return file_sbox_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *EnvironmentVariable) GetName() string {
+ if x != nil && x.Name != nil {
+ return *x.Name
+ }
+ return ""
+}
+
+func (m *EnvironmentVariable) GetState() isEnvironmentVariable_State {
+ if m != nil {
+ return m.State
+ }
+ return nil
+}
+
+func (x *EnvironmentVariable) GetValue() string {
+ if x, ok := x.GetState().(*EnvironmentVariable_Value); ok {
+ return x.Value
+ }
+ return ""
+}
+
+func (x *EnvironmentVariable) GetUnset() bool {
+ if x, ok := x.GetState().(*EnvironmentVariable_Unset); ok {
+ return x.Unset
+ }
+ return false
+}
+
+func (x *EnvironmentVariable) GetInherit() bool {
+ if x, ok := x.GetState().(*EnvironmentVariable_Inherit); ok {
+ return x.Inherit
+ }
+ return false
+}
+
+type isEnvironmentVariable_State interface {
+ isEnvironmentVariable_State()
+}
+
+type EnvironmentVariable_Value struct {
+ // The value to set the environment variable to.
+ Value string `protobuf:"bytes,2,opt,name=value,oneof"`
+}
+
+type EnvironmentVariable_Unset struct {
+ // This environment variable should be unset in the command.
+ Unset bool `protobuf:"varint,3,opt,name=unset,oneof"`
+}
+
+type EnvironmentVariable_Inherit struct {
+ // This environment variable should be inherited from the parent process.
+ // Can be combined with dont_inherit_env to only inherit certain environment
+ // variables.
+ Inherit bool `protobuf:"varint,4,opt,name=inherit,oneof"`
+}
+
+func (*EnvironmentVariable_Value) isEnvironmentVariable_State() {}
+
+func (*EnvironmentVariable_Unset) isEnvironmentVariable_State() {}
+
+func (*EnvironmentVariable_Inherit) isEnvironmentVariable_State() {}
+
// Copy describes a from-to pair of files to copy. The paths may be relative, the root that they
// are relative to is specific to the context the Copy is used in and will be different for
// from and to.
@@ -209,7 +339,7 @@
func (x *Copy) Reset() {
*x = Copy{}
if protoimpl.UnsafeEnabled {
- mi := &file_sbox_proto_msgTypes[2]
+ mi := &file_sbox_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -222,7 +352,7 @@
func (*Copy) ProtoMessage() {}
func (x *Copy) ProtoReflect() protoreflect.Message {
- mi := &file_sbox_proto_msgTypes[2]
+ mi := &file_sbox_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -235,7 +365,7 @@
// Deprecated: Use Copy.ProtoReflect.Descriptor instead.
func (*Copy) Descriptor() ([]byte, []int) {
- return file_sbox_proto_rawDescGZIP(), []int{2}
+ return file_sbox_proto_rawDescGZIP(), []int{3}
}
func (x *Copy) GetFrom() string {
@@ -274,7 +404,7 @@
func (x *RspFile) Reset() {
*x = RspFile{}
if protoimpl.UnsafeEnabled {
- mi := &file_sbox_proto_msgTypes[3]
+ mi := &file_sbox_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -287,7 +417,7 @@
func (*RspFile) ProtoMessage() {}
func (x *RspFile) ProtoReflect() protoreflect.Message {
- mi := &file_sbox_proto_msgTypes[3]
+ mi := &file_sbox_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -300,7 +430,7 @@
// Deprecated: Use RspFile.ProtoReflect.Descriptor instead.
func (*RspFile) Descriptor() ([]byte, []int) {
- return file_sbox_proto_rawDescGZIP(), []int{3}
+ return file_sbox_proto_rawDescGZIP(), []int{4}
}
func (x *RspFile) GetFile() string {
@@ -330,7 +460,7 @@
func (x *PathMapping) Reset() {
*x = PathMapping{}
if protoimpl.UnsafeEnabled {
- mi := &file_sbox_proto_msgTypes[4]
+ mi := &file_sbox_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -343,7 +473,7 @@
func (*PathMapping) ProtoMessage() {}
func (x *PathMapping) ProtoReflect() protoreflect.Message {
- mi := &file_sbox_proto_msgTypes[4]
+ mi := &file_sbox_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -356,7 +486,7 @@
// Deprecated: Use PathMapping.ProtoReflect.Descriptor instead.
func (*PathMapping) Descriptor() ([]byte, []int) {
- return file_sbox_proto_rawDescGZIP(), []int{4}
+ return file_sbox_proto_rawDescGZIP(), []int{5}
}
func (x *PathMapping) GetFrom() string {
@@ -383,7 +513,7 @@
0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6f, 0x75, 0x74,
0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x70, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0d, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x44, 0x65, 0x70, 0x66, 0x69, 0x6c, 0x65,
- 0x22, 0xdc, 0x01, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x2b, 0x0a, 0x0b,
+ 0x22, 0xb3, 0x02, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x2b, 0x0a, 0x0b,
0x63, 0x6f, 0x70, 0x79, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x0a, 0x2e, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x43, 0x6f, 0x70, 0x79, 0x52, 0x0a, 0x63,
0x6f, 0x70, 0x79, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x64,
@@ -396,23 +526,37 @@
0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x48,
0x61, 0x73, 0x68, 0x12, 0x2a, 0x0a, 0x09, 0x72, 0x73, 0x70, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73,
0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x52, 0x73,
- 0x70, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x08, 0x72, 0x73, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x22,
- 0x4a, 0x0a, 0x04, 0x43, 0x6f, 0x70, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18,
- 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74,
- 0x6f, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x1e, 0x0a, 0x0a, 0x65,
- 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52,
- 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x55, 0x0a, 0x07, 0x52,
- 0x73, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01,
- 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x36, 0x0a, 0x0d, 0x70, 0x61,
- 0x74, 0x68, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
- 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x70,
- 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0c, 0x70, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e,
- 0x67, 0x73, 0x22, 0x31, 0x0a, 0x0b, 0x50, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e,
- 0x67, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52,
- 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x02, 0x28,
- 0x09, 0x52, 0x02, 0x74, 0x6f, 0x42, 0x23, 0x5a, 0x21, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
- 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x73, 0x62, 0x6f, 0x78, 0x2f,
- 0x73, 0x62, 0x6f, 0x78, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x70, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x08, 0x72, 0x73, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12,
+ 0x2b, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73,
+ 0x62, 0x6f, 0x78, 0x2e, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56,
+ 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x12, 0x28, 0x0a, 0x10,
+ 0x64, 0x6f, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x5f, 0x65, 0x6e, 0x76,
+ 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x6f, 0x6e, 0x74, 0x49, 0x6e, 0x68, 0x65,
+ 0x72, 0x69, 0x74, 0x45, 0x6e, 0x76, 0x22, 0x7e, 0x0a, 0x13, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f,
+ 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x12, 0x0a,
+ 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
+ 0x65, 0x12, 0x16, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x48, 0x00, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x16, 0x0a, 0x05, 0x75, 0x6e, 0x73,
+ 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x05, 0x75, 0x6e, 0x73, 0x65,
+ 0x74, 0x12, 0x1a, 0x0a, 0x07, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01,
+ 0x28, 0x08, 0x48, 0x00, 0x52, 0x07, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x42, 0x07, 0x0a,
+ 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x4a, 0x0a, 0x04, 0x43, 0x6f, 0x70, 0x79, 0x12, 0x12,
+ 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72,
+ 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x02,
+ 0x74, 0x6f, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62,
+ 0x6c, 0x65, 0x22, 0x55, 0x0a, 0x07, 0x52, 0x73, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a,
+ 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c,
+ 0x65, 0x12, 0x36, 0x0a, 0x0d, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e,
+ 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x62, 0x6f, 0x78, 0x2e,
+ 0x50, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0c, 0x70, 0x61, 0x74,
+ 0x68, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x31, 0x0a, 0x0b, 0x50, 0x61, 0x74,
+ 0x68, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d,
+ 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02,
+ 0x74, 0x6f, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x42, 0x23, 0x5a, 0x21,
+ 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x63, 0x6d,
+ 0x64, 0x2f, 0x73, 0x62, 0x6f, 0x78, 0x2f, 0x73, 0x62, 0x6f, 0x78, 0x5f, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f,
}
var (
@@ -427,25 +571,27 @@
return file_sbox_proto_rawDescData
}
-var file_sbox_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
+var file_sbox_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_sbox_proto_goTypes = []interface{}{
- (*Manifest)(nil), // 0: sbox.Manifest
- (*Command)(nil), // 1: sbox.Command
- (*Copy)(nil), // 2: sbox.Copy
- (*RspFile)(nil), // 3: sbox.RspFile
- (*PathMapping)(nil), // 4: sbox.PathMapping
+ (*Manifest)(nil), // 0: sbox.Manifest
+ (*Command)(nil), // 1: sbox.Command
+ (*EnvironmentVariable)(nil), // 2: sbox.EnvironmentVariable
+ (*Copy)(nil), // 3: sbox.Copy
+ (*RspFile)(nil), // 4: sbox.RspFile
+ (*PathMapping)(nil), // 5: sbox.PathMapping
}
var file_sbox_proto_depIdxs = []int32{
1, // 0: sbox.Manifest.commands:type_name -> sbox.Command
- 2, // 1: sbox.Command.copy_before:type_name -> sbox.Copy
- 2, // 2: sbox.Command.copy_after:type_name -> sbox.Copy
- 3, // 3: sbox.Command.rsp_files:type_name -> sbox.RspFile
- 4, // 4: sbox.RspFile.path_mappings:type_name -> sbox.PathMapping
- 5, // [5:5] is the sub-list for method output_type
- 5, // [5:5] is the sub-list for method input_type
- 5, // [5:5] is the sub-list for extension type_name
- 5, // [5:5] is the sub-list for extension extendee
- 0, // [0:5] is the sub-list for field type_name
+ 3, // 1: sbox.Command.copy_before:type_name -> sbox.Copy
+ 3, // 2: sbox.Command.copy_after:type_name -> sbox.Copy
+ 4, // 3: sbox.Command.rsp_files:type_name -> sbox.RspFile
+ 2, // 4: sbox.Command.env:type_name -> sbox.EnvironmentVariable
+ 5, // 5: sbox.RspFile.path_mappings:type_name -> sbox.PathMapping
+ 6, // [6:6] is the sub-list for method output_type
+ 6, // [6:6] is the sub-list for method input_type
+ 6, // [6:6] is the sub-list for extension type_name
+ 6, // [6:6] is the sub-list for extension extendee
+ 0, // [0:6] is the sub-list for field type_name
}
func init() { file_sbox_proto_init() }
@@ -479,7 +625,7 @@
}
}
file_sbox_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*Copy); i {
+ switch v := v.(*EnvironmentVariable); i {
case 0:
return &v.state
case 1:
@@ -491,7 +637,7 @@
}
}
file_sbox_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*RspFile); i {
+ switch v := v.(*Copy); i {
case 0:
return &v.state
case 1:
@@ -503,6 +649,18 @@
}
}
file_sbox_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*RspFile); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_sbox_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PathMapping); i {
case 0:
return &v.state
@@ -515,13 +673,18 @@
}
}
}
+ file_sbox_proto_msgTypes[2].OneofWrappers = []interface{}{
+ (*EnvironmentVariable_Value)(nil),
+ (*EnvironmentVariable_Unset)(nil),
+ (*EnvironmentVariable_Inherit)(nil),
+ }
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_sbox_proto_rawDesc,
NumEnums: 0,
- NumMessages: 5,
+ NumMessages: 6,
NumExtensions: 0,
NumServices: 0,
},
diff --git a/cmd/sbox/sbox_proto/sbox.proto b/cmd/sbox/sbox_proto/sbox.proto
index 2f0dcf0..1158554 100644
--- a/cmd/sbox/sbox_proto/sbox.proto
+++ b/cmd/sbox/sbox_proto/sbox.proto
@@ -51,6 +51,30 @@
// A list of files that will be copied before the sandboxed command, and whose contents should be
// copied as if they were listed in copy_before.
repeated RspFile rsp_files = 6;
+
+ // The environment variables that will be set or unset while running the command.
+ // Also see dont_inherit_env.
+ repeated EnvironmentVariable env = 7;
+
+ // By default, all environment variables are inherited from the calling process, but may be
+ // replaced or unset by env. If dont_inherit_env is set, no environment variables will be
+ // inherited, and instead only the variables in env will be defined.
+ optional bool dont_inherit_env = 8;
+}
+
+message EnvironmentVariable {
+ // The name of the environment variable
+ required string name = 1;
+ oneof state {
+ // The value to set the environment variable to.
+ string value = 2;
+ // This environment variable should be unset in the command.
+ bool unset = 3;
+ // This environment variable should be inherited from the parent process.
+ // Can be combined with dont_inherit_env to only inherit certain environment
+ // variables.
+ bool inherit = 4;
+ }
}
// Copy describes a from-to pair of files to copy. The paths may be relative, the root that they
diff --git a/cmd/soong_build/Android.bp b/cmd/soong_build/Android.bp
index 72af3e0..d8f563b 100644
--- a/cmd/soong_build/Android.bp
+++ b/cmd/soong_build/Android.bp
@@ -26,13 +26,11 @@
"soong",
"soong-android",
"soong-provenance",
- "soong-bp2build",
"soong-ui-metrics_proto",
],
srcs: [
"main.go",
"writedocs.go",
- "queryview.go",
],
primaryBuilder: true,
}
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index a8be7ec..cd4e9bd 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -15,7 +15,6 @@
package main
import (
- "bytes"
"encoding/json"
"errors"
"flag"
@@ -27,12 +26,13 @@
"android/soong/android"
"android/soong/android/allowlists"
- "android/soong/bp2build"
"android/soong/shared"
+
"github.com/google/blueprint"
"github.com/google/blueprint/bootstrap"
"github.com/google/blueprint/deptools"
"github.com/google/blueprint/metrics"
+ "github.com/google/blueprint/pathtools"
"github.com/google/blueprint/proptools"
androidProtobuf "google.golang.org/protobuf/android"
)
@@ -42,8 +42,6 @@
availableEnvFile string
usedEnvFile string
- globFile string
- globListDir string
delveListen string
delvePath string
@@ -64,10 +62,9 @@
flag.StringVar(&cmdlineArgs.SoongOutDir, "soong_out", "", "Soong output directory (usually $TOP/out/soong)")
flag.StringVar(&availableEnvFile, "available_env", "", "File containing available environment variables")
flag.StringVar(&usedEnvFile, "used_env", "", "File containing used environment variables")
- flag.StringVar(&globFile, "globFile", "build-globs.ninja", "the Ninja file of globs to output")
- flag.StringVar(&globListDir, "globListDir", "", "the directory containing the glob list files")
flag.StringVar(&cmdlineArgs.OutDir, "out", "", "the ninja builddir directory")
flag.StringVar(&cmdlineArgs.ModuleListFile, "l", "", "file that lists filepaths to parse")
+ flag.StringVar(&cmdlineArgs.KatiSuffix, "kati_suffix", "", "the suffix for kati and ninja files, so that different configurations don't clobber each other")
// Debug flags
flag.StringVar(&delveListen, "delve_listen", "", "Delve port to listen on for debugging")
@@ -81,7 +78,6 @@
flag.StringVar(&cmdlineArgs.ModuleGraphFile, "module_graph_file", "", "JSON module graph file to output")
flag.StringVar(&cmdlineArgs.ModuleActionsFile, "module_actions_file", "", "JSON file to output inputs/outputs of actions of modules")
flag.StringVar(&cmdlineArgs.DocFile, "soong_docs", "", "build documentation file to output")
- flag.StringVar(&cmdlineArgs.BazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory relative to --top")
flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output")
flag.StringVar(&cmdlineArgs.SoongVariables, "soong_variables", "soong.variables", "the file contains all build variables")
flag.BoolVar(&cmdlineArgs.EmptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file")
@@ -124,16 +120,6 @@
return false
}
-// Run the code-generation phase to convert BazelTargetModules to BUILD files.
-func runQueryView(queryviewDir, queryviewMarker string, ctx *android.Context) {
- ctx.EventHandler.Begin("queryview")
- defer ctx.EventHandler.End("queryview")
- codegenContext := bp2build.NewCodegenContext(ctx.Config(), ctx, bp2build.QueryView, topDir)
- err := createBazelWorkspace(codegenContext, shared.JoinPath(topDir, queryviewDir), false)
- maybeQuit(err, "")
- touch(shared.JoinPath(topDir, queryviewMarker))
-}
-
func writeNinjaHint(ctx *android.Context) error {
ctx.BeginEvent("ninja_hint")
defer ctx.EndEvent("ninja_hint")
@@ -206,20 +192,6 @@
ctx.Context.PrintJSONGraphAndActions(graphFile, actionsFile)
}
-func writeBuildGlobsNinjaFile(ctx *android.Context) {
- ctx.EventHandler.Begin("globs_ninja_file")
- defer ctx.EventHandler.End("globs_ninja_file")
-
- globDir := bootstrap.GlobDirectory(ctx.Config().SoongOutDir(), globListDir)
- err := bootstrap.WriteBuildGlobsNinjaFile(&bootstrap.GlobSingleton{
- GlobLister: ctx.Globs,
- GlobFile: globFile,
- GlobDir: globDir,
- SrcDir: ctx.SrcDir(),
- }, ctx.Config())
- maybeQuit(err, "")
-}
-
func writeDepFile(outputFile string, eventHandler *metrics.EventHandler, ninjaDeps []string) {
eventHandler.Begin("ninja_deps")
defer eventHandler.End("ninja_deps")
@@ -229,7 +201,14 @@
}
// Check if there are changes to the environment file, product variable file and
-// soong_build binary, in which case no incremental will be performed.
+// soong_build binary, in which case no incremental will be performed. For env
+// variables we check the used env file, which will be removed in soong ui if
+// there is any changes to the env variables used last time, in which case the
+// check below will fail and a full build will be attempted. If any new env
+// variables are added in the new run, soong ui won't be able to detect it, the
+// used env file check below will pass. But unless there is a soong build code
+// change, in which case the soong build binary check will fail, otherwise the
+// new env variables shouldn't have any affect.
func incrementalValid(config android.Config, configCacheFile string) (*ConfigCache, bool) {
var newConfigCache ConfigCache
data, err := os.ReadFile(shared.JoinPath(topDir, usedEnvFile))
@@ -283,7 +262,9 @@
}
// runSoongOnlyBuild runs the standard Soong build in a number of different modes.
-func runSoongOnlyBuild(ctx *android.Context, extraNinjaDeps []string) string {
+// It returns the path to the output file (usually the ninja file) and the deps that need
+// to trigger a soong rerun.
+func runSoongOnlyBuild(ctx *android.Context) (string, []string) {
ctx.EventHandler.Begin("soong_build")
defer ctx.EventHandler.End("soong_build")
@@ -291,7 +272,7 @@
switch ctx.Config().BuildMode {
case android.GenerateModuleGraph:
stopBefore = bootstrap.StopBeforeWriteNinja
- case android.GenerateQueryView, android.GenerateDocFile:
+ case android.GenerateDocFile:
stopBefore = bootstrap.StopBeforePrepareBuildActions
default:
stopBefore = bootstrap.DoEverything
@@ -299,37 +280,26 @@
ninjaDeps, err := bootstrap.RunBlueprint(cmdlineArgs.Args, stopBefore, ctx.Context, ctx.Config())
maybeQuit(err, "")
- ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
-
- writeBuildGlobsNinjaFile(ctx)
// Convert the Soong module graph into Bazel BUILD files.
switch ctx.Config().BuildMode {
- case android.GenerateQueryView:
- queryviewMarkerFile := cmdlineArgs.BazelQueryViewDir + ".marker"
- runQueryView(cmdlineArgs.BazelQueryViewDir, queryviewMarkerFile, ctx)
- writeDepFile(queryviewMarkerFile, ctx.EventHandler, ninjaDeps)
- return queryviewMarkerFile
case android.GenerateModuleGraph:
writeJsonModuleGraphAndActions(ctx, cmdlineArgs)
- writeDepFile(cmdlineArgs.ModuleGraphFile, ctx.EventHandler, ninjaDeps)
- return cmdlineArgs.ModuleGraphFile
+ return cmdlineArgs.ModuleGraphFile, ninjaDeps
case android.GenerateDocFile:
// TODO: we could make writeDocs() return the list of documentation files
// written and add them to the .d file. Then soong_docs would be re-run
// whenever one is deleted.
err := writeDocs(ctx, shared.JoinPath(topDir, cmdlineArgs.DocFile))
maybeQuit(err, "error building Soong documentation")
- writeDepFile(cmdlineArgs.DocFile, ctx.EventHandler, ninjaDeps)
- return cmdlineArgs.DocFile
+ return cmdlineArgs.DocFile, ninjaDeps
default:
// The actual output (build.ninja) was written in the RunBlueprint() call
// above
- writeDepFile(cmdlineArgs.OutFile, ctx.EventHandler, ninjaDeps)
if needToWriteNinjaHint(ctx) {
writeNinjaHint(ctx)
}
- return cmdlineArgs.OutFile
+ return cmdlineArgs.OutFile, ninjaDeps
}
}
@@ -359,6 +329,8 @@
func main() {
flag.Parse()
+ soongStartTime := time.Now()
+
shared.ReexecWithDelveMaybe(delveListen, delvePath)
android.InitSandbox(topDir)
@@ -369,13 +341,6 @@
configuration.SetAllowMissingDependencies()
}
- extraNinjaDeps := []string{configuration.ProductVariablesFileName, usedEnvFile}
- if shared.IsDebugging() {
- // Add a non-existent file to the dependencies so that soong_build will rerun when the debugger is
- // enabled even if it completed successfully.
- extraNinjaDeps = append(extraNinjaDeps, filepath.Join(configuration.SoongOutDir(), "always_rerun_for_delve"))
- }
-
// Bypass configuration.Getenv, as LOG_DIR does not need to be dependency tracked. By definition, it will
// change between every CI build, so tracking it would require re-running Soong for every build.
metricsDir := availableEnv["LOG_DIR"]
@@ -393,7 +358,17 @@
ctx.SetIncrementalAnalysis(incremental)
ctx.Register()
- finalOutputFile := runSoongOnlyBuild(ctx, extraNinjaDeps)
+ finalOutputFile, ninjaDeps := runSoongOnlyBuild(ctx)
+
+ ninjaDeps = append(ninjaDeps, configuration.ProductVariablesFileName)
+ ninjaDeps = append(ninjaDeps, usedEnvFile)
+ if shared.IsDebugging() {
+ // Add a non-existent file to the dependencies so that soong_build will rerun when the debugger is
+ // enabled even if it completed successfully.
+ ninjaDeps = append(ninjaDeps, filepath.Join(configuration.SoongOutDir(), "always_rerun_for_delve"))
+ }
+
+ writeDepFile(finalOutputFile, ctx.EventHandler, ninjaDeps)
if ctx.GetIncrementalEnabled() {
data, err := shared.EnvFileContents(configuration.EnvDeps())
@@ -407,6 +382,9 @@
writeUsedEnvironmentFile(configuration)
+ err = writeGlobFile(ctx.EventHandler, finalOutputFile, ctx.Globs(), soongStartTime)
+ maybeQuit(err, "")
+
// Touch the output file so that it's the newest file created by soong_build.
// This is necessary because, if soong_build generated any files which
// are ninja inputs to the main output file, then ninja would superfluously
@@ -423,18 +401,33 @@
data, err := shared.EnvFileContents(configuration.EnvDeps())
maybeQuit(err, "error writing used environment file '%s'\n", usedEnvFile)
- if preexistingData, err := os.ReadFile(path); err != nil {
- if !os.IsNotExist(err) {
- maybeQuit(err, "error reading used environment file '%s'", usedEnvFile)
- }
- } else if bytes.Equal(preexistingData, data) {
- // used environment file is unchanged
- return
- }
- err = os.WriteFile(path, data, 0666)
+ err = pathtools.WriteFileIfChanged(path, data, 0666)
maybeQuit(err, "error writing used environment file '%s'", usedEnvFile)
}
+func writeGlobFile(eventHandler *metrics.EventHandler, finalOutFile string, globs pathtools.MultipleGlobResults, soongStartTime time.Time) error {
+ eventHandler.Begin("writeGlobFile")
+ defer eventHandler.End("writeGlobFile")
+
+ globsFile, err := os.Create(shared.JoinPath(topDir, finalOutFile+".globs"))
+ if err != nil {
+ return err
+ }
+ defer globsFile.Close()
+ globsFileEncoder := json.NewEncoder(globsFile)
+ for _, glob := range globs {
+ if err := globsFileEncoder.Encode(glob); err != nil {
+ return err
+ }
+ }
+
+ return os.WriteFile(
+ shared.JoinPath(topDir, finalOutFile+".globs_time"),
+ []byte(fmt.Sprintf("%d\n", soongStartTime.UnixMicro())),
+ 0666,
+ )
+}
+
func touch(path string) {
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
maybeQuit(err, "Error touching '%s'", path)
diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go
deleted file mode 100644
index eafd67a..0000000
--- a/cmd/soong_build/queryview.go
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2020 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package main
-
-import (
- "io/fs"
- "io/ioutil"
- "os"
- "path/filepath"
-
- "android/soong/android"
- "android/soong/bp2build"
-)
-
-// A helper function to generate a Read-only Bazel workspace in outDir
-func createBazelWorkspace(ctx *bp2build.CodegenContext, outDir string, generateFilegroups bool) error {
- os.RemoveAll(outDir)
- ruleShims := bp2build.CreateRuleShims(android.ModuleTypeFactories())
-
- res, err := bp2build.GenerateBazelTargets(ctx, generateFilegroups)
- if err != nil {
- panic(err)
- }
-
- filesToWrite := bp2build.CreateBazelFiles(ruleShims, res.BuildDirToTargets(), ctx.Mode())
- bazelRcFiles, err2 := CopyBazelRcFiles()
- if err2 != nil {
- return err2
- }
- filesToWrite = append(filesToWrite, bazelRcFiles...)
- for _, f := range filesToWrite {
- if err := writeReadOnlyFile(outDir, f); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-// CopyBazelRcFiles creates BazelFiles for all the bazelrc files under
-// build/bazel. They're needed because the rc files are still read when running
-// queryview, so they have to be in the queryview workspace.
-func CopyBazelRcFiles() ([]bp2build.BazelFile, error) {
- result := make([]bp2build.BazelFile, 0)
- err := filepath.WalkDir(filepath.Join(topDir, "build/bazel"), func(path string, info fs.DirEntry, err error) error {
- if filepath.Ext(path) == ".bazelrc" {
- contents, err := os.ReadFile(path)
- if err != nil {
- return err
- }
- path, err = filepath.Rel(topDir, path)
- if err != nil {
- return err
- }
- result = append(result, bp2build.BazelFile{
- Dir: filepath.Dir(path),
- Basename: filepath.Base(path),
- Contents: string(contents),
- })
- }
- return nil
- })
- return result, err
-}
-
-// The auto-conversion directory should be read-only, sufficient for bazel query. The files
-// are not intended to be edited by end users.
-func writeReadOnlyFile(dir string, f bp2build.BazelFile) error {
- dir = filepath.Join(dir, f.Dir)
- if err := createDirectoryIfNonexistent(dir); err != nil {
- return err
- }
- pathToFile := filepath.Join(dir, f.Basename)
-
- // 0444 is read-only
- err := ioutil.WriteFile(pathToFile, []byte(f.Contents), 0444)
-
- return err
-}
-
-func writeReadWriteFile(dir string, f bp2build.BazelFile) error {
- dir = filepath.Join(dir, f.Dir)
- if err := createDirectoryIfNonexistent(dir); err != nil {
- return err
- }
- pathToFile := filepath.Join(dir, f.Basename)
-
- // 0644 is read-write
- err := ioutil.WriteFile(pathToFile, []byte(f.Contents), 0644)
-
- return err
-}
-
-func createDirectoryIfNonexistent(dir string) error {
- if _, err := os.Stat(dir); os.IsNotExist(err) {
- return os.MkdirAll(dir, os.ModePerm)
- } else {
- return err
- }
-}
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 2d3156a..4f6de82 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -27,6 +27,7 @@
"android/soong/shared"
"android/soong/ui/build"
+ "android/soong/ui/execution_metrics"
"android/soong/ui/logger"
"android/soong/ui/metrics"
"android/soong/ui/signal"
@@ -170,14 +171,16 @@
stat.Finish()
})
criticalPath := status.NewCriticalPath()
+ emet := execution_metrics.NewExecutionMetrics(log)
buildCtx := build.Context{ContextImpl: &build.ContextImpl{
- Context: ctx,
- Logger: log,
- Metrics: met,
- Tracer: trace,
- Writer: output,
- Status: stat,
- CriticalPath: criticalPath,
+ Context: ctx,
+ Logger: log,
+ Metrics: met,
+ ExecutionMetrics: emet,
+ Tracer: trace,
+ Writer: output,
+ Status: stat,
+ CriticalPath: criticalPath,
}}
freshConfig := func() build.Config {
@@ -194,6 +197,7 @@
rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
soongBuildMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_build_metrics.pb")
buildTraceFile := filepath.Join(logsDir, c.logsPrefix+"build.trace.gz")
+ executionMetricsFile := filepath.Join(logsDir, c.logsPrefix+"execution_metrics.pb")
metricsFiles := []string{
buildErrorFile, // build error strings
@@ -204,9 +208,15 @@
}
defer func() {
+ emet.Finish(buildCtx)
stat.Finish()
criticalPath.WriteToMetrics(met)
met.Dump(soongMetricsFile)
+ emet.Dump(executionMetricsFile, args)
+ // If there are execution metrics, upload them.
+ if _, err := os.Stat(executionMetricsFile); err == nil {
+ metricsFiles = append(metricsFiles, executionMetricsFile)
+ }
if !config.SkipMetricsUpload() {
build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, metricsFiles...)
}
@@ -251,11 +261,10 @@
buildErrorFile := filepath.Join(logsDir, logsPrefix+"build_error")
rbeMetricsFile := filepath.Join(logsDir, logsPrefix+"rbe_metrics.pb")
soongMetricsFile := filepath.Join(logsDir, logsPrefix+"soong_metrics")
- bp2buildMetricsFile := filepath.Join(logsDir, logsPrefix+"bp2build_metrics.pb")
soongBuildMetricsFile := filepath.Join(logsDir, logsPrefix+"soong_build_metrics.pb")
//Delete the stale metrics files
- staleFileSlice := []string{buildErrorFile, rbeMetricsFile, soongMetricsFile, bp2buildMetricsFile, soongBuildMetricsFile}
+ staleFileSlice := []string{buildErrorFile, rbeMetricsFile, soongMetricsFile, soongBuildMetricsFile}
if err := deleteStaleMetrics(staleFileSlice); err != nil {
log.Fatalln(err)
}
@@ -329,7 +338,7 @@
ctx.Fatal(err)
}
- fmt.Println(build.Banner(varData))
+ fmt.Println(build.Banner(config, varData))
} else {
varData, err := build.DumpMakeVars(ctx, config, nil, []string{varName})
if err != nil {
@@ -405,7 +414,7 @@
for _, name := range vars {
if name == "report_config" {
- fmt.Printf("%sreport_config='%s'\n", *varPrefix, build.Banner(varData))
+ fmt.Printf("%sreport_config='%s'\n", *varPrefix, build.Banner(config, varData))
} else {
fmt.Printf("%s%s='%s'\n", *varPrefix, name, varData[name])
}
@@ -462,20 +471,6 @@
description: "Build action: build from the top of the source tree.",
action: build.BUILD_MODULES,
}, {
- // This is redirecting to mma build command behaviour. Once it has soaked for a
- // while, the build command is deleted from here once it has been removed from the
- // envsetup.sh.
- name: "modules-in-a-dir-no-deps",
- description: "Build action: builds all of the modules in the current directory without their dependencies.",
- action: build.BUILD_MODULES_IN_A_DIRECTORY,
- }, {
- // This is redirecting to mmma build command behaviour. Once it has soaked for a
- // while, the build command is deleted from here once it has been removed from the
- // envsetup.sh.
- name: "modules-in-dirs-no-deps",
- description: "Build action: builds all of the modules in the supplied directories without their dependencies.",
- action: build.BUILD_MODULES_IN_DIRECTORIES,
- }, {
name: "modules-in-a-dir",
description: "Build action: builds all of the modules in the current directory and their dependencies.",
action: build.BUILD_MODULES_IN_A_DIRECTORY,
diff --git a/testing/code_metadata_internal_proto/Android.bp b/cmd/source_tree_size/Android.bp
similarity index 65%
copy from testing/code_metadata_internal_proto/Android.bp
copy to cmd/source_tree_size/Android.bp
index a534cc2..97d29c6 100644
--- a/testing/code_metadata_internal_proto/Android.bp
+++ b/cmd/source_tree_size/Android.bp
@@ -1,4 +1,4 @@
-// Copyright 2022 Google Inc. All rights reserved.
+// 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.
@@ -16,14 +16,13 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-bootstrap_go_package {
- name: "soong-testing-code_metadata_internal_proto",
- pkgPath: "android/soong/testing/code_metadata_internal_proto",
- deps: [
- "golang-protobuf-reflect-protoreflect",
- "golang-protobuf-runtime-protoimpl",
- ],
+blueprint_go_binary {
+ name: "source_tree_size",
srcs: [
- "code_metadata_internal.pb.go",
+ "source_tree.pb.go",
+ "source_tree_size.go",
+ ],
+ deps: [
+ "golang-protobuf-runtime-protoimpl",
],
}
diff --git a/cmd/source_tree_size/regen.sh b/cmd/source_tree_size/regen.sh
new file mode 100755
index 0000000..b0f1c80
--- /dev/null
+++ b/cmd/source_tree_size/regen.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+aprotoc --go_out=paths=source_relative:. source_tree.proto
+
diff --git a/cmd/source_tree_size/source_tree.pb.go b/cmd/source_tree_size/source_tree.pb.go
new file mode 100644
index 0000000..da8cba5
--- /dev/null
+++ b/cmd/source_tree_size/source_tree.pb.go
@@ -0,0 +1,230 @@
+// 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.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.30.0
+// protoc v3.21.12
+// source: source_tree.proto
+
+package main
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type SourceFile struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Path *string `protobuf:"bytes,1,opt,name=path" json:"path,omitempty"`
+ SizeBytes *int32 `protobuf:"varint,2,opt,name=size_bytes,json=sizeBytes" json:"size_bytes,omitempty"`
+}
+
+func (x *SourceFile) Reset() {
+ *x = SourceFile{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_source_tree_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SourceFile) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SourceFile) ProtoMessage() {}
+
+func (x *SourceFile) ProtoReflect() protoreflect.Message {
+ mi := &file_source_tree_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SourceFile.ProtoReflect.Descriptor instead.
+func (*SourceFile) Descriptor() ([]byte, []int) {
+ return file_source_tree_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *SourceFile) GetPath() string {
+ if x != nil && x.Path != nil {
+ return *x.Path
+ }
+ return ""
+}
+
+func (x *SourceFile) GetSizeBytes() int32 {
+ if x != nil && x.SizeBytes != nil {
+ return *x.SizeBytes
+ }
+ return 0
+}
+
+type SourceTree struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Files []*SourceFile `protobuf:"bytes,1,rep,name=files" json:"files,omitempty"`
+}
+
+func (x *SourceTree) Reset() {
+ *x = SourceTree{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_source_tree_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SourceTree) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SourceTree) ProtoMessage() {}
+
+func (x *SourceTree) ProtoReflect() protoreflect.Message {
+ mi := &file_source_tree_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SourceTree.ProtoReflect.Descriptor instead.
+func (*SourceTree) Descriptor() ([]byte, []int) {
+ return file_source_tree_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *SourceTree) GetFiles() []*SourceFile {
+ if x != nil {
+ return x.Files
+ }
+ return nil
+}
+
+var File_source_tree_proto protoreflect.FileDescriptor
+
+var file_source_tree_proto_rawDesc = []byte{
+ 0x0a, 0x11, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65,
+ 0x73, 0x22, 0x3f, 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12,
+ 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70,
+ 0x61, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65,
+ 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74,
+ 0x65, 0x73, 0x22, 0x3c, 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, 0x65,
+ 0x12, 0x2e, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+ 0x18, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x53,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73,
+ 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x2f, 0x6d, 0x61, 0x69, 0x6e,
+}
+
+var (
+ file_source_tree_proto_rawDescOnce sync.Once
+ file_source_tree_proto_rawDescData = file_source_tree_proto_rawDesc
+)
+
+func file_source_tree_proto_rawDescGZIP() []byte {
+ file_source_tree_proto_rawDescOnce.Do(func() {
+ file_source_tree_proto_rawDescData = protoimpl.X.CompressGZIP(file_source_tree_proto_rawDescData)
+ })
+ return file_source_tree_proto_rawDescData
+}
+
+var file_source_tree_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_source_tree_proto_goTypes = []interface{}{
+ (*SourceFile)(nil), // 0: source_files.SourceFile
+ (*SourceTree)(nil), // 1: source_files.SourceTree
+}
+var file_source_tree_proto_depIdxs = []int32{
+ 0, // 0: source_files.SourceTree.files:type_name -> source_files.SourceFile
+ 1, // [1:1] is the sub-list for method output_type
+ 1, // [1:1] is the sub-list for method input_type
+ 1, // [1:1] is the sub-list for extension type_name
+ 1, // [1:1] is the sub-list for extension extendee
+ 0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_source_tree_proto_init() }
+func file_source_tree_proto_init() {
+ if File_source_tree_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_source_tree_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SourceFile); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_source_tree_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SourceTree); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_source_tree_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 2,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_source_tree_proto_goTypes,
+ DependencyIndexes: file_source_tree_proto_depIdxs,
+ MessageInfos: file_source_tree_proto_msgTypes,
+ }.Build()
+ File_source_tree_proto = out.File
+ file_source_tree_proto_rawDesc = nil
+ file_source_tree_proto_goTypes = nil
+ file_source_tree_proto_depIdxs = nil
+}
diff --git a/cmd/multiproduct_kati/main_linux.go b/cmd/source_tree_size/source_tree.proto
similarity index 61%
rename from cmd/multiproduct_kati/main_linux.go
rename to cmd/source_tree_size/source_tree.proto
index db74496..1a5b89f 100644
--- a/cmd/multiproduct_kati/main_linux.go
+++ b/cmd/source_tree_size/source_tree.proto
@@ -1,10 +1,10 @@
-// Copyright 2017 Google Inc. All rights reserved.
+// 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
+// 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,
@@ -12,17 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+syntax = "proto2";
-import (
- "syscall"
-)
+package source_files;
+option go_package = "./main";
-func detectTotalRAM() uint64 {
- var info syscall.Sysinfo_t
- err := syscall.Sysinfo(&info)
- if err != nil {
- panic(err)
- }
- return info.Totalram * uint64(info.Unit)
+message SourceFile {
+ optional string path = 1;
+ optional int32 size_bytes = 2;
+}
+
+message SourceTree {
+ repeated SourceFile files = 1;
}
diff --git a/cmd/source_tree_size/source_tree_size.go b/cmd/source_tree_size/source_tree_size.go
new file mode 100644
index 0000000..8b2a4cf
--- /dev/null
+++ b/cmd/source_tree_size/source_tree_size.go
@@ -0,0 +1,126 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path"
+ "path/filepath"
+ "sort"
+ "strings"
+ "sync"
+
+ "google.golang.org/protobuf/proto"
+)
+
+var root string
+var repo string
+var outDir string
+var channel chan SourceFile
+var waiter sync.WaitGroup
+var sourceTree SourceTree
+
+func normalizeOutDir(outDir, root string) string {
+ if len(outDir) == 0 {
+ return ""
+ }
+ if filepath.IsAbs(outDir) {
+ if strings.HasPrefix(outDir, root) {
+ // Absolute path inside root, use it
+ return outDir
+ } else {
+ // Not inside root, we don't care about it
+ return ""
+ }
+ } else {
+ // Relative path inside root, make it absolute
+ return root + outDir
+ }
+}
+
+func walkDir(dir string) {
+ defer waiter.Done()
+
+ visit := func(path string, info os.FileInfo, err error) error {
+ name := info.Name()
+
+ // Repo git projects are symlinks. A real directory called .git counts as checked in
+ // (and is very likely to be wasted space)
+ if info.Mode().Type()&os.ModeSymlink != 0 && name == ".git" {
+ return nil
+ }
+
+ // Skip .repo and out
+ if info.IsDir() && (path == repo || path == outDir) {
+ return filepath.SkipDir
+ }
+
+ if info.IsDir() && path != dir {
+ waiter.Add(1)
+ go walkDir(path)
+ return filepath.SkipDir
+ }
+
+ if !info.IsDir() {
+ sourcePath := strings.TrimPrefix(path, root)
+ file := SourceFile{
+ Path: proto.String(sourcePath),
+ SizeBytes: proto.Int32(42),
+ }
+ channel <- file
+ }
+ return nil
+
+ }
+ filepath.Walk(dir, visit)
+}
+
+func main() {
+ var outputFile string
+ flag.StringVar(&outputFile, "o", "", "The file to write")
+ flag.StringVar(&outDir, "out_dir", "out", "The out directory")
+ flag.Parse()
+
+ if outputFile == "" {
+ fmt.Fprintf(os.Stderr, "source_tree_size: Missing argument: -o\n")
+ os.Exit(1)
+ }
+
+ root, _ = os.Getwd()
+ if root[len(root)-1] != '/' {
+ root += "/"
+ }
+
+ outDir = normalizeOutDir(outDir, root)
+ repo = path.Join(root, ".repo")
+
+ // The parallel scanning reduces the run time by about a minute
+ channel = make(chan SourceFile)
+ waiter.Add(1)
+ go walkDir(root)
+ go func() {
+ waiter.Wait()
+ close(channel)
+ }()
+ for sourceFile := range channel {
+ sourceTree.Files = append(sourceTree.Files, &sourceFile)
+ }
+
+ // Sort the results, for a stable output
+ sort.Slice(sourceTree.Files, func(i, j int) bool {
+ return *sourceTree.Files[i].Path < *sourceTree.Files[j].Path
+ })
+
+ // Flatten and write
+ buf, err := proto.Marshal(&sourceTree)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Couldn't marshal protobuf\n")
+ os.Exit(1)
+ }
+ err = ioutil.WriteFile(outputFile, buf, 0644)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error writing file: %v\n", err)
+ os.Exit(1)
+ }
+}
diff --git a/cmd/symbols_map/Android.bp b/cmd/symbols_map/Android.bp
index e3ae6ed..272e806 100644
--- a/cmd/symbols_map/Android.bp
+++ b/cmd/symbols_map/Android.bp
@@ -30,4 +30,5 @@
srcs: [
"symbols_map_proto/symbols_map.pb.go",
],
+ visibility: ["//visibility:public"],
}
diff --git a/cmd/symbols_map/symbols_map_proto/symbols_map.proto b/cmd/symbols_map/symbols_map_proto/symbols_map.proto
index 693fe3e..a76d171 100644
--- a/cmd/symbols_map/symbols_map_proto/symbols_map.proto
+++ b/cmd/symbols_map/symbols_map_proto/symbols_map.proto
@@ -37,6 +37,21 @@
// type is the type of the mapping, either ELF or R8.
optional Type type = 3;
+
+ // LocationType is the place where to look for the file with the given
+ // identifier.
+ Enum LocationType {
+ // ZIP denotes the file with the given identifier is in the distribuited
+ // symbols.zip or proguard_dict.zip files, or the local disc.
+ ZIP = 0;
+ // AB denotes the file with the given identifier is in the AB artifacts but
+ // not in a symbols.zip or proguard_dict.zip.
+ AB = 1;
+ }
+
+ // location_type is the Location Type that dictates where to search for the
+ // file with the given identifier. Defaults to ZIP if not present.
+ optional LocationType location_type = 4;
}
message Mappings {
diff --git a/cmd/zip2zip/Android.bp b/cmd/zip2zip/Android.bp
index 3ef7668..7f9b165 100644
--- a/cmd/zip2zip/Android.bp
+++ b/cmd/zip2zip/Android.bp
@@ -27,4 +27,6 @@
"zip2zip.go",
],
testSrcs: ["zip2zip_test.go"],
+ // Used by genrules
+ visibility: ["//visibility:public"],
}
diff --git a/compliance/Android.bp b/compliance/Android.bp
new file mode 100644
index 0000000..a1f2015
--- /dev/null
+++ b/compliance/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-compliance",
+ pkgPath: "android/soong/compliance",
+ deps: [
+ "soong-android",
+ ],
+ srcs: [
+ "notice.go",
+ ],
+ testSrcs: [
+ ],
+ pluginFor: ["soong_build"],
+}
+
+notice_xml {
+ name: "notice_xml_system",
+ partition_name: "system",
+ visibility: [
+ "//visibility:any_system_partition",
+ ],
+}
diff --git a/compliance/license_metadata_proto/Android.bp b/compliance/license_metadata_proto/Android.bp
index 3c041e4..4761285 100644
--- a/compliance/license_metadata_proto/Android.bp
+++ b/compliance/license_metadata_proto/Android.bp
@@ -24,4 +24,8 @@
"golang-protobuf-reflect-protoreflect",
"golang-protobuf-runtime-protoimpl",
],
+ visibility: [
+ "//build/make/tools/compliance:__subpackages__",
+ "//build/soong:__subpackages__",
+ ],
}
diff --git a/compliance/notice.go b/compliance/notice.go
new file mode 100644
index 0000000..0d5fce3
--- /dev/null
+++ b/compliance/notice.go
@@ -0,0 +1,103 @@
+// 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 compliance
+
+import (
+ "path/filepath"
+
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+)
+
+func init() {
+ RegisterNoticeXmlBuildComponents(android.InitRegistrationContext)
+}
+
+var PrepareForTestWithNoticeXmlBuildComponents = android.GroupFixturePreparers(
+ android.FixtureRegisterWithContext(RegisterNoticeXmlBuildComponents),
+)
+
+var PrepareForTestWithNoticeXml = android.GroupFixturePreparers(
+ PrepareForTestWithNoticeXmlBuildComponents,
+)
+
+func RegisterNoticeXmlBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("notice_xml", NoticeXmlFactory)
+}
+
+var (
+ pctx = android.NewPackageContext("android/soong/compliance")
+
+ genNoticeXml = pctx.HostBinToolVariable("genNoticeXml", "gen_notice_xml")
+
+ // Command to generate NOTICE.xml.gz for a partition
+ genNoticeXmlRule = pctx.AndroidStaticRule("genNoticeXmlRule", blueprint.RuleParams{
+ Command: "rm -rf $out && " +
+ "${genNoticeXml} --output_file ${out} --metadata ${in} --partition ${partition} --product_out ${productOut} --soong_out ${soongOut}",
+ CommandDeps: []string{"${genNoticeXml}"},
+ }, "partition", "productOut", "soongOut")
+)
+
+func NoticeXmlFactory() android.Module {
+ m := &NoticeXmlModule{}
+ m.AddProperties(&m.props)
+ android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibFirst)
+ return m
+}
+
+type NoticeXmlModule struct {
+ android.ModuleBase
+
+ props noticeXmlProperties
+
+ outputFile android.OutputPath
+}
+
+type noticeXmlProperties struct {
+ Partition_name string
+}
+
+func (nx *NoticeXmlModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ prodVars := ctx.Config().ProductVariables()
+ buildFingerprintFile := android.PathForArbitraryOutput(ctx, "target", "product", android.String(prodVars.DeviceName), "build_fingerprint.txt")
+ implicits := []android.Path{buildFingerprintFile}
+
+ output := android.PathForModuleOut(ctx, "NOTICE.xml.gz")
+ metadataDb := android.PathForOutput(ctx, "compliance-metadata", ctx.Config().DeviceProduct(), "compliance-metadata.db")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: genNoticeXmlRule,
+ Input: metadataDb,
+ Implicits: implicits,
+ Output: output,
+ Args: map[string]string{
+ "productOut": filepath.Join(ctx.Config().OutDir(), "target", "product", ctx.Config().DeviceName()),
+ "soongOut": ctx.Config().SoongOutDir(),
+ "partition": nx.props.Partition_name,
+ },
+ })
+
+ nx.outputFile = output.OutputPath
+
+ installPath := android.PathForModuleInPartitionInstall(ctx, nx.props.Partition_name, "etc")
+ ctx.PackageFile(installPath, "NOTICE.xml.gz", nx.outputFile)
+}
+
+func (nx *NoticeXmlModule) AndroidMkEntries() []android.AndroidMkEntries {
+ return []android.AndroidMkEntries{{
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(nx.outputFile),
+ }}
+}
diff --git a/compliance/notice_test.go b/compliance/notice_test.go
new file mode 100644
index 0000000..e8578ec
--- /dev/null
+++ b/compliance/notice_test.go
@@ -0,0 +1,38 @@
+// 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 compliance
+
+import (
+ "testing"
+
+ "android/soong/android"
+)
+
+var prepareForNoticeXmlTest = android.GroupFixturePreparers(
+ android.PrepareForTestWithArchMutator,
+ PrepareForTestWithNoticeXml,
+)
+
+func TestPrebuiltEtcOutputFile(t *testing.T) {
+ result := prepareForNoticeXmlTest.RunTestWithBp(t, `
+ notice_xml {
+ name: "notice_xml_system",
+ partition_name: "system",
+ }
+ `)
+
+ m := result.Module("notice_xml_system", "android_arm64_armv8-a").(*NoticeXmlModule)
+ android.AssertStringEquals(t, "output file", "NOTICE.xml.gz", m.outputFile.Base())
+}
diff --git a/compliance/project_metadata_proto/Android.bp b/compliance/project_metadata_proto/Android.bp
index 56e76e7..0c807b2 100644
--- a/compliance/project_metadata_proto/Android.bp
+++ b/compliance/project_metadata_proto/Android.bp
@@ -24,4 +24,5 @@
"golang-protobuf-reflect-protoreflect",
"golang-protobuf-runtime-protoimpl",
],
+ visibility: ["//build/make/tools/compliance:__subpackages__"],
}
diff --git a/cuj/Android.bp b/cuj/Android.bp
deleted file mode 100644
index f9cfdc1..0000000
--- a/cuj/Android.bp
+++ /dev/null
@@ -1,17 +0,0 @@
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-blueprint_go_binary {
- name: "cuj_tests",
- deps: [
- "soong-ui-build",
- "soong-ui-logger",
- "soong-ui-signal",
- "soong-ui-terminal",
- "soong-ui-tracer",
- ],
- srcs: [
- "cuj.go",
- ],
-}
diff --git a/cuj/cuj.go b/cuj/cuj.go
deleted file mode 100644
index de6f10d..0000000
--- a/cuj/cuj.go
+++ /dev/null
@@ -1,239 +0,0 @@
-// Copyright 2019 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.
-
-// This executable runs a series of build commands to test and benchmark some critical user journeys.
-package main
-
-import (
- "context"
- "fmt"
- "os"
- "path/filepath"
- "strconv"
- "strings"
- "time"
-
- "android/soong/ui/build"
- "android/soong/ui/logger"
- "android/soong/ui/metrics"
- "android/soong/ui/signal"
- "android/soong/ui/status"
- "android/soong/ui/terminal"
- "android/soong/ui/tracer"
-)
-
-type Test struct {
- name string
- args []string
- before func() error
-
- results TestResults
-}
-
-type TestResults struct {
- metrics *metrics.Metrics
- err error
-}
-
-// Run runs a single build command. It emulates the "m" command line by calling into Soong UI directly.
-func (t *Test) Run(logsDir string) {
- output := terminal.NewStatusOutput(os.Stdout, "", false, false, false)
-
- log := logger.New(output)
- defer log.Cleanup()
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- trace := tracer.New(log)
- defer trace.Close()
-
- met := metrics.New()
-
- stat := &status.Status{}
- defer stat.Finish()
- stat.AddOutput(output)
- stat.AddOutput(trace.StatusTracer())
-
- signal.SetupSignals(log, cancel, func() {
- trace.Close()
- log.Cleanup()
- stat.Finish()
- })
-
- buildCtx := build.Context{ContextImpl: &build.ContextImpl{
- Context: ctx,
- Logger: log,
- Metrics: met,
- Tracer: trace,
- Writer: output,
- Status: stat,
- }}
-
- defer logger.Recover(func(err error) {
- t.results.err = err
- })
-
- config := build.NewConfig(buildCtx, t.args...)
- build.SetupOutDir(buildCtx, config)
-
- os.MkdirAll(logsDir, 0777)
- log.SetOutput(filepath.Join(logsDir, "soong.log"))
- trace.SetOutput(filepath.Join(logsDir, "build.trace"))
- stat.AddOutput(status.NewVerboseLog(log, filepath.Join(logsDir, "verbose.log")))
- stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, "error.log")))
- stat.AddOutput(status.NewProtoErrorLog(log, filepath.Join(logsDir, "build_error")))
- stat.AddOutput(status.NewCriticalPathLogger(log, nil))
-
- defer met.Dump(filepath.Join(logsDir, "soong_metrics"))
-
- if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok {
- if !strings.HasSuffix(start, "N") {
- if start_time, err := strconv.ParseUint(start, 10, 64); err == nil {
- log.Verbosef("Took %dms to start up.",
- time.Since(time.Unix(0, int64(start_time))).Nanoseconds()/time.Millisecond.Nanoseconds())
- buildCtx.CompleteTrace(metrics.RunSetupTool, "startup", start_time, uint64(time.Now().UnixNano()))
- }
- }
-
- if executable, err := os.Executable(); err == nil {
- trace.ImportMicrofactoryLog(filepath.Join(filepath.Dir(executable), "."+filepath.Base(executable)+".trace"))
- }
- }
-
- f := build.NewSourceFinder(buildCtx, config)
- defer f.Shutdown()
- build.FindSources(buildCtx, config, f)
-
- build.Build(buildCtx, config)
-
- t.results.metrics = met
-}
-
-// Touch the Intent.java file to cause a rebuild of the frameworks to monitor the
-// incremental build speed as mentioned b/152046247. Intent.java file was chosen
-// as it is a key component of the framework and is often modified.
-func touchIntentFile() error {
- const intentFileName = "frameworks/base/core/java/android/content/Intent.java"
- currentTime := time.Now().Local()
- return os.Chtimes(intentFileName, currentTime, currentTime)
-}
-
-func main() {
- outDir := os.Getenv("OUT_DIR")
- if outDir == "" {
- outDir = "out"
- }
-
- cujDir := filepath.Join(outDir, "cuj_tests")
-
- wd, _ := os.Getwd()
- os.Setenv("TOP", wd)
- // Use a subdirectory for the out directory for the tests to keep them isolated.
- os.Setenv("OUT_DIR", filepath.Join(cujDir, "out"))
-
- // Each of these tests is run in sequence without resetting the output tree. The state of the output tree will
- // affect each successive test. To maintain the validity of the benchmarks across changes, care must be taken
- // to avoid changing the state of the tree when a test is run. This is most easily accomplished by adding tests
- // at the end.
- tests := []Test{
- {
- // Reset the out directory to get reproducible results.
- name: "clean",
- args: []string{"clean"},
- },
- {
- // Parse the build files.
- name: "nothing",
- args: []string{"nothing"},
- },
- {
- // Parse the build files again to monitor issues like globs rerunning.
- name: "nothing_rebuild",
- args: []string{"nothing"},
- },
- {
- // Parse the build files again, this should always be very short.
- name: "nothing_rebuild_twice",
- args: []string{"nothing"},
- },
- {
- // Build the framework as a common developer task and one that keeps getting longer.
- name: "framework",
- args: []string{"framework"},
- },
- {
- // Build the framework again to make sure it doesn't rebuild anything.
- name: "framework_rebuild",
- args: []string{"framework"},
- },
- {
- // Build the framework again to make sure it doesn't rebuild anything even if it did the second time.
- name: "framework_rebuild_twice",
- args: []string{"framework"},
- },
- {
- // Scenario major_inc_build (b/152046247): tracking build speed of major incremental build.
- name: "major_inc_build_droid",
- args: []string{"droid"},
- },
- {
- name: "major_inc_build_framework_minus_apex_after_droid_build",
- args: []string{"framework-minus-apex"},
- before: touchIntentFile,
- },
- {
- name: "major_inc_build_framework_after_droid_build",
- args: []string{"framework"},
- before: touchIntentFile,
- },
- {
- name: "major_inc_build_sync_after_droid_build",
- args: []string{"sync"},
- before: touchIntentFile,
- },
- {
- name: "major_inc_build_droid_rebuild",
- args: []string{"droid"},
- before: touchIntentFile,
- },
- {
- name: "major_inc_build_update_api_after_droid_rebuild",
- args: []string{"update-api"},
- before: touchIntentFile,
- },
- }
-
- cujMetrics := metrics.NewCriticalUserJourneysMetrics()
- defer cujMetrics.Dump(filepath.Join(cujDir, "logs", "cuj_metrics.pb"))
-
- for i, t := range tests {
- logsSubDir := fmt.Sprintf("%02d_%s", i, t.name)
- logsDir := filepath.Join(cujDir, "logs", logsSubDir)
- if t.before != nil {
- if err := t.before(); err != nil {
- fmt.Printf("error running before function on test %q: %v\n", t.name, err)
- break
- }
- }
- t.Run(logsDir)
- if t.results.err != nil {
- fmt.Printf("error running test %q: %s\n", t.name, t.results.err)
- break
- }
- if t.results.metrics != nil {
- cujMetrics.Add(t.name, t.results.metrics)
- }
- }
-}
diff --git a/cuj/run_cuj_tests.sh b/cuj/run_cuj_tests.sh
deleted file mode 100755
index a746bd5..0000000
--- a/cuj/run_cuj_tests.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/bash -e
-
-readonly UNAME="$(uname)"
-case "$UNAME" in
-Linux)
- readonly OS='linux'
- ;;
-Darwin)
- readonly OS='darwin'
- ;;
-*)
- echo "Unsupported OS '$UNAME'"
- exit 1
- ;;
-esac
-
-readonly ANDROID_TOP="$(cd $(dirname $0)/../../..; pwd)"
-cd "$ANDROID_TOP"
-
-export OUT_DIR="${OUT_DIR:-out}"
-
-build/soong/soong_ui.bash --make-mode "${OUT_DIR}/host/${OS}-x86/bin/cuj_tests"
-
-"${OUT_DIR}/host/${OS}-x86/bin/cuj_tests" || true
-
-if [ -n "${DIST_DIR}" ]; then
- cp -r "${OUT_DIR}/cuj_tests/logs" "${DIST_DIR}"
-fi
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index fe6317c..c5cafb1 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -191,6 +191,10 @@
ForceCreateAppImage bool
PresignedPrebuilt bool
+
+ // ApexPartition is the partition in which the dexpreopt files of apex system server jars (if any) are installed.
+ // This is a noop unless the module is apex system server jar.
+ ApexPartition string
}
type globalSoongConfigSingleton struct{}
@@ -458,6 +462,12 @@
return target.IsReplacedByPrebuilt()
}
+func (d dex2oatDependencyTag) AllowDisabledModuleDependencyProxy(
+ ctx android.OtherModuleProviderContext, target android.ModuleProxy) bool {
+ return android.OtherModuleProviderOrDefault(
+ ctx, target, android.CommonModuleInfoKey).ReplacedByPrebuilt
+}
+
// Dex2oatDepTag represents the dependency onto the dex2oatd module. It is added to any module that
// needs dexpreopting and so it makes no sense for it to be checked for visibility or included in
// the apex.
@@ -497,36 +507,37 @@
// final variants, while prebuilt_postdeps needs to run before many of the
// PostDeps mutators, like the APEX mutators). Hence we need to dig out the
// prebuilt explicitly here instead.
- var dex2oatModule android.Module
- ctx.WalkDeps(func(child, parent android.Module) bool {
- if parent == ctx.Module() && ctx.OtherModuleDependencyTag(child) == Dex2oatDepTag {
+ var dex2oatModule android.ModuleProxy
+ ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool {
+ prebuiltInfo, isPrebuilt := android.OtherModuleProvider(ctx, child, android.PrebuiltModuleInfoProvider)
+ if ctx.EqualModules(parent, ctx.Module()) && ctx.OtherModuleDependencyTag(child) == Dex2oatDepTag {
// Found the source module, or prebuilt module that has replaced the source.
dex2oatModule = child
- if android.IsModulePrebuilt(child) {
+ if isPrebuilt {
return false // If it's the prebuilt we're done.
} else {
return true // Recurse to check if the source has a prebuilt dependency.
}
}
- if parent == dex2oatModule && ctx.OtherModuleDependencyTag(child) == android.PrebuiltDepTag {
- if p := android.GetEmbeddedPrebuilt(child); p != nil && p.UsePrebuilt() {
+ if ctx.EqualModules(parent, dex2oatModule) && ctx.OtherModuleDependencyTag(child) == android.PrebuiltDepTag {
+ if isPrebuilt && prebuiltInfo.UsePrebuilt {
dex2oatModule = child // Found a prebuilt that should be used.
}
}
return false
})
- if dex2oatModule == nil {
+ if dex2oatModule.IsNil() {
// If this happens there's probably a missing call to AddToolDeps in DepsMutator.
panic(fmt.Sprintf("Failed to lookup %s dependency", dex2oatBin))
}
- dex2oatPath := dex2oatModule.(android.HostToolProvider).HostToolPath()
- if !dex2oatPath.Valid() {
+ dex2oatPath, ok := android.OtherModuleProvider(ctx, dex2oatModule, android.HostToolProviderInfoProvider)
+ if !ok || !dex2oatPath.HostToolPath.Valid() {
panic(fmt.Sprintf("Failed to find host tool path in %s", dex2oatModule))
}
- return dex2oatPath.Path()
+ return dex2oatPath.HostToolPath.Path()
}
// createGlobalSoongConfig creates a GlobalSoongConfig from the current context.
@@ -708,6 +719,16 @@
} else if global.EnableUffdGc == "default" {
// Generated by `build/make/core/Makefile`.
kernelVersionFile := android.PathForOutput(ctx, "dexpreopt/kernel_version_for_uffd_gc.txt")
+ if !ctx.Config().KatiEnabled() {
+ // In soong-only mode, we need to generate the kernel_version_for_uffd_gc.txt with kernel version
+ kernelVersion := android.String(ctx.Config().ProductVariables().BoardKernelVersion)
+ if kernelVersion == "" {
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=5382;drc=66783fca85911af9da48d9b4f35a61b3873023e9
+ panic("BOARD_KERNEL_VERSION is not set. Build team will convert more stuff from Make to Soong to support this scenario.")
+ }
+ android.WriteFileRule(ctx, kernelVersionFile, kernelVersion)
+ }
+
// Determine the UFFD GC flag by the kernel version file.
rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 5616483..7a39fa1 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -219,9 +219,9 @@
}
// Returns the location to the odex file for the dex file at `path`.
-func ToOdexPath(path string, arch android.ArchType) string {
+func ToOdexPath(path string, arch android.ArchType, partition string) string {
if strings.HasPrefix(path, "/apex/") {
- return filepath.Join("/system/framework/oat", arch.String(),
+ return filepath.Join(partition, "framework/oat", arch.String(),
strings.ReplaceAll(path[1:], "/", "@")+"@classes.odex")
}
@@ -245,7 +245,7 @@
odexPath := module.BuildPath.InSameDir(ctx, "oat", arch.String(), pathtools.ReplaceExtension(base, "odex"))
odexSymbolsPath := odexPath.ReplaceExtension(ctx, "symbols.odex")
- odexInstallPath := ToOdexPath(module.DexLocation, arch)
+ odexInstallPath := ToOdexPath(module.DexLocation, arch, module.ApexPartition)
if odexOnSystemOther(module, global) {
odexInstallPath = filepath.Join(SystemOtherPartition, odexInstallPath)
}
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 6f7d3bb..1f188d5 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -15,9 +15,10 @@
package dexpreopt
import (
- "android/soong/android"
"fmt"
"testing"
+
+ "android/soong/android"
)
func testSystemModuleConfig(ctx android.PathContext, name string) *ModuleConfig {
@@ -42,12 +43,14 @@
}
func testApexModuleConfig(ctx android.PathContext, name, apexName string) *ModuleConfig {
- return createTestModuleConfig(
+ ret := createTestModuleConfig(
name,
fmt.Sprintf("/apex/%s/javalib/%s.jar", apexName, name),
android.PathForOutput(ctx, fmt.Sprintf("%s/dexpreopt/%s.jar", name, name)),
android.PathForOutput(ctx, fmt.Sprintf("%s/aligned/%s.jar", name, name)),
android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name)))
+ ret.ApexPartition = "/system"
+ return ret
}
func testPlatformSystemServerModuleConfig(ctx android.PathContext, name string) *ModuleConfig {
@@ -221,6 +224,49 @@
DexpreoptRunningInSoong = oldDexpreoptRunningInSoong
}
+// Same as `TestDexPreoptApexSystemServerJars`, but the apex jar is in /system_ext
+func TestDexPreoptApexSystemServerJarsSystemExt(t *testing.T) {
+ // modify the global variable for test
+ var oldDexpreoptRunningInSoong = DexpreoptRunningInSoong
+ DexpreoptRunningInSoong = true
+
+ // test begin
+ config := android.TestConfig("out", nil, "", nil)
+ ctx := android.BuilderContextForTesting(config)
+ globalSoong := globalSoongConfigForTests(ctx)
+ global := GlobalConfigForTests(ctx)
+ module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
+ module.ApexPartition = "/system_ext"
+ productPackages := android.PathForTesting("product_packages.txt")
+
+ global.ApexSystemServerJars = android.CreateTestConfiguredJarList(
+ []string{"com.android.apex1:service-A"})
+
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ wantInstalls := android.RuleBuilderInstalls{
+ {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.odex"), "/system_ext/framework/oat/arm/apex@com.android.apex1@javalib@service-A.jar@classes.odex"},
+ {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.vdex"), "/system_ext/framework/oat/arm/apex@com.android.apex1@javalib@service-A.jar@classes.vdex"},
+ }
+
+ android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String())
+
+ android.AssertStringListContains(t, "apex sscp jar copy", rule.Outputs().Strings(), "out/soong/system_server_dexjars/service-A.jar")
+
+ // rule with apex sscp cp as false
+ rule, err = GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, false)
+ if err != nil {
+ t.Fatal(err)
+ }
+ android.AssertStringListDoesNotContain(t, "apex sscp jar copy", rule.Outputs().Strings(), "out/soong/system_server_dexjars/service-A.jar")
+
+ // cleanup the global variable for test
+ DexpreoptRunningInSoong = oldDexpreoptRunningInSoong
+}
+
func TestDexPreoptStandaloneSystemServerJars(t *testing.T) {
config := android.TestConfig("out", nil, "", nil)
ctx := android.BuilderContextForTesting(config)
@@ -358,6 +404,7 @@
preparers := android.GroupFixturePreparers(
PrepareForTestWithFakeDex2oatd,
PrepareForTestWithDexpreoptConfig,
+ android.FixtureModifyConfig(android.SetKatiEnabledForTests),
FixtureSetEnableUffdGc("default"),
)
diff --git a/docs/OWNERS b/docs/OWNERS
new file mode 100644
index 0000000..776beca
--- /dev/null
+++ b/docs/OWNERS
@@ -0,0 +1 @@
+per-file map_files.md = danalbert@google.com
diff --git a/docs/map_files.md b/docs/map_files.md
index e1ddefc..8d6af87 100644
--- a/docs/map_files.md
+++ b/docs/map_files.md
@@ -88,12 +88,17 @@
### introduced
-Indicates the version in which an API was first introduced. For example,
-`introduced=21` specifies that the API was first added (or first made public) in
-API level 21. This tag can be applied to either a version definition or an
-individual symbol. If applied to a version, all symbols contained in the version
-will have the tag applied. An `introduced` tag on a symbol overrides the value
-set for the version, if both are defined.
+Indicates the version in which an API was first introduced in the NDK. For
+example, `introduced=21` specifies that the API was first added (or first made
+public) in API level 21. This tag can be applied to either a version definition
+or an individual symbol. If applied to a version, all symbols contained in the
+version will have the tag applied. An `introduced` tag on a symbol overrides the
+value set for the version, if both are defined.
+
+The `introduced` tag should only be used with NDK APIs. Other API surface tags
+(such as `apex`) will override `introduced`. APIs that are in the NDK should
+never use tags like `apex`, and APIs that are not in the NDK should never use
+`introduced`.
Note: The map file alone does not contain all the information needed to
determine which API level an API was added in. The `first_version` property of
diff --git a/docs/perf.md b/docs/perf.md
index 5b53c8d..446ba9d 100644
--- a/docs/perf.md
+++ b/docs/perf.md
@@ -61,8 +61,7 @@
saves CPU profile for each Soong invocation in /tmp/foo._step_ file, where
_step_ is Soong execution step. The main step is `build`. The others as
-`bp2build_files`, `bp2build_workspace`, `modulegraph`, `queryview`,
-`api_bp2build`, `soong_docs` (not all of them necessarily run during the build).
+`soong_docs` (not all of them necessarily run during the build).
The profiles can be inspected with `go tool pprof` from the command line or
with _Run>Open Profiler Snapshot_ in IntelliJ IDEA.
diff --git a/docs/selects.md b/docs/selects.md
new file mode 100644
index 0000000..4f436ac
--- /dev/null
+++ b/docs/selects.md
@@ -0,0 +1,170 @@
+# Select statements
+
+## Introduction
+
+Soong currently has the arch, target, product_variables, and soong config variable properties that all support changing the values of soong properties based on some condition. These are confusing for users, and particularly the soong config variable properties require a lot of boilerplate that is annoying to write.
+
+In addition, these properties are all implemented using reflection on property structs, and can combine in ways that the original authors did not expect. For example, soong config variables can be combined with arch/target by saying that they operate on "arch.arm.enabled" instead of just "enabled". But product variables do not have the same abilities.
+
+The goal here is to combine all these different configuration mechanisms into one, to reduce complexity and boilerplate both in Android.bp files and in soong code.
+
+## Usage
+
+The soong select statements take their name and inspiration from [bazel select statements](https://bazel.build/docs/configurable-attributes).
+
+### Syntax
+
+#### Basic
+
+The basic syntax for select statements looks like:
+
+```
+my_module_type {
+ name: "my_module",
+ some_string_property: select(arch(), {
+ "arm": "foo",
+ "x86": "bar",
+ default: "baz",
+ }),
+}
+```
+
+That is, `select(` followed by a variable function, then a map of values of the variable to values to set the property to.
+
+Arguments can be passed to the "functions" that look up axes:
+
+```
+select(soong_config_variable("my_namespace", "my_variable"), {
+ "value1": "foo",
+ default: "bar",
+})
+```
+
+
+The list of functions that can currently be selected on:
+ - `arch()`
+ - `os()`
+ - `soong_config_variable(namespace, variable)`
+ - `release_flag(flag)`
+
+The functions are [defined here](https://cs.android.com/android/platform/superproject/main/+/main:build/soong/android/module.go;l=2144;drc=3f01580c04bfe37c920e247015cce93cff2451c0), and it should be easy to add more.
+
+#### Multivariable
+
+To handle multivariable selects, multiple axes can be specified within parenthesis, to look like tuple destructuring. All of the variables being selected must match the corresponding value from the branch in order for the branch to be chosen.
+
+```
+select((arch(), os()), {
+ ("arm", "linux"): "foo",
+ (default, "windows"): "bar",
+ (default, default): "baz",
+})
+```
+
+#### Unset
+
+You can have unset branches of selects using the "unset" keyword, which will act as if the property was not assigned to. This is only really useful if you’re using defaults modules.
+
+```
+cc_binary {
+ name: "my_binary",
+ enabled: select(os(), {
+ "darwin": false,
+ default: unset,
+ }),
+}
+```
+
+#### Appending
+
+You can append select statements to both scalar values and other select statements:
+
+```
+my_module_type {
+ name: "my_module",
+ // string_property will be set to something like penguin-four, apple-two, etc.
+ string_property: select(os(), {
+ "linux_glibc": "penguin",
+ "darwin": "apple",
+ default: "unknown",
+ }) + "-" + select(soong_config_variable("ANDROID", "favorite_vehicle"), {
+ "car": "four",
+ "tricycle": "three",
+ "bike": "two",
+ default: "unknown",
+ })
+}
+```
+
+
+You can also append a select with a value with another select that may not have a value, because some of its branches are "unset". If an unset branch was selected it will not append anything to the other select.
+
+#### Binding the selected value to a Blueprint variable and the "any" keyword
+
+In case you want to allow a selected value to have an unbounded number of possible values, you can bind its value to a blueprint variable and use it within the expression for that select branch.
+
+```
+my_module_type {
+ name: "my_module",
+ my_string_property: select(soong_config_variable("my_namespace", "my_variable"), {
+ "some_value": "baz",
+ any @ my_var: "foo" + my_var,
+ default: "bar",
+ }),
+}
+```
+
+The syntax is `any @ my_variable_name: <expression using my_variable_name>`. `any` is currently the only pattern that can be bound to a variable, but we may add more in the future. `any` is equivalent to `default` except it will not match undefined select conditions.
+
+#### Errors
+
+If a select statement does not have a "default" branch, and none of the other branches match the variable being selected on, it’s a compile-time error. This may be useful for enforcing a variable is 1 of only a few values.
+
+```
+# in product config:
+$(call soong_config_set,ANDROID,my_variable,foo)
+
+// in an Android.bp:
+my_module_type {
+ name: "my_module",
+ // Will error out with: soong_config_variable("ANDROID", "my_variable") had value "foo", which was not handled by the select
+ enabled: select(soong_config_variable("ANDROID", "my_variable"), {
+ "bar": true,
+ "baz": false,
+ }),
+}
+```
+
+### Changes to property structs to support selects
+
+Currently, the way configurable properties work is that there is secretly another property struct that has the `target`, `arch`, etc. properties, and then when the arch mutator (or other relevant mutator) runs, it copies the values of these properties onto the regular property structs. There’s nothing stopping you from accessing your properties from a mutator that runs before the one that updates the properties based on configurable values. This is a potential source of bugs, and we want to make sure that select statements don’t have the same pitfall. For that reason, you have to read property’s values through a getter which can do this check. This requires changing the code on a property-by-property basis to support selects.
+
+To make a property support selects, it must be of type [proptools.Configurable[T]](https://cs.android.com/android/platform/superproject/main/+/main:build/blueprint/proptools/configurable.go;l=341;drc=a52b058cccd2caa778d0f97077adcd4ef7ffb68a). T is the old type of the property. Currently we support bool, string, and []string. Configurable has a `Get(evaluator)` method to get the value of the property. The evaluator can be a ModuleContext, or if you’re in a situation where you only have a very limited context and a module, (such as in a singleton) you can use [ModuleBase.ConfigurableEvaluator](https://cs.android.com/android/platform/superproject/main/+/main:build/soong/android/module.go;l=2133;drc=e19f741052cce097da940d9083d3f29e668de5cb).
+
+`proptools.Configurable[T]` will handle unset properties for you, so you don’t need to make it a pointer type. However, there is a not-widely-known feature of property structs, where normally, properties are appended when squashing defaults. But if the property was a pointer property, later defaults replace earlier values instead of appending. With selects, to maintain this behavior, add the `android:"replace_instead_of_append"` struct tag. The "append" behavior for boolean values is to boolean OR them together, which is rarely what you want, so most boolean properties are pointers today.
+
+Old:
+```
+type commonProperties struct {
+ Enabled *bool `android:"arch_variant"`
+}
+
+func (m *ModuleBase) Enabled() *bool {
+ return m.commonProperties.Enabled
+}
+```
+
+New:
+```
+type commonProperties struct {
+ Enabled proptools.Configurable[bool] `android:"arch_variant,replace_instead_of_append"`
+}
+
+func (m *ModuleBase) Enabled(ctx ConfigAndErrorContext) *bool {
+ return m.commonProperties.Enabled.Get(m.ConfigurableEvaluator(ctx))
+}
+```
+
+The `android:"arch_variant"` tag is kept to support the old `target:` and `arch:` properties with this property, but if all their usages in bp files were replaced by selects, then that tag could be removed.
+
+The enabled property underwent this migration in https://r.android.com/3066188
diff --git a/docs/tidy.md b/docs/tidy.md
index ae0ca93..2e4c957 100644
--- a/docs/tidy.md
+++ b/docs/tidy.md
@@ -38,7 +38,7 @@
clang-tidy is enabled explicitly and with a different check list:
```
cc_defaults {
- name: "bpf_defaults",
+ name: "bpf_cc_defaults",
// snipped
tidy: true,
tidy_checks: [
@@ -52,7 +52,7 @@
}
```
That means in normal builds, even without `WITH_TIDY=1`,
-the modules that use `bpf_defaults` _should_ run clang-tidy
+the modules that use `bpf_cc_defaults` _should_ run clang-tidy
over C/C++ source files with the given `tidy_checks`.
However since clang-tidy warnings and its runtime cost might
diff --git a/etc/Android.bp b/etc/Android.bp
index f02c12a..e92437e 100644
--- a/etc/Android.bp
+++ b/etc/Android.bp
@@ -11,6 +11,8 @@
"soong-android",
],
srcs: [
+ "adb_keys.go",
+ "avbpubkey.go",
"install_symlink.go",
"otacerts_zip.go",
"prebuilt_etc.go",
@@ -20,4 +22,6 @@
"install_symlink_test.go",
],
pluginFor: ["soong_build"],
+ // Used by plugins
+ visibility: ["//visibility:public"],
}
diff --git a/etc/adb_keys.go b/etc/adb_keys.go
new file mode 100644
index 0000000..cfcb1d5
--- /dev/null
+++ b/etc/adb_keys.go
@@ -0,0 +1,71 @@
+// 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 etc
+
+import (
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterModuleType("adb_keys", AdbKeysModuleFactory)
+}
+
+type AdbKeysModule struct {
+ android.ModuleBase
+ outputPath android.Path
+ installPath android.InstallPath
+}
+
+func AdbKeysModuleFactory() android.Module {
+ module := &AdbKeysModule{}
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ return module
+}
+
+func (m *AdbKeysModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ productVariables := ctx.Config().ProductVariables()
+
+ if !m.ProductSpecific() {
+ ctx.ModuleErrorf("adb_keys module type must set product_specific to true")
+ }
+
+ if !(android.Bool(productVariables.Debuggable) && len(android.String(productVariables.AdbKeys)) > 0) {
+ m.SkipInstall()
+ return
+ }
+
+ outputPath := android.PathForModuleOut(ctx, "adb_keys")
+ input := android.ExistentPathForSource(ctx, android.String(productVariables.AdbKeys))
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Output: outputPath,
+ Input: input.Path(),
+ })
+ m.installPath = android.PathForModuleInstall(ctx, "etc/security")
+ ctx.InstallFile(m.installPath, "adb_keys", outputPath)
+ m.outputPath = outputPath
+}
+
+func (m *AdbKeysModule) AndroidMkEntries() []android.AndroidMkEntries {
+ if m.IsSkipInstall() {
+ return []android.AndroidMkEntries{}
+ }
+
+ return []android.AndroidMkEntries{
+ {
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(m.outputPath),
+ }}
+}
diff --git a/etc/avbpubkey.go b/etc/avbpubkey.go
new file mode 100644
index 0000000..dc242ce
--- /dev/null
+++ b/etc/avbpubkey.go
@@ -0,0 +1,85 @@
+// 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 etc
+
+import (
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+func init() {
+ android.RegisterModuleType("avbpubkey", AvbpubkeyModuleFactory)
+ pctx.HostBinToolVariable("avbtool", "avbtool")
+}
+
+type avbpubkeyProperty struct {
+ Private_key *string `android:"path"`
+}
+
+type AvbpubkeyModule struct {
+ android.ModuleBase
+
+ properties avbpubkeyProperty
+
+ outputPath android.WritablePath
+ installPath android.InstallPath
+}
+
+func AvbpubkeyModuleFactory() android.Module {
+ module := &AvbpubkeyModule{}
+ module.AddProperties(&module.properties)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ return module
+}
+
+var avbPubKeyRule = pctx.AndroidStaticRule("avbpubkey",
+ blueprint.RuleParams{
+ Command: `${avbtool} extract_public_key --key ${in} --output ${out}.tmp` +
+ ` && ( if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`,
+ CommandDeps: []string{"${avbtool}"},
+ Restat: true,
+ Description: "Extracting system_other avb key",
+ })
+
+func (m *AvbpubkeyModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ if !m.ProductSpecific() {
+ ctx.ModuleErrorf("avbpubkey module type must set product_specific to true")
+ }
+
+ m.outputPath = android.PathForModuleOut(ctx, ctx.ModuleName(), "system_other.avbpubkey")
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: avbPubKeyRule,
+ Input: android.PathForModuleSrc(ctx, proptools.String(m.properties.Private_key)),
+ Output: m.outputPath,
+ })
+
+ m.installPath = android.PathForModuleInstall(ctx, "etc/security/avb")
+ ctx.InstallFile(m.installPath, "system_other.avbpubkey", m.outputPath)
+}
+
+func (m *AvbpubkeyModule) AndroidMkEntries() []android.AndroidMkEntries {
+ if m.IsSkipInstall() {
+ return []android.AndroidMkEntries{}
+ }
+
+ return []android.AndroidMkEntries{
+ {
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(m.outputPath),
+ }}
+}
diff --git a/etc/install_symlink.go b/etc/install_symlink.go
index 2182b86..aa33445 100644
--- a/etc/install_symlink.go
+++ b/etc/install_symlink.go
@@ -26,6 +26,7 @@
func RegisterInstallSymlinkBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("install_symlink", InstallSymlinkFactory)
+ ctx.RegisterModuleType("install_symlink_host", InstallSymlinkHostFactory)
}
// install_symlink can be used to install an symlink with an arbitrary target to an arbitrary path
@@ -37,6 +38,14 @@
return module
}
+// install_symlink can be used to install an symlink to an arbitrary path on the host.
+func InstallSymlinkHostFactory() android.Module {
+ module := &InstallSymlink{}
+ module.AddProperties(&module.properties)
+ android.InitAndroidMultiTargetsArchModule(module, android.HostSupported, android.MultilibCommon)
+ return module
+}
+
type InstallSymlinkProperties struct {
// Where to install this symlink, relative to the partition it's installed on.
// Which partition it's installed on can be controlled by the vendor, system_ext, ramdisk, etc.
diff --git a/etc/install_symlink_test.go b/etc/install_symlink_test.go
index d7165e5..c97d97c 100644
--- a/etc/install_symlink_test.go
+++ b/etc/install_symlink_test.go
@@ -133,3 +133,39 @@
}
`)
}
+
+var prepareForInstallSymlinkHostTest = android.GroupFixturePreparers(
+ android.PrepareForTestWithAndroidBuildComponents,
+ android.FixtureRegisterWithContext(RegisterInstallSymlinkBuildComponents),
+)
+
+func TestInstallSymlinkHostBasic(t *testing.T) {
+ result := prepareForInstallSymlinkHostTest.RunTestWithBp(t, `
+ install_symlink_host {
+ name: "foo",
+ installed_location: "bin/foo",
+ symlink_target: "aa/bb/cc",
+ }
+ `)
+
+ buildOS := result.Config.BuildOS.String()
+ foo := result.ModuleForTests("foo", buildOS+"_common").Module()
+
+ androidMkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, foo)
+ if len(androidMkEntries) != 1 {
+ t.Fatalf("expected 1 androidmkentry, got %d", len(androidMkEntries))
+ }
+
+ symlinks := androidMkEntries[0].EntryMap["LOCAL_SOONG_INSTALL_SYMLINKS"]
+ if len(symlinks) != 1 {
+ t.Fatalf("Expected 1 symlink, got %d", len(symlinks))
+ }
+
+ if !strings.HasSuffix(symlinks[0], "bin/foo") {
+ t.Fatalf("Expected symlink install path to end in bin/foo, got: %s", symlinks[0])
+ }
+
+ if !strings.Contains(symlinks[0], "host") {
+ t.Fatalf("Expected symlink install path to contain `host`, got: %s", symlinks[0])
+ }
+}
diff --git a/etc/otacerts_zip.go b/etc/otacerts_zip.go
index b6f175a..53ddc50 100644
--- a/etc/otacerts_zip.go
+++ b/etc/otacerts_zip.go
@@ -44,7 +44,7 @@
android.ModuleBase
properties otacertsZipProperties
- outputPath android.OutputPath
+ outputPath android.Path
}
// otacerts_zip collects key files defined in PRODUCT_DEFAULT_DEV_CERTIFICATE
@@ -61,41 +61,41 @@
var _ android.ImageInterface = (*otacertsZipModule)(nil)
-func (m *otacertsZipModule) ImageMutatorBegin(ctx android.BaseModuleContext) {}
+func (m *otacertsZipModule) ImageMutatorBegin(ctx android.ImageInterfaceContext) {}
-func (m *otacertsZipModule) VendorVariantNeeded(ctx android.BaseModuleContext) bool {
+func (m *otacertsZipModule) VendorVariantNeeded(ctx android.ImageInterfaceContext) bool {
return false
}
-func (m *otacertsZipModule) ProductVariantNeeded(ctx android.BaseModuleContext) bool {
+func (m *otacertsZipModule) ProductVariantNeeded(ctx android.ImageInterfaceContext) bool {
return false
}
-func (m *otacertsZipModule) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+func (m *otacertsZipModule) CoreVariantNeeded(ctx android.ImageInterfaceContext) bool {
return !m.ModuleBase.InstallInRecovery()
}
-func (m *otacertsZipModule) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (m *otacertsZipModule) RamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return false
}
-func (m *otacertsZipModule) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (m *otacertsZipModule) VendorRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return false
}
-func (m *otacertsZipModule) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (m *otacertsZipModule) DebugRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return false
}
-func (m *otacertsZipModule) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
+func (m *otacertsZipModule) RecoveryVariantNeeded(ctx android.ImageInterfaceContext) bool {
return proptools.Bool(m.properties.Recovery_available) || m.ModuleBase.InstallInRecovery()
}
-func (m *otacertsZipModule) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+func (m *otacertsZipModule) ExtraImageVariations(ctx android.ImageInterfaceContext) []string {
return nil
}
-func (m *otacertsZipModule) SetImageVariation(ctx android.BaseModuleContext, variation string) {
+func (m *otacertsZipModule) SetImageVariation(ctx android.ImageInterfaceContext, variation string) {
}
func (m *otacertsZipModule) InRecovery() bool {
@@ -111,17 +111,21 @@
return proptools.StringDefault(m.properties.Filename, "otacerts.zip")
}
+func (m *otacertsZipModule) onlyInRecovery() bool {
+ return m.ModuleBase.InstallInRecovery()
+}
+
func (m *otacertsZipModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// Read .x509.pem file defined in PRODUCT_DEFAULT_DEV_CERTIFICATE or the default test key.
pem, _ := ctx.Config().DefaultAppCertificate(ctx)
// Read .x509.pem files listed in PRODUCT_EXTRA_OTA_KEYS or PRODUCT_EXTRA_RECOVERY_KEYS.
extras := ctx.Config().ExtraOtaKeys(ctx, m.InRecovery())
srcPaths := append([]android.SourcePath{pem}, extras...)
- m.outputPath = android.PathForModuleOut(ctx, m.outputFileName()).OutputPath
+ outputPath := android.PathForModuleOut(ctx, m.outputFileName())
rule := android.NewRuleBuilder(pctx, ctx)
cmd := rule.Command().BuiltTool("soong_zip").
- FlagWithOutput("-o ", m.outputPath).
+ FlagWithOutput("-o ", outputPath).
Flag("-j ").
Flag("-symlinks=false ")
for _, src := range srcPaths {
@@ -130,12 +134,13 @@
rule.Build(ctx.ModuleName(), "Generating the otacerts zip file")
installPath := android.PathForModuleInstall(ctx, "etc", proptools.String(m.properties.Relative_install_path))
- ctx.InstallFile(installPath, m.outputFileName(), m.outputPath)
+ ctx.InstallFile(installPath, m.outputFileName(), outputPath)
+ m.outputPath = outputPath
}
func (m *otacertsZipModule) AndroidMkEntries() []android.AndroidMkEntries {
nameSuffix := ""
- if m.InRecovery() {
+ if m.InRecovery() && !m.onlyInRecovery() {
nameSuffix = ".recovery"
}
return []android.AndroidMkEntries{android.AndroidMkEntries{
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index fc6d1f7..2bcbde1 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -59,12 +59,32 @@
ctx.RegisterModuleType("prebuilt_usr_keylayout", PrebuiltUserKeyLayoutFactory)
ctx.RegisterModuleType("prebuilt_usr_keychars", PrebuiltUserKeyCharsFactory)
ctx.RegisterModuleType("prebuilt_usr_idc", PrebuiltUserIdcFactory)
+ ctx.RegisterModuleType("prebuilt_usr_srec", PrebuiltUserSrecFactory)
ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
ctx.RegisterModuleType("prebuilt_overlay", PrebuiltOverlayFactory)
ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory)
ctx.RegisterModuleType("prebuilt_rfsa", PrebuiltRFSAFactory)
ctx.RegisterModuleType("prebuilt_renderscript_bitcode", PrebuiltRenderScriptBitcodeFactory)
+ ctx.RegisterModuleType("prebuilt_media", PrebuiltMediaFactory)
+ ctx.RegisterModuleType("prebuilt_voicepack", PrebuiltVoicepackFactory)
+ ctx.RegisterModuleType("prebuilt_bin", PrebuiltBinaryFactory)
+ ctx.RegisterModuleType("prebuilt_wallpaper", PrebuiltWallpaperFactory)
+ ctx.RegisterModuleType("prebuilt_priv_app", PrebuiltPrivAppFactory)
+ ctx.RegisterModuleType("prebuilt_rfs", PrebuiltRfsFactory)
+ ctx.RegisterModuleType("prebuilt_framework", PrebuiltFrameworkFactory)
+ ctx.RegisterModuleType("prebuilt_res", PrebuiltResFactory)
+ ctx.RegisterModuleType("prebuilt_wlc_upt", PrebuiltWlcUptFactory)
+ ctx.RegisterModuleType("prebuilt_odm", PrebuiltOdmFactory)
+ ctx.RegisterModuleType("prebuilt_vendor_dlkm", PrebuiltVendorDlkmFactory)
+ ctx.RegisterModuleType("prebuilt_bt_firmware", PrebuiltBtFirmwareFactory)
+ ctx.RegisterModuleType("prebuilt_tvservice", PrebuiltTvServiceFactory)
+ ctx.RegisterModuleType("prebuilt_optee", PrebuiltOpteeFactory)
+ ctx.RegisterModuleType("prebuilt_tvconfig", PrebuiltTvConfigFactory)
+ ctx.RegisterModuleType("prebuilt_vendor", PrebuiltVendorFactory)
+ ctx.RegisterModuleType("prebuilt_sbin", PrebuiltSbinFactory)
+ ctx.RegisterModuleType("prebuilt_system", PrebuiltSystemFactory)
+ ctx.RegisterModuleType("prebuilt_first_stage_ramdisk", PrebuiltFirstStageRamdiskFactory)
ctx.RegisterModuleType("prebuilt_defaults", defaultsFactory)
@@ -72,15 +92,22 @@
var PrepareForTestWithPrebuiltEtc = android.FixtureRegisterWithContext(RegisterPrebuiltEtcBuildComponents)
-type prebuiltEtcProperties struct {
+type PrebuiltEtcProperties struct {
// Source file of this prebuilt. Can reference a genrule type module with the ":module" syntax.
// Mutually exclusive with srcs.
Src proptools.Configurable[string] `android:"path,arch_variant,replace_instead_of_append"`
// Source files of this prebuilt. Can reference a genrule type module with the ":module" syntax.
- // Mutually exclusive with src. When used, filename_from_src is set to true.
+ // Mutually exclusive with src. When used, filename_from_src is set to true unless dsts is also
+ // set. May use globs in filenames.
Srcs proptools.Configurable[[]string] `android:"path,arch_variant"`
+ // Destination files of this prebuilt. Requires srcs to be used and causes srcs not to implicitly
+ // set filename_from_src. This can be used to install each source file to a different directory
+ // and/or change filenames when files are installed. Must be exactly one entry per source file,
+ // which means care must be taken if srcs has globs.
+ Dsts proptools.Configurable[[]string] `android:"path,arch_variant"`
+
// Optional name for the installed file. If unspecified, name of the module is used as the file
// name. Only available when using a single source (src).
Filename *string `android:"arch_variant"`
@@ -114,6 +141,9 @@
// Install symlinks to the installed file.
Symlinks []string `android:"arch_variant"`
+
+ // Install to partition oem when set to true.
+ Oem_specific *bool `android:"arch_variant"`
}
type prebuiltSubdirProperties struct {
@@ -149,7 +179,7 @@
android.ModuleBase
android.DefaultableModuleBase
- properties prebuiltEtcProperties
+ properties PrebuiltEtcProperties
// rootProperties is used to return the value of the InstallInRoot() method. Currently, only
// prebuilt_avb and prebuilt_root modules use this.
@@ -158,7 +188,7 @@
subdirProperties prebuiltSubdirProperties
sourceFilePaths android.Paths
- outputFilePaths android.OutputPaths
+ outputFilePaths android.WritablePaths
// The base install location, e.g. "etc" for prebuilt_etc, "usr/share" for prebuilt_usr_share.
installDirBase string
installDirBase64 string
@@ -166,7 +196,7 @@
// The base install location when soc_specific property is set to true, e.g. "firmware" for
// prebuilt_firmware.
socInstallDirBase string
- installDirPath android.InstallPath
+ installDirPaths []android.InstallPath
additionalDependencies *android.Paths
usedSrcsProperty bool
@@ -229,30 +259,30 @@
var _ android.ImageInterface = (*PrebuiltEtc)(nil)
-func (p *PrebuiltEtc) ImageMutatorBegin(ctx android.BaseModuleContext) {}
+func (p *PrebuiltEtc) ImageMutatorBegin(ctx android.ImageInterfaceContext) {}
-func (p *PrebuiltEtc) VendorVariantNeeded(ctx android.BaseModuleContext) bool {
+func (p *PrebuiltEtc) VendorVariantNeeded(ctx android.ImageInterfaceContext) bool {
return false
}
-func (p *PrebuiltEtc) ProductVariantNeeded(ctx android.BaseModuleContext) bool {
+func (p *PrebuiltEtc) ProductVariantNeeded(ctx android.ImageInterfaceContext) bool {
return false
}
-func (p *PrebuiltEtc) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+func (p *PrebuiltEtc) CoreVariantNeeded(ctx android.ImageInterfaceContext) bool {
return !p.ModuleBase.InstallInRecovery() && !p.ModuleBase.InstallInRamdisk() &&
!p.ModuleBase.InstallInVendorRamdisk() && !p.ModuleBase.InstallInDebugRamdisk()
}
-func (p *PrebuiltEtc) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (p *PrebuiltEtc) RamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return proptools.Bool(p.properties.Ramdisk_available) || p.ModuleBase.InstallInRamdisk()
}
-func (p *PrebuiltEtc) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (p *PrebuiltEtc) VendorRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return proptools.Bool(p.properties.Vendor_ramdisk_available) || p.ModuleBase.InstallInVendorRamdisk()
}
-func (p *PrebuiltEtc) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (p *PrebuiltEtc) DebugRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return proptools.Bool(p.properties.Debug_ramdisk_available) || p.ModuleBase.InstallInDebugRamdisk()
}
@@ -260,15 +290,15 @@
return proptools.Bool(p.rootProperties.Install_in_root)
}
-func (p *PrebuiltEtc) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
+func (p *PrebuiltEtc) RecoveryVariantNeeded(ctx android.ImageInterfaceContext) bool {
return proptools.Bool(p.properties.Recovery_available) || p.ModuleBase.InstallInRecovery()
}
-func (p *PrebuiltEtc) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+func (p *PrebuiltEtc) ExtraImageVariations(ctx android.ImageInterfaceContext) []string {
return nil
}
-func (p *PrebuiltEtc) SetImageVariation(ctx android.BaseModuleContext, variation string) {
+func (p *PrebuiltEtc) SetImageVariation(ctx android.ImageInterfaceContext, variation string) {
}
func (p *PrebuiltEtc) SourceFilePath(ctx android.ModuleContext) android.Path {
@@ -279,7 +309,10 @@
}
func (p *PrebuiltEtc) InstallDirPath() android.InstallPath {
- return p.installDirPath
+ if len(p.installDirPaths) != 1 {
+ panic(fmt.Errorf("InstallDirPath not available on multi-source prebuilt %q", p.Name()))
+ }
+ return p.installDirPaths[0]
}
// This allows other derivative modules (e.g. prebuilt_etc_xml) to perform
@@ -288,7 +321,7 @@
p.additionalDependencies = &paths
}
-func (p *PrebuiltEtc) OutputFile() android.OutputPath {
+func (p *PrebuiltEtc) OutputFile() android.Path {
if p.usedSrcsProperty {
panic(fmt.Errorf("OutputFile not available on multi-source prebuilt %q", p.Name()))
}
@@ -338,12 +371,20 @@
if srcProperty.IsPresent() && len(srcsProperty) > 0 {
ctx.PropertyErrorf("src", "src is set. Cannot set srcs")
}
+ dstsProperty := p.properties.Dsts.GetOrDefault(ctx, nil)
+ if len(dstsProperty) > 0 && len(srcsProperty) == 0 {
+ ctx.PropertyErrorf("dsts", "dsts is set. Must use srcs")
+ }
// Check that `sub_dir` and `relative_install_path` are not set at the same time.
if p.subdirProperties.Sub_dir != nil && p.subdirProperties.Relative_install_path != nil {
ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir")
}
- p.installDirPath = android.PathForModuleInstall(ctx, p.installBaseDir(ctx), p.SubDir())
+ baseInstallDirPath := android.PathForModuleInstall(ctx, p.installBaseDir(ctx), p.SubDir())
+ // TODO(b/377304441)
+ if android.Bool(p.properties.Oem_specific) {
+ baseInstallDirPath = android.PathForModuleInPartitionInstall(ctx, ctx.DeviceConfig().OemPath(), p.installBaseDir(ctx), p.SubDir())
+ }
filename := proptools.String(p.properties.Filename)
filenameFromSrc := proptools.Bool(p.properties.Filename_from_src)
@@ -373,16 +414,17 @@
ctx.PropertyErrorf("filename", "filename cannot contain separator '/'")
return
}
- p.outputFilePaths = android.OutputPaths{android.PathForModuleOut(ctx, filename).OutputPath}
+ p.outputFilePaths = android.WritablePaths{android.PathForModuleOut(ctx, filename)}
ip := installProperties{
filename: filename,
sourceFilePath: p.sourceFilePaths[0],
outputFilePath: p.outputFilePaths[0],
- installDirPath: p.installDirPath,
+ installDirPath: baseInstallDirPath,
symlinks: p.properties.Symlinks,
}
installs = append(installs, ip)
+ p.installDirPaths = append(p.installDirPaths, baseInstallDirPath)
} else if len(srcsProperty) > 0 {
p.usedSrcsProperty = true
if filename != "" {
@@ -392,20 +434,39 @@
ctx.PropertyErrorf("symlinks", "symlinks cannot be set when using srcs")
}
if p.properties.Filename_from_src != nil {
- ctx.PropertyErrorf("filename_from_src", "filename_from_src is implicitly set to true when using srcs")
+ if len(dstsProperty) > 0 {
+ ctx.PropertyErrorf("filename_from_src", "dsts is set. Cannot set filename_from_src")
+ } else {
+ ctx.PropertyErrorf("filename_from_src", "filename_from_src is implicitly set to true when using srcs")
+ }
}
p.sourceFilePaths = android.PathsForModuleSrc(ctx, srcsProperty)
- for _, src := range p.sourceFilePaths {
- filename := src.Base()
- output := android.PathForModuleOut(ctx, filename).OutputPath
+ if len(dstsProperty) > 0 && len(p.sourceFilePaths) != len(dstsProperty) {
+ ctx.PropertyErrorf("dsts", "Must have one entry in dsts per source file")
+ }
+ for i, src := range p.sourceFilePaths {
+ var filename string
+ var installDirPath android.InstallPath
+
+ if len(dstsProperty) > 0 {
+ var dstdir string
+
+ dstdir, filename = filepath.Split(dstsProperty[i])
+ installDirPath = baseInstallDirPath.Join(ctx, dstdir)
+ } else {
+ filename = src.Base()
+ installDirPath = baseInstallDirPath
+ }
+ output := android.PathForModuleOut(ctx, filename)
ip := installProperties{
filename: filename,
sourceFilePath: src,
outputFilePath: output,
- installDirPath: p.installDirPath,
+ installDirPath: installDirPath,
}
p.outputFilePaths = append(p.outputFilePaths, output)
installs = append(installs, ip)
+ p.installDirPaths = append(p.installDirPaths, installDirPath)
}
} else if ctx.Config().AllowMissingDependencies() {
// If no srcs was set and AllowMissingDependencies is enabled then
@@ -416,14 +477,15 @@
if filename == "" {
filename = ctx.ModuleName()
}
- p.outputFilePaths = android.OutputPaths{android.PathForModuleOut(ctx, filename).OutputPath}
+ p.outputFilePaths = android.WritablePaths{android.PathForModuleOut(ctx, filename)}
ip := installProperties{
filename: filename,
sourceFilePath: p.sourceFilePaths[0],
outputFilePath: p.outputFilePaths[0],
- installDirPath: p.installDirPath,
+ installDirPath: baseInstallDirPath,
}
installs = append(installs, ip)
+ p.installDirPaths = append(p.installDirPaths, baseInstallDirPath)
} else {
ctx.PropertyErrorf("src", "missing prebuilt source file")
return
@@ -443,7 +505,7 @@
type installProperties struct {
filename string
sourceFilePath android.Path
- outputFilePath android.OutputPath
+ outputFilePath android.WritablePath
installDirPath android.InstallPath
symlinks []string
}
@@ -493,7 +555,7 @@
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_MODULE_TAGS", "optional")
- entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.String())
+ entries.SetString("LOCAL_MODULE_PATH", p.installDirPaths[0].String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePaths[0].Base())
if len(p.properties.Symlinks) > 0 {
entries.AddStrings("LOCAL_MODULE_SYMLINKS", p.properties.Symlinks...)
@@ -515,6 +577,7 @@
p.installDirBase = dirBase
p.AddProperties(&p.properties)
p.AddProperties(&p.subdirProperties)
+ p.AddProperties(&p.rootProperties)
}
func InitPrebuiltRootModule(p *PrebuiltEtc) {
@@ -549,7 +612,7 @@
module.AddProperties(props...)
module.AddProperties(
- &prebuiltEtcProperties{},
+ &PrebuiltEtcProperties{},
&prebuiltSubdirProperties{},
)
@@ -681,12 +744,23 @@
return module
}
+// prebuilt_usr_srec is for a prebuilt artifact that is installed in
+// <partition>/usr/srec/<sub_dir> directory.
+func PrebuiltUserSrecFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "usr/srec")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ android.InitDefaultableModule(module)
+ return module
+}
+
// prebuilt_font installs a font in <partition>/fonts directory.
func PrebuiltFontFactory() android.Module {
module := &PrebuiltEtc{}
InitPrebuiltEtcModule(module, "fonts")
// This module is device-only
- android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
return module
}
@@ -753,3 +827,193 @@
android.InitDefaultableModule(module)
return module
}
+
+// prebuilt_media installs media files in <partition>/media directory.
+func PrebuiltMediaFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "media")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_voicepack installs voice pack files in <partition>/tts directory.
+func PrebuiltVoicepackFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "tts")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_bin installs files in <partition>/bin directory.
+func PrebuiltBinaryFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "bin")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_wallpaper installs image files in <partition>/wallpaper directory.
+func PrebuiltWallpaperFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "wallpaper")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_priv_app installs files in <partition>/priv-app directory.
+func PrebuiltPrivAppFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "priv-app")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_rfs installs files in <partition>/rfs directory.
+func PrebuiltRfsFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "rfs")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_framework installs files in <partition>/framework directory.
+func PrebuiltFrameworkFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "framework")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_res installs files in <partition>/res directory.
+func PrebuiltResFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "res")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_wlc_upt installs files in <partition>/wlc_upt directory.
+func PrebuiltWlcUptFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "wlc_upt")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_odm installs files in <partition>/odm directory.
+func PrebuiltOdmFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "odm")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_vendor_dlkm installs files in <partition>/vendor_dlkm directory.
+func PrebuiltVendorDlkmFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "vendor_dlkm")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_bt_firmware installs files in <partition>/bt_firmware directory.
+func PrebuiltBtFirmwareFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "bt_firmware")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_tvservice installs files in <partition>/tvservice directory.
+func PrebuiltTvServiceFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "tvservice")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_optee installs files in <partition>/optee directory.
+func PrebuiltOpteeFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "optee")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_tvconfig installs files in <partition>/tvconfig directory.
+func PrebuiltTvConfigFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "tvconfig")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_vendor installs files in <partition>/vendor directory.
+func PrebuiltVendorFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "vendor")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_sbin installs files in <partition>/sbin directory.
+func PrebuiltSbinFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "sbin")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_system installs files in <partition>/system directory.
+func PrebuiltSystemFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "system")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+// prebuilt_first_stage_ramdisk installs files in <partition>/first_stage_ramdisk directory.
+func PrebuiltFirstStageRamdiskFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "first_stage_ramdisk")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index e739afe..70b5462 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -119,6 +119,113 @@
android.AssertStringEquals(t, "output file path", "foo.conf", p.outputFilePaths[2].Base())
}
+func TestPrebuiltEtcDsts(t *testing.T) {
+ result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
+ prebuilt_etc {
+ name: "foo",
+ srcs: ["foo.conf", "bar.conf"],
+ dsts: ["foodir/foo.conf", "bardir/extradir/different.name"],
+ }
+ `)
+
+ p := result.Module("foo", "android_arm64_armv8-a").(*PrebuiltEtc)
+ android.AssertStringEquals(t, "output file path", "foo.conf", p.outputFilePaths[0].Base())
+ android.AssertStringEquals(t, "output file path", "different.name", p.outputFilePaths[1].Base())
+
+ expectedPaths := [...]string{
+ "out/target/product/test_device/system/etc/foodir",
+ "out/target/product/test_device/system/etc/bardir/extradir",
+ }
+ android.AssertPathRelativeToTopEquals(t, "install dir", expectedPaths[0], p.installDirPaths[0])
+ android.AssertPathRelativeToTopEquals(t, "install dir", expectedPaths[1], p.installDirPaths[1])
+}
+
+func TestPrebuiltEtcDstsPlusRelativeInstallPath(t *testing.T) {
+ result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
+ prebuilt_etc {
+ name: "foo",
+ srcs: ["foo.conf", "bar.conf"],
+ dsts: ["foodir/foo.conf", "bardir/extradir/different.name"],
+ relative_install_path: "somewhere",
+ }
+ `)
+
+ p := result.Module("foo", "android_arm64_armv8-a").(*PrebuiltEtc)
+ android.AssertStringEquals(t, "output file path", "foo.conf", p.outputFilePaths[0].Base())
+ android.AssertStringEquals(t, "output file path", "different.name", p.outputFilePaths[1].Base())
+
+ expectedPaths := [...]string{
+ "out/target/product/test_device/system/etc/somewhere/foodir",
+ "out/target/product/test_device/system/etc/somewhere/bardir/extradir",
+ }
+ android.AssertPathRelativeToTopEquals(t, "install dir", expectedPaths[0], p.installDirPaths[0])
+ android.AssertPathRelativeToTopEquals(t, "install dir", expectedPaths[1], p.installDirPaths[1])
+}
+
+func TestPrebuiltEtcDstsSrcGlob(t *testing.T) {
+ result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
+ prebuilt_etc {
+ name: "foo",
+ srcs: ["*.conf"],
+ dsts: ["a.conf", "b.conf", "c.conf"],
+ }
+ `)
+
+ p := result.Module("foo", "android_arm64_armv8-a").(*PrebuiltEtc)
+ android.AssertStringEquals(t, "output file path", "a.conf", p.outputFilePaths[0].Base())
+ android.AssertStringEquals(t, "output file path", "b.conf", p.outputFilePaths[1].Base())
+ android.AssertStringEquals(t, "output file path", "c.conf", p.outputFilePaths[2].Base())
+}
+
+func TestPrebuiltEtcDstsSrcGlobDstsTooShort(t *testing.T) {
+ prepareForPrebuiltEtcTest.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern("Must have one entry in dsts per source file")).
+ RunTestWithBp(t, `
+ prebuilt_etc {
+ name: "foo",
+ srcs: ["*.conf"],
+ dsts: ["a.conf", "b.conf"],
+ }
+ `)
+}
+
+func TestPrebuiltEtcDstsSrcGlobDstsTooLong(t *testing.T) {
+ prepareForPrebuiltEtcTest.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern("Must have one entry in dsts per source file")).
+ RunTestWithBp(t, `
+ prebuilt_etc {
+ name: "foo",
+ srcs: ["*.conf"],
+ dsts: ["a.conf", "b.conf", "c.conf", "d.conf"],
+ }
+ `)
+}
+
+func TestPrebuiltEtcCannotDstsWithSrc(t *testing.T) {
+ prepareForPrebuiltEtcTest.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern("dsts is set. Must use srcs")).
+ RunTestWithBp(t, `
+ prebuilt_etc {
+ name: "foo.conf",
+ src: "foo.conf",
+ dsts: ["a.conf"],
+ }
+ `)
+}
+
+func TestPrebuiltEtcCannotDstsWithFilenameFromSrc(t *testing.T) {
+ prepareForPrebuiltEtcTest.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern("dsts is set. Cannot set filename_from_src")).
+ RunTestWithBp(t, `
+ prebuilt_etc {
+ name: "foo.conf",
+ srcs: ["foo.conf"],
+ dsts: ["a.conf"],
+ filename_from_src: true,
+ }
+ `)
+}
+
func TestPrebuiltEtcAndroidMk(t *testing.T) {
result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
prebuilt_etc {
@@ -164,8 +271,8 @@
`)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- expected := "out/soong/target/product/test_device/system/etc/bar"
- android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
+ expected := "out/target/product/test_device/system/etc/bar"
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0])
}
func TestPrebuiltEtcCannotSetRelativeInstallPathAndSubDir(t *testing.T) {
@@ -230,8 +337,8 @@
`)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- expected := "out/soong/target/product/test_device/system"
- android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
+ expected := "out/target/product/test_device/system"
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0])
}
func TestPrebuiltRootInstallDirPathValidate(t *testing.T) {
@@ -255,8 +362,8 @@
`)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- expected := "out/soong/target/product/test_device/root/avb"
- android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
+ expected := "out/target/product/test_device/root/avb"
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0])
}
func TestPrebuiltAvdInstallDirPathValidate(t *testing.T) {
@@ -279,8 +386,8 @@
`)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- expected := "out/soong/target/product/test_device/system/usr/share/bar"
- android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
+ expected := "out/target/product/test_device/system/usr/share/bar"
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0])
}
func TestPrebuiltUserShareHostInstallDirPath(t *testing.T) {
@@ -294,8 +401,8 @@
buildOS := result.Config.BuildOS.String()
p := result.Module("foo.conf", buildOS+"_common").(*PrebuiltEtc)
- expected := filepath.Join("out/soong/host", result.Config.PrebuiltOS(), "usr", "share", "bar")
- android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
+ expected := filepath.Join("out/host", result.Config.PrebuiltOS(), "usr", "share", "bar")
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0])
}
func TestPrebuiltPrebuiltUserHyphenDataInstallDirPath(t *testing.T) {
@@ -308,8 +415,8 @@
`)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- expected := "out/soong/target/product/test_device/system/usr/hyphen-data/bar"
- android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
+ expected := "out/target/product/test_device/system/usr/hyphen-data/bar"
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0])
}
func TestPrebuiltPrebuiltUserKeyLayoutInstallDirPath(t *testing.T) {
@@ -322,8 +429,8 @@
`)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- expected := "out/soong/target/product/test_device/system/usr/keylayout/bar"
- android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
+ expected := "out/target/product/test_device/system/usr/keylayout/bar"
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0])
}
func TestPrebuiltPrebuiltUserKeyCharsInstallDirPath(t *testing.T) {
@@ -336,8 +443,8 @@
`)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- expected := "out/soong/target/product/test_device/system/usr/keychars/bar"
- android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
+ expected := "out/target/product/test_device/system/usr/keychars/bar"
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0])
}
func TestPrebuiltPrebuiltUserIdcInstallDirPath(t *testing.T) {
@@ -350,8 +457,8 @@
`)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- expected := "out/soong/target/product/test_device/system/usr/idc/bar"
- android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
+ expected := "out/target/product/test_device/system/usr/idc/bar"
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0])
}
func TestPrebuiltFontInstallDirPath(t *testing.T) {
@@ -362,9 +469,9 @@
}
`)
- p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- expected := "out/soong/target/product/test_device/system/fonts"
- android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
+ p := result.Module("foo.conf", "android_common").(*PrebuiltEtc)
+ expected := "out/target/product/test_device/system/fonts"
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0])
}
func TestPrebuiltOverlayInstallDirPath(t *testing.T) {
@@ -376,12 +483,12 @@
`)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- expected := "out/soong/target/product/test_device/system/overlay"
- android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
+ expected := "out/target/product/test_device/system/overlay"
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0])
}
func TestPrebuiltFirmwareDirPath(t *testing.T) {
- targetPath := "out/soong/target/product/test_device"
+ targetPath := "out/target/product/test_device"
tests := []struct {
description string
config string
@@ -409,13 +516,13 @@
t.Run(tt.description, func(t *testing.T) {
result := prepareForPrebuiltEtcTest.RunTestWithBp(t, tt.config)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- android.AssertPathRelativeToTopEquals(t, "install dir", tt.expectedPath, p.installDirPath)
+ android.AssertPathRelativeToTopEquals(t, "install dir", tt.expectedPath, p.installDirPaths[0])
})
}
}
func TestPrebuiltDSPDirPath(t *testing.T) {
- targetPath := "out/soong/target/product/test_device"
+ targetPath := "out/target/product/test_device"
tests := []struct {
description string
config string
@@ -443,13 +550,13 @@
t.Run(tt.description, func(t *testing.T) {
result := prepareForPrebuiltEtcTest.RunTestWithBp(t, tt.config)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- android.AssertPathRelativeToTopEquals(t, "install dir", tt.expectedPath, p.installDirPath)
+ android.AssertPathRelativeToTopEquals(t, "install dir", tt.expectedPath, p.installDirPaths[0])
})
}
}
func TestPrebuiltRFSADirPath(t *testing.T) {
- targetPath := "out/soong/target/product/test_device"
+ targetPath := "out/target/product/test_device"
tests := []struct {
description string
config string
@@ -477,7 +584,22 @@
t.Run(tt.description, func(t *testing.T) {
result := prepareForPrebuiltEtcTest.RunTestWithBp(t, tt.config)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- android.AssertPathRelativeToTopEquals(t, "install dir", tt.expectedPath, p.installDirPath)
+ android.AssertPathRelativeToTopEquals(t, "install dir", tt.expectedPath, p.installDirPaths[0])
})
}
}
+
+func TestPrebuiltMediaAutoDirPath(t *testing.T) {
+ result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
+ prebuilt_media {
+ name: "foo",
+ src: "Alarm_Beep_01.ogg",
+ product_specific: true,
+ relative_install_path: "alarms"
+ }
+ `)
+
+ p := result.Module("foo", "android_common").(*PrebuiltEtc)
+ expected := "out/target/product/test_device/product/media/alarms"
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0])
+}
diff --git a/filesystem/Android.bp b/filesystem/Android.bp
index a08f7cf..cb76df2 100644
--- a/filesystem/Android.bp
+++ b/filesystem/Android.bp
@@ -16,14 +16,19 @@
],
srcs: [
"aconfig_files.go",
+ "android_device.go",
+ "android_device_product_out.go",
"avb_add_hash_footer.go",
"avb_gen_vbmeta_image.go",
"bootimg.go",
+ "bootconfig.go",
"filesystem.go",
"fsverity_metadata.go",
"logical_partition.go",
"raw_binary.go",
+ "super_image.go",
"system_image.go",
+ "system_other.go",
"vbmeta.go",
"testing.go",
],
diff --git a/filesystem/aconfig_files.go b/filesystem/aconfig_files.go
index 5c047bc..6d03402 100644
--- a/filesystem/aconfig_files.go
+++ b/filesystem/aconfig_files.go
@@ -16,69 +16,101 @@
import (
"android/soong/android"
- "strings"
+ "strconv"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
-func (f *filesystem) buildAconfigFlagsFiles(ctx android.ModuleContext, builder *android.RuleBuilder, specs map[string]android.PackagingSpec, dir android.OutputPath) {
+type installedAconfigFlagsInfo struct {
+ aconfigFiles android.Paths
+}
+
+var installedAconfigFlagsProvider = blueprint.NewProvider[installedAconfigFlagsInfo]()
+
+type importAconfigDepDag struct {
+ blueprint.BaseDependencyTag
+}
+
+var importAconfigDependencyTag = interPartitionDepTag{}
+
+func (f *filesystem) buildAconfigFlagsFiles(
+ ctx android.ModuleContext,
+ builder *android.RuleBuilder,
+ specs map[string]android.PackagingSpec,
+ dir android.OutputPath,
+ fullInstallPaths *[]FullInstallPathInfo,
+) {
+ var caches []android.Path
+ for _, ps := range specs {
+ caches = append(caches, ps.GetAconfigPaths()...)
+ }
+
+ ctx.VisitDirectDepsWithTag(importAconfigDependencyTag, func(m android.Module) {
+ info, ok := android.OtherModuleProvider(ctx, m, installedAconfigFlagsProvider)
+ if !ok {
+ ctx.ModuleErrorf("expected dependency %s to have an installedAconfigFlagsProvider", m.Name())
+ return
+ }
+ caches = append(caches, info.aconfigFiles...)
+ })
+ caches = android.SortedUniquePaths(caches)
+
+ android.SetProvider(ctx, installedAconfigFlagsProvider, installedAconfigFlagsInfo{
+ aconfigFiles: caches,
+ })
+
if !proptools.Bool(f.properties.Gen_aconfig_flags_pb) {
return
}
- aconfigFlagsBuilderPath := android.PathForModuleOut(ctx, "aconfig_flags_builder.sh")
- aconfigToolPath := ctx.Config().HostToolPath(ctx, "aconfig")
- cmd := builder.Command().Tool(aconfigFlagsBuilderPath).Implicit(aconfigToolPath)
-
- var caches []string
- for _, ps := range specs {
- cmd.Implicits(ps.GetAconfigPaths())
- caches = append(caches, ps.GetAconfigPaths().Strings()...)
- }
- caches = android.SortedUniqueStrings(caches)
-
- var sbCaches strings.Builder
- for _, cache := range caches {
- sbCaches.WriteString(" --cache ")
- sbCaches.WriteString(cache)
- sbCaches.WriteString(" \\\n")
- }
- sbCaches.WriteRune('\n')
-
- var sb strings.Builder
- sb.WriteString("set -e\n")
+ container := f.PartitionType()
installAconfigFlagsPath := dir.Join(ctx, "etc", "aconfig_flags.pb")
- sb.WriteString(aconfigToolPath.String())
- sb.WriteString(" dump-cache --dedup --format protobuf --out ")
- sb.WriteString(installAconfigFlagsPath.String())
- sb.WriteString(" \\\n")
- sb.WriteString(sbCaches.String())
- cmd.ImplicitOutput(installAconfigFlagsPath)
+ cmd := builder.Command().
+ BuiltTool("aconfig").
+ Text(" dump-cache --dedup --format protobuf --out").
+ Output(installAconfigFlagsPath).
+ Textf("--filter container:%s+state:ENABLED", container).
+ Textf("--filter container:%s+permission:READ_WRITE", container)
+ for _, cache := range caches {
+ cmd.FlagWithInput("--cache ", cache)
+ }
+ *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
+ FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), "etc/aconfig_flags.pb"),
+ SourcePath: installAconfigFlagsPath,
+ })
f.appendToEntry(ctx, installAconfigFlagsPath)
installAconfigStorageDir := dir.Join(ctx, "etc", "aconfig")
- sb.WriteString("mkdir -p ")
- sb.WriteString(installAconfigStorageDir.String())
- sb.WriteRune('\n')
+ builder.Command().Text("mkdir -p").Text(installAconfigStorageDir.String())
+
+ // To enable fingerprint, we need to have v2 storage files. The default version is 1.
+ storageFilesVersion := 1
+ if ctx.Config().ReleaseFingerprintAconfigPackages() {
+ storageFilesVersion = 2
+ }
generatePartitionAconfigStorageFile := func(fileType, fileName string) {
outputPath := installAconfigStorageDir.Join(ctx, fileName)
- sb.WriteString(aconfigToolPath.String())
- sb.WriteString(" create-storage --container ")
- sb.WriteString(f.PartitionType())
- sb.WriteString(" --file ")
- sb.WriteString(fileType)
- sb.WriteString(" --out ")
- sb.WriteString(outputPath.String())
- sb.WriteString(" \\\n")
- sb.WriteString(sbCaches.String())
- cmd.ImplicitOutput(outputPath)
+ builder.Command().
+ BuiltTool("aconfig").
+ FlagWithArg("create-storage --container ", container).
+ FlagWithArg("--file ", fileType).
+ FlagWithOutput("--out ", outputPath).
+ FlagWithArg("--cache ", installAconfigFlagsPath.String()).
+ FlagWithArg("--version ", strconv.Itoa(storageFilesVersion))
+ *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
+ FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), "etc/aconfig", fileName),
+ SourcePath: outputPath,
+ })
f.appendToEntry(ctx, outputPath)
}
- generatePartitionAconfigStorageFile("package_map", "package.map")
- generatePartitionAconfigStorageFile("flag_map", "flag.map")
- generatePartitionAconfigStorageFile("flag_val", "flag.val")
- android.WriteExecutableFileRuleVerbatim(ctx, aconfigFlagsBuilderPath, sb.String())
+ if ctx.Config().ReleaseCreateAconfigStorageFile() {
+ generatePartitionAconfigStorageFile("package_map", "package.map")
+ generatePartitionAconfigStorageFile("flag_map", "flag.map")
+ generatePartitionAconfigStorageFile("flag_val", "flag.val")
+ generatePartitionAconfigStorageFile("flag_info", "flag.info")
+ }
}
diff --git a/filesystem/android_device.go b/filesystem/android_device.go
new file mode 100644
index 0000000..6c04828
--- /dev/null
+++ b/filesystem/android_device.go
@@ -0,0 +1,428 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package filesystem
+
+import (
+ "fmt"
+ "strings"
+ "sync/atomic"
+
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+type PartitionNameProperties struct {
+ // Name of the super partition filesystem module
+ Super_partition_name *string
+ // Name of the boot partition filesystem module
+ Boot_partition_name *string
+ // Name of the vendor boot partition filesystem module
+ Vendor_boot_partition_name *string
+ // Name of the init boot partition filesystem module
+ Init_boot_partition_name *string
+ // Name of the system partition filesystem module
+ System_partition_name *string
+ // Name of the system_ext partition filesystem module
+ System_ext_partition_name *string
+ // Name of the product partition filesystem module
+ Product_partition_name *string
+ // Name of the vendor partition filesystem module
+ Vendor_partition_name *string
+ // Name of the odm partition filesystem module
+ Odm_partition_name *string
+ // Name of the recovery partition filesystem module
+ Recovery_partition_name *string
+ // The vbmeta partition and its "chained" partitions
+ Vbmeta_partitions []string
+ // Name of the userdata partition filesystem module
+ Userdata_partition_name *string
+ // Name of the system_dlkm partition filesystem module
+ System_dlkm_partition_name *string
+ // Name of the vendor_dlkm partition filesystem module
+ Vendor_dlkm_partition_name *string
+ // Name of the odm_dlkm partition filesystem module
+ Odm_dlkm_partition_name *string
+}
+
+type DeviceProperties struct {
+ // Path to the prebuilt bootloader that would be copied to PRODUCT_OUT
+ Bootloader *string `android:"path"`
+ // Path to android-info.txt file containing board specific info.
+ Android_info *string `android:"path"`
+ // If this is the "main" android_device target for the build, i.e. the one that gets built
+ // when running a plain `m` command. Currently, this is the autogenerated android_device module
+ // in soong-only builds, but in the future when we check in android_device modules, the main
+ // one will be determined based on the lunch product. TODO: Figure out how to make this
+ // blueprint:"mutated" and still set it from filesystem_creator
+ Main_device *bool
+
+ Ab_ota_updater *bool
+}
+
+type androidDevice struct {
+ android.ModuleBase
+
+ partitionProps PartitionNameProperties
+
+ deviceProps DeviceProperties
+}
+
+func AndroidDeviceFactory() android.Module {
+ module := &androidDevice{}
+ module.AddProperties(&module.partitionProps, &module.deviceProps)
+ android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ return module
+}
+
+var numMainAndroidDevicesOnceKey android.OnceKey = android.NewOnceKey("num_auto_generated_anroid_devices")
+
+type partitionDepTagType struct {
+ blueprint.BaseDependencyTag
+}
+
+type superPartitionDepTagType struct {
+ blueprint.BaseDependencyTag
+}
+type targetFilesMetadataDepTagType struct {
+ blueprint.BaseDependencyTag
+}
+
+var superPartitionDepTag superPartitionDepTagType
+var filesystemDepTag partitionDepTagType
+var targetFilesMetadataDepTag targetFilesMetadataDepTagType
+
+func (a *androidDevice) DepsMutator(ctx android.BottomUpMutatorContext) {
+ addDependencyIfDefined := func(dep *string) {
+ if dep != nil {
+ ctx.AddDependency(ctx.Module(), filesystemDepTag, proptools.String(dep))
+ }
+ }
+
+ if a.partitionProps.Super_partition_name != nil {
+ ctx.AddDependency(ctx.Module(), superPartitionDepTag, *a.partitionProps.Super_partition_name)
+ }
+ addDependencyIfDefined(a.partitionProps.Boot_partition_name)
+ addDependencyIfDefined(a.partitionProps.Init_boot_partition_name)
+ addDependencyIfDefined(a.partitionProps.Vendor_boot_partition_name)
+ addDependencyIfDefined(a.partitionProps.System_partition_name)
+ addDependencyIfDefined(a.partitionProps.System_ext_partition_name)
+ addDependencyIfDefined(a.partitionProps.Product_partition_name)
+ addDependencyIfDefined(a.partitionProps.Vendor_partition_name)
+ addDependencyIfDefined(a.partitionProps.Odm_partition_name)
+ addDependencyIfDefined(a.partitionProps.Userdata_partition_name)
+ addDependencyIfDefined(a.partitionProps.System_dlkm_partition_name)
+ addDependencyIfDefined(a.partitionProps.Vendor_dlkm_partition_name)
+ addDependencyIfDefined(a.partitionProps.Odm_dlkm_partition_name)
+ addDependencyIfDefined(a.partitionProps.Recovery_partition_name)
+ for _, vbmetaPartition := range a.partitionProps.Vbmeta_partitions {
+ ctx.AddDependency(ctx.Module(), filesystemDepTag, vbmetaPartition)
+ }
+ a.addDepsForTargetFilesMetadata(ctx)
+}
+
+func (a *androidDevice) addDepsForTargetFilesMetadata(ctx android.BottomUpMutatorContext) {
+ ctx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), targetFilesMetadataDepTag, "liblz4") // host variant
+}
+
+func (a *androidDevice) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ if proptools.Bool(a.deviceProps.Main_device) {
+ numMainAndroidDevices := ctx.Config().Once(numMainAndroidDevicesOnceKey, func() interface{} {
+ return &atomic.Int32{}
+ }).(*atomic.Int32)
+ total := numMainAndroidDevices.Add(1)
+ if total > 1 {
+ // There should only be 1 main android_device module. That one will be
+ // made the default thing to build in soong-only builds.
+ ctx.ModuleErrorf("There cannot be more than 1 main android_device module")
+ }
+ }
+
+ //a.buildTargetFilesZip(ctx) TODO(b/393203512): re-enable target_files.zip
+ var deps []android.Path
+ if proptools.String(a.partitionProps.Super_partition_name) != "" {
+ superImage := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag)
+ if info, ok := android.OtherModuleProvider(ctx, superImage, SuperImageProvider); ok {
+ assertUnset := func(prop *string, propName string) {
+ if prop != nil && *prop != "" {
+ ctx.PropertyErrorf(propName, "Cannot be set because it's already part of the super image")
+ }
+ }
+ for _, subPartitionType := range android.SortedKeys(info.SubImageInfo) {
+ switch subPartitionType {
+ case "system":
+ assertUnset(a.partitionProps.System_partition_name, "system_partition_name")
+ case "system_ext":
+ assertUnset(a.partitionProps.System_ext_partition_name, "system_ext_partition_name")
+ case "system_dlkm":
+ assertUnset(a.partitionProps.System_dlkm_partition_name, "system_dlkm_partition_name")
+ case "system_other":
+ // TODO
+ case "product":
+ assertUnset(a.partitionProps.Product_partition_name, "product_partition_name")
+ case "vendor":
+ assertUnset(a.partitionProps.Vendor_partition_name, "vendor_partition_name")
+ case "vendor_dlkm":
+ assertUnset(a.partitionProps.Vendor_dlkm_partition_name, "vendor_dlkm_partition_name")
+ case "odm":
+ assertUnset(a.partitionProps.Odm_partition_name, "odm_partition_name")
+ case "odm_dlkm":
+ assertUnset(a.partitionProps.Odm_dlkm_partition_name, "odm_dlkm_partition_name")
+ default:
+ ctx.ModuleErrorf("Unsupported sub-partition of super partition: %q", subPartitionType)
+ }
+ }
+
+ deps = append(deps, info.SuperImage)
+ } else {
+ ctx.ModuleErrorf("Expected super image dep to provide SuperImageProvider")
+ }
+ }
+ ctx.VisitDirectDepsProxyWithTag(filesystemDepTag, func(m android.ModuleProxy) {
+ imageOutput, ok := android.OtherModuleProvider(ctx, m, android.OutputFilesProvider)
+ if !ok {
+ ctx.ModuleErrorf("Partition module %s doesn't set OutputfilesProvider", m.Name())
+ }
+ if len(imageOutput.DefaultOutputFiles) != 1 {
+ ctx.ModuleErrorf("Partition module %s should provide exact 1 output file", m.Name())
+ }
+ deps = append(deps, imageOutput.DefaultOutputFiles[0])
+ })
+
+ allImagesStamp := android.PathForModuleOut(ctx, "all_images_stamp")
+ var validations android.Paths
+ if !ctx.Config().KatiEnabled() && proptools.Bool(a.deviceProps.Main_device) {
+ // In soong-only builds, build this module by default.
+ // This is the analogue to this make code:
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/main.mk;l=1396;drc=6595459cdd8164a6008335f6372c9f97b9094060
+ ctx.Phony("droidcore-unbundled", allImagesStamp)
+
+ deps = append(deps, a.copyFilesToProductOutForSoongOnly(ctx))
+ }
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Touch,
+ Output: allImagesStamp,
+ Implicits: deps,
+ Validations: validations,
+ })
+
+ // Checkbuilding it causes soong to make a phony, so you can say `m <module name>`
+ ctx.CheckbuildFile(allImagesStamp)
+
+ a.setVbmetaPhonyTargets(ctx)
+}
+
+// Helper structs for target_files.zip creation
+type targetFilesZipCopy struct {
+ srcModule *string
+ destSubdir string
+}
+
+type targetFilesystemZipCopy struct {
+ fsInfo FilesystemInfo
+ destSubdir string
+}
+
+func (a *androidDevice) buildTargetFilesZip(ctx android.ModuleContext) {
+ targetFilesDir := android.PathForModuleOut(ctx, "target_files_dir")
+ targetFilesZip := android.PathForModuleOut(ctx, "target_files.zip")
+
+ builder := android.NewRuleBuilder(pctx, ctx)
+ builder.Command().Textf("rm -rf %s", targetFilesDir.String())
+ builder.Command().Textf("mkdir -p %s", targetFilesDir.String())
+ toCopy := []targetFilesZipCopy{
+ targetFilesZipCopy{a.partitionProps.System_partition_name, "SYSTEM"},
+ targetFilesZipCopy{a.partitionProps.System_ext_partition_name, "SYSTEM_EXT"},
+ targetFilesZipCopy{a.partitionProps.Product_partition_name, "PRODUCT"},
+ targetFilesZipCopy{a.partitionProps.Vendor_partition_name, "VENDOR"},
+ targetFilesZipCopy{a.partitionProps.Odm_partition_name, "ODM"},
+ targetFilesZipCopy{a.partitionProps.System_dlkm_partition_name, "SYSTEM_DLKM"},
+ targetFilesZipCopy{a.partitionProps.Vendor_dlkm_partition_name, "VENDOR_DLKM"},
+ targetFilesZipCopy{a.partitionProps.Odm_dlkm_partition_name, "ODM_DLKM"},
+ targetFilesZipCopy{a.partitionProps.Init_boot_partition_name, "BOOT/RAMDISK"},
+ targetFilesZipCopy{a.partitionProps.Init_boot_partition_name, "INIT_BOOT/RAMDISK"},
+ targetFilesZipCopy{a.partitionProps.Vendor_boot_partition_name, "VENDOR_BOOT/RAMDISK"},
+ }
+ // TODO: Handle cases where recovery files are copied to BOOT/ or RECOVERY/
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=6211-6219?q=core%2FMakefile&ss=android%2Fplatform%2Fsuperproject%2Fmain
+ if ctx.DeviceConfig().BoardMoveRecoveryResourcesToVendorBoot() {
+ toCopy = append(toCopy, targetFilesZipCopy{a.partitionProps.Recovery_partition_name, "VENDOR_BOOT/RAMDISK"})
+ }
+
+ filesystemsToCopy := []targetFilesystemZipCopy{}
+ for _, zipCopy := range toCopy {
+ if zipCopy.srcModule == nil {
+ continue
+ }
+ filesystemsToCopy = append(
+ filesystemsToCopy,
+ targetFilesystemZipCopy{a.getFilesystemInfo(ctx, *zipCopy.srcModule), zipCopy.destSubdir},
+ )
+ }
+ // Get additional filesystems from super_partition dependency
+ if a.partitionProps.Super_partition_name != nil {
+ superPartition := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag)
+ if info, ok := android.OtherModuleProvider(ctx, superPartition, SuperImageProvider); ok {
+ for _, partition := range android.SortedStringKeys(info.SubImageInfo) {
+ filesystemsToCopy = append(
+ filesystemsToCopy,
+ targetFilesystemZipCopy{info.SubImageInfo[partition], strings.ToUpper(partition)},
+ )
+ }
+ } else {
+ ctx.ModuleErrorf("Super partition %s does set SuperImageProvider\n", superPartition.Name())
+ }
+ }
+
+ for _, toCopy := range filesystemsToCopy {
+ rootDirString := toCopy.fsInfo.RootDir.String()
+ if toCopy.destSubdir == "SYSTEM" {
+ rootDirString = rootDirString + "/system"
+ }
+ builder.Command().Textf("mkdir -p %s/%s", targetFilesDir.String(), toCopy.destSubdir)
+ builder.Command().
+ BuiltTool("acp").
+ Textf("-rd %s/. %s/%s", rootDirString, targetFilesDir, toCopy.destSubdir).
+ Implicit(toCopy.fsInfo.Output) // so that the staging dir is built
+
+ if toCopy.destSubdir == "SYSTEM" {
+ // Create the ROOT partition in target_files.zip
+ builder.Command().Textf("rsync --links --exclude=system/* %s/ -r %s/ROOT", toCopy.fsInfo.RootDir, targetFilesDir.String())
+ }
+ }
+ // Copy cmdline, kernel etc. files of boot images
+ if a.partitionProps.Vendor_boot_partition_name != nil {
+ bootImg := ctx.GetDirectDepProxyWithTag(proptools.String(a.partitionProps.Vendor_boot_partition_name), filesystemDepTag)
+ bootImgInfo, _ := android.OtherModuleProvider(ctx, bootImg, BootimgInfoProvider)
+ builder.Command().Textf("echo %s > %s/VENDOR_BOOT/cmdline", proptools.ShellEscape(strings.Join(bootImgInfo.Cmdline, " ")), targetFilesDir)
+ builder.Command().Textf("echo %s > %s/VENDOR_BOOT/vendor_cmdline", proptools.ShellEscape(strings.Join(bootImgInfo.Cmdline, " ")), targetFilesDir)
+ if bootImgInfo.Dtb != nil {
+ builder.Command().Textf("cp ").Input(bootImgInfo.Dtb).Textf(" %s/VENDOR_BOOT/dtb", targetFilesDir)
+ }
+ if bootImgInfo.Bootconfig != nil {
+ builder.Command().Textf("cp ").Input(bootImgInfo.Bootconfig).Textf(" %s/VENDOR_BOOT/vendor_bootconfig", targetFilesDir)
+ }
+ }
+ if a.partitionProps.Boot_partition_name != nil {
+ bootImg := ctx.GetDirectDepProxyWithTag(proptools.String(a.partitionProps.Boot_partition_name), filesystemDepTag)
+ bootImgInfo, _ := android.OtherModuleProvider(ctx, bootImg, BootimgInfoProvider)
+ builder.Command().Textf("echo %s > %s/BOOT/cmdline", proptools.ShellEscape(strings.Join(bootImgInfo.Cmdline, " ")), targetFilesDir)
+ if bootImgInfo.Dtb != nil {
+ builder.Command().Textf("cp ").Input(bootImgInfo.Dtb).Textf(" %s/BOOT/dtb", targetFilesDir)
+ }
+ if bootImgInfo.Kernel != nil {
+ builder.Command().Textf("cp ").Input(bootImgInfo.Kernel).Textf(" %s/BOOT/kernel", targetFilesDir)
+ // Even though kernel is not used to build vendor_boot, copy the kernel to VENDOR_BOOT to match the behavior of make packaging.
+ builder.Command().Textf("cp ").Input(bootImgInfo.Kernel).Textf(" %s/VENDOR_BOOT/kernel", targetFilesDir)
+ }
+ if bootImgInfo.Bootconfig != nil {
+ builder.Command().Textf("cp ").Input(bootImgInfo.Bootconfig).Textf(" %s/BOOT/bootconfig", targetFilesDir)
+ }
+ }
+
+ if a.deviceProps.Android_info != nil {
+ builder.Command().Textf("mkdir -p %s/OTA", targetFilesDir)
+ builder.Command().Textf("cp ").Input(android.PathForModuleSrc(ctx, *a.deviceProps.Android_info)).Textf(" %s/OTA/android-info.txt", targetFilesDir)
+ }
+
+ a.copyImagesToTargetZip(ctx, builder, targetFilesDir)
+ a.copyMetadataToTargetZip(ctx, builder, targetFilesDir)
+
+ builder.Command().
+ BuiltTool("soong_zip").
+ Text("-d").
+ FlagWithOutput("-o ", targetFilesZip).
+ FlagWithArg("-C ", targetFilesDir.String()).
+ FlagWithArg("-D ", targetFilesDir.String()).
+ Text("-sha256")
+ builder.Build("target_files_"+ctx.ModuleName(), "Build target_files.zip")
+}
+
+func (a *androidDevice) copyImagesToTargetZip(ctx android.ModuleContext, builder *android.RuleBuilder, targetFilesDir android.WritablePath) {
+ // Create an IMAGES/ subdirectory
+ builder.Command().Textf("mkdir -p %s/IMAGES", targetFilesDir.String())
+ if a.deviceProps.Bootloader != nil {
+ builder.Command().Textf("cp ").Input(android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Bootloader))).Textf(" %s/IMAGES/bootloader", targetFilesDir.String())
+ }
+ // Copy the filesystem ,boot and vbmeta img files to IMAGES/
+ ctx.VisitDirectDepsProxyWithTag(filesystemDepTag, func(child android.ModuleProxy) {
+ if strings.Contains(child.Name(), "recovery") {
+ return // skip recovery.img to match the make packaging behavior
+ }
+ if info, ok := android.OtherModuleProvider(ctx, child, BootimgInfoProvider); ok {
+ // Check Boot img first so that the boot.img is copied and not its dep ramdisk.img
+ builder.Command().Textf("cp ").Input(info.Output).Textf(" %s/IMAGES/", targetFilesDir.String())
+ } else if info, ok := android.OtherModuleProvider(ctx, child, FilesystemProvider); ok {
+ builder.Command().Textf("cp ").Input(info.Output).Textf(" %s/IMAGES/", targetFilesDir.String())
+ } else if info, ok := android.OtherModuleProvider(ctx, child, vbmetaPartitionProvider); ok {
+ builder.Command().Textf("cp ").Input(info.Output).Textf(" %s/IMAGES/", targetFilesDir.String())
+ } else {
+ ctx.ModuleErrorf("Module %s does not provide an .img file output for target_files.zip", child.Name())
+ }
+ })
+
+ if a.partitionProps.Super_partition_name != nil {
+ superPartition := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag)
+ if info, ok := android.OtherModuleProvider(ctx, superPartition, SuperImageProvider); ok {
+ for _, partition := range android.SortedKeys(info.SubImageInfo) {
+ builder.Command().Textf("cp ").Input(info.SubImageInfo[partition].OutputHermetic).Textf(" %s/IMAGES/", targetFilesDir.String())
+ builder.Command().Textf("cp ").Input(info.SubImageInfo[partition].MapFile).Textf(" %s/IMAGES/", targetFilesDir.String())
+ }
+ } else {
+ ctx.ModuleErrorf("Super partition %s does set SuperImageProvider\n", superPartition.Name())
+ }
+ }
+}
+
+func (a *androidDevice) copyMetadataToTargetZip(ctx android.ModuleContext, builder *android.RuleBuilder, targetFilesDir android.WritablePath) {
+ // Create a META/ subdirectory
+ builder.Command().Textf("mkdir -p %s/META", targetFilesDir.String())
+ if proptools.Bool(a.deviceProps.Ab_ota_updater) {
+ ctx.VisitDirectDepsProxyWithTag(targetFilesMetadataDepTag, func(child android.ModuleProxy) {
+ info, _ := android.OtherModuleProvider(ctx, child, android.OutputFilesProvider)
+ builder.Command().Textf("cp").Inputs(info.DefaultOutputFiles).Textf(" %s/META/", targetFilesDir.String())
+ })
+ }
+ builder.Command().Textf("cp").Input(android.PathForSource(ctx, "external/zucchini/version_info.h")).Textf(" %s/META/zucchini_config.txt", targetFilesDir.String())
+ builder.Command().Textf("cp").Input(android.PathForSource(ctx, "system/update_engine/update_engine.conf")).Textf(" %s/META/update_engine_config.txt", targetFilesDir.String())
+}
+
+func (a *androidDevice) getFilesystemInfo(ctx android.ModuleContext, depName string) FilesystemInfo {
+ fsMod := ctx.GetDirectDepProxyWithTag(depName, filesystemDepTag)
+ fsInfo, ok := android.OtherModuleProvider(ctx, fsMod, FilesystemProvider)
+ if !ok {
+ ctx.ModuleErrorf("Expected dependency %s to be a filesystem", depName)
+ }
+ return fsInfo
+}
+
+func (a *androidDevice) setVbmetaPhonyTargets(ctx android.ModuleContext) {
+ if !proptools.Bool(a.deviceProps.Main_device) {
+ return
+ }
+
+ if !ctx.Config().KatiEnabled() {
+ for _, vbmetaPartitionName := range a.partitionProps.Vbmeta_partitions {
+ img := ctx.GetDirectDepProxyWithTag(vbmetaPartitionName, filesystemDepTag)
+ if provider, ok := android.OtherModuleProvider(ctx, img, vbmetaPartitionProvider); ok {
+ // make generates `vbmetasystemimage` phony target instead of `vbmeta_systemimage` phony target.
+ partitionName := strings.ReplaceAll(provider.Name, "_", "")
+ ctx.Phony(fmt.Sprintf("%simage", partitionName), provider.Output)
+ }
+ }
+ }
+}
diff --git a/filesystem/android_device_product_out.go b/filesystem/android_device_product_out.go
new file mode 100644
index 0000000..405d710
--- /dev/null
+++ b/filesystem/android_device_product_out.go
@@ -0,0 +1,228 @@
+// Copyright (C) 2025 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package filesystem
+
+import (
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+var (
+ copyStagingDirRule = pctx.AndroidStaticRule("copy_staging_dir", blueprint.RuleParams{
+ Command: "rsync -a --checksum $dir/ $dest && touch $out",
+ }, "dir", "dest")
+)
+
+func (a *androidDevice) copyToProductOut(ctx android.ModuleContext, builder *android.RuleBuilder, src android.Path, dest string) {
+ destPath := android.PathForModuleInPartitionInstall(ctx, "").Join(ctx, dest)
+ builder.Command().Text("rsync").Flag("-a").Flag("--checksum").Input(src).Text(destPath.String())
+}
+
+func (a *androidDevice) copyFilesToProductOutForSoongOnly(ctx android.ModuleContext) android.Path {
+ filesystemInfos := a.getFsInfos(ctx)
+
+ var deps android.Paths
+
+ for _, partition := range android.SortedKeys(filesystemInfos) {
+ info := filesystemInfos[partition]
+ imgInstallPath := android.PathForModuleInPartitionInstall(ctx, "", partition+".img")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: info.Output,
+ Output: imgInstallPath,
+ })
+
+ // Make it so doing `m <moduleName>` or `m <partitionType>image` will copy the files to
+ // PRODUCT_OUT
+ if partition == "system_ext" {
+ partition = "systemext"
+ }
+ partition = partition + "imgage"
+ ctx.Phony(info.ModuleName, imgInstallPath)
+ ctx.Phony(partition, imgInstallPath)
+ for _, fip := range info.FullInstallPaths {
+ // TODO: Directories. But maybe they're not necessary? Adevice doesn't care
+ // about empty directories, still need to check if adb sync does.
+ if !fip.IsDir {
+ if !fip.RequiresFullInstall {
+ // Some modules set requires_full_install: false, which causes their staging
+ // directory file to not be installed. This is usually because the file appears
+ // in both PRODUCT_COPY_FILES and a soong module for the handwritten soong system
+ // image. In this case, that module's installed files would conflict with the
+ // PRODUCT_COPY_FILES. However, in soong-only builds, we don't automatically
+ // create rules for PRODUCT_COPY_FILES unless they're needed in the partition.
+ // So in that case, nothing is creating the installed path. Create them now
+ // if that's the case.
+ if fip.SymlinkTarget == "" {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: fip.SourcePath,
+ Output: fip.FullInstallPath,
+ })
+ } else {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.SymlinkWithBash,
+ Output: fip.FullInstallPath,
+ Args: map[string]string{
+ "fromPath": fip.SymlinkTarget,
+ },
+ })
+ }
+ }
+ ctx.Phony(info.ModuleName, fip.FullInstallPath)
+ ctx.Phony(partition, fip.FullInstallPath)
+ deps = append(deps, fip.FullInstallPath)
+ ctx.Phony("sync_"+partition, fip.FullInstallPath)
+ ctx.Phony("sync", fip.FullInstallPath)
+ }
+ }
+
+ deps = append(deps, imgInstallPath)
+ }
+
+ // List all individual files to be copied to PRODUCT_OUT here
+ if a.deviceProps.Bootloader != nil {
+ bootloaderInstallPath := android.PathForModuleInPartitionInstall(ctx, "", "bootloader")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: android.PathForModuleSrc(ctx, *a.deviceProps.Bootloader),
+ Output: bootloaderInstallPath,
+ })
+ deps = append(deps, bootloaderInstallPath)
+ }
+
+ copyBootImg := func(prop *string, type_ string) {
+ if proptools.String(prop) != "" {
+ partition := ctx.GetDirectDepWithTag(*prop, filesystemDepTag)
+ if info, ok := android.OtherModuleProvider(ctx, partition, BootimgInfoProvider); ok {
+ installPath := android.PathForModuleInPartitionInstall(ctx, "", type_+".img")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: info.Output,
+ Output: installPath,
+ })
+ deps = append(deps, installPath)
+ } else {
+ ctx.ModuleErrorf("%s does not set BootimgInfo\n", *prop)
+ }
+ }
+ }
+
+ copyBootImg(a.partitionProps.Init_boot_partition_name, "init_boot")
+ copyBootImg(a.partitionProps.Boot_partition_name, "boot")
+ copyBootImg(a.partitionProps.Vendor_boot_partition_name, "vendor_boot")
+
+ for _, vbmetaModName := range a.partitionProps.Vbmeta_partitions {
+ partition := ctx.GetDirectDepWithTag(vbmetaModName, filesystemDepTag)
+ if info, ok := android.OtherModuleProvider(ctx, partition, vbmetaPartitionProvider); ok {
+ installPath := android.PathForModuleInPartitionInstall(ctx, "", info.Name+".img")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: info.Output,
+ Output: installPath,
+ })
+ deps = append(deps, installPath)
+ } else {
+ ctx.ModuleErrorf("%s does not set vbmetaPartitionProvider\n", vbmetaModName)
+ }
+ }
+
+ if proptools.String(a.partitionProps.Super_partition_name) != "" {
+ partition := ctx.GetDirectDepWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag)
+ if info, ok := android.OtherModuleProvider(ctx, partition, SuperImageProvider); ok {
+ installPath := android.PathForModuleInPartitionInstall(ctx, "", "super.img")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: info.SuperImage,
+ Output: installPath,
+ })
+ deps = append(deps, installPath)
+ } else {
+ ctx.ModuleErrorf("%s does not set SuperImageProvider\n", *a.partitionProps.Super_partition_name)
+ }
+ }
+
+ if proptools.String(a.deviceProps.Android_info) != "" {
+ installPath := android.PathForModuleInPartitionInstall(ctx, "", "android_info.txt")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: android.PathForModuleSrc(ctx, *a.deviceProps.Android_info),
+ Output: installPath,
+ })
+ deps = append(deps, installPath)
+ }
+
+ copyToProductOutTimestamp := android.PathForModuleOut(ctx, "product_out_copy_timestamp")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Touch,
+ Output: copyToProductOutTimestamp,
+ Implicits: deps,
+ })
+
+ return copyToProductOutTimestamp
+}
+
+// Returns a mapping from partition type -> FilesystemInfo. This includes filesystems that are
+// nested inside of other partitions, such as the partitions inside super.img, or ramdisk inside
+// of boot.
+func (a *androidDevice) getFsInfos(ctx android.ModuleContext) map[string]FilesystemInfo {
+ type propToType struct {
+ prop *string
+ ty string
+ }
+
+ filesystemInfos := make(map[string]FilesystemInfo)
+
+ partitionDefinitions := []propToType{
+ propToType{a.partitionProps.System_partition_name, "system"},
+ propToType{a.partitionProps.System_ext_partition_name, "system_ext"},
+ propToType{a.partitionProps.Product_partition_name, "product"},
+ propToType{a.partitionProps.Vendor_partition_name, "vendor"},
+ propToType{a.partitionProps.Odm_partition_name, "odm"},
+ propToType{a.partitionProps.Recovery_partition_name, "recovery"},
+ propToType{a.partitionProps.System_dlkm_partition_name, "system_dlkm"},
+ propToType{a.partitionProps.Vendor_dlkm_partition_name, "vendor_dlkm"},
+ propToType{a.partitionProps.Odm_dlkm_partition_name, "odm_dlkm"},
+ propToType{a.partitionProps.Userdata_partition_name, "userdata"},
+ // filesystemInfo from init_boot and vendor_boot actually are re-exports of the ramdisk
+ // images inside of them
+ propToType{a.partitionProps.Init_boot_partition_name, "ramdisk"},
+ propToType{a.partitionProps.Vendor_boot_partition_name, "vendor_ramdisk"},
+ }
+ for _, partitionDefinition := range partitionDefinitions {
+ if proptools.String(partitionDefinition.prop) != "" {
+ partition := ctx.GetDirectDepWithTag(*partitionDefinition.prop, filesystemDepTag)
+ if info, ok := android.OtherModuleProvider(ctx, partition, FilesystemProvider); ok {
+ filesystemInfos[partitionDefinition.ty] = info
+ } else {
+ ctx.ModuleErrorf("Super partition %s does not set FilesystemProvider\n", partition.Name())
+ }
+ }
+ }
+ if a.partitionProps.Super_partition_name != nil {
+ superPartition := ctx.GetDirectDepWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag)
+ if info, ok := android.OtherModuleProvider(ctx, superPartition, SuperImageProvider); ok {
+ for partition := range info.SubImageInfo {
+ filesystemInfos[partition] = info.SubImageInfo[partition]
+ }
+ } else {
+ ctx.ModuleErrorf("Super partition %s does not set SuperImageProvider\n", superPartition.Name())
+ }
+ }
+
+ return filesystemInfos
+}
diff --git a/filesystem/avb_add_hash_footer.go b/filesystem/avb_add_hash_footer.go
index 469f1fb..f32993c 100644
--- a/filesystem/avb_add_hash_footer.go
+++ b/filesystem/avb_add_hash_footer.go
@@ -29,7 +29,7 @@
properties avbAddHashFooterProperties
- output android.OutputPath
+ output android.Path
installDir android.InstallPath
}
@@ -46,7 +46,7 @@
type avbAddHashFooterProperties struct {
// Source file of this image. Can reference a genrule type module with the ":module" syntax.
- Src *string `android:"path,arch_variant"`
+ Src proptools.Configurable[string] `android:"path,arch_variant,replace_instead_of_append"`
// Set the name of the output. Defaults to <module_name>.img.
Filename *string
@@ -91,14 +91,15 @@
func (a *avbAddHashFooter) GenerateAndroidBuildActions(ctx android.ModuleContext) {
builder := android.NewRuleBuilder(pctx, ctx)
+ src := a.properties.Src.GetOrDefault(ctx, "")
- if a.properties.Src == nil {
+ if src == "" {
ctx.PropertyErrorf("src", "missing source file")
return
}
- input := android.PathForModuleSrc(ctx, proptools.String(a.properties.Src))
- a.output = android.PathForModuleOut(ctx, a.installFileName()).OutputPath
- builder.Command().Text("cp").Input(input).Output(a.output)
+ input := android.PathForModuleSrc(ctx, src)
+ output := android.PathForModuleOut(ctx, a.installFileName())
+ builder.Command().Text("cp").Input(input).Output(output)
cmd := builder.Command().BuiltTool("avbtool").Text("add_hash_footer")
@@ -141,12 +142,13 @@
cmd.Flag(fmt.Sprintf(" --rollback_index %d", rollbackIndex))
}
- cmd.FlagWithOutput("--image ", a.output)
+ cmd.FlagWithOutput("--image ", output)
builder.Build("avbAddHashFooter", fmt.Sprintf("avbAddHashFooter %s", ctx.ModuleName()))
a.installDir = android.PathForModuleInstall(ctx, "etc")
- ctx.InstallFile(a.installDir, a.installFileName(), a.output)
+ ctx.InstallFile(a.installDir, a.installFileName(), output)
+ a.output = output
}
func addAvbProp(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, prop avbProp) {
diff --git a/filesystem/avb_gen_vbmeta_image.go b/filesystem/avb_gen_vbmeta_image.go
index a7fd782..0669a2c 100644
--- a/filesystem/avb_gen_vbmeta_image.go
+++ b/filesystem/avb_gen_vbmeta_image.go
@@ -28,7 +28,7 @@
properties avbGenVbmetaImageProperties
- output android.OutputPath
+ output android.Path
installDir android.InstallPath
}
@@ -78,11 +78,12 @@
}
cmd.FlagWithArg("--salt ", proptools.String(a.properties.Salt))
- a.output = android.PathForModuleOut(ctx, a.installFileName()).OutputPath
- cmd.FlagWithOutput("--output_vbmeta_image ", a.output)
+ output := android.PathForModuleOut(ctx, a.installFileName())
+ cmd.FlagWithOutput("--output_vbmeta_image ", output)
builder.Build("avbGenVbmetaImage", fmt.Sprintf("avbGenVbmetaImage %s", ctx.ModuleName()))
- ctx.SetOutputFiles([]android.Path{a.output}, "")
+ ctx.SetOutputFiles([]android.Path{output}, "")
+ a.output = output
}
var _ android.AndroidMkEntriesProvider = (*avbGenVbmetaImage)(nil)
diff --git a/filesystem/bootconfig.go b/filesystem/bootconfig.go
new file mode 100644
index 0000000..b125824
--- /dev/null
+++ b/filesystem/bootconfig.go
@@ -0,0 +1,80 @@
+// 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 filesystem
+
+import (
+ "android/soong/android"
+ "strings"
+
+ "github.com/google/blueprint/proptools"
+)
+
+func init() {
+ android.RegisterModuleType("bootconfig", BootconfigModuleFactory)
+ pctx.Import("android/soong/android")
+}
+
+type bootconfigProperty struct {
+ // List of bootconfig parameters that will be written as a line separated list in the output
+ // file.
+ Boot_config []string
+ // Path to the file that contains the list of bootconfig parameters. This will be appended
+ // to the output file, after the entries in boot_config.
+ Boot_config_file *string `android:"path"`
+}
+
+type BootconfigModule struct {
+ android.ModuleBase
+
+ properties bootconfigProperty
+}
+
+// bootconfig module generates the `vendor-bootconfig.img` file, which lists the bootconfig
+// parameters and can be passed as a `--vendor_bootconfig` value in mkbootimg invocation.
+func BootconfigModuleFactory() android.Module {
+ module := &BootconfigModule{}
+ module.AddProperties(&module.properties)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ return module
+}
+
+func (m *BootconfigModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ bootConfig := m.properties.Boot_config
+ bootConfigFileStr := proptools.String(m.properties.Boot_config_file)
+ if len(bootConfig) == 0 && len(bootConfigFileStr) == 0 {
+ return
+ }
+
+ var bootConfigFile android.Path
+ if len(bootConfigFileStr) > 0 {
+ bootConfigFile = android.PathForModuleSrc(ctx, bootConfigFileStr)
+ }
+
+ outputPath := android.PathForModuleOut(ctx, ctx.ModuleName(), "vendor-bootconfig.img")
+ bootConfigOutput := android.PathForModuleOut(ctx, ctx.ModuleName(), "bootconfig.txt")
+ android.WriteFileRule(ctx, bootConfigOutput, strings.Join(bootConfig, "\n"))
+
+ bcFiles := android.Paths{bootConfigOutput}
+ if bootConfigFile != nil {
+ bcFiles = append(bcFiles, bootConfigFile)
+ }
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cat,
+ Description: "concatenate bootconfig parameters",
+ Inputs: bcFiles,
+ Output: outputPath,
+ })
+ ctx.SetOutputFiles(android.Paths{outputPath}, "")
+}
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index e796ab9..6d6c15c 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -26,19 +26,21 @@
)
func init() {
- android.RegisterModuleType("bootimg", bootimgFactory)
+ android.RegisterModuleType("bootimg", BootimgFactory)
}
type bootimg struct {
android.ModuleBase
- properties bootimgProperties
+ properties BootimgProperties
- output android.OutputPath
+ output android.Path
installDir android.InstallPath
+
+ bootImageType bootImageType
}
-type bootimgProperties struct {
+type BootimgProperties struct {
// Set the name of the output. Defaults to <module_name>.img.
Stem *string
@@ -56,9 +58,13 @@
// https://source.android.com/devices/bootloader/boot-image-header
Header_version *string
- // Determines if this image is for the vendor_boot partition. Default is false. Refer to
- // https://source.android.com/devices/bootloader/partitions/vendor-boot-partitions
- Vendor_boot *bool
+ // Determines the specific type of boot image this module is building. Can be boot,
+ // vendor_boot or init_boot. Defaults to boot.
+ // Refer to https://source.android.com/devices/bootloader/partitions/vendor-boot-partitions
+ // for vendor_boot.
+ // Refer to https://source.android.com/docs/core/architecture/partitions/generic-boot for
+ // init_boot.
+ Boot_image_type *string
// Optional kernel commandline arguments
Cmdline []string `android:"arch_variant"`
@@ -67,22 +73,90 @@
// and `header_version` is greater than or equal to 4.
Bootconfig *string `android:"arch_variant,path"`
+ // The size of the partition on the device. It will be a build error if this built partition
+ // image exceeds this size.
+ Partition_size *int64
+
// When set to true, sign the image with avbtool. Default is false.
Use_avb *bool
+ // This can either be "default", or "make_legacy". "make_legacy" will sign the boot image
+ // like how build/make/core/Makefile does, to get bit-for-bit backwards compatibility. But
+ // we may want to reconsider if it's necessary to have two modes in the future. The default
+ // is "default"
+ Avb_mode *string
+
// Name of the partition stored in vbmeta desc. Defaults to the name of this module.
Partition_name *string
// Path to the private key that avbtool will use to sign this filesystem image.
// TODO(jiyong): allow apex_key to be specified here
- Avb_private_key *string `android:"path"`
+ Avb_private_key *string `android:"path_device_first"`
// Hash and signing algorithm for avbtool. Default is SHA256_RSA4096.
Avb_algorithm *string
+
+ // The index used to prevent rollback of the image on device.
+ Avb_rollback_index *int64
+
+ // Rollback index location of this image. Must be 0, 1, 2, etc.
+ Avb_rollback_index_location *int64
+
+ // The security patch passed to as the com.android.build.<type>.security_patch avb property.
+ // Replacement for the make variables BOOT_SECURITY_PATCH / INIT_BOOT_SECURITY_PATCH.
+ Security_patch *string
+}
+
+type bootImageType int
+
+const (
+ unsupported bootImageType = iota
+ boot
+ vendorBoot
+ initBoot
+)
+
+func toBootImageType(ctx android.ModuleContext, bootImageType string) bootImageType {
+ switch bootImageType {
+ case "boot":
+ return boot
+ case "vendor_boot":
+ return vendorBoot
+ case "init_boot":
+ return initBoot
+ default:
+ ctx.ModuleErrorf("Unknown boot_image_type %s. Must be one of \"boot\", \"vendor_boot\", or \"init_boot\"", bootImageType)
+ }
+ return unsupported
+}
+
+func (b bootImageType) String() string {
+ switch b {
+ case boot:
+ return "boot"
+ case vendorBoot:
+ return "vendor_boot"
+ case initBoot:
+ return "init_boot"
+ default:
+ panic("unknown boot image type")
+ }
+}
+
+func (b bootImageType) isBoot() bool {
+ return b == boot
+}
+
+func (b bootImageType) isVendorBoot() bool {
+ return b == vendorBoot
+}
+
+func (b bootImageType) isInitBoot() bool {
+ return b == initBoot
}
// bootimg is the image for the boot partition. It consists of header, kernel, ramdisk, and dtb.
-func bootimgFactory() android.Module {
+func BootimgFactory() android.Module {
module := &bootimg{}
module.AddProperties(&module.properties)
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
@@ -112,50 +186,144 @@
}
func (b *bootimg) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- vendor := proptools.Bool(b.properties.Vendor_boot)
- unsignedOutput := b.buildBootImage(ctx, vendor)
+ b.bootImageType = toBootImageType(ctx, proptools.StringDefault(b.properties.Boot_image_type, "boot"))
+ if b.bootImageType == unsupported {
+ return
+ }
+ kernelProp := proptools.String(b.properties.Kernel_prebuilt)
+ if b.bootImageType.isVendorBoot() && kernelProp != "" {
+ ctx.PropertyErrorf("kernel_prebuilt", "vendor_boot partition can't have kernel")
+ return
+ }
+ if b.bootImageType.isBoot() && kernelProp == "" {
+ ctx.PropertyErrorf("kernel_prebuilt", "boot partition must have kernel")
+ return
+ }
+
+ unsignedOutput := b.buildBootImage(ctx, b.getKernelPath(ctx))
+
+ output := unsignedOutput
if proptools.Bool(b.properties.Use_avb) {
- b.output = b.signImage(ctx, unsignedOutput)
- } else {
- b.output = unsignedOutput
+ // This bootimg module supports 2 modes of avb signing. It is not clear to this author
+ // why there are differences, but one of them is to match the behavior of make-built boot
+ // images.
+ switch proptools.StringDefault(b.properties.Avb_mode, "default") {
+ case "default":
+ output = b.signImage(ctx, unsignedOutput)
+ case "make_legacy":
+ output = b.addAvbFooter(ctx, unsignedOutput, b.getKernelPath(ctx))
+ default:
+ ctx.PropertyErrorf("avb_mode", `Unknown value for avb_mode, expected "default" or "make_legacy", got: %q`, *b.properties.Avb_mode)
+ }
}
b.installDir = android.PathForModuleInstall(ctx, "etc")
- ctx.InstallFile(b.installDir, b.installFileName(), b.output)
+ ctx.InstallFile(b.installDir, b.installFileName(), output)
- ctx.SetOutputFiles([]android.Path{b.output}, "")
+ ctx.SetOutputFiles([]android.Path{output}, "")
+ b.output = output
+
+ // Set the Filesystem info of the ramdisk dependency.
+ // `android_device` will use this info to package `target_files.zip`
+ if ramdisk := proptools.String(b.properties.Ramdisk_module); ramdisk != "" {
+ ramdiskModule := ctx.GetDirectDepWithTag(ramdisk, bootimgRamdiskDep)
+ fsInfo, _ := android.OtherModuleProvider(ctx, ramdiskModule, FilesystemProvider)
+ android.SetProvider(ctx, FilesystemProvider, fsInfo)
+ }
+
+ // Set BootimgInfo for building target_files.zip
+ android.SetProvider(ctx, BootimgInfoProvider, BootimgInfo{
+ Cmdline: b.properties.Cmdline,
+ Kernel: b.getKernelPath(ctx),
+ Dtb: b.getDtbPath(ctx),
+ Bootconfig: b.getBootconfigPath(ctx),
+ Output: output,
+ })
+
+ extractedPublicKey := android.PathForModuleOut(ctx, b.partitionName()+".avbpubkey")
+ if b.properties.Avb_private_key != nil {
+ key := android.PathForModuleSrc(ctx, proptools.String(b.properties.Avb_private_key))
+ ctx.Build(pctx, android.BuildParams{
+ Rule: extractPublicKeyRule,
+ Input: key,
+ Output: extractedPublicKey,
+ })
+ }
+ var ril int
+ if b.properties.Avb_rollback_index_location != nil {
+ ril = proptools.Int(b.properties.Avb_rollback_index_location)
+ }
+
+ android.SetProvider(ctx, vbmetaPartitionProvider, vbmetaPartitionInfo{
+ Name: b.bootImageType.String(),
+ RollbackIndexLocation: ril,
+ PublicKey: extractedPublicKey,
+ Output: output,
+ })
}
-func (b *bootimg) buildBootImage(ctx android.ModuleContext, vendor bool) android.OutputPath {
- output := android.PathForModuleOut(ctx, "unsigned", b.installFileName()).OutputPath
+var BootimgInfoProvider = blueprint.NewProvider[BootimgInfo]()
+
+type BootimgInfo struct {
+ Cmdline []string
+ Kernel android.Path
+ Dtb android.Path
+ Bootconfig android.Path
+ Output android.Path
+}
+
+func (b *bootimg) getKernelPath(ctx android.ModuleContext) android.Path {
+ var kernelPath android.Path
+ kernelName := proptools.String(b.properties.Kernel_prebuilt)
+ if kernelName != "" {
+ kernelPath = android.PathForModuleSrc(ctx, kernelName)
+ }
+ return kernelPath
+}
+
+func (b *bootimg) getDtbPath(ctx android.ModuleContext) android.Path {
+ var dtbPath android.Path
+ dtbName := proptools.String(b.properties.Dtb_prebuilt)
+ if dtbName != "" {
+ dtbPath = android.PathForModuleSrc(ctx, dtbName)
+ }
+ return dtbPath
+}
+
+func (b *bootimg) getBootconfigPath(ctx android.ModuleContext) android.Path {
+ var bootconfigPath android.Path
+ bootconfigName := proptools.String(b.properties.Bootconfig)
+ if bootconfigName != "" {
+ bootconfigPath = android.PathForModuleSrc(ctx, bootconfigName)
+ }
+ return bootconfigPath
+}
+
+func (b *bootimg) buildBootImage(ctx android.ModuleContext, kernel android.Path) android.Path {
+ output := android.PathForModuleOut(ctx, "unsigned", b.installFileName())
builder := android.NewRuleBuilder(pctx, ctx)
cmd := builder.Command().BuiltTool("mkbootimg")
- kernel := proptools.String(b.properties.Kernel_prebuilt)
- if vendor && kernel != "" {
- ctx.PropertyErrorf("kernel_prebuilt", "vendor_boot partition can't have kernel")
- return output
- }
- if !vendor && kernel == "" {
- ctx.PropertyErrorf("kernel_prebuilt", "boot partition must have kernel")
- return output
- }
- if kernel != "" {
- cmd.FlagWithInput("--kernel ", android.PathForModuleSrc(ctx, kernel))
+ if kernel != nil {
+ cmd.FlagWithInput("--kernel ", kernel)
}
- dtbName := proptools.String(b.properties.Dtb_prebuilt)
- if dtbName != "" {
- dtb := android.PathForModuleSrc(ctx, dtbName)
- cmd.FlagWithInput("--dtb ", dtb)
+ // These arguments are passed for boot.img and init_boot.img generation
+ if b.bootImageType.isBoot() || b.bootImageType.isInitBoot() {
+ cmd.FlagWithArg("--os_version ", ctx.Config().PlatformVersionLastStable())
+ cmd.FlagWithArg("--os_patch_level ", ctx.Config().PlatformSecurityPatch())
+ }
+
+ if b.getDtbPath(ctx) != nil {
+ cmd.FlagWithInput("--dtb ", b.getDtbPath(ctx))
}
cmdline := strings.Join(b.properties.Cmdline, " ")
if cmdline != "" {
flag := "--cmdline "
- if vendor {
+ if b.bootImageType.isVendorBoot() {
flag = "--vendor_cmdline "
}
cmd.FlagWithArg(flag, proptools.ShellEscapeIncludingSpaces(cmdline))
@@ -182,7 +350,7 @@
ramdisk := ctx.GetDirectDepWithTag(ramdiskName, bootimgRamdiskDep)
if filesystem, ok := ramdisk.(*filesystem); ok {
flag := "--ramdisk "
- if vendor {
+ if b.bootImageType.isVendorBoot() {
flag = "--vendor_ramdisk "
}
cmd.FlagWithInput(flag, filesystem.OutputPath())
@@ -194,7 +362,7 @@
bootconfig := proptools.String(b.properties.Bootconfig)
if bootconfig != "" {
- if !vendor {
+ if !b.bootImageType.isVendorBoot() {
ctx.PropertyErrorf("bootconfig", "requires vendor_boot: true")
return output
}
@@ -205,20 +373,85 @@
cmd.FlagWithInput("--vendor_bootconfig ", android.PathForModuleSrc(ctx, bootconfig))
}
+ // Output flag for boot.img and init_boot.img
flag := "--output "
- if vendor {
+ if b.bootImageType.isVendorBoot() {
flag = "--vendor_boot "
}
cmd.FlagWithOutput(flag, output)
+ if b.properties.Partition_size != nil {
+ assertMaxImageSize(builder, output, *b.properties.Partition_size, proptools.Bool(b.properties.Use_avb))
+ }
+
builder.Build("build_bootimg", fmt.Sprintf("Creating %s", b.BaseModuleName()))
return output
}
-func (b *bootimg) signImage(ctx android.ModuleContext, unsignedImage android.OutputPath) android.OutputPath {
+func (b *bootimg) addAvbFooter(ctx android.ModuleContext, unsignedImage android.Path, kernel android.Path) android.Path {
+ output := android.PathForModuleOut(ctx, b.installFileName())
+ builder := android.NewRuleBuilder(pctx, ctx)
+ builder.Command().Text("cp").Input(unsignedImage).Output(output)
+ cmd := builder.Command().BuiltTool("avbtool").
+ Text("add_hash_footer").
+ FlagWithInput("--image ", output)
+
+ if b.properties.Partition_size != nil {
+ cmd.FlagWithArg("--partition_size ", strconv.FormatInt(*b.properties.Partition_size, 10))
+ } else {
+ cmd.Flag("--dynamic_partition_size")
+ }
+
+ // If you don't provide a salt, avbtool will use random bytes for the salt.
+ // This is bad for determinism (cached builds and diff tests are affected), so instead,
+ // we try to provide a salt. The requirements for a salt are not very clear, one aspect of it
+ // is that if it's unpredictable, attackers trying to change the contents of a partition need
+ // to find a new hash collision every release, because the salt changed.
+ if kernel != nil {
+ cmd.Textf(`--salt $(sha256sum "%s" | cut -d " " -f 1)`, kernel.String())
+ cmd.Implicit(kernel)
+ } else {
+ cmd.Textf(`--salt $(sha256sum "%s" "%s" | cut -d " " -f 1 | tr -d '\n')`, ctx.Config().BuildNumberFile(ctx), ctx.Config().Getenv("BUILD_DATETIME_FILE"))
+ cmd.OrderOnly(ctx.Config().BuildNumberFile(ctx))
+ }
+
+ cmd.FlagWithArg("--partition_name ", b.bootImageType.String())
+
+ if b.properties.Avb_algorithm != nil {
+ cmd.FlagWithArg("--algorithm ", proptools.NinjaAndShellEscape(*b.properties.Avb_algorithm))
+ }
+
+ if b.properties.Avb_private_key != nil {
+ key := android.PathForModuleSrc(ctx, proptools.String(b.properties.Avb_private_key))
+ cmd.FlagWithInput("--key ", key)
+ }
+
+ if !b.bootImageType.isVendorBoot() {
+ cmd.FlagWithArg("--prop ", proptools.NinjaAndShellEscape(fmt.Sprintf(
+ "com.android.build.%s.os_version:%s", b.bootImageType.String(), ctx.Config().PlatformVersionLastStable())))
+ }
+
+ fingerprintFile := ctx.Config().BuildFingerprintFile(ctx)
+ cmd.FlagWithArg("--prop ", fmt.Sprintf("com.android.build.%s.fingerprint:$(cat %s)", b.bootImageType.String(), fingerprintFile.String()))
+ cmd.OrderOnly(fingerprintFile)
+
+ if b.properties.Security_patch != nil {
+ cmd.FlagWithArg("--prop ", proptools.NinjaAndShellEscape(fmt.Sprintf(
+ "com.android.build.%s.security_patch:%s", b.bootImageType.String(), *b.properties.Security_patch)))
+ }
+
+ if b.properties.Avb_rollback_index != nil {
+ cmd.FlagWithArg("--rollback_index ", strconv.FormatInt(*b.properties.Avb_rollback_index, 10))
+ }
+
+ builder.Build("add_avb_footer", fmt.Sprintf("Adding avb footer to %s", b.BaseModuleName()))
+ return output
+}
+
+func (b *bootimg) signImage(ctx android.ModuleContext, unsignedImage android.Path) android.Path {
propFile, toolDeps := b.buildPropFile(ctx)
- output := android.PathForModuleOut(ctx, b.installFileName()).OutputPath
+ output := android.PathForModuleOut(ctx, b.installFileName())
builder := android.NewRuleBuilder(pctx, ctx)
builder.Command().Text("cp").Input(unsignedImage).Output(output)
builder.Command().BuiltTool("verity_utils").
@@ -230,16 +463,7 @@
return output
}
-// Calculates avb_salt from some input for deterministic output.
-func (b *bootimg) salt() string {
- var input []string
- input = append(input, b.properties.Cmdline...)
- input = append(input, proptools.StringDefault(b.properties.Partition_name, b.Name()))
- input = append(input, proptools.String(b.properties.Header_version))
- return sha1sum(input)
-}
-
-func (b *bootimg) buildPropFile(ctx android.ModuleContext) (propFile android.OutputPath, toolDeps android.Paths) {
+func (b *bootimg) buildPropFile(ctx android.ModuleContext) (android.Path, android.Paths) {
var sb strings.Builder
var deps android.Paths
addStr := func(name string, value string) {
@@ -259,9 +483,8 @@
addStr("avb_add_hash_footer_args", "") // TODO(jiyong): add --rollback_index
partitionName := proptools.StringDefault(b.properties.Partition_name, b.Name())
addStr("partition_name", partitionName)
- addStr("avb_salt", b.salt())
- propFile = android.PathForModuleOut(ctx, "prop").OutputPath
+ propFile := android.PathForModuleOut(ctx, "prop")
android.WriteFileRule(ctx, propFile, sb.String())
return propFile, deps
}
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 5c7ef43..6606037 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -20,11 +20,14 @@
"io"
"path/filepath"
"slices"
+ "sort"
"strconv"
"strings"
"android/soong/android"
"android/soong/cc"
+ "android/soong/java"
+ "android/soong/linkerconfig"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -32,46 +35,79 @@
func init() {
registerBuildComponents(android.InitRegistrationContext)
+ registerMutators(android.InitRegistrationContext)
}
func registerBuildComponents(ctx android.RegistrationContext) {
- ctx.RegisterModuleType("android_filesystem", filesystemFactory)
+ ctx.RegisterModuleType("android_filesystem", FilesystemFactory)
ctx.RegisterModuleType("android_filesystem_defaults", filesystemDefaultsFactory)
- ctx.RegisterModuleType("android_system_image", systemImageFactory)
+ ctx.RegisterModuleType("android_system_image", SystemImageFactory)
ctx.RegisterModuleType("avb_add_hash_footer", avbAddHashFooterFactory)
ctx.RegisterModuleType("avb_add_hash_footer_defaults", avbAddHashFooterDefaultsFactory)
ctx.RegisterModuleType("avb_gen_vbmeta_image", avbGenVbmetaImageFactory)
ctx.RegisterModuleType("avb_gen_vbmeta_image_defaults", avbGenVbmetaImageDefaultsFactory)
}
+func registerMutators(ctx android.RegistrationContext) {
+ ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("add_autogenerated_rro_deps", addAutogeneratedRroDeps)
+ })
+}
+
+// Remember to add referenced files to implicits!
+var textFileProcessorRule = pctx.AndroidStaticRule("text_file_processing", blueprint.RuleParams{
+ Command: "build/soong/scripts/text_file_processor.py $in $out",
+ CommandDeps: []string{"build/soong/scripts/text_file_processor.py"},
+})
+
type filesystem struct {
android.ModuleBase
android.PackagingBase
android.DefaultableModuleBase
- properties filesystemProperties
+ properties FilesystemProperties
- // Function that builds extra files under the root directory and returns the files
- buildExtraFiles func(ctx android.ModuleContext, root android.OutputPath) android.OutputPaths
-
- // Function that filters PackagingSpec in PackagingBase.GatherPackagingSpecs()
- filterPackagingSpec func(spec android.PackagingSpec) bool
-
- output android.OutputPath
+ output android.Path
installDir android.InstallPath
- fileListFile android.OutputPath
+ fileListFile android.Path
// Keeps the entries installed from this filesystem
entries []string
+
+ filesystemBuilder filesystemBuilder
}
-type symlinkDefinition struct {
+type filesystemBuilder interface {
+ BuildLinkerConfigFile(ctx android.ModuleContext, builder *android.RuleBuilder, rebasedDir android.OutputPath, fullInstallPaths *[]FullInstallPathInfo)
+ // Function that filters PackagingSpec in PackagingBase.GatherPackagingSpecs()
+ FilterPackagingSpec(spec android.PackagingSpec) bool
+ // Function that modifies PackagingSpec in PackagingBase.GatherPackagingSpecs() to customize.
+ // For example, GSI system.img contains system_ext and product artifacts and their
+ // relPathInPackage need to be rebased to system/system_ext and system/system_product.
+ ModifyPackagingSpec(spec *android.PackagingSpec)
+
+ // Function to check if the filesystem should not use `vintf_fragments` property,
+ // but use `vintf_fragment` module type instead
+ ShouldUseVintfFragmentModuleOnly() bool
+}
+
+var _ filesystemBuilder = (*filesystem)(nil)
+
+type SymlinkDefinition struct {
Target *string
Name *string
}
-type filesystemProperties struct {
+// CopyWithNamePrefix returns a new [SymlinkDefinition] with prefix added to Name.
+func (s *SymlinkDefinition) CopyWithNamePrefix(prefix string) SymlinkDefinition {
+ return SymlinkDefinition{
+ Target: s.Target,
+ Name: proptools.StringPtr(filepath.Join(prefix, proptools.String(s.Name))),
+ }
+}
+
+type FilesystemProperties struct {
// When set to true, sign the image with avbtool. Default is false.
Use_avb *bool
@@ -86,13 +122,22 @@
// avbtool. Default used by avbtool is sha1.
Avb_hash_algorithm *string
+ // The security patch passed to as the com.android.build.<type>.security_patch avb property.
+ Security_patch *string
+
+ // Whether or not to use forward-error-correction codes when signing with AVB. Defaults to true.
+ Use_fec *bool
+
// The index used to prevent rollback of the image. Only used if use_avb is true.
Rollback_index *int64
+ // Rollback index location of this image. Must be 0, 1, 2, etc.
+ Rollback_index_location *int64
+
// Name of the partition stored in vbmeta desc. Defaults to the name of this module.
Partition_name *string
- // Type of the filesystem. Currently, ext4, cpio, and compressed_cpio are supported. Default
+ // Type of the filesystem. Currently, ext4, erofs, cpio, and compressed_cpio are supported. Default
// is ext4.
Type *string
@@ -100,9 +145,13 @@
// checks, and will be used in the future for API surface checks.
Partition_type *string
- // file_contexts file to make image. Currently, only ext4 is supported.
+ // file_contexts file to make image. Currently, only ext4 is supported. These file contexts
+ // will be compiled with sefcontext_compile
File_contexts *string `android:"path"`
+ // The selinux file contexts, after having already run them through sefcontext_compile
+ Precompiled_file_contexts *string `android:"path"`
+
// Base directory relative to root, to which deps are installed, e.g. "system". Default is "."
// (root).
Base_dir *string
@@ -110,8 +159,13 @@
// Directories to be created under root. e.g. /dev, /proc, etc.
Dirs proptools.Configurable[[]string]
+ // List of filesystem modules to include in creating the partition. The root directory of
+ // the provided filesystem modules are included in creating the partition.
+ // This is only supported for cpio and compressed cpio filesystem types.
+ Include_files_of []string
+
// Symbolic links to be created under root with "ln -sf <target> <name>".
- Symlinks []symlinkDefinition
+ Symlinks []SymlinkDefinition
// Seconds since unix epoch to override timestamps of file entries
Fake_timestamp *string
@@ -123,12 +177,6 @@
// Mount point for this image. Default is "/"
Mount_point *string
- // If set to the name of a partition ("system", "vendor", etc), this filesystem module
- // will also include the contents of the make-built staging directories. If any soong
- // modules would be installed to the same location as a make module, they will overwrite
- // the make version.
- Include_make_built_files string
-
// When set, builds etc/event-log-tags file by merging logtags from all dependencies.
// Default is false
Build_logtags *bool
@@ -136,7 +184,83 @@
// Install aconfig_flags.pb file for the modules installed in this partition.
Gen_aconfig_flags_pb *bool
+ // List of names of other filesystem partitions to import their aconfig flags from.
+ // This is used for the system partition to import system_ext's aconfig flags, as currently
+ // those are considered one "container": aosp/3261300
+ Import_aconfig_flags_from []string
+
Fsverity fsverityProperties
+
+ // If this property is set to true, the filesystem will call ctx.UncheckedModule(), causing
+ // it to not be built on checkbuilds. Used for the automatic migration from make to soong
+ // build modules, where we want to emit some not-yet-working filesystems and we don't want them
+ // to be built.
+ Unchecked_module *bool `blueprint:"mutated"`
+
+ Erofs ErofsProperties
+
+ F2fs F2fsProperties
+
+ Linker_config LinkerConfigProperties
+
+ // Determines if the module is auto-generated from Soong or not. If the module is
+ // auto-generated, its deps are exempted from visibility enforcement.
+ Is_auto_generated *bool
+
+ // Path to the dev nodes description file. This is only needed for building the ramdisk
+ // partition and should not be explicitly specified.
+ Dev_nodes_description_file *string `android:"path" blueprint:"mutated"`
+
+ // Additional dependencies used for building android products
+ Android_filesystem_deps AndroidFilesystemDeps
+
+ // Name of the output. Default is $(module_name).img
+ Stem *string
+
+ // The size of the partition on the device. It will be a build error if this built partition
+ // image exceeds this size.
+ Partition_size *int64
+
+ // Whether to format f2fs and ext4 in a way that supports casefolding
+ Support_casefolding *bool
+
+ // Whether to format f2fs and ext4 in a way that supports project quotas
+ Support_project_quota *bool
+
+ // Whether to enable per-file compression in f2fs
+ Enable_compression *bool
+}
+
+type AndroidFilesystemDeps struct {
+ System *string
+ System_ext *string
+}
+
+// Additional properties required to generate erofs FS partitions.
+type ErofsProperties struct {
+ // Compressor and Compression level passed to mkfs.erofs. e.g. (lz4hc,9)
+ // Please see external/erofs-utils/README for complete documentation.
+ Compressor *string
+
+ // Used as --compress-hints for mkfs.erofs
+ Compress_hints *string `android:"path"`
+
+ Sparse *bool
+}
+
+// Additional properties required to generate f2fs FS partitions.
+type F2fsProperties struct {
+ Sparse *bool
+}
+
+type LinkerConfigProperties struct {
+
+ // Build a linker.config.pb file
+ Gen_linker_config *bool
+
+ // List of files (in .json format) that will be converted to a linker config file (in .pb format).
+ // The linker config file be installed in the filesystem at /etc/linker.config.pb
+ Linker_config_srcs []string `android:"path"`
}
// android_filesystem packages a set of modules and their transitive dependencies into a filesystem
@@ -144,79 +268,288 @@
// modules in the filesystem image are built for the target device (i.e. Android, not Linux host).
// The modules are placed in the filesystem image just like they are installed to the ordinary
// partitions like system.img. For example, cc_library modules are placed under ./lib[64] directory.
-func filesystemFactory() android.Module {
+func FilesystemFactory() android.Module {
module := &filesystem{}
- module.filterPackagingSpec = module.filterInstallablePackagingSpec
- initFilesystemModule(module)
+ module.filesystemBuilder = module
+ initFilesystemModule(module, module)
return module
}
-func initFilesystemModule(module *filesystem) {
- module.AddProperties(&module.properties)
- android.InitPackageModule(module)
- module.PackagingBase.DepsCollectFirstTargetOnly = true
+func initFilesystemModule(module android.DefaultableModule, filesystemModule *filesystem) {
+ module.AddProperties(&filesystemModule.properties)
+ android.InitPackageModule(filesystemModule)
+ filesystemModule.PackagingBase.DepsCollectFirstTargetOnly = true
+ filesystemModule.PackagingBase.AllowHighPriorityDeps = true
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
+
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ filesystemModule.setDevNodesDescriptionProp()
+ })
}
-var dependencyTag = struct {
+type depTag struct {
blueprint.BaseDependencyTag
android.PackagingItemAlwaysDepTag
-}{}
+}
+
+var dependencyTag = depTag{}
+
+type depTagWithVisibilityEnforcementBypass struct {
+ depTag
+}
+
+type interPartitionDepTag struct {
+ blueprint.BaseDependencyTag
+}
+
+var interPartitionDependencyTag = interPartitionDepTag{}
+
+var interPartitionInstallDependencyTag = interPartitionDepTag{}
+
+var _ android.ExcludeFromVisibilityEnforcementTag = (*depTagWithVisibilityEnforcementBypass)(nil)
+
+func (t depTagWithVisibilityEnforcementBypass) ExcludeFromVisibilityEnforcement() {}
+
+var dependencyTagWithVisibilityEnforcementBypass = depTagWithVisibilityEnforcementBypass{}
+
+// ramdiskDevNodesDescription is the name of the filegroup module that provides the file that
+// contains the description of dev nodes added to the CPIO archive for the ramdisk partition.
+const ramdiskDevNodesDescription = "ramdisk_node_list"
+
+func (f *filesystem) setDevNodesDescriptionProp() {
+ if proptools.String(f.properties.Partition_name) == "ramdisk" {
+ f.properties.Dev_nodes_description_file = proptools.StringPtr(":" + ramdiskDevNodesDescription)
+ }
+}
func (f *filesystem) DepsMutator(ctx android.BottomUpMutatorContext) {
- f.AddDeps(ctx, dependencyTag)
+ if proptools.Bool(f.properties.Is_auto_generated) {
+ f.AddDeps(ctx, dependencyTagWithVisibilityEnforcementBypass)
+ } else {
+ f.AddDeps(ctx, dependencyTag)
+ }
+ if f.properties.Android_filesystem_deps.System != nil {
+ ctx.AddDependency(ctx.Module(), interPartitionDependencyTag, proptools.String(f.properties.Android_filesystem_deps.System))
+ }
+ if f.properties.Android_filesystem_deps.System_ext != nil {
+ ctx.AddDependency(ctx.Module(), interPartitionDependencyTag, proptools.String(f.properties.Android_filesystem_deps.System_ext))
+ }
+ for _, partition := range f.properties.Import_aconfig_flags_from {
+ ctx.AddDependency(ctx.Module(), importAconfigDependencyTag, partition)
+ }
+ for _, partition := range f.properties.Include_files_of {
+ ctx.AddDependency(ctx.Module(), interPartitionInstallDependencyTag, partition)
+ }
}
type fsType int
const (
ext4Type fsType = iota
+ erofsType
+ f2fsType
compressedCpioType
cpioType // uncompressed
unknown
)
-func (f *filesystem) fsType(ctx android.ModuleContext) fsType {
- typeStr := proptools.StringDefault(f.properties.Type, "ext4")
+func (fs fsType) IsUnknown() bool {
+ return fs == unknown
+}
+
+type FilesystemInfo struct {
+ // The built filesystem image
+ Output android.Path
+ // An additional hermetic filesystem image.
+ // e.g. this will contain inodes with pinned timestamps.
+ // This will be copied to target_files.zip
+ OutputHermetic android.Path
+ // A text file containing the list of paths installed on the partition.
+ FileListFile android.Path
+ // The root staging directory used to build the output filesystem. If consuming this, make sure
+ // to add a dependency on the Output file, as you cannot add dependencies on directories
+ // in ninja.
+ RootDir android.Path
+ // The rebased staging directory used to build the output filesystem. If consuming this, make
+ // sure to add a dependency on the Output file, as you cannot add dependencies on directories
+ // in ninja. In many cases this is the same as RootDir, only in the system partition is it
+ // different. There, it points to the "system" sub-directory of RootDir.
+ RebasedDir android.Path
+ // A text file with block data of the .img file
+ // This is an implicit output of `build_image`
+ MapFile android.Path
+ // Name of the module that produced this FilesystemInfo origionally. (though it may be
+ // re-exported by super images or boot images)
+ ModuleName string
+ // The property file generated by this module and passed to build_image.
+ // It's exported here so that system_other can reuse system's property file.
+ BuildImagePropFile android.Path
+ // Paths to all the tools referenced inside of the build image property file.
+ BuildImagePropFileDeps android.Paths
+ // Packaging specs to be installed on the system_other image, for the initial boot's dexpreopt.
+ SpecsForSystemOther map[string]android.PackagingSpec
+
+ FullInstallPaths []FullInstallPathInfo
+}
+
+// FullInstallPathInfo contains information about the "full install" paths of all the files
+// inside this partition. The full install paths are the files installed in
+// out/target/product/<device>/<partition>. This is essentially legacy behavior, maintained for
+// tools like adb sync and adevice, but we should update them to query the build system for the
+// installed files no matter where they are.
+type FullInstallPathInfo struct {
+ // RequiresFullInstall tells us if the origional module did the install to FullInstallPath
+ // already. If it's false, the android_device module needs to emit the install rule.
+ RequiresFullInstall bool
+ // The "full install" paths for the files in this filesystem. This is the paths in the
+ // out/target/product/<device>/<partition> folder. They're not used by this filesystem,
+ // but can be depended on by the top-level android_device module to cause the staging
+ // directories to be built.
+ FullInstallPath android.InstallPath
+
+ // The file that's copied to FullInstallPath. May be nil if SymlinkTarget is set or IsDir is
+ // true.
+ SourcePath android.Path
+
+ // The target of the symlink, if this file is a symlink.
+ SymlinkTarget string
+
+ // If this file is a directory. Only used for empty directories, which are mostly mount points.
+ IsDir bool
+}
+
+var FilesystemProvider = blueprint.NewProvider[FilesystemInfo]()
+
+type FilesystemDefaultsInfo struct {
+ // Identifies which partition this is for //visibility:any_system_image (and others) visibility
+ // checks, and will be used in the future for API surface checks.
+ PartitionType string
+}
+
+var FilesystemDefaultsInfoProvider = blueprint.NewProvider[FilesystemDefaultsInfo]()
+
+func GetFsTypeFromString(ctx android.EarlyModuleContext, typeStr string) fsType {
switch typeStr {
case "ext4":
return ext4Type
+ case "erofs":
+ return erofsType
+ case "f2fs":
+ return f2fsType
case "compressed_cpio":
return compressedCpioType
case "cpio":
return cpioType
default:
- ctx.PropertyErrorf("type", "%q not supported", typeStr)
return unknown
}
}
+func (f *filesystem) fsType(ctx android.ModuleContext) fsType {
+ typeStr := proptools.StringDefault(f.properties.Type, "ext4")
+ fsType := GetFsTypeFromString(ctx, typeStr)
+ if fsType == unknown {
+ ctx.PropertyErrorf("type", "%q not supported", typeStr)
+ }
+ return fsType
+}
+
func (f *filesystem) installFileName() string {
- return f.BaseModuleName() + ".img"
+ return proptools.StringDefault(f.properties.Stem, f.BaseModuleName()+".img")
}
func (f *filesystem) partitionName() string {
return proptools.StringDefault(f.properties.Partition_name, f.Name())
}
-func (f *filesystem) filterInstallablePackagingSpec(ps android.PackagingSpec) bool {
+func (f *filesystem) FilterPackagingSpec(ps android.PackagingSpec) bool {
// Filesystem module respects the installation semantic. A PackagingSpec from a module with
// IsSkipInstall() is skipped.
- return !ps.SkipInstall()
+ if ps.SkipInstall() {
+ return false
+ }
+ // "apex" is a fake partition used to install files in out/target/product/<device>/apex/.
+ // Don't include these files in the partition. We should also look into removing the following
+ // TODO to check the PackagingSpec's partition against this filesystem's partition for all
+ // modules, not just autogenerated ones, which will fix this as well.
+ if ps.Partition() == "apex" {
+ return false
+ }
+ if proptools.Bool(f.properties.Is_auto_generated) { // TODO (spandandas): Remove this.
+ pt := f.PartitionType()
+ return ps.Partition() == pt || strings.HasPrefix(ps.Partition(), pt+"/")
+ }
+ return true
+}
+
+func (f *filesystem) ModifyPackagingSpec(ps *android.PackagingSpec) {
+ // Sometimes, android.modulePartition() returns a path with >1 path components.
+ // This makes the partition field of packagingSpecs have multiple components, like
+ // "system/product". Right now, the filesystem module doesn't look at the partition field
+ // when deciding what path to install the file under, only the RelPathInPackage field, so
+ // we move the later path components from partition to relPathInPackage. This should probably
+ // be revisited in the future.
+ prefix := f.PartitionType() + "/"
+ if strings.HasPrefix(ps.Partition(), prefix) {
+ subPartition := strings.TrimPrefix(ps.Partition(), prefix)
+ ps.SetPartition(f.PartitionType())
+ ps.SetRelPathInPackage(filepath.Join(subPartition, ps.RelPathInPackage()))
+ }
}
var pctx = android.NewPackageContext("android/soong/filesystem")
func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) {
validatePartitionType(ctx, f)
+ if f.filesystemBuilder.ShouldUseVintfFragmentModuleOnly() {
+ f.validateVintfFragments(ctx)
+ }
+
+ if len(f.properties.Include_files_of) > 0 && !android.InList(f.fsType(ctx), []fsType{compressedCpioType, cpioType}) {
+ ctx.PropertyErrorf("include_files_of", "include_files_of is only supported for cpio and compressed cpio filesystem types.")
+ }
+
+ rootDir := android.PathForModuleOut(ctx, f.rootDirString()).OutputPath
+ rebasedDir := rootDir
+ if f.properties.Base_dir != nil {
+ rebasedDir = rootDir.Join(ctx, *f.properties.Base_dir)
+ }
+ builder := android.NewRuleBuilder(pctx, ctx)
+
+ // Wipe the root dir to get rid of leftover files from prior builds
+ builder.Command().Textf("rm -rf %s && mkdir -p %s", rootDir, rootDir)
+ specs := f.gatherFilteredPackagingSpecs(ctx)
+
+ var fullInstallPaths []FullInstallPathInfo
+ for _, spec := range specs {
+ fullInstallPaths = append(fullInstallPaths, FullInstallPathInfo{
+ FullInstallPath: spec.FullInstallPath(),
+ RequiresFullInstall: spec.RequiresFullInstall(),
+ SourcePath: spec.SrcPath(),
+ SymlinkTarget: spec.ToGob().SymlinkTarget,
+ })
+ }
+
+ f.entries = f.copyPackagingSpecs(ctx, builder, specs, rootDir, rebasedDir)
+ f.buildNonDepsFiles(ctx, builder, rootDir, rebasedDir, &fullInstallPaths)
+ f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir, &fullInstallPaths)
+ f.buildEventLogtagsFile(ctx, builder, rebasedDir, &fullInstallPaths)
+ f.buildAconfigFlagsFiles(ctx, builder, specs, rebasedDir, &fullInstallPaths)
+ f.filesystemBuilder.BuildLinkerConfigFile(ctx, builder, rebasedDir, &fullInstallPaths)
+
+ var mapFile android.Path
+ var outputHermetic android.Path
+ var buildImagePropFile android.Path
+ var buildImagePropFileDeps android.Paths
switch f.fsType(ctx) {
- case ext4Type:
- f.output = f.buildImageUsingBuildImage(ctx)
+ case ext4Type, erofsType, f2fsType:
+ f.output, outputHermetic, buildImagePropFile, buildImagePropFileDeps = f.buildImageUsingBuildImage(ctx, builder, rootDir, rebasedDir)
+ mapFile = f.getMapFile(ctx)
case compressedCpioType:
- f.output = f.buildCpioImage(ctx, true)
+ f.output = f.buildCpioImage(ctx, builder, rootDir, true)
case cpioType:
- f.output = f.buildCpioImage(ctx, false)
+ f.output = f.buildCpioImage(ctx, builder, rootDir, false)
default:
return
}
@@ -225,12 +558,107 @@
ctx.InstallFile(f.installDir, f.installFileName(), f.output)
ctx.SetOutputFiles([]android.Path{f.output}, "")
- f.fileListFile = android.PathForModuleOut(ctx, "fileList").OutputPath
- android.WriteFileRule(ctx, f.fileListFile, f.installedFilesList())
+ if f.partitionName() == "recovery" {
+ rootDir = rootDir.Join(ctx, "root")
+ }
+
+ fileListFile := android.PathForModuleOut(ctx, "fileList")
+ android.WriteFileRule(ctx, fileListFile, f.installedFilesList())
+
+ fsInfo := FilesystemInfo{
+ Output: f.output,
+ OutputHermetic: outputHermetic,
+ FileListFile: fileListFile,
+ RootDir: rootDir,
+ RebasedDir: rebasedDir,
+ MapFile: mapFile,
+ ModuleName: ctx.ModuleName(),
+ BuildImagePropFile: buildImagePropFile,
+ BuildImagePropFileDeps: buildImagePropFileDeps,
+ SpecsForSystemOther: f.systemOtherFiles(ctx),
+ FullInstallPaths: fullInstallPaths,
+ }
+
+ android.SetProvider(ctx, FilesystemProvider, fsInfo)
+
+ f.fileListFile = fileListFile
+
+ if proptools.Bool(f.properties.Unchecked_module) {
+ ctx.UncheckedModule()
+ }
+
+ f.setVbmetaPartitionProvider(ctx)
}
-func (f *filesystem) appendToEntry(ctx android.ModuleContext, installedFile android.OutputPath) {
- partitionBaseDir := android.PathForModuleOut(ctx, "root", f.partitionName()).String() + "/"
+func (f *filesystem) setVbmetaPartitionProvider(ctx android.ModuleContext) {
+ var extractedPublicKey android.ModuleOutPath
+ if f.properties.Avb_private_key != nil {
+ key := android.PathForModuleSrc(ctx, proptools.String(f.properties.Avb_private_key))
+ extractedPublicKey = android.PathForModuleOut(ctx, f.partitionName()+".avbpubkey")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: extractPublicKeyRule,
+ Input: key,
+ Output: extractedPublicKey,
+ })
+ }
+
+ var ril int
+ if f.properties.Rollback_index_location != nil {
+ ril = proptools.Int(f.properties.Rollback_index_location)
+ }
+
+ android.SetProvider(ctx, vbmetaPartitionProvider, vbmetaPartitionInfo{
+ Name: f.partitionName(),
+ RollbackIndexLocation: ril,
+ PublicKey: extractedPublicKey,
+ Output: f.output,
+ })
+}
+
+func (f *filesystem) getMapFile(ctx android.ModuleContext) android.WritablePath {
+ // create the filepath by replacing the extension of the corresponding img file
+ return android.PathForModuleOut(ctx, f.installFileName()).ReplaceExtension(ctx, "map")
+}
+
+func (f *filesystem) validateVintfFragments(ctx android.ModuleContext) {
+ visitedModule := map[string]bool{}
+ packagingSpecs := f.gatherFilteredPackagingSpecs(ctx)
+
+ moduleInFileSystem := func(mod android.Module) bool {
+ for _, ps := range android.OtherModuleProviderOrDefault(
+ ctx, mod, android.InstallFilesProvider).PackagingSpecs {
+ if _, ok := packagingSpecs[ps.RelPathInPackage()]; ok {
+ return true
+ }
+ }
+ return false
+ }
+
+ ctx.WalkDeps(func(child, parent android.Module) bool {
+ if visitedModule[child.Name()] {
+ return false
+ }
+ if !moduleInFileSystem(child) {
+ visitedModule[child.Name()] = true
+ return true
+ }
+ if vintfFragments := child.VintfFragments(ctx); vintfFragments != nil {
+ ctx.PropertyErrorf(
+ "vintf_fragments",
+ "Module %s is referenced by soong-defined filesystem %s with property vintf_fragments(%s) in use."+
+ " Use vintf_fragment_modules property instead.",
+ child.Name(),
+ f.BaseModuleName(),
+ strings.Join(vintfFragments, ", "),
+ )
+ }
+ visitedModule[child.Name()] = true
+ return true
+ })
+}
+
+func (f *filesystem) appendToEntry(ctx android.ModuleContext, installedFile android.Path) {
+ partitionBaseDir := android.PathForModuleOut(ctx, f.rootDirString(), proptools.String(f.properties.Base_dir)).String() + "/"
relPath, inTargetPartition := strings.CutPrefix(installedFile.String(), partitionBaseDir)
if inTargetPartition {
@@ -250,12 +678,12 @@
ctx.PropertyErrorf("partition_type", "partition_type must be one of %s, found: %s", validPartitions, p.PartitionType())
}
- ctx.VisitDirectDepsWithTag(android.DefaultsDepTag, func(m android.Module) {
- if fdm, ok := m.(*filesystemDefaults); ok {
- if p.PartitionType() != fdm.PartitionType() {
+ ctx.VisitDirectDepsProxyWithTag(android.DefaultsDepTag, func(m android.ModuleProxy) {
+ if fdm, ok := android.OtherModuleProvider(ctx, m, FilesystemDefaultsInfoProvider); ok {
+ if p.PartitionType() != fdm.PartitionType {
ctx.PropertyErrorf("partition_type",
"%s doesn't match with the partition type %s of the filesystem default module %s",
- p.PartitionType(), fdm.PartitionType(), m.Name())
+ p.PartitionType(), fdm.PartitionType, m.Name())
}
}
})
@@ -263,11 +691,36 @@
// Copy extra files/dirs that are not from the `deps` property to `rootDir`, checking for conflicts with files
// already in `rootDir`.
-func (f *filesystem) buildNonDepsFiles(ctx android.ModuleContext, builder *android.RuleBuilder, rootDir android.OutputPath) {
+func (f *filesystem) buildNonDepsFiles(
+ ctx android.ModuleContext,
+ builder *android.RuleBuilder,
+ rootDir android.OutputPath,
+ rebasedDir android.OutputPath,
+ fullInstallPaths *[]FullInstallPathInfo,
+) {
+ rebasedPrefix, err := filepath.Rel(rootDir.String(), rebasedDir.String())
+ if err != nil || strings.HasPrefix(rebasedPrefix, "../") {
+ panic("rebasedDir could not be made relative to rootDir")
+ }
+ if !strings.HasSuffix(rebasedPrefix, "/") {
+ rebasedPrefix += "/"
+ }
+ if rebasedPrefix == "./" {
+ rebasedPrefix = ""
+ }
+
// create dirs and symlinks
for _, dir := range f.properties.Dirs.GetOrDefault(ctx, nil) {
// OutputPath.Join verifies dir
builder.Command().Text("mkdir -p").Text(rootDir.Join(ctx, dir).String())
+ // Only add the fullInstallPath logic for files in the rebased dir. The root dir
+ // is harder to install to.
+ if strings.HasPrefix(dir, rebasedPrefix) {
+ *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
+ FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), strings.TrimPrefix(dir, rebasedPrefix)),
+ IsDir: true,
+ })
+ }
}
for _, symlink := range f.properties.Symlinks {
@@ -290,25 +743,20 @@
builder.Command().Text("mkdir -p").Text(filepath.Dir(dst.String()))
builder.Command().Text("ln -sf").Text(proptools.ShellEscape(target)).Text(dst.String())
f.appendToEntry(ctx, dst)
+ // Only add the fullInstallPath logic for files in the rebased dir. The root dir
+ // is harder to install to.
+ if strings.HasPrefix(name, rebasedPrefix) {
+ *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
+ FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), strings.TrimPrefix(name, rebasedPrefix)),
+ SymlinkTarget: target,
+ })
+ }
}
- // create extra files if there's any
- if f.buildExtraFiles != nil {
- rootForExtraFiles := android.PathForModuleGen(ctx, "root-extra").OutputPath
- extraFiles := f.buildExtraFiles(ctx, rootForExtraFiles)
- for _, extraFile := range extraFiles {
- rel, err := filepath.Rel(rootForExtraFiles.String(), extraFile.String())
- if err != nil || strings.HasPrefix(rel, "..") {
- ctx.ModuleErrorf("can't make %q relative to %q", extraFile, rootForExtraFiles)
- }
- f.appendToEntry(ctx, rootDir.Join(ctx, rel))
- }
- if len(extraFiles) > 0 {
- builder.Command().BuiltTool("merge_directories").
- Implicits(extraFiles.Paths()).
- Text(rootDir.String()).
- Text(rootForExtraFiles.String())
- }
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=2835;drc=b186569ef00ff2f2a1fab28aedc75ebc32bcd67b
+ if f.partitionName() == "recovery" {
+ builder.Command().Text("mkdir -p").Text(rootDir.Join(ctx, "root/linkerconfig").String())
+ builder.Command().Text("touch").Text(rootDir.Join(ctx, "root/linkerconfig/ld.config.txt").String())
}
}
@@ -331,24 +779,16 @@
return f.CopySpecsToDirs(ctx, builder, dirsToSpecs)
}
-func (f *filesystem) buildImageUsingBuildImage(ctx android.ModuleContext) android.OutputPath {
- rootDir := android.PathForModuleOut(ctx, "root").OutputPath
- rebasedDir := rootDir
- if f.properties.Base_dir != nil {
- rebasedDir = rootDir.Join(ctx, *f.properties.Base_dir)
- }
- builder := android.NewRuleBuilder(pctx, ctx)
- // Wipe the root dir to get rid of leftover files from prior builds
- builder.Command().Textf("rm -rf %s && mkdir -p %s", rootDir, rootDir)
- specs := f.gatherFilteredPackagingSpecs(ctx)
- f.entries = f.copyPackagingSpecs(ctx, builder, specs, rootDir, rebasedDir)
+func (f *filesystem) rootDirString() string {
+ return f.partitionName()
+}
- f.buildNonDepsFiles(ctx, builder, rootDir)
- f.addMakeBuiltFiles(ctx, builder, rootDir)
- f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir)
- f.buildEventLogtagsFile(ctx, builder, rebasedDir)
- f.buildAconfigFlagsFiles(ctx, builder, specs, rebasedDir)
-
+func (f *filesystem) buildImageUsingBuildImage(
+ ctx android.ModuleContext,
+ builder *android.RuleBuilder,
+ rootDir android.OutputPath,
+ rebasedDir android.OutputPath,
+) (android.Path, android.Path, android.Path, android.Paths) {
// run host_init_verifier
// Ideally we should have a concept of pluggable linters that verify the generated image.
// While such concept is not implement this will do.
@@ -358,43 +798,68 @@
FlagWithArg("--out_system=", rootDir.String()+"/system")
propFile, toolDeps := f.buildPropFile(ctx)
- output := android.PathForModuleOut(ctx, f.installFileName()).OutputPath
- builder.Command().BuiltTool("build_image").
+
+ // Most of the time, if build_image were to call a host tool, it accepts the path to the
+ // host tool in a field in the prop file. However, it doesn't have that option for fec, which
+ // it expects to just be on the PATH. Add fec to the PATH.
+ fec := ctx.Config().HostToolPath(ctx, "fec")
+ pathToolDirs := []string{filepath.Dir(fec.String())}
+
+ output := android.PathForModuleOut(ctx, f.installFileName())
+ builder.Command().Text("touch").Output(f.getMapFile(ctx))
+ builder.Command().
+ Textf("PATH=%s:$PATH", strings.Join(pathToolDirs, ":")).
+ BuiltTool("build_image").
Text(rootDir.String()). // input directory
Input(propFile).
Implicits(toolDeps).
+ Implicit(fec).
Output(output).
Text(rootDir.String()) // directory where to find fs_config_files|dirs
+ // TODO (b/393203512): Re-enable hermetic img file creation for target_files.zip
+ // Add an additional cmd to create a hermetic img file. This will contain pinned timestamps e.g.
+ //propFilePinnedTimestamp := android.PathForModuleOut(ctx, "for_target_files", "prop")
+ //builder.Command().Textf("cat").Input(propFile).Flag(">").Output(propFilePinnedTimestamp).
+ // Textf(" && echo use_fixed_timestamp=true >> %s", propFilePinnedTimestamp).
+ // Textf(" && echo block_list=%s >> %s", f.getMapFile(ctx).String(), propFilePinnedTimestamp) // mapfile will be an implicit output
+
+ //outputHermetic := android.PathForModuleOut(ctx, "for_target_files", f.installFileName())
+ //builder.Command().
+ // Textf("PATH=%s:$PATH", strings.Join(pathToolDirs, ":")).
+ // BuiltTool("build_image").
+ // Text(rootDir.String()). // input directory
+ // Flag(propFilePinnedTimestamp.String()).
+ // Implicits(toolDeps).
+ // Implicit(fec).
+ // Output(outputHermetic).
+ // Text(rootDir.String()) // directory where to find fs_config_files|dirs
+
+ if f.properties.Partition_size != nil {
+ assertMaxImageSize(builder, output, *f.properties.Partition_size, false)
+ }
+
// rootDir is not deleted. Might be useful for quick inspection.
builder.Build("build_filesystem_image", fmt.Sprintf("Creating filesystem %s", f.BaseModuleName()))
- return output
+ return output, nil, propFile, toolDeps
}
-func (f *filesystem) buildFileContexts(ctx android.ModuleContext) android.OutputPath {
+func (f *filesystem) buildFileContexts(ctx android.ModuleContext) android.Path {
builder := android.NewRuleBuilder(pctx, ctx)
fcBin := android.PathForModuleOut(ctx, "file_contexts.bin")
builder.Command().BuiltTool("sefcontext_compile").
FlagWithOutput("-o ", fcBin).
Input(android.PathForModuleSrc(ctx, proptools.String(f.properties.File_contexts)))
builder.Build("build_filesystem_file_contexts", fmt.Sprintf("Creating filesystem file contexts for %s", f.BaseModuleName()))
- return fcBin.OutputPath
+ return fcBin
}
-// Calculates avb_salt from entry list (sorted) for deterministic output.
-func (f *filesystem) salt() string {
- return sha1sum(f.entries)
-}
-
-func (f *filesystem) buildPropFile(ctx android.ModuleContext) (propFile android.OutputPath, toolDeps android.Paths) {
+func (f *filesystem) buildPropFile(ctx android.ModuleContext) (android.Path, android.Paths) {
var deps android.Paths
- var propFileString strings.Builder
+ var lines []string
addStr := func(name string, value string) {
- propFileString.WriteString(name)
- propFileString.WriteRune('=')
- propFileString.WriteString(value)
- propFileString.WriteRune('\n')
+ lines = append(lines, fmt.Sprintf("%s=%s", name, value))
}
addPath := func(name string, path android.Path) {
addStr(name, path.String())
@@ -404,9 +869,13 @@
// Type string that build_image.py accepts.
fsTypeStr := func(t fsType) string {
switch t {
- // TODO(jiyong): add more types like f2fs, erofs, etc.
+ // TODO(372522486): add more types like f2fs, erofs, etc.
case ext4Type:
return "ext4"
+ case erofsType:
+ return "erofs"
+ case f2fsType:
+ return "f2fs"
}
panic(fmt.Errorf("unsupported fs type %v", t))
}
@@ -425,10 +894,15 @@
addPath("avb_avbtool", ctx.Config().HostToolPath(ctx, "avbtool"))
algorithm := proptools.StringDefault(f.properties.Avb_algorithm, "SHA256_RSA4096")
addStr("avb_algorithm", algorithm)
- key := android.PathForModuleSrc(ctx, proptools.String(f.properties.Avb_private_key))
- addPath("avb_key_path", key)
+ if f.properties.Avb_private_key != nil {
+ key := android.PathForModuleSrc(ctx, *f.properties.Avb_private_key)
+ addPath("avb_key_path", key)
+ }
addStr("partition_name", f.partitionName())
- avb_add_hashtree_footer_args := "--do_not_generate_fec"
+ avb_add_hashtree_footer_args := ""
+ if !proptools.BoolDefault(f.properties.Use_fec, true) {
+ avb_add_hashtree_footer_args += " --do_not_generate_fec"
+ }
if hashAlgorithm := proptools.String(f.properties.Avb_hash_algorithm); hashAlgorithm != "" {
avb_add_hashtree_footer_args += " --hash_algorithm " + hashAlgorithm
}
@@ -439,29 +913,133 @@
}
avb_add_hashtree_footer_args += " --rollback_index " + strconv.Itoa(rollbackIndex)
}
- securityPatchKey := "com.android.build." + f.partitionName() + ".security_patch"
- securityPatchValue := ctx.Config().PlatformSecurityPatch()
- avb_add_hashtree_footer_args += " --prop " + securityPatchKey + ":" + securityPatchValue
+ avb_add_hashtree_footer_args += fmt.Sprintf(" --prop com.android.build.%s.os_version:%s", f.partitionName(), ctx.Config().PlatformVersionLastStable())
+ // We're not going to add BuildFingerPrintFile as a dep. If it changed, it's likely because
+ // the build number changed, and we don't want to trigger rebuilds solely based on the build
+ // number.
+ avb_add_hashtree_footer_args += fmt.Sprintf(" --prop com.android.build.%s.fingerprint:{CONTENTS_OF:%s}", f.partitionName(), ctx.Config().BuildFingerprintFile(ctx))
+ if f.properties.Security_patch != nil && proptools.String(f.properties.Security_patch) != "" {
+ avb_add_hashtree_footer_args += fmt.Sprintf(" --prop com.android.build.%s.security_patch:%s", f.partitionName(), proptools.String(f.properties.Security_patch))
+ }
addStr("avb_add_hashtree_footer_args", avb_add_hashtree_footer_args)
- addStr("avb_salt", f.salt())
}
- if proptools.String(f.properties.File_contexts) != "" {
+ if f.properties.File_contexts != nil && f.properties.Precompiled_file_contexts != nil {
+ ctx.ModuleErrorf("file_contexts and precompiled_file_contexts cannot both be set")
+ } else if f.properties.File_contexts != nil {
addPath("selinux_fc", f.buildFileContexts(ctx))
+ } else if f.properties.Precompiled_file_contexts != nil {
+ src := android.PathForModuleSrc(ctx, *f.properties.Precompiled_file_contexts)
+ if src != nil {
+ addPath("selinux_fc", src)
+ }
}
if timestamp := proptools.String(f.properties.Fake_timestamp); timestamp != "" {
addStr("timestamp", timestamp)
+ } else if ctx.Config().Getenv("USE_FIXED_TIMESTAMP_IMG_FILES") == "true" {
+ addStr("use_fixed_timestamp", "true")
}
+
if uuid := proptools.String(f.properties.Uuid); uuid != "" {
addStr("uuid", uuid)
addStr("hash_seed", uuid)
}
- propFile = android.PathForModuleOut(ctx, "prop").OutputPath
- android.WriteFileRuleVerbatim(ctx, propFile, propFileString.String())
+
+ // Disable sparse only when partition size is not defined. disable_sparse has the same
+ // effect as <partition name>_disable_sparse.
+ if f.properties.Partition_size == nil {
+ addStr("disable_sparse", "true")
+ }
+
+ fst := f.fsType(ctx)
+ switch fst {
+ case erofsType:
+ // Add erofs properties
+ addStr("erofs_default_compressor", proptools.StringDefault(f.properties.Erofs.Compressor, "lz4hc,9"))
+ if f.properties.Erofs.Compress_hints != nil {
+ src := android.PathForModuleSrc(ctx, *f.properties.Erofs.Compress_hints)
+ addPath("erofs_default_compress_hints", src)
+ }
+ if proptools.BoolDefault(f.properties.Erofs.Sparse, true) {
+ // https://source.corp.google.com/h/googleplex-android/platform/build/+/88b1c67239ca545b11580237242774b411f2fed9:core/Makefile;l=2292;bpv=1;bpt=0;drc=ea8f34bc1d6e63656b4ec32f2391e9d54b3ebb6b
+ addStr("erofs_sparse_flag", "-s")
+ }
+ case f2fsType:
+ if proptools.BoolDefault(f.properties.F2fs.Sparse, true) {
+ // https://source.corp.google.com/h/googleplex-android/platform/build/+/88b1c67239ca545b11580237242774b411f2fed9:core/Makefile;l=2294;drc=ea8f34bc1d6e63656b4ec32f2391e9d54b3ebb6b;bpv=1;bpt=0
+ addStr("f2fs_sparse_flag", "-S")
+ }
+ }
+ f.checkFsTypePropertyError(ctx, fst, fsTypeStr(fst))
+
+ if f.properties.Partition_size != nil {
+ addStr("partition_size", strconv.FormatInt(*f.properties.Partition_size, 10))
+ }
+
+ if proptools.BoolDefault(f.properties.Support_casefolding, false) {
+ addStr("needs_casefold", "1")
+ }
+
+ if proptools.BoolDefault(f.properties.Support_project_quota, false) {
+ addStr("needs_projid", "1")
+ }
+
+ if proptools.BoolDefault(f.properties.Enable_compression, false) {
+ addStr("needs_compress", "1")
+ }
+
+ sort.Strings(lines)
+
+ propFilePreProcessing := android.PathForModuleOut(ctx, "prop_pre_processing")
+ android.WriteFileRule(ctx, propFilePreProcessing, strings.Join(lines, "\n"))
+ propFile := android.PathForModuleOut(ctx, "prop")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: textFileProcessorRule,
+ Input: propFilePreProcessing,
+ Output: propFile,
+ })
return propFile, deps
}
-func (f *filesystem) buildCpioImage(ctx android.ModuleContext, compressed bool) android.OutputPath {
+// This method checks if there is any property set for the fstype(s) other than
+// the current fstype.
+func (f *filesystem) checkFsTypePropertyError(ctx android.ModuleContext, t fsType, fs string) {
+ raiseError := func(otherFsType, currentFsType string) {
+ errMsg := fmt.Sprintf("%s is non-empty, but FS type is %s\n. Please delete %s properties if this partition should use %s\n", otherFsType, currentFsType, otherFsType, currentFsType)
+ ctx.PropertyErrorf(otherFsType, errMsg)
+ }
+
+ if t != erofsType {
+ if f.properties.Erofs.Compressor != nil || f.properties.Erofs.Compress_hints != nil || f.properties.Erofs.Sparse != nil {
+ raiseError("erofs", fs)
+ }
+ }
+ if t != f2fsType {
+ if f.properties.F2fs.Sparse != nil {
+ raiseError("f2fs", fs)
+ }
+ }
+}
+
+func includeFilesRootDir(ctx android.ModuleContext) (rootDirs android.Paths, partitions android.Paths) {
+ ctx.VisitDirectDepsWithTag(interPartitionInstallDependencyTag, func(m android.Module) {
+ if fsProvider, ok := android.OtherModuleProvider(ctx, m, FilesystemProvider); ok {
+ rootDirs = append(rootDirs, fsProvider.RootDir)
+ partitions = append(partitions, fsProvider.Output)
+ } else {
+ ctx.PropertyErrorf("include_files_of", "only filesystem modules can be listed in "+
+ "include_files_of but %s is not a filesystem module", m.Name())
+ }
+ })
+ return rootDirs, partitions
+}
+
+func (f *filesystem) buildCpioImage(
+ ctx android.ModuleContext,
+ builder *android.RuleBuilder,
+ rootDir android.OutputPath,
+ compressed bool,
+) android.Path {
if proptools.Bool(f.properties.Use_avb) {
ctx.PropertyErrorf("use_avb", "signing compresed cpio image using avbtool is not supported."+
"Consider adding this to bootimg module and signing the entire boot image.")
@@ -471,30 +1049,21 @@
ctx.PropertyErrorf("file_contexts", "file_contexts is not supported for compressed cpio image.")
}
- if f.properties.Include_make_built_files != "" {
- ctx.PropertyErrorf("include_make_built_files", "include_make_built_files is not supported for compressed cpio image.")
- }
+ rootDirs, partitions := includeFilesRootDir(ctx)
- rootDir := android.PathForModuleOut(ctx, "root").OutputPath
- rebasedDir := rootDir
- if f.properties.Base_dir != nil {
- rebasedDir = rootDir.Join(ctx, *f.properties.Base_dir)
- }
- builder := android.NewRuleBuilder(pctx, ctx)
- // Wipe the root dir to get rid of leftover files from prior builds
- builder.Command().Textf("rm -rf %s && mkdir -p %s", rootDir, rootDir)
- specs := f.gatherFilteredPackagingSpecs(ctx)
- f.entries = f.copyPackagingSpecs(ctx, builder, specs, rootDir, rebasedDir)
-
- f.buildNonDepsFiles(ctx, builder, rootDir)
- f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir)
- f.buildEventLogtagsFile(ctx, builder, rebasedDir)
- f.buildAconfigFlagsFiles(ctx, builder, specs, rebasedDir)
-
- output := android.PathForModuleOut(ctx, f.installFileName()).OutputPath
+ output := android.PathForModuleOut(ctx, f.installFileName())
cmd := builder.Command().
BuiltTool("mkbootfs").
Text(rootDir.String()) // input directory
+
+ for i := range len(rootDirs) {
+ cmd.Text(rootDirs[i].String())
+ }
+ cmd.Implicits(partitions)
+
+ if nodeList := f.properties.Dev_nodes_description_file; nodeList != nil {
+ cmd.FlagWithInput("-n ", android.PathForModuleSrc(ctx, proptools.String(nodeList)))
+ }
if compressed {
cmd.Text("|").
BuiltTool("lz4").
@@ -524,62 +1093,62 @@
"vendor_dlkm",
"odm_dlkm",
"system_dlkm",
+ "ramdisk",
+ "vendor_ramdisk",
+ "recovery",
}
-func (f *filesystem) addMakeBuiltFiles(ctx android.ModuleContext, builder *android.RuleBuilder, rootDir android.Path) {
- partition := f.properties.Include_make_built_files
- if partition == "" {
- return
- }
- if !slices.Contains(validPartitions, partition) {
- ctx.PropertyErrorf("include_make_built_files", "Expected one of %#v, found %q", validPartitions, partition)
- return
- }
- stampFile := fmt.Sprintf("target/product/%s/obj/PACKAGING/%s_intermediates/staging_dir.stamp", ctx.Config().DeviceName(), partition)
- fileListFile := fmt.Sprintf("target/product/%s/obj/PACKAGING/%s_intermediates/file_list.txt", ctx.Config().DeviceName(), partition)
- stagingDir := fmt.Sprintf("target/product/%s/%s", ctx.Config().DeviceName(), partition)
-
- builder.Command().BuiltTool("merge_directories").
- Implicit(android.PathForArbitraryOutput(ctx, stampFile)).
- Text("--ignore-duplicates").
- FlagWithInput("--file-list", android.PathForArbitraryOutput(ctx, fileListFile)).
- Text(rootDir.String()).
- Text(android.PathForArbitraryOutput(ctx, stagingDir).String())
-}
-
-func (f *filesystem) buildEventLogtagsFile(ctx android.ModuleContext, builder *android.RuleBuilder, rebasedDir android.OutputPath) {
+func (f *filesystem) buildEventLogtagsFile(
+ ctx android.ModuleContext,
+ builder *android.RuleBuilder,
+ rebasedDir android.OutputPath,
+ fullInstallPaths *[]FullInstallPathInfo,
+) {
if !proptools.Bool(f.properties.Build_logtags) {
return
}
- logtagsFilePaths := make(map[string]bool)
- ctx.WalkDeps(func(child, parent android.Module) bool {
- if logtagsInfo, ok := android.OtherModuleProvider(ctx, child, android.LogtagsProviderKey); ok {
- for _, path := range logtagsInfo.Logtags {
- logtagsFilePaths[path.String()] = true
- }
- }
- return true
- })
-
- if len(logtagsFilePaths) == 0 {
- return
- }
-
etcPath := rebasedDir.Join(ctx, "etc")
eventLogtagsPath := etcPath.Join(ctx, "event-log-tags")
builder.Command().Text("mkdir").Flag("-p").Text(etcPath.String())
- cmd := builder.Command().BuiltTool("merge-event-log-tags").
- FlagWithArg("-o ", eventLogtagsPath.String()).
- FlagWithInput("-m ", android.MergedLogtagsPath(ctx))
+ builder.Command().Text("cp").Input(android.MergedLogtagsPath(ctx)).Text(eventLogtagsPath.String())
- for _, path := range android.SortedKeys(logtagsFilePaths) {
- cmd.Text(path)
- }
+ *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
+ FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), "etc", "event-log-tags"),
+ SourcePath: android.MergedLogtagsPath(ctx),
+ })
f.appendToEntry(ctx, eventLogtagsPath)
}
+func (f *filesystem) BuildLinkerConfigFile(
+ ctx android.ModuleContext,
+ builder *android.RuleBuilder,
+ rebasedDir android.OutputPath,
+ fullInstallPaths *[]FullInstallPathInfo,
+) {
+ if !proptools.Bool(f.properties.Linker_config.Gen_linker_config) {
+ return
+ }
+
+ provideModules, _ := f.getLibsForLinkerConfig(ctx)
+ intermediateOutput := android.PathForModuleOut(ctx, "linker.config.pb")
+ linkerconfig.BuildLinkerConfig(ctx, android.PathsForModuleSrc(ctx, f.properties.Linker_config.Linker_config_srcs), provideModules, nil, intermediateOutput)
+ output := rebasedDir.Join(ctx, "etc", "linker.config.pb")
+ builder.Command().Text("cp").Input(intermediateOutput).Output(output)
+
+ *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
+ FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), "etc", "linker.config.pb"),
+ SourcePath: intermediateOutput,
+ })
+
+ f.appendToEntry(ctx, output)
+}
+
+func (f *filesystem) ShouldUseVintfFragmentModuleOnly() bool {
+ return false
+}
+
type partition interface {
PartitionType() string
}
@@ -635,8 +1204,21 @@
// Note that "apex" module installs its contents to "apex"(fake partition) as well
// for symbol lookup by imitating "activated" paths.
func (f *filesystem) gatherFilteredPackagingSpecs(ctx android.ModuleContext) map[string]android.PackagingSpec {
- specs := f.PackagingBase.GatherPackagingSpecsWithFilter(ctx, f.filterPackagingSpec)
- return specs
+ return f.PackagingBase.GatherPackagingSpecsWithFilterAndModifier(ctx, f.filesystemBuilder.FilterPackagingSpec, f.filesystemBuilder.ModifyPackagingSpec)
+}
+
+// Dexpreopt files are installed to system_other. Collect the packaingSpecs for the dexpreopt files
+// from this partition to export to the system_other partition later.
+func (f *filesystem) systemOtherFiles(ctx android.ModuleContext) map[string]android.PackagingSpec {
+ filter := func(spec android.PackagingSpec) bool {
+ // For some reason system_other packaging specs don't set the partition field.
+ return strings.HasPrefix(spec.RelPathInPackage(), "system_other/")
+ }
+ modifier := func(spec *android.PackagingSpec) {
+ spec.SetRelPathInPackage(strings.TrimPrefix(spec.RelPathInPackage(), "system_other/"))
+ spec.SetPartition("system_other")
+ }
+ return f.PackagingBase.GatherPackagingSpecsWithFilterAndModifier(ctx, filter, modifier)
}
func sha1sum(values []string) string {
@@ -661,13 +1243,7 @@
android.ModuleBase
android.DefaultsModuleBase
- properties filesystemDefaultsProperties
-}
-
-type filesystemDefaultsProperties struct {
- // Identifies which partition this is for //visibility:any_system_image (and others) visibility
- // checks, and will be used in the future for API surface checks.
- Partition_type *string
+ properties FilesystemProperties
}
// android_filesystem_defaults is a default module for android_filesystem and android_system_image
@@ -687,4 +1263,114 @@
func (f *filesystemDefaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
validatePartitionType(ctx, f)
+ android.SetProvider(ctx, FilesystemDefaultsInfoProvider, FilesystemDefaultsInfo{
+ PartitionType: f.PartitionType(),
+ })
+}
+
+// getLibsForLinkerConfig returns
+// 1. A list of libraries installed in this filesystem
+// 2. A list of dep libraries _not_ installed in this filesystem
+//
+// `linkerconfig.BuildLinkerConfig` will convert these two to a linker.config.pb for the filesystem
+// (1) will be added to --provideLibs if they are C libraries with a stable interface (has stubs)
+// (2) will be added to --requireLibs if they are C libraries with a stable interface (has stubs)
+func (f *filesystem) getLibsForLinkerConfig(ctx android.ModuleContext) ([]android.ModuleProxy, []android.ModuleProxy) {
+ // we need "Module"s for packaging items
+ modulesInPackageByModule := make(map[android.ModuleProxy]bool)
+ modulesInPackageByName := make(map[string]bool)
+
+ deps := f.gatherFilteredPackagingSpecs(ctx)
+ ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool {
+ if !android.OtherModuleProviderOrDefault(ctx, child, android.CommonModuleInfoKey).Enabled {
+ return false
+ }
+ for _, ps := range android.OtherModuleProviderOrDefault(
+ ctx, child, android.InstallFilesProvider).PackagingSpecs {
+ if _, ok := deps[ps.RelPathInPackage()]; ok && ps.Partition() == f.PartitionType() {
+ modulesInPackageByModule[child] = true
+ modulesInPackageByName[child.Name()] = true
+ return true
+ }
+ }
+ return true
+ })
+
+ provideModules := make([]android.ModuleProxy, 0, len(modulesInPackageByModule))
+ for mod := range modulesInPackageByModule {
+ provideModules = append(provideModules, mod)
+ }
+
+ var requireModules []android.ModuleProxy
+ ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool {
+ if !android.OtherModuleProviderOrDefault(ctx, child, android.CommonModuleInfoKey).Enabled {
+ return false
+ }
+ _, parentInPackage := modulesInPackageByModule[parent]
+ _, childInPackageName := modulesInPackageByName[child.Name()]
+
+ // When parent is in the package, and child (or its variant) is not, this can be from an interface.
+ if parentInPackage && !childInPackageName {
+ requireModules = append(requireModules, child)
+ }
+ return true
+ })
+
+ return provideModules, requireModules
+}
+
+// Checks that the given file doesn't exceed the given size, and will also print a warning
+// if it's nearing the maximum size. Equivalent to assert-max-image-size in make:
+// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/definitions.mk;l=3455;drc=993c4de29a02a6accd60ceaaee153307e1a18d10
+func assertMaxImageSize(builder *android.RuleBuilder, image android.Path, maxSize int64, addAvbLater bool) {
+ if addAvbLater {
+ // The value 69632 is derived from MAX_VBMETA_SIZE + MAX_FOOTER_SIZE in avbtool.
+ // Logic copied from make:
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=228;drc=a6a0007ef24e16c0b79f439beac4a118416717e6
+ maxSize -= 69632
+ }
+ cmd := builder.Command()
+ cmd.Textf(`file="%s"; maxsize="%d";`+
+ `total=$(stat -c "%%s" "$file" | tr -d '\n');`+
+ `if [ "$total" -gt "$maxsize" ]; then `+
+ ` echo "error: $file too large ($total > $maxsize)";`+
+ ` false;`+
+ `elif [ "$total" -gt $((maxsize - 32768)) ]; then `+
+ ` echo "WARNING: $file approaching size limit ($total now; limit $maxsize)";`+
+ `fi`,
+ image, maxSize)
+ cmd.Implicit(image)
+}
+
+// addAutogeneratedRroDeps walks the transitive closure of vendor and product partitions.
+// It visits apps installed in system and system_ext partitions, and adds the autogenerated
+// RRO modules to its own deps.
+func addAutogeneratedRroDeps(ctx android.BottomUpMutatorContext) {
+ f, ok := ctx.Module().(*filesystem)
+ if !ok {
+ return
+ }
+ thisPartition := f.PartitionType()
+ if thisPartition != "vendor" && thisPartition != "product" {
+ if f.properties.Android_filesystem_deps.System != nil {
+ ctx.PropertyErrorf("android_filesystem_deps.system", "only vendor or product partitions can use android_filesystem_deps")
+ }
+ if f.properties.Android_filesystem_deps.System_ext != nil {
+ ctx.PropertyErrorf("android_filesystem_deps.system_ext", "only vendor or product partitions can use android_filesystem_deps")
+ }
+ return
+ }
+ ctx.WalkDeps(func(child, parent android.Module) bool {
+ depTag := ctx.OtherModuleDependencyTag(child)
+ if parent.Name() == f.Name() && depTag != interPartitionDependencyTag {
+ return false // This is a module listed in deps of vendor/product filesystem
+ }
+ if vendorOverlay := java.AutogeneratedRroModuleName(ctx, child.Name(), "vendor"); ctx.OtherModuleExists(vendorOverlay) && thisPartition == "vendor" {
+ ctx.AddFarVariationDependencies(nil, dependencyTagWithVisibilityEnforcementBypass, vendorOverlay)
+ }
+ if productOverlay := java.AutogeneratedRroModuleName(ctx, child.Name(), "product"); ctx.OtherModuleExists(productOverlay) && thisPartition == "product" {
+ ctx.AddFarVariationDependencies(nil, dependencyTagWithVisibilityEnforcementBypass, productOverlay)
+ }
+ return true
+ })
}
diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go
index 8c0d111..d9bf242 100644
--- a/filesystem/filesystem_test.go
+++ b/filesystem/filesystem_test.go
@@ -136,31 +136,19 @@
}
}
-func TestIncludeMakeBuiltFiles(t *testing.T) {
- result := fixture.RunTestWithBp(t, `
- android_filesystem {
- name: "myfilesystem",
- include_make_built_files: "system",
- }
- `)
-
- output := result.ModuleForTests("myfilesystem", "android_common").Output("myfilesystem.img")
-
- stampFile := "out/target/product/test_device/obj/PACKAGING/system_intermediates/staging_dir.stamp"
- fileListFile := "out/target/product/test_device/obj/PACKAGING/system_intermediates/file_list.txt"
- android.AssertStringListContains(t, "deps of filesystem must include the staging dir stamp file", output.Implicits.Strings(), stampFile)
- android.AssertStringListContains(t, "deps of filesystem must include the staging dir file list", output.Implicits.Strings(), fileListFile)
-}
-
func TestFileSystemFillsLinkerConfigWithStubLibs(t *testing.T) {
result := fixture.RunTestWithBp(t, `
android_system_image {
name: "myfilesystem",
+ base_dir: "system",
deps: [
"libfoo",
"libbar",
],
- linker_config_src: "linker.config.json",
+ linker_config: {
+ gen_linker_config: true,
+ linker_config_srcs: ["linker.config.json"],
+ },
}
cc_library {
@@ -176,12 +164,14 @@
`)
module := result.ModuleForTests("myfilesystem", "android_common")
- output := module.Output("system/etc/linker.config.pb")
+ output := module.Output("out/soong/.intermediates/myfilesystem/android_common/linker.config.pb")
+
+ linkerConfigCommand := output.RuleParams.Command
android.AssertStringDoesContain(t, "linker.config.pb should have libfoo",
- output.RuleParams.Command, "libfoo.so")
+ linkerConfigCommand, "libfoo.so")
android.AssertStringDoesNotContain(t, "linker.config.pb should not have libbar",
- output.RuleParams.Command, "libbar.so")
+ linkerConfigCommand, "libbar.so")
}
func registerComponent(ctx android.RegistrationContext) {
@@ -223,7 +213,10 @@
deps: ["foo"],
},
},
- linker_config_src: "linker.config.json",
+ linker_config: {
+ gen_linker_config: true,
+ linker_config_srcs: ["linker.config.json"],
+ },
}
component {
name: "foo",
@@ -232,7 +225,7 @@
`)
module := result.ModuleForTests("myfilesystem", "android_common").Module().(*systemImage)
- android.AssertDeepEquals(t, "entries should have foo only", []string{"components/foo"}, module.entries)
+ android.AssertDeepEquals(t, "entries should have foo and not bar", []string{"components/foo", "etc/linker.config.pb"}, module.entries)
}
func TestAvbGenVbmetaImage(t *testing.T) {
@@ -318,7 +311,10 @@
deps: [
"libfoo",
],
- linker_config_src: "linker.config.json",
+ linker_config: {
+ gen_linker_config: true,
+ linker_config_srcs: ["linker.config.json"],
+ },
}
cc_library {
@@ -344,7 +340,7 @@
inputs.Strings(),
"out/soong/.intermediates/libbar/android_arm64_armv8-a_shared_cov/libbar.so")
- filesystemOutput := filesystem.Output("myfilesystem.img").Output
+ filesystemOutput := filesystem.OutputFiles(result.TestContext, t, "")[0]
prebuiltInput := result.ModuleForTests("prebuilt", "android_arm64_armv8-a").Rule("Cp").Input
if filesystemOutput != prebuiltInput {
t.Error("prebuilt should use cov variant of filesystem")
@@ -559,3 +555,217 @@
}
}
}
+
+func TestErofsPartition(t *testing.T) {
+ result := fixture.RunTestWithBp(t, `
+ android_filesystem {
+ name: "erofs_partition",
+ type: "erofs",
+ erofs: {
+ compressor: "lz4hc,9",
+ compress_hints: "compress_hints.txt",
+ },
+ deps: ["binfoo"],
+ }
+
+ cc_binary {
+ name: "binfoo",
+ }
+ `)
+
+ partition := result.ModuleForTests("erofs_partition", "android_common")
+ buildImageConfig := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("prop_pre_processing"))
+ android.AssertStringDoesContain(t, "erofs fs type", buildImageConfig, "fs_type=erofs")
+ android.AssertStringDoesContain(t, "erofs fs type compress algorithm", buildImageConfig, "erofs_default_compressor=lz4hc,9")
+ android.AssertStringDoesContain(t, "erofs fs type compress hint", buildImageConfig, "erofs_default_compress_hints=compress_hints.txt")
+ android.AssertStringDoesContain(t, "erofs fs type sparse", buildImageConfig, "erofs_sparse_flag=-s")
+}
+
+func TestF2fsPartition(t *testing.T) {
+ result := fixture.RunTestWithBp(t, `
+ android_filesystem {
+ name: "f2fs_partition",
+ type: "f2fs",
+ }
+ `)
+
+ partition := result.ModuleForTests("f2fs_partition", "android_common")
+ buildImageConfig := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("prop_pre_processing"))
+ android.AssertStringDoesContain(t, "f2fs fs type", buildImageConfig, "fs_type=f2fs")
+ android.AssertStringDoesContain(t, "f2fs fs type sparse", buildImageConfig, "f2fs_sparse_flag=-S")
+}
+
+func TestFsTypesPropertyError(t *testing.T) {
+ fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(
+ "erofs: erofs is non-empty, but FS type is f2fs\n. Please delete erofs properties if this partition should use f2fs\n")).
+ RunTestWithBp(t, `
+ android_filesystem {
+ name: "f2fs_partition",
+ type: "f2fs",
+ erofs: {
+ compressor: "lz4hc,9",
+ compress_hints: "compress_hints.txt",
+ },
+ }
+ `)
+}
+
+// If a system_ext/ module depends on system/ module, the dependency should *not*
+// be installed in system_ext/
+func TestDoNotPackageCrossPartitionDependencies(t *testing.T) {
+ t.Skip() // TODO (spandandas): Re-enable this
+ result := fixture.RunTestWithBp(t, `
+ android_filesystem {
+ name: "myfilesystem",
+ deps: ["binfoo"],
+ partition_type: "system_ext",
+ }
+
+ cc_binary {
+ name: "binfoo",
+ shared_libs: ["libfoo"],
+ system_ext_specific: true,
+ }
+ cc_library_shared {
+ name: "libfoo", // installed in system/
+ }
+ `)
+
+ partition := result.ModuleForTests("myfilesystem", "android_common")
+ fileList := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("fileList"))
+ android.AssertDeepEquals(t, "filesystem with dependencies on different partition", "bin/binfoo\n", fileList)
+}
+
+// If a cc_library is listed in `deps`, and it has a shared and static variant, then the shared variant
+// should be installed.
+func TestUseSharedVariationOfNativeLib(t *testing.T) {
+ result := fixture.RunTestWithBp(t, `
+ android_filesystem {
+ name: "myfilesystem",
+ deps: ["libfoo"],
+ }
+ // cc_library will create a static and shared variant.
+ cc_library {
+ name: "libfoo",
+ }
+ `)
+
+ partition := result.ModuleForTests("myfilesystem", "android_common")
+ fileList := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("fileList"))
+ android.AssertDeepEquals(t, "cc_library listed in deps",
+ "lib64/bootstrap/libc.so\nlib64/bootstrap/libdl.so\nlib64/bootstrap/libm.so\nlib64/libc++.so\nlib64/libc.so\nlib64/libdl.so\nlib64/libfoo.so\nlib64/libm.so\n",
+ fileList)
+}
+
+// binfoo1 overrides binbar. transitive deps of binbar should not be installed.
+func TestDoNotInstallTransitiveDepOfOverriddenModule(t *testing.T) {
+ result := fixture.RunTestWithBp(t, `
+android_filesystem {
+ name: "myfilesystem",
+ deps: ["binfoo1", "libfoo2", "binbar"],
+}
+cc_binary {
+ name: "binfoo1",
+ shared_libs: ["libfoo"],
+ overrides: ["binbar"],
+}
+cc_library {
+ name: "libfoo",
+}
+cc_library {
+ name: "libfoo2",
+ overrides: ["libfoo"],
+}
+// binbar gets overridden by binfoo1
+// therefore, libbar should not be installed
+cc_binary {
+ name: "binbar",
+ shared_libs: ["libbar"]
+}
+cc_library {
+ name: "libbar",
+}
+ `)
+
+ partition := result.ModuleForTests("myfilesystem", "android_common")
+ fileList := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("fileList"))
+ android.AssertDeepEquals(t, "Shared library dep of overridden binary should not be installed",
+ "bin/binfoo1\nlib64/bootstrap/libc.so\nlib64/bootstrap/libdl.so\nlib64/bootstrap/libm.so\nlib64/libc++.so\nlib64/libc.so\nlib64/libdl.so\nlib64/libfoo2.so\nlib64/libm.so\n",
+ fileList)
+}
+
+func TestInstallLinkerConfigFile(t *testing.T) {
+ result := fixture.RunTestWithBp(t, `
+android_filesystem {
+ name: "myfilesystem",
+ deps: ["libfoo_has_no_stubs", "libfoo_has_stubs"],
+ linker_config: {
+ gen_linker_config: true,
+ linker_config_srcs: ["linker.config.json"],
+ },
+ partition_type: "vendor",
+}
+cc_library {
+ name: "libfoo_has_no_stubs",
+ vendor: true,
+}
+cc_library {
+ name: "libfoo_has_stubs",
+ stubs: {symbol_file: "libfoo.map.txt"},
+ vendor: true,
+}
+ `)
+
+ linkerConfigCmd := result.ModuleForTests("myfilesystem", "android_common").Output("out/soong/.intermediates/myfilesystem/android_common/linker.config.pb").RuleParams.Command
+ android.AssertStringDoesContain(t, "Could not find linker.config.json file in cmd", linkerConfigCmd, "conv_linker_config proto --force -s linker.config.json")
+ android.AssertStringDoesContain(t, "Could not find stub in `provideLibs`", linkerConfigCmd, "--key provideLibs --value libfoo_has_stubs.so")
+}
+
+// override_android_* modules implicitly override their base module.
+// If both of these are listed in `deps`, the base module should not be installed.
+func TestOverrideModulesInDeps(t *testing.T) {
+ result := fixture.RunTestWithBp(t, `
+ android_filesystem {
+ name: "myfilesystem",
+ deps: ["myapp", "myoverrideapp"],
+ }
+
+ android_app {
+ name: "myapp",
+ platform_apis: true,
+ }
+ override_android_app {
+ name: "myoverrideapp",
+ base: "myapp",
+ }
+ `)
+
+ partition := result.ModuleForTests("myfilesystem", "android_common")
+ fileList := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("fileList"))
+ android.AssertStringEquals(t, "filesystem with override app", "app/myoverrideapp/myoverrideapp.apk\n", fileList)
+}
+
+func TestRamdiskPartitionSetsDevNodes(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ fixture,
+ android.FixtureMergeMockFs(android.MockFS{
+ "ramdisk_node_list": nil,
+ }),
+ ).RunTestWithBp(t, `
+ android_filesystem {
+ name: "ramdisk_filesystem",
+ partition_name: "ramdisk",
+ }
+ filegroup {
+ name: "ramdisk_node_list",
+ srcs: ["ramdisk_node_list"],
+ }
+ `)
+
+ android.AssertBoolEquals(
+ t,
+ "Generated ramdisk image expected to depend on \"ramdisk_node_list\" module",
+ true,
+ java.CheckModuleHasDependency(t, result.TestContext, "ramdisk_filesystem", "android_common", "ramdisk_node_list"),
+ )
+}
diff --git a/filesystem/fsverity_metadata.go b/filesystem/fsverity_metadata.go
index d7bb654..a3a2086 100644
--- a/filesystem/fsverity_metadata.go
+++ b/filesystem/fsverity_metadata.go
@@ -15,10 +15,13 @@
package filesystem
import (
+ "fmt"
"path/filepath"
"strings"
"android/soong/android"
+
+ "github.com/google/blueprint/proptools"
)
type fsverityProperties struct {
@@ -26,13 +29,13 @@
// will be generated and included to the filesystem image.
// etc/security/fsverity/BuildManifest.apk will also be generated which contains information
// about generated .fsv_meta files.
- Inputs []string
+ Inputs proptools.Configurable[[]string]
// APK libraries to link against, for etc/security/fsverity/BuildManifest.apk
- Libs []string `android:"path"`
+ Libs proptools.Configurable[[]string] `android:"path"`
}
-func (f *filesystem) writeManifestGeneratorListFile(ctx android.ModuleContext, outputPath android.OutputPath, matchedSpecs []android.PackagingSpec, rebasedDir android.OutputPath) {
+func (f *filesystem) writeManifestGeneratorListFile(ctx android.ModuleContext, outputPath android.WritablePath, matchedSpecs []android.PackagingSpec, rebasedDir android.OutputPath) {
var buf strings.Builder
for _, spec := range matchedSpecs {
buf.WriteString(rebasedDir.Join(ctx, spec.RelPathInPackage()).String())
@@ -41,9 +44,16 @@
android.WriteFileRuleVerbatim(ctx, outputPath, buf.String())
}
-func (f *filesystem) buildFsverityMetadataFiles(ctx android.ModuleContext, builder *android.RuleBuilder, specs map[string]android.PackagingSpec, rootDir android.OutputPath, rebasedDir android.OutputPath) {
+func (f *filesystem) buildFsverityMetadataFiles(
+ ctx android.ModuleContext,
+ builder *android.RuleBuilder,
+ specs map[string]android.PackagingSpec,
+ rootDir android.OutputPath,
+ rebasedDir android.OutputPath,
+ fullInstallPaths *[]FullInstallPathInfo,
+) {
match := func(path string) bool {
- for _, pattern := range f.properties.Fsverity.Inputs {
+ for _, pattern := range f.properties.Fsverity.Inputs.GetOrDefault(ctx, nil) {
if matched, err := filepath.Match(pattern, path); matched {
return true
} else if err != nil {
@@ -65,115 +75,110 @@
return
}
- fsverityBuilderPath := android.PathForModuleOut(ctx, "fsverity_builder.sh")
- metadataGeneratorPath := ctx.Config().HostToolPath(ctx, "fsverity_metadata_generator")
fsverityPath := ctx.Config().HostToolPath(ctx, "fsverity")
- cmd := builder.Command().Tool(fsverityBuilderPath)
-
// STEP 1: generate .fsv_meta
var sb strings.Builder
sb.WriteString("set -e\n")
- cmd.Implicit(metadataGeneratorPath).Implicit(fsverityPath)
for _, spec := range matchedSpecs {
// srcPath is copied by CopySpecsToDir()
srcPath := rebasedDir.Join(ctx, spec.RelPathInPackage())
destPath := rebasedDir.Join(ctx, spec.RelPathInPackage()+".fsv_meta")
- sb.WriteString(metadataGeneratorPath.String())
- sb.WriteString(" --fsverity-path ")
- sb.WriteString(fsverityPath.String())
- sb.WriteString(" --signature none --hash-alg sha256 --output ")
- sb.WriteString(destPath.String())
- sb.WriteRune(' ')
- sb.WriteString(srcPath.String())
- sb.WriteRune('\n')
+ builder.Command().
+ BuiltTool("fsverity_metadata_generator").
+ FlagWithInput("--fsverity-path ", fsverityPath).
+ FlagWithArg("--signature ", "none").
+ FlagWithArg("--hash-alg ", "sha256").
+ FlagWithOutput("--output ", destPath).
+ Text(srcPath.String())
f.appendToEntry(ctx, destPath)
+ *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
+ SourcePath: destPath,
+ FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), spec.RelPathInPackage()+".fsv_meta"),
+ })
+ }
+
+ fsVerityBaseDir := rootDir.String()
+ if f.PartitionType() == "system_ext" {
+ // Use the equivalent of $PRODUCT_OUT as the base dir.
+ // This ensures that the paths in build_manifest.pb contain on-device paths
+ // e.g. system_ext/framework/javalib.jar
+ // and not framework/javalib.jar.
+ //
+ // Although base-dir is outside the rootdir provided for packaging, this action
+ // is hermetic since it uses `manifestGeneratorListPath` to filter the files to be written to build_manifest.pb
+ fsVerityBaseDir = filepath.Dir(rootDir.String())
}
// STEP 2: generate signed BuildManifest.apk
// STEP 2-1: generate build_manifest.pb
+ manifestGeneratorListPath := android.PathForModuleOut(ctx, "fsverity_manifest.list")
+ f.writeManifestGeneratorListFile(ctx, manifestGeneratorListPath, matchedSpecs, rebasedDir)
assetsPath := android.PathForModuleOut(ctx, "fsverity_manifest/assets")
manifestPbPath := assetsPath.Join(ctx, "build_manifest.pb")
- manifestGeneratorPath := ctx.Config().HostToolPath(ctx, "fsverity_manifest_generator")
- cmd.Implicit(manifestGeneratorPath)
- sb.WriteString("rm -rf ")
- sb.WriteString(assetsPath.String())
- sb.WriteString(" && mkdir -p ")
- sb.WriteString(assetsPath.String())
- sb.WriteRune('\n')
- sb.WriteString(manifestGeneratorPath.String())
- sb.WriteString(" --fsverity-path ")
- sb.WriteString(fsverityPath.String())
- sb.WriteString(" --base-dir ")
- sb.WriteString(rootDir.String())
- sb.WriteString(" --output ")
- sb.WriteString(manifestPbPath.String())
- sb.WriteRune(' ')
- f.appendToEntry(ctx, manifestPbPath)
+ builder.Command().Text("rm -rf " + assetsPath.String())
+ builder.Command().Text("mkdir -p " + assetsPath.String())
+ builder.Command().
+ BuiltTool("fsverity_manifest_generator").
+ FlagWithInput("--fsverity-path ", fsverityPath).
+ FlagWithArg("--base-dir ", fsVerityBaseDir).
+ FlagWithArg("--output ", manifestPbPath.String()).
+ FlagWithInput("@", manifestGeneratorListPath)
- manifestGeneratorListPath := android.PathForModuleOut(ctx, "fsverity_manifest.list")
- f.writeManifestGeneratorListFile(ctx, manifestGeneratorListPath.OutputPath, matchedSpecs, rebasedDir)
- sb.WriteRune('@')
- sb.WriteString(manifestGeneratorListPath.String())
- sb.WriteRune('\n')
- cmd.Implicit(manifestGeneratorListPath)
- f.appendToEntry(ctx, manifestGeneratorListPath.OutputPath)
+ f.appendToEntry(ctx, manifestPbPath)
+ f.appendToEntry(ctx, manifestGeneratorListPath)
// STEP 2-2: generate BuildManifest.apk (unsigned)
- aapt2Path := ctx.Config().HostToolPath(ctx, "aapt2")
- apkPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", "BuildManifest.apk")
- idsigPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", "BuildManifest.apk.idsig")
- manifestTemplatePath := android.PathForSource(ctx, "system/security/fsverity/AndroidManifest.xml")
- libs := android.PathsForModuleSrc(ctx, f.properties.Fsverity.Libs)
- cmd.Implicit(aapt2Path)
- cmd.Implicit(manifestTemplatePath)
- cmd.Implicits(libs)
- cmd.ImplicitOutput(apkPath)
-
- sb.WriteString(aapt2Path.String())
- sb.WriteString(" link -o ")
- sb.WriteString(apkPath.String())
- sb.WriteString(" -A ")
- sb.WriteString(assetsPath.String())
- for _, lib := range libs {
- sb.WriteString(" -I ")
- sb.WriteString(lib.String())
+ apkNameSuffix := ""
+ if f.PartitionType() == "system_ext" {
+ //https://source.corp.google.com/h/googleplex-android/platform/build/+/e392d2b486c2d4187b20a72b1c67cc737ecbcca5:core/Makefile;l=3410;drc=ea8f34bc1d6e63656b4ec32f2391e9d54b3ebb6b;bpv=1;bpt=0
+ apkNameSuffix = "SystemExt"
}
+ apkPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", fmt.Sprintf("BuildManifest%s.apk", apkNameSuffix))
+ idsigPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", fmt.Sprintf("BuildManifest%s.apk.idsig", apkNameSuffix))
+ manifestTemplatePath := android.PathForSource(ctx, "system/security/fsverity/AndroidManifest.xml")
+ libs := android.PathsForModuleSrc(ctx, f.properties.Fsverity.Libs.GetOrDefault(ctx, nil))
+
minSdkVersion := ctx.Config().PlatformSdkCodename()
if minSdkVersion == "REL" {
minSdkVersion = ctx.Config().PlatformSdkVersion().String()
}
- sb.WriteString(" --min-sdk-version ")
- sb.WriteString(minSdkVersion)
- sb.WriteString(" --version-code ")
- sb.WriteString(ctx.Config().PlatformSdkVersion().String())
- sb.WriteString(" --version-name ")
- sb.WriteString(ctx.Config().AppsDefaultVersionName())
- sb.WriteString(" --manifest ")
- sb.WriteString(manifestTemplatePath.String())
- sb.WriteString(" --rename-manifest-package com.android.security.fsverity_metadata.")
- sb.WriteString(f.partitionName())
- sb.WriteRune('\n')
+
+ unsignedApkCommand := builder.Command().
+ Textf("mkdir -p %s && ", filepath.Dir(apkPath.String())).
+ BuiltTool("aapt2").
+ Text("link").
+ FlagWithOutput("-o ", apkPath).
+ FlagWithArg("-A ", assetsPath.String())
+ for _, lib := range libs {
+ unsignedApkCommand.FlagWithInput("-I ", lib)
+ }
+ unsignedApkCommand.
+ FlagWithArg("--min-sdk-version ", minSdkVersion).
+ FlagWithArg("--version-code ", ctx.Config().PlatformSdkVersion().String()).
+ FlagWithArg("--version-name ", ctx.Config().AppsDefaultVersionName()).
+ FlagWithInput("--manifest ", manifestTemplatePath).
+ Text(" --rename-manifest-package com.android.security.fsverity_metadata." + f.partitionName())
+ *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
+ SourcePath: apkPath,
+ FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), fmt.Sprintf("etc/security/fsverity/BuildManifest%s.apk", apkNameSuffix)),
+ })
f.appendToEntry(ctx, apkPath)
// STEP 2-3: sign BuildManifest.apk
- apksignerPath := ctx.Config().HostToolPath(ctx, "apksigner")
pemPath, keyPath := ctx.Config().DefaultAppCertificate(ctx)
- cmd.Implicit(apksignerPath)
- cmd.Implicit(pemPath)
- cmd.Implicit(keyPath)
- cmd.ImplicitOutput(idsigPath)
- sb.WriteString(apksignerPath.String())
- sb.WriteString(" sign --in ")
- sb.WriteString(apkPath.String())
- sb.WriteString(" --cert ")
- sb.WriteString(pemPath.String())
- sb.WriteString(" --key ")
- sb.WriteString(keyPath.String())
- sb.WriteRune('\n')
+ builder.Command().
+ BuiltTool("apksigner").
+ Text("sign").
+ FlagWithArg("--in ", apkPath.String()).
+ FlagWithInput("--cert ", pemPath).
+ FlagWithInput("--key ", keyPath).
+ ImplicitOutput(idsigPath)
+ *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
+ SourcePath: idsigPath,
+ FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), fmt.Sprintf("etc/security/fsverity/BuildManifest%s.apk.idsig", apkNameSuffix)),
+ })
f.appendToEntry(ctx, idsigPath)
-
- android.WriteExecutableFileRuleVerbatim(ctx, fsverityBuilderPath, sb.String())
}
diff --git a/filesystem/logical_partition.go b/filesystem/logical_partition.go
index e483fe4..d0888a9 100644
--- a/filesystem/logical_partition.go
+++ b/filesystem/logical_partition.go
@@ -32,7 +32,7 @@
properties logicalPartitionProperties
- output android.OutputPath
+ output android.Path
installDir android.InstallPath
}
@@ -95,11 +95,14 @@
builder := android.NewRuleBuilder(pctx, ctx)
// Sparse the filesystem images and calculate their sizes
- sparseImages := make(map[string]android.OutputPath)
- sparseImageSizes := make(map[string]android.OutputPath)
+ sparseImages := make(map[string]android.Path)
+ sparseImageSizes := make(map[string]android.Path)
sparsePartitions := func(partitions []partitionProperties) {
for _, part := range partitions {
+ if part.Filesystem == nil {
+ continue
+ }
sparseImg, sizeTxt := sparseFilesystem(ctx, part, builder)
pName := proptools.String(part.Name)
sparseImages[pName] = sparseImg
@@ -146,9 +149,16 @@
partitionNames[pName] = true
}
// Get size of the partition by reading the -size.txt file
- pSize := fmt.Sprintf("$(cat %s)", sparseImageSizes[pName])
+ var pSize string
+ if size, hasSize := sparseImageSizes[pName]; hasSize {
+ pSize = fmt.Sprintf("$(cat %s)", size)
+ } else {
+ pSize = "0"
+ }
cmd.FlagWithArg("--partition=", fmt.Sprintf("%s:readonly:%s:%s", pName, pSize, gName))
- cmd.FlagWithInput("--image="+pName+"=", sparseImages[pName])
+ if image, hasImage := sparseImages[pName]; hasImage {
+ cmd.FlagWithInput("--image="+pName+"=", image)
+ }
}
}
@@ -178,28 +188,29 @@
addPartitionsToGroup(group.Partitions, gName)
}
- l.output = android.PathForModuleOut(ctx, l.installFileName()).OutputPath
- cmd.FlagWithOutput("--output=", l.output)
+ output := android.PathForModuleOut(ctx, l.installFileName())
+ cmd.FlagWithOutput("--output=", output)
builder.Build("build_logical_partition", fmt.Sprintf("Creating %s", l.BaseModuleName()))
l.installDir = android.PathForModuleInstall(ctx, "etc")
- ctx.InstallFile(l.installDir, l.installFileName(), l.output)
+ ctx.InstallFile(l.installDir, l.installFileName(), output)
- ctx.SetOutputFiles([]android.Path{l.output}, "")
+ ctx.SetOutputFiles([]android.Path{output}, "")
+ l.output = output
}
// Add a rule that converts the filesystem for the given partition to the given rule builder. The
// path to the sparse file and the text file having the size of the partition are returned.
-func sparseFilesystem(ctx android.ModuleContext, p partitionProperties, builder *android.RuleBuilder) (sparseImg android.OutputPath, sizeTxt android.OutputPath) {
- img := android.PathForModuleSrc(ctx, proptools.String(p.Filesystem))
+func sparseFilesystem(ctx android.ModuleContext, p partitionProperties, builder *android.RuleBuilder) (android.Path, android.Path) {
+ img := android.PathForModuleSrc(ctx, *p.Filesystem)
name := proptools.String(p.Name)
- sparseImg = android.PathForModuleOut(ctx, name+".img").OutputPath
+ sparseImg := android.PathForModuleOut(ctx, name+".img")
builder.Temporary(sparseImg)
builder.Command().BuiltTool("img2simg").Input(img).Output(sparseImg)
- sizeTxt = android.PathForModuleOut(ctx, name+"-size.txt").OutputPath
+ sizeTxt := android.PathForModuleOut(ctx, name+"-size.txt")
builder.Temporary(sizeTxt)
builder.Command().BuiltTool("sparse_img").Flag("--get_partition_size").Input(sparseImg).
Text("| ").Text("tr").FlagWithArg("-d ", "'\n'").
diff --git a/filesystem/raw_binary.go b/filesystem/raw_binary.go
index ad36c29..707fba0 100644
--- a/filesystem/raw_binary.go
+++ b/filesystem/raw_binary.go
@@ -42,7 +42,7 @@
properties rawBinaryProperties
- output android.OutputPath
+ output android.Path
installDir android.InstallPath
}
@@ -71,7 +71,7 @@
func (r *rawBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
inputFile := android.PathForModuleSrc(ctx, proptools.String(r.properties.Src))
- outputFile := android.PathForModuleOut(ctx, r.installFileName()).OutputPath
+ outputFile := android.PathForModuleOut(ctx, r.installFileName())
ctx.Build(pctx, android.BuildParams{
Rule: toRawBinary,
@@ -83,11 +83,11 @@
},
})
- r.output = outputFile
r.installDir = android.PathForModuleInstall(ctx, "etc")
- ctx.InstallFile(r.installDir, r.installFileName(), r.output)
+ ctx.InstallFile(r.installDir, r.installFileName(), outputFile)
- ctx.SetOutputFiles([]android.Path{r.output}, "")
+ ctx.SetOutputFiles([]android.Path{outputFile}, "")
+ r.output = outputFile
}
var _ android.AndroidMkEntriesProvider = (*rawBinary)(nil)
diff --git a/filesystem/super_image.go b/filesystem/super_image.go
new file mode 100644
index 0000000..5332462
--- /dev/null
+++ b/filesystem/super_image.go
@@ -0,0 +1,351 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package filesystem
+
+import (
+ "fmt"
+ "path/filepath"
+ "regexp"
+ "slices"
+ "strconv"
+ "strings"
+
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+func init() {
+ android.RegisterModuleType("super_image", SuperImageFactory)
+}
+
+type superImage struct {
+ android.ModuleBase
+
+ properties SuperImageProperties
+ partitionProps SuperImagePartitionNameProperties
+
+ installDir android.InstallPath
+}
+
+type SuperImageProperties struct {
+ // the size of the super partition
+ Size *int64
+ // the block device where metadata for dynamic partitions is stored
+ Metadata_device *string
+ // the super partition block device list
+ Block_devices []string
+ // whether A/B updater is used
+ Ab_update *bool
+ // whether dynamic partitions is enabled on devices that were launched without this support
+ Retrofit *bool
+ // whether the output is a sparse image
+ Sparse *bool
+ // information about how partitions within the super partition are grouped together
+ Partition_groups []PartitionGroupsInfo
+ // Name of the system_other partition filesystem module. This module will be installed to
+ // the "b" slot of the system partition in a/b partition builds.
+ System_other_partition *string
+ // whether dynamic partitions is used
+ Use_dynamic_partitions *bool
+ Virtual_ab struct {
+ // whether virtual A/B seamless update is enabled
+ Enable *bool
+ // whether retrofitting virtual A/B seamless update is enabled
+ Retrofit *bool
+ // If set, device uses virtual A/B Compression
+ Compression *bool
+ // This value controls the compression algorithm used for VABC.
+ // Valid options are defined in system/core/fs_mgr/libsnapshot/cow_writer.cpp
+ // e.g. "none", "gz", "brotli"
+ Compression_method *string
+ // Specifies maximum bytes to be compressed at once during ota. Options: 4096, 8192, 16384, 32768, 65536, 131072, 262144.
+ Compression_factor *int64
+ // Specifies COW version to be used by update_engine and libsnapshot. If this value is not
+ // specified we default to COW version 2 in update_engine for backwards compatibility
+ Cow_version *int64
+ }
+}
+
+type PartitionGroupsInfo struct {
+ Name string
+ GroupSize string
+ PartitionList []string
+}
+
+type SuperImagePartitionNameProperties struct {
+ // Name of the System partition filesystem module
+ System_partition *string
+ // Name of the System_ext partition filesystem module
+ System_ext_partition *string
+ // Name of the System_dlkm partition filesystem module
+ System_dlkm_partition *string
+ // Name of the System_other partition filesystem module
+ System_other_partition *string
+ // Name of the Product partition filesystem module
+ Product_partition *string
+ // Name of the Vendor partition filesystem module
+ Vendor_partition *string
+ // Name of the Vendor_dlkm partition filesystem module
+ Vendor_dlkm_partition *string
+ // Name of the Odm partition filesystem module
+ Odm_partition *string
+ // Name of the Odm_dlkm partition filesystem module
+ Odm_dlkm_partition *string
+}
+
+type SuperImageInfo struct {
+ // The built super.img file, which contains the sub-partitions
+ SuperImage android.Path
+
+ // Mapping from the sub-partition type to its re-exported FileSystemInfo providers from the
+ // sub-partitions.
+ SubImageInfo map[string]FilesystemInfo
+}
+
+var SuperImageProvider = blueprint.NewProvider[SuperImageInfo]()
+
+func SuperImageFactory() android.Module {
+ module := &superImage{}
+ module.AddProperties(&module.properties, &module.partitionProps)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ return module
+}
+
+type superImageDepTagType struct {
+ blueprint.BaseDependencyTag
+}
+
+var subImageDepTag superImageDepTagType
+
+type systemOtherDepTagType struct {
+ blueprint.BaseDependencyTag
+}
+
+var systemOtherDepTag systemOtherDepTagType
+
+func (s *superImage) DepsMutator(ctx android.BottomUpMutatorContext) {
+ addDependencyIfDefined := func(dep *string) {
+ if dep != nil {
+ ctx.AddDependency(ctx.Module(), subImageDepTag, proptools.String(dep))
+ }
+ }
+
+ addDependencyIfDefined(s.partitionProps.System_partition)
+ addDependencyIfDefined(s.partitionProps.System_ext_partition)
+ addDependencyIfDefined(s.partitionProps.System_dlkm_partition)
+ addDependencyIfDefined(s.partitionProps.System_other_partition)
+ addDependencyIfDefined(s.partitionProps.Product_partition)
+ addDependencyIfDefined(s.partitionProps.Vendor_partition)
+ addDependencyIfDefined(s.partitionProps.Vendor_dlkm_partition)
+ addDependencyIfDefined(s.partitionProps.Odm_partition)
+ addDependencyIfDefined(s.partitionProps.Odm_dlkm_partition)
+ if s.properties.System_other_partition != nil {
+ ctx.AddDependency(ctx.Module(), systemOtherDepTag, *s.properties.System_other_partition)
+ }
+}
+
+func (s *superImage) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ miscInfo, deps, subImageInfos := s.buildMiscInfo(ctx)
+ builder := android.NewRuleBuilder(pctx, ctx)
+ output := android.PathForModuleOut(ctx, s.installFileName())
+ lpMake := ctx.Config().HostToolPath(ctx, "lpmake")
+ lpMakeDir := filepath.Dir(lpMake.String())
+ deps = append(deps, lpMake)
+ builder.Command().Textf("PATH=%s:\\$PATH", lpMakeDir).
+ BuiltTool("build_super_image").
+ Text("-v").
+ Input(miscInfo).
+ Implicits(deps).
+ Output(output)
+ builder.Build("build_super_image", fmt.Sprintf("Creating super image %s", s.BaseModuleName()))
+ android.SetProvider(ctx, SuperImageProvider, SuperImageInfo{
+ SuperImage: output,
+ SubImageInfo: subImageInfos,
+ })
+ ctx.SetOutputFiles([]android.Path{output}, "")
+ ctx.CheckbuildFile(output)
+}
+
+func (s *superImage) installFileName() string {
+ return s.BaseModuleName() + ".img"
+}
+
+func (s *superImage) buildMiscInfo(ctx android.ModuleContext) (android.Path, android.Paths, map[string]FilesystemInfo) {
+ var miscInfoString strings.Builder
+ addStr := func(name string, value string) {
+ miscInfoString.WriteString(name)
+ miscInfoString.WriteRune('=')
+ miscInfoString.WriteString(value)
+ miscInfoString.WriteRune('\n')
+ }
+
+ addStr("build_super_partition", "true")
+ addStr("use_dynamic_partitions", strconv.FormatBool(proptools.Bool(s.properties.Use_dynamic_partitions)))
+ if proptools.Bool(s.properties.Retrofit) {
+ addStr("dynamic_partition_retrofit", "true")
+ }
+ addStr("lpmake", "lpmake")
+ addStr("super_metadata_device", proptools.String(s.properties.Metadata_device))
+ if len(s.properties.Block_devices) > 0 {
+ addStr("super_block_devices", strings.Join(s.properties.Block_devices, " "))
+ }
+ addStr("super_partition_size", strconv.Itoa(proptools.Int(s.properties.Size)))
+ // TODO: In make, there's more complicated logic than just this surrounding super_*_device_size
+ addStr("super_super_device_size", strconv.Itoa(proptools.Int(s.properties.Size)))
+ var groups, partitionList []string
+ for _, groupInfo := range s.properties.Partition_groups {
+ groups = append(groups, groupInfo.Name)
+ partitionList = append(partitionList, groupInfo.PartitionList...)
+ addStr("super_"+groupInfo.Name+"_group_size", groupInfo.GroupSize)
+ addStr("super_"+groupInfo.Name+"_partition_list", strings.Join(groupInfo.PartitionList, " "))
+ }
+ initialPartitionListLen := len(partitionList)
+ partitionList = android.SortedUniqueStrings(partitionList)
+ if len(partitionList) != initialPartitionListLen {
+ ctx.ModuleErrorf("Duplicate partitions found in the partition_groups property")
+ }
+ addStr("super_partition_groups", strings.Join(groups, " "))
+ addStr("dynamic_partition_list", strings.Join(partitionList, " "))
+
+ addStr("ab_update", strconv.FormatBool(proptools.Bool(s.properties.Ab_update)))
+
+ if proptools.Bool(s.properties.Virtual_ab.Enable) {
+ addStr("virtual_ab", "true")
+ if proptools.Bool(s.properties.Virtual_ab.Retrofit) {
+ addStr("virtual_ab_retrofit", "true")
+ }
+ addStr("virtual_ab_compression", strconv.FormatBool(proptools.Bool(s.properties.Virtual_ab.Compression)))
+ if s.properties.Virtual_ab.Compression_method != nil {
+ matched, _ := regexp.MatchString("^[a-zA-Z0-9_-]+$", *s.properties.Virtual_ab.Compression_method)
+ if !matched {
+ ctx.PropertyErrorf("virtual_ab.compression_method", "compression_method cannot have special characters")
+ }
+ addStr("virtual_ab_compression_method", *s.properties.Virtual_ab.Compression_method)
+ }
+ if s.properties.Virtual_ab.Compression_factor != nil {
+ addStr("virtual_ab_compression_factor", strconv.FormatInt(*s.properties.Virtual_ab.Compression_factor, 10))
+ }
+ if s.properties.Virtual_ab.Cow_version != nil {
+ addStr("virtual_ab_cow_version", strconv.FormatInt(*s.properties.Virtual_ab.Cow_version, 10))
+ }
+
+ } else {
+ if s.properties.Virtual_ab.Retrofit != nil {
+ ctx.PropertyErrorf("virtual_ab.retrofit", "This property cannot be set when virtual_ab is disabled")
+ }
+ if s.properties.Virtual_ab.Compression != nil {
+ ctx.PropertyErrorf("virtual_ab.compression", "This property cannot be set when virtual_ab is disabled")
+ }
+ if s.properties.Virtual_ab.Compression_method != nil {
+ ctx.PropertyErrorf("virtual_ab.compression_method", "This property cannot be set when virtual_ab is disabled")
+ }
+ if s.properties.Virtual_ab.Compression_factor != nil {
+ ctx.PropertyErrorf("virtual_ab.compression_factor", "This property cannot be set when virtual_ab is disabled")
+ }
+ }
+
+ subImageInfo := make(map[string]FilesystemInfo)
+ var deps android.Paths
+
+ missingPartitionErrorMessage := ""
+ handleSubPartition := func(partitionType string, name *string) {
+ if proptools.String(name) == "" {
+ missingPartitionErrorMessage += fmt.Sprintf("%s image listed in partition groups, but its module was not specified. ", partitionType)
+ return
+ }
+ mod := ctx.GetDirectDepWithTag(*name, subImageDepTag)
+ if mod == nil {
+ ctx.ModuleErrorf("Could not get dep %q", *name)
+ return
+ }
+ info, ok := android.OtherModuleProvider(ctx, mod, FilesystemProvider)
+ if !ok {
+ ctx.ModuleErrorf("Expected dep %q to provide FilesystemInfo", *name)
+ return
+ }
+ addStr(partitionType+"_image", info.Output.String())
+ deps = append(deps, info.Output)
+ if _, ok := subImageInfo[partitionType]; ok {
+ ctx.ModuleErrorf("Already set subimageInfo for %q", partitionType)
+ }
+ subImageInfo[partitionType] = info
+ }
+
+ // Build partitionToImagePath, because system partition may need system_other
+ // partition image path
+ for _, p := range partitionList {
+ switch p {
+ case "system":
+ handleSubPartition("system", s.partitionProps.System_partition)
+ // TODO: add system_other to deps after it can be generated
+ //getFsInfo("system_other", s.partitionProps.System_other_partition, &subImageInfo.System_other)
+ case "system_dlkm":
+ handleSubPartition("system_dlkm", s.partitionProps.System_dlkm_partition)
+ case "system_ext":
+ handleSubPartition("system_ext", s.partitionProps.System_ext_partition)
+ case "product":
+ handleSubPartition("product", s.partitionProps.Product_partition)
+ case "vendor":
+ handleSubPartition("vendor", s.partitionProps.Vendor_partition)
+ case "vendor_dlkm":
+ handleSubPartition("vendor_dlkm", s.partitionProps.Vendor_dlkm_partition)
+ case "odm":
+ handleSubPartition("odm", s.partitionProps.Odm_partition)
+ case "odm_dlkm":
+ handleSubPartition("odm_dlkm", s.partitionProps.Odm_dlkm_partition)
+ default:
+ ctx.ModuleErrorf("partition %q is not a super image supported partition", p)
+ }
+ }
+
+ if s.properties.System_other_partition != nil {
+ if !slices.Contains(partitionList, "system") {
+ ctx.PropertyErrorf("system_other_partition", "Must have a system partition to use a system_other partition")
+ }
+ systemOther := ctx.GetDirectDepProxyWithTag(*s.properties.System_other_partition, systemOtherDepTag)
+ systemOtherFiles := android.OutputFilesForModule(ctx, systemOther, "")
+ if len(systemOtherFiles) != 1 {
+ ctx.PropertyErrorf("system_other_partition", "Expected 1 output file from module %q", *&s.properties.System_other_partition)
+ } else {
+ addStr("system_other_image", systemOtherFiles[0].String())
+ deps = append(deps, systemOtherFiles[0])
+ }
+ }
+
+ // Delay the error message until execution time because on aosp-main-future-without-vendor,
+ // BUILDING_VENDOR_IMAGE is false so we don't get the vendor image, but it's still listed in
+ // BOARD_GOOGLE_DYNAMIC_PARTITIONS_PARTITION_LIST.
+ missingPartitionErrorMessageFile := android.PathForModuleOut(ctx, "missing_partition_error.txt")
+ if missingPartitionErrorMessage != "" {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.ErrorRule,
+ Output: missingPartitionErrorMessageFile,
+ Args: map[string]string{
+ "error": missingPartitionErrorMessage,
+ },
+ })
+ } else {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Touch,
+ Output: missingPartitionErrorMessageFile,
+ })
+ }
+
+ miscInfo := android.PathForModuleOut(ctx, "misc_info.txt")
+ android.WriteFileRule(ctx, miscInfo, miscInfoString.String(), missingPartitionErrorMessageFile)
+ return miscInfo, deps, subImageInfo
+}
diff --git a/filesystem/system_image.go b/filesystem/system_image.go
index a8fd368..cc9093f 100644
--- a/filesystem/system_image.go
+++ b/filesystem/system_image.go
@@ -16,89 +16,106 @@
import (
"android/soong/android"
+ "android/soong/cc"
"android/soong/linkerconfig"
+
+ "strings"
+
+ "github.com/google/blueprint/proptools"
)
type systemImage struct {
filesystem
-
- properties systemImageProperties
}
-type systemImageProperties struct {
- // Path to the input linker config json file.
- Linker_config_src *string
-}
+var _ filesystemBuilder = (*systemImage)(nil)
// android_system_image is a specialization of android_filesystem for the 'system' partition.
// Currently, the only difference is the inclusion of linker.config.pb file which specifies
// the provided and the required libraries to and from APEXes.
-func systemImageFactory() android.Module {
+func SystemImageFactory() android.Module {
module := &systemImage{}
- module.AddProperties(&module.properties)
- module.filesystem.buildExtraFiles = module.buildExtraFiles
- module.filesystem.filterPackagingSpec = module.filterPackagingSpec
- initFilesystemModule(&module.filesystem)
+ module.filesystemBuilder = module
+ initFilesystemModule(module, &module.filesystem)
return module
}
-func (s *systemImage) buildExtraFiles(ctx android.ModuleContext, root android.OutputPath) android.OutputPaths {
- if s.filesystem.properties.Partition_type != nil {
- ctx.PropertyErrorf("partition_type", "partition_type must be unset on an android_system_image module. It is assumed to be 'system'.")
- }
- lc := s.buildLinkerConfigFile(ctx, root)
- // Add more files if needed
- return []android.OutputPath{lc}
+func (s systemImage) FsProps() FilesystemProperties {
+ return s.filesystem.properties
}
-func (s *systemImage) buildLinkerConfigFile(ctx android.ModuleContext, root android.OutputPath) android.OutputPath {
- input := android.PathForModuleSrc(ctx, android.String(s.properties.Linker_config_src))
- output := root.Join(ctx, "system", "etc", "linker.config.pb")
-
- // we need "Module"s for packaging items
- modulesInPackageByModule := make(map[android.Module]bool)
- modulesInPackageByName := make(map[string]bool)
-
- deps := s.gatherFilteredPackagingSpecs(ctx)
- ctx.WalkDeps(func(child, parent android.Module) bool {
- for _, ps := range android.OtherModuleProviderOrDefault(
- ctx, child, android.InstallFilesProvider).PackagingSpecs {
- if _, ok := deps[ps.RelPathInPackage()]; ok {
- modulesInPackageByModule[child] = true
- modulesInPackageByName[child.Name()] = true
- return true
- }
- }
- return true
- })
-
- provideModules := make([]android.Module, 0, len(modulesInPackageByModule))
- for mod := range modulesInPackageByModule {
- provideModules = append(provideModules, mod)
+func (s *systemImage) BuildLinkerConfigFile(
+ ctx android.ModuleContext,
+ builder *android.RuleBuilder,
+ rebasedDir android.OutputPath,
+ fullInstallPaths *[]FullInstallPathInfo,
+) {
+ if !proptools.Bool(s.filesystem.properties.Linker_config.Gen_linker_config) {
+ return
}
- var requireModules []android.Module
- ctx.WalkDeps(func(child, parent android.Module) bool {
- _, parentInPackage := modulesInPackageByModule[parent]
- _, childInPackageName := modulesInPackageByName[child.Name()]
+ output := rebasedDir.Join(ctx, "etc", "linker.config.pb")
+ if s.filesystem.properties.Linker_config.Linker_config_srcs != nil {
+ provideModules, requireModules := s.getLibsForLinkerConfig(ctx)
+ intermediateOutput := android.PathForModuleOut(ctx, "linker.config.pb")
+ linkerconfig.BuildLinkerConfig(ctx, android.PathsForModuleSrc(ctx, s.filesystem.properties.Linker_config.Linker_config_srcs), provideModules, requireModules, intermediateOutput)
+ builder.Command().Text("cp").Input(intermediateOutput).Output(output)
- // When parent is in the package, and child (or its variant) is not, this can be from an interface.
- if parentInPackage && !childInPackageName {
- requireModules = append(requireModules, child)
- }
- return true
- })
+ *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
+ FullInstallPath: android.PathForModuleInPartitionInstall(ctx, s.PartitionType(), "etc", "linker.config.pb"),
+ SourcePath: intermediateOutput,
+ })
+ } else {
+ // TODO: This branch is the logic that make uses for the linker config file, which is
+ // different than linkerconfig.BuildLinkerConfig used above. Keeping both branches for now
+ // because microdroid uses the other method and is in theory happy with it. But we should
+ // consider deduping them.
+ stubLibraries := cc.StubLibrariesFile(ctx)
+ llndkMovedToApexLibraries := cc.MovedToApexLlndkLibrariesFile(ctx)
+ outputStep1 := android.PathForModuleOut(ctx, "linker.config.pb.step1")
+ builder.Command().
+ BuiltTool("conv_linker_config").
+ Text("proto --force").
+ FlagWithInput("-s ", android.PathForSource(ctx, "system/core/rootdir/etc/linker.config.json")).
+ FlagWithOutput("-o ", outputStep1)
+ builder.Temporary(outputStep1)
+ builder.Command().
+ BuiltTool("conv_linker_config").
+ Text("systemprovide").
+ FlagWithInput("--source ", outputStep1).
+ FlagWithArg("--output ", output.String()).
+ Textf(`--value "$(cat %s)"`, stubLibraries).
+ Implicit(stubLibraries).
+ FlagWithArg("--system ", rebasedDir.String())
+ builder.Command().
+ BuiltTool("conv_linker_config").
+ Text("append").
+ FlagWithArg("--source ", output.String()).
+ FlagWithOutput("--output ", output).
+ FlagWithArg("--key ", "requireLibs").
+ Textf(`--value "$(cat %s)"`, llndkMovedToApexLibraries).
+ Implicit(llndkMovedToApexLibraries)
+ // TODO: Make also supports adding an extra append command with PRODUCT_EXTRA_STUB_LIBRARIES,
+ // but that variable appears to have no usages.
- builder := android.NewRuleBuilder(pctx, ctx)
- linkerconfig.BuildLinkerConfig(ctx, builder, input, provideModules, requireModules, output)
- builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String())
- return output
+ *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
+ FullInstallPath: android.PathForModuleInPartitionInstall(ctx, s.PartitionType(), "etc", "linker.config.pb"),
+ SourcePath: output,
+ })
+ }
+
+ s.appendToEntry(ctx, output)
}
// Filter the result of GatherPackagingSpecs to discard items targeting outside "system" / "root"
// partition. Note that "apex" module installs its contents to "apex"(fake partition) as well
// for symbol lookup by imitating "activated" paths.
-func (s *systemImage) filterPackagingSpec(ps android.PackagingSpec) bool {
- return s.filesystem.filterInstallablePackagingSpec(ps) &&
- (ps.Partition() == "system" || ps.Partition() == "root")
+func (s *systemImage) FilterPackagingSpec(ps android.PackagingSpec) bool {
+ return !ps.SkipInstall() &&
+ (ps.Partition() == "system" || ps.Partition() == "root" ||
+ strings.HasPrefix(ps.Partition(), "system/"))
+}
+
+func (s *systemImage) ShouldUseVintfFragmentModuleOnly() bool {
+ return true
}
diff --git a/filesystem/system_other.go b/filesystem/system_other.go
new file mode 100644
index 0000000..28fe1ce
--- /dev/null
+++ b/filesystem/system_other.go
@@ -0,0 +1,137 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package filesystem
+
+import (
+ "android/soong/android"
+ "path/filepath"
+ "strings"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+type SystemOtherImageProperties struct {
+ // The system_other image always requires a reference to the system image. The system_other
+ // partition gets built into the system partition's "b" slot in a/b partition builds. Thus, it
+ // copies most of its configuration from the system image, such as filesystem type, avb signing
+ // info, etc. Including it here does not automatically mean that it will pick up the system
+ // image's dexpropt files, it must also be listed in Preinstall_dexpreopt_files_from for that.
+ System_image *string
+
+ // This system_other partition will include all the dexpreopt files from the apps on these
+ // partitions.
+ Preinstall_dexpreopt_files_from []string
+}
+
+type systemOtherImage struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+ properties SystemOtherImageProperties
+}
+
+// The system_other image is the default contents of the "b" slot of the system image.
+// It contains the dexpreopt files of all the apps on the device, for a faster first boot.
+// Afterwards, at runtime, it will be used as a regular b slot for OTA updates, and the initial
+// dexpreopt files will be deleted.
+func SystemOtherImageFactory() android.Module {
+ module := &systemOtherImage{}
+ module.AddProperties(&module.properties)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+type systemImageDeptag struct {
+ blueprint.BaseDependencyTag
+}
+
+var systemImageDependencyTag = systemImageDeptag{}
+
+type dexpreoptDeptag struct {
+ blueprint.BaseDependencyTag
+}
+
+var dexpreoptDependencyTag = dexpreoptDeptag{}
+
+func (m *systemOtherImage) DepsMutator(ctx android.BottomUpMutatorContext) {
+ if proptools.String(m.properties.System_image) == "" {
+ ctx.ModuleErrorf("system_image property must be set")
+ return
+ }
+ ctx.AddDependency(ctx.Module(), systemImageDependencyTag, *m.properties.System_image)
+ ctx.AddDependency(ctx.Module(), dexpreoptDependencyTag, m.properties.Preinstall_dexpreopt_files_from...)
+}
+
+func (m *systemOtherImage) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ systemImage := ctx.GetDirectDepProxyWithTag(*m.properties.System_image, systemImageDependencyTag)
+ systemInfo, ok := android.OtherModuleProvider(ctx, systemImage, FilesystemProvider)
+ if !ok {
+ ctx.PropertyErrorf("system_image", "Expected system_image module to provide FilesystemProvider")
+ return
+ }
+
+ output := android.PathForModuleOut(ctx, "system_other.img")
+ stagingDir := android.PathForModuleOut(ctx, "staging_dir")
+
+ builder := android.NewRuleBuilder(pctx, ctx)
+ builder.Command().Textf("rm -rf %s && mkdir -p %s", stagingDir, stagingDir)
+
+ specs := make(map[string]android.PackagingSpec)
+ for _, otherPartition := range m.properties.Preinstall_dexpreopt_files_from {
+ dexModule := ctx.GetDirectDepProxyWithTag(otherPartition, dexpreoptDependencyTag)
+ fsInfo, ok := android.OtherModuleProvider(ctx, dexModule, FilesystemProvider)
+ if !ok {
+ ctx.PropertyErrorf("preinstall_dexpreopt_files_from", "Expected module %q to provide FilesystemProvider", otherPartition)
+ return
+ }
+ // Merge all the packaging specs into 1 map
+ for k := range fsInfo.SpecsForSystemOther {
+ if _, ok := specs[k]; ok {
+ ctx.ModuleErrorf("Packaging spec %s given by two different partitions", k)
+ continue
+ }
+ specs[k] = fsInfo.SpecsForSystemOther[k]
+ }
+ }
+
+ // TOOD: CopySpecsToDir only exists on PackagingBase, but doesn't use any fields from it. Clean this up.
+ (&android.PackagingBase{}).CopySpecsToDir(ctx, builder, specs, stagingDir)
+
+ if len(m.properties.Preinstall_dexpreopt_files_from) > 0 {
+ builder.Command().Textf("touch %s", filepath.Join(stagingDir.String(), "system-other-odex-marker"))
+ }
+
+ // Most of the time, if build_image were to call a host tool, it accepts the path to the
+ // host tool in a field in the prop file. However, it doesn't have that option for fec, which
+ // it expects to just be on the PATH. Add fec to the PATH.
+ fec := ctx.Config().HostToolPath(ctx, "fec")
+ pathToolDirs := []string{filepath.Dir(fec.String())}
+
+ builder.Command().
+ Textf("PATH=%s:$PATH", strings.Join(pathToolDirs, ":")).
+ BuiltTool("build_image").
+ Text(stagingDir.String()). // input directory
+ Input(systemInfo.BuildImagePropFile).
+ Implicits(systemInfo.BuildImagePropFileDeps).
+ Implicit(fec).
+ Output(output).
+ Text(stagingDir.String())
+
+ builder.Build("build_system_other", "build system other")
+
+ ctx.SetOutputFiles(android.Paths{output}, "")
+ ctx.CheckbuildFile(output)
+}
diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go
index 3a9a64d..91826b2 100644
--- a/filesystem/vbmeta.go
+++ b/filesystem/vbmeta.go
@@ -25,19 +25,30 @@
)
func init() {
- android.RegisterModuleType("vbmeta", vbmetaFactory)
+ android.RegisterModuleType("vbmeta", VbmetaFactory)
+ pctx.HostBinToolVariable("avbtool", "avbtool")
}
+var (
+ extractPublicKeyRule = pctx.AndroidStaticRule("avb_extract_public_key",
+ blueprint.RuleParams{
+ Command: `${avbtool} extract_public_key --key $in --output $out`,
+ CommandDeps: []string{
+ "${avbtool}",
+ },
+ })
+)
+
type vbmeta struct {
android.ModuleBase
- properties vbmetaProperties
+ properties VbmetaProperties
- output android.OutputPath
+ output android.Path
installDir android.InstallPath
}
-type vbmetaProperties struct {
+type VbmetaProperties struct {
// Name of the partition stored in vbmeta desc. Defaults to the name of this module.
Partition_name *string
@@ -50,9 +61,8 @@
// Algorithm that avbtool will use to sign this vbmeta image. Default is SHA256_RSA4096.
Algorithm *string
- // File whose content will provide the rollback index. If unspecified, the rollback index
- // is from PLATFORM_SECURITY_PATCH
- Rollback_index_file *string `android:"path"`
+ // The rollback index. If unspecified, the rollback index is from PLATFORM_SECURITY_PATCH
+ Rollback_index *int64
// Rollback index location of this vbmeta image. Must be 0, 1, 2, etc. Default is 0.
Rollback_index_location *int64
@@ -61,8 +71,15 @@
// have to be signed (use_avb: true).
Partitions proptools.Configurable[[]string]
- // List of chained partitions that this vbmeta deletages the verification.
- Chained_partitions []chainedPartitionProperties
+ // Metadata about the chained partitions that this vbmeta delegates the verification.
+ // This is an alternative to chained_partitions, using chained_partitions instead is simpler
+ // in most cases. However, this property allows building this vbmeta partition without
+ // its chained partitions existing in this build.
+ Chained_partition_metadata []ChainedPartitionProperties
+
+ // List of chained partitions that this vbmeta delegates the verification. They are the
+ // names of other vbmeta modules.
+ Chained_partitions []string
// List of key-value pair of avb properties
Avb_properties []avbProperty
@@ -76,7 +93,7 @@
Value *string
}
-type chainedPartitionProperties struct {
+type ChainedPartitionProperties struct {
// Name of the chained partition
Name *string
@@ -94,23 +111,45 @@
Private_key *string `android:"path"`
}
+type vbmetaPartitionInfo struct {
+ // Name of the partition
+ Name string
+
+ // Rollback index location, non-negative int
+ RollbackIndexLocation int
+
+ // The path to the public key of the private key used to sign this partition. Derived from
+ // the private key.
+ PublicKey android.Path
+
+ // The output of the vbmeta module
+ Output android.Path
+}
+
+var vbmetaPartitionProvider = blueprint.NewProvider[vbmetaPartitionInfo]()
+
// vbmeta is the partition image that has the verification information for other partitions.
-func vbmetaFactory() android.Module {
+func VbmetaFactory() android.Module {
module := &vbmeta{}
module.AddProperties(&module.properties)
- android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
return module
}
type vbmetaDep struct {
blueprint.BaseDependencyTag
- kind string
}
-var vbmetaPartitionDep = vbmetaDep{kind: "partition"}
+type chainedPartitionDep struct {
+ blueprint.BaseDependencyTag
+}
+
+var vbmetaPartitionDep = vbmetaDep{}
+var vbmetaChainedPartitionDep = chainedPartitionDep{}
func (v *vbmeta) DepsMutator(ctx android.BottomUpMutatorContext) {
- ctx.AddDependency(ctx.Module(), vbmetaPartitionDep, v.properties.Partitions.GetOrDefault(ctx, nil)...)
+ ctx.AddVariationDependencies(ctx.Config().AndroidFirstDeviceTarget.Variations(), vbmetaPartitionDep, v.properties.Partitions.GetOrDefault(ctx, nil)...)
+ ctx.AddVariationDependencies(ctx.Config().AndroidFirstDeviceTarget.Variations(), vbmetaChainedPartitionDep, v.properties.Chained_partitions...)
}
func (v *vbmeta) installFileName() string {
@@ -125,10 +164,6 @@
const vbmetaMaxSize = 64 * 1024
func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- extractedPublicKeys := v.extractPublicKeys(ctx)
-
- v.output = android.PathForModuleOut(ctx, v.installFileName()).OutputPath
-
builder := android.NewRuleBuilder(pctx, ctx)
cmd := builder.Command().BuiltTool("avbtool").Text("make_vbmeta_image")
@@ -138,13 +173,14 @@
algorithm := proptools.StringDefault(v.properties.Algorithm, "SHA256_RSA4096")
cmd.FlagWithArg("--algorithm ", algorithm)
+ cmd.FlagWithArg("--padding_size ", "4096")
+
cmd.FlagWithArg("--rollback_index ", v.rollbackIndexCommand(ctx))
ril := proptools.IntDefault(v.properties.Rollback_index_location, 0)
if ril < 0 {
ctx.PropertyErrorf("rollback_index_location", "must be 0, 1, 2, ...")
return
}
- cmd.FlagWithArg("--rollback_index_location ", strconv.Itoa(ril))
for _, avb_prop := range v.properties.Avb_properties {
key := proptools.String(avb_prop.Key)
@@ -176,109 +212,125 @@
cmd.FlagWithInput("--include_descriptors_from_image ", signedImage)
}
- for i, cp := range v.properties.Chained_partitions {
- name := proptools.String(cp.Name)
+ seenRils := make(map[int]bool)
+ for _, cp := range ctx.GetDirectDepsWithTag(vbmetaChainedPartitionDep) {
+ info, ok := android.OtherModuleProvider(ctx, cp, vbmetaPartitionProvider)
+ if !ok {
+ ctx.PropertyErrorf("chained_partitions", "Expected all modules in chained_partitions to provide vbmetaPartitionProvider, but %s did not", cp.Name())
+ continue
+ }
+ if info.Name == "" {
+ ctx.PropertyErrorf("chained_partitions", "name must be specified")
+ continue
+ }
+
+ ril := info.RollbackIndexLocation
+ if ril < 0 {
+ ctx.PropertyErrorf("chained_partitions", "rollback index location must be 0, 1, 2, ...")
+ continue
+ } else if seenRils[ril] {
+ ctx.PropertyErrorf("chained_partitions", "Multiple chained partitions with the same rollback index location %d", ril)
+ continue
+ }
+ seenRils[ril] = true
+
+ publicKey := info.PublicKey
+ cmd.FlagWithArg("--chain_partition ", fmt.Sprintf("%s:%d:%s", info.Name, ril, publicKey.String()))
+ cmd.Implicit(publicKey)
+ }
+ for _, cpm := range v.properties.Chained_partition_metadata {
+ name := proptools.String(cpm.Name)
if name == "" {
ctx.PropertyErrorf("chained_partitions", "name must be specified")
continue
}
- ril := proptools.IntDefault(cp.Rollback_index_location, i+1)
+ ril := proptools.IntDefault(cpm.Rollback_index_location, -1)
if ril < 0 {
- ctx.PropertyErrorf("chained_partitions", "must be 0, 1, 2, ...")
+ ctx.PropertyErrorf("chained_partition_metadata", "rollback index location must be 0, 1, 2, ...")
+ continue
+ } else if seenRils[ril] {
+ ctx.PropertyErrorf("chained_partition_metadata", "Multiple chained partitions with the same rollback index location %d", ril)
+ continue
+ }
+ seenRils[ril] = true
+
+ var publicKey android.Path
+ if cpm.Public_key != nil {
+ publicKey = android.PathForModuleSrc(ctx, *cpm.Public_key)
+ } else if cpm.Private_key != nil {
+ privateKey := android.PathForModuleSrc(ctx, *cpm.Private_key)
+ extractedPublicKey := android.PathForModuleOut(ctx, "chained_metadata", name+".avbpubkey")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: extractPublicKeyRule,
+ Input: privateKey,
+ Output: extractedPublicKey,
+ })
+ publicKey = extractedPublicKey
+ } else {
+ ctx.PropertyErrorf("public_key", "Either public_key or private_key must be specified")
continue
}
- var publicKey android.Path
- if cp.Public_key != nil {
- publicKey = android.PathForModuleSrc(ctx, proptools.String(cp.Public_key))
- } else {
- publicKey = extractedPublicKeys[name]
- }
cmd.FlagWithArg("--chain_partition ", fmt.Sprintf("%s:%d:%s", name, ril, publicKey.String()))
cmd.Implicit(publicKey)
}
- cmd.FlagWithOutput("--output ", v.output)
+ output := android.PathForModuleOut(ctx, v.installFileName())
+ cmd.FlagWithOutput("--output ", output)
// libavb expects to be able to read the maximum vbmeta size, so we must provide a partition
// which matches this or the read will fail.
builder.Command().Text("truncate").
FlagWithArg("-s ", strconv.Itoa(vbmetaMaxSize)).
- Output(v.output)
+ Output(output)
builder.Build("vbmeta", fmt.Sprintf("vbmeta %s", ctx.ModuleName()))
v.installDir = android.PathForModuleInstall(ctx, "etc")
- ctx.InstallFile(v.installDir, v.installFileName(), v.output)
+ ctx.InstallFile(v.installDir, v.installFileName(), output)
- ctx.SetOutputFiles([]android.Path{v.output}, "")
+ extractedPublicKey := android.PathForModuleOut(ctx, v.partitionName()+".avbpubkey")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: extractPublicKeyRule,
+ Input: key,
+ Output: extractedPublicKey,
+ })
+
+ android.SetProvider(ctx, vbmetaPartitionProvider, vbmetaPartitionInfo{
+ Name: v.partitionName(),
+ RollbackIndexLocation: ril,
+ PublicKey: extractedPublicKey,
+ Output: output,
+ })
+
+ ctx.SetOutputFiles([]android.Path{output}, "")
+ v.output = output
}
// Returns the embedded shell command that prints the rollback index
func (v *vbmeta) rollbackIndexCommand(ctx android.ModuleContext) string {
- var cmd string
- if v.properties.Rollback_index_file != nil {
- f := android.PathForModuleSrc(ctx, proptools.String(v.properties.Rollback_index_file))
- cmd = "cat " + f.String()
+ if v.properties.Rollback_index != nil {
+ return fmt.Sprintf("%d", *v.properties.Rollback_index)
} else {
- cmd = "date -d 'TZ=\"GMT\" " + ctx.Config().PlatformSecurityPatch() + "' +%s"
+ // Take the first line and remove the newline char
+ return "$(date -d 'TZ=\"GMT\" " + ctx.Config().PlatformSecurityPatch() + "' +%s | head -1 | tr -d '\n'" + ")"
}
- // Take the first line and remove the newline char
- return "$(" + cmd + " | head -1 | tr -d '\n'" + ")"
}
-// Extract public keys from chained_partitions.private_key. The keys are indexed with the partition
-// name.
-func (v *vbmeta) extractPublicKeys(ctx android.ModuleContext) map[string]android.OutputPath {
- result := make(map[string]android.OutputPath)
+var _ android.AndroidMkProviderInfoProducer = (*vbmeta)(nil)
- builder := android.NewRuleBuilder(pctx, ctx)
- for _, cp := range v.properties.Chained_partitions {
- if cp.Private_key == nil {
- continue
- }
-
- name := proptools.String(cp.Name)
- if name == "" {
- ctx.PropertyErrorf("chained_partitions", "name must be specified")
- continue
- }
-
- if _, ok := result[name]; ok {
- ctx.PropertyErrorf("chained_partitions", "name %q is duplicated", name)
- continue
- }
-
- privateKeyFile := android.PathForModuleSrc(ctx, proptools.String(cp.Private_key))
- publicKeyFile := android.PathForModuleOut(ctx, name+".avbpubkey").OutputPath
-
- builder.Command().
- BuiltTool("avbtool").
- Text("extract_public_key").
- FlagWithInput("--key ", privateKeyFile).
- FlagWithOutput("--output ", publicKeyFile)
-
- result[name] = publicKeyFile
- }
- builder.Build("vbmeta_extract_public_key", fmt.Sprintf("Extract public keys for %s", ctx.ModuleName()))
- return result
-}
-
-var _ android.AndroidMkEntriesProvider = (*vbmeta)(nil)
-
-// Implements android.AndroidMkEntriesProvider
-func (v *vbmeta) AndroidMkEntries() []android.AndroidMkEntries {
- return []android.AndroidMkEntries{android.AndroidMkEntries{
- Class: "ETC",
- OutputFile: android.OptionalPathForPath(v.output),
- ExtraEntries: []android.AndroidMkExtraEntriesFunc{
- func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", v.installDir.String())
- entries.SetString("LOCAL_INSTALLED_MODULE_STEM", v.installFileName())
- },
+func (v *vbmeta) PrepareAndroidMKProviderInfo(config android.Config) *android.AndroidMkProviderInfo {
+ providerData := android.AndroidMkProviderInfo{
+ PrimaryInfo: android.AndroidMkInfo{
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(v.output),
+ EntryMap: make(map[string][]string),
},
- }}
+ }
+ providerData.PrimaryInfo.SetString("LOCAL_MODULE_PATH", v.installDir.String())
+ providerData.PrimaryInfo.SetString("LOCAL_INSTALLED_MODULE_STEM", v.installFileName())
+ return &providerData
}
var _ Filesystem = (*vbmeta)(nil)
diff --git a/fsgen/Android.bp b/fsgen/Android.bp
new file mode 100644
index 0000000..1b828c5
--- /dev/null
+++ b/fsgen/Android.bp
@@ -0,0 +1,34 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-fsgen",
+ pkgPath: "android/soong/fsgen",
+ deps: [
+ "blueprint",
+ "soong",
+ "soong-android",
+ "soong-filesystem",
+ "soong-kernel",
+ ],
+ srcs: [
+ "boot_imgs.go",
+ "config.go",
+ "filesystem_creator.go",
+ "fsgen_mutators.go",
+ "prebuilt_etc_modules_gen.go",
+ "super_img.go",
+ "util.go",
+ "vbmeta_partitions.go",
+ ],
+ testSrcs: [
+ "filesystem_creator_test.go",
+ ],
+ pluginFor: ["soong_build"],
+ visibility: ["//visibility:public"],
+}
+
+soong_filesystem_creator {
+ name: "soong_filesystem_creator",
+}
diff --git a/fsgen/boot_imgs.go b/fsgen/boot_imgs.go
new file mode 100644
index 0000000..58ebcc4
--- /dev/null
+++ b/fsgen/boot_imgs.go
@@ -0,0 +1,339 @@
+package fsgen
+
+import (
+ "android/soong/android"
+ "android/soong/filesystem"
+ "fmt"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ "github.com/google/blueprint/proptools"
+)
+
+func createBootImage(ctx android.LoadHookContext, dtbImg dtbImg) bool {
+ partitionVariables := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+
+ if partitionVariables.TargetKernelPath == "" {
+ // There are potentially code paths that don't set TARGET_KERNEL_PATH
+ return false
+ }
+
+ kernelDir := filepath.Dir(partitionVariables.TargetKernelPath)
+ kernelBase := filepath.Base(partitionVariables.TargetKernelPath)
+ kernelFilegroupName := generatedModuleName(ctx.Config(), "kernel")
+
+ ctx.CreateModuleInDirectory(
+ android.FileGroupFactory,
+ kernelDir,
+ &struct {
+ Name *string
+ Srcs []string
+ Visibility []string
+ }{
+ Name: proptools.StringPtr(kernelFilegroupName),
+ Srcs: []string{kernelBase},
+ Visibility: []string{"//visibility:public"},
+ },
+ )
+
+ var partitionSize *int64
+ if partitionVariables.BoardBootimagePartitionSize != "" {
+ // Base of zero will allow base 10 or base 16 if starting with 0x
+ parsed, err := strconv.ParseInt(partitionVariables.BoardBootimagePartitionSize, 0, 64)
+ if err != nil {
+ panic(fmt.Sprintf("BOARD_BOOTIMAGE_PARTITION_SIZE must be an int, got %s", partitionVariables.BoardBootimagePartitionSize))
+ }
+ partitionSize = &parsed
+ }
+
+ var securityPatch *string
+ if partitionVariables.BootSecurityPatch != "" {
+ securityPatch = &partitionVariables.BootSecurityPatch
+ }
+
+ avbInfo := getAvbInfo(ctx.Config(), "boot")
+
+ bootImageName := generatedModuleNameForPartition(ctx.Config(), "boot")
+
+ var dtbPrebuilt *string
+ if dtbImg.include && dtbImg.imgType == "boot" {
+ dtbPrebuilt = proptools.StringPtr(":" + dtbImg.name)
+ }
+
+ var cmdline []string
+ if !buildingVendorBootImage(partitionVariables) {
+ cmdline = partitionVariables.InternalKernelCmdline
+ }
+
+ ctx.CreateModule(
+ filesystem.BootimgFactory,
+ &filesystem.BootimgProperties{
+ Kernel_prebuilt: proptools.StringPtr(":" + kernelFilegroupName),
+ Header_version: proptools.StringPtr(partitionVariables.BoardBootHeaderVersion),
+ Partition_size: partitionSize,
+ Use_avb: avbInfo.avbEnable,
+ Avb_mode: avbInfo.avbMode,
+ Avb_private_key: avbInfo.avbkeyFilegroup,
+ Avb_rollback_index: avbInfo.avbRollbackIndex,
+ Avb_rollback_index_location: avbInfo.avbRollbackIndexLocation,
+ Avb_algorithm: avbInfo.avbAlgorithm,
+ Security_patch: securityPatch,
+ Dtb_prebuilt: dtbPrebuilt,
+ Cmdline: cmdline,
+ Stem: proptools.StringPtr("boot.img"),
+ },
+ &struct {
+ Name *string
+ Visibility []string
+ }{
+ Name: proptools.StringPtr(bootImageName),
+ Visibility: []string{"//visibility:public"},
+ },
+ )
+ return true
+}
+
+func createVendorBootImage(ctx android.LoadHookContext, dtbImg dtbImg) bool {
+ partitionVariables := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+
+ bootImageName := generatedModuleNameForPartition(ctx.Config(), "vendor_boot")
+
+ avbInfo := getAvbInfo(ctx.Config(), "vendor_boot")
+
+ var dtbPrebuilt *string
+ if dtbImg.include && dtbImg.imgType == "vendor_boot" {
+ dtbPrebuilt = proptools.StringPtr(":" + dtbImg.name)
+ }
+
+ cmdline := partitionVariables.InternalKernelCmdline
+
+ var vendorBootConfigImg *string
+ if name, ok := createVendorBootConfigImg(ctx); ok {
+ vendorBootConfigImg = proptools.StringPtr(":" + name)
+ }
+
+ var partitionSize *int64
+ if partitionVariables.BoardVendorBootimagePartitionSize != "" {
+ // Base of zero will allow base 10 or base 16 if starting with 0x
+ parsed, err := strconv.ParseInt(partitionVariables.BoardVendorBootimagePartitionSize, 0, 64)
+ if err != nil {
+ ctx.ModuleErrorf("BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE must be an int, got %s", partitionVariables.BoardVendorBootimagePartitionSize)
+ }
+ partitionSize = &parsed
+ }
+
+ ctx.CreateModule(
+ filesystem.BootimgFactory,
+ &filesystem.BootimgProperties{
+ Boot_image_type: proptools.StringPtr("vendor_boot"),
+ Ramdisk_module: proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "vendor_ramdisk")),
+ Header_version: proptools.StringPtr(partitionVariables.BoardBootHeaderVersion),
+ Partition_size: partitionSize,
+ Use_avb: avbInfo.avbEnable,
+ Avb_mode: avbInfo.avbMode,
+ Avb_private_key: avbInfo.avbkeyFilegroup,
+ Avb_rollback_index: avbInfo.avbRollbackIndex,
+ Avb_rollback_index_location: avbInfo.avbRollbackIndexLocation,
+ Dtb_prebuilt: dtbPrebuilt,
+ Cmdline: cmdline,
+ Bootconfig: vendorBootConfigImg,
+ Stem: proptools.StringPtr("vendor_boot.img"),
+ },
+ &struct {
+ Name *string
+ Visibility []string
+ }{
+ Name: proptools.StringPtr(bootImageName),
+ Visibility: []string{"//visibility:public"},
+ },
+ )
+ return true
+}
+
+func createInitBootImage(ctx android.LoadHookContext) bool {
+ partitionVariables := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+
+ bootImageName := generatedModuleNameForPartition(ctx.Config(), "init_boot")
+
+ var securityPatch *string
+ if partitionVariables.InitBootSecurityPatch != "" {
+ securityPatch = &partitionVariables.InitBootSecurityPatch
+ } else if partitionVariables.BootSecurityPatch != "" {
+ securityPatch = &partitionVariables.BootSecurityPatch
+ }
+
+ var partitionSize *int64
+ if partitionVariables.BoardInitBootimagePartitionSize != "" {
+ // Base of zero will allow base 10 or base 16 if starting with 0x
+ parsed, err := strconv.ParseInt(partitionVariables.BoardInitBootimagePartitionSize, 0, 64)
+ if err != nil {
+ panic(fmt.Sprintf("BOARD_INIT_BOOT_IMAGE_PARTITION_SIZE must be an int, got %s", partitionVariables.BoardInitBootimagePartitionSize))
+ }
+ partitionSize = &parsed
+ }
+
+ avbInfo := getAvbInfo(ctx.Config(), "init_boot")
+
+ ctx.CreateModule(
+ filesystem.BootimgFactory,
+ &filesystem.BootimgProperties{
+ Boot_image_type: proptools.StringPtr("init_boot"),
+ Ramdisk_module: proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "ramdisk")),
+ Header_version: proptools.StringPtr(partitionVariables.BoardBootHeaderVersion),
+ Security_patch: securityPatch,
+ Partition_size: partitionSize,
+ Use_avb: avbInfo.avbEnable,
+ Avb_mode: avbInfo.avbMode,
+ Avb_private_key: avbInfo.avbkeyFilegroup,
+ Avb_rollback_index: avbInfo.avbRollbackIndex,
+ Avb_rollback_index_location: avbInfo.avbRollbackIndexLocation,
+ Avb_algorithm: avbInfo.avbAlgorithm,
+ Stem: proptools.StringPtr("init_boot.img"),
+ },
+ &struct {
+ Name *string
+ Visibility []string
+ }{
+ Name: proptools.StringPtr(bootImageName),
+ Visibility: []string{"//visibility:public"},
+ },
+ )
+ return true
+}
+
+// Returns the equivalent of the BUILDING_BOOT_IMAGE variable in make. Derived from this logic:
+// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/board_config.mk;l=458;drc=5b55f926830963c02ab1d2d91e46442f04ba3af0
+func buildingBootImage(partitionVars android.PartitionVariables) bool {
+ if partitionVars.BoardUsesRecoveryAsBoot {
+ return false
+ }
+
+ if partitionVars.ProductBuildBootImage {
+ return true
+ }
+
+ if len(partitionVars.BoardPrebuiltBootimage) > 0 {
+ return false
+ }
+
+ if len(partitionVars.BoardBootimagePartitionSize) > 0 {
+ return true
+ }
+
+ // TODO: return true if BOARD_KERNEL_BINARIES is set and has a *_BOOTIMAGE_PARTITION_SIZE
+ // variable. However, I don't think BOARD_KERNEL_BINARIES is ever set in practice.
+
+ return false
+}
+
+// Returns the equivalent of the BUILDING_VENDOR_BOOT_IMAGE variable in make. Derived from this logic:
+// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/board_config.mk;l=518;drc=5b55f926830963c02ab1d2d91e46442f04ba3af0
+func buildingVendorBootImage(partitionVars android.PartitionVariables) bool {
+ if v, exists := boardBootHeaderVersion(partitionVars); exists && v >= 3 {
+ x := partitionVars.ProductBuildVendorBootImage
+ if x == "" || x == "true" {
+ return true
+ }
+ }
+
+ return false
+}
+
+// Derived from: https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/board_config.mk;l=480;drc=5b55f926830963c02ab1d2d91e46442f04ba3af0
+func buildingInitBootImage(partitionVars android.PartitionVariables) bool {
+ if !partitionVars.ProductBuildInitBootImage {
+ if partitionVars.BoardUsesRecoveryAsBoot || len(partitionVars.BoardPrebuiltInitBootimage) > 0 {
+ return false
+ } else if len(partitionVars.BoardInitBootimagePartitionSize) > 0 {
+ return true
+ }
+ } else {
+ if partitionVars.BoardUsesRecoveryAsBoot {
+ panic("PRODUCT_BUILD_INIT_BOOT_IMAGE is true, but so is BOARD_USES_RECOVERY_AS_BOOT. Use only one option.")
+ }
+ return true
+ }
+ return false
+}
+
+func boardBootHeaderVersion(partitionVars android.PartitionVariables) (int, bool) {
+ if len(partitionVars.BoardBootHeaderVersion) == 0 {
+ return 0, false
+ }
+ v, err := strconv.ParseInt(partitionVars.BoardBootHeaderVersion, 10, 32)
+ if err != nil {
+ panic(fmt.Sprintf("BOARD_BOOT_HEADER_VERSION must be an int, got: %q", partitionVars.BoardBootHeaderVersion))
+ }
+ return int(v), true
+}
+
+type dtbImg struct {
+ // whether to include the dtb image in boot image
+ include bool
+
+ // name of the generated dtb image filegroup name
+ name string
+
+ // type of the boot image that the dtb image argument should be specified
+ imgType string
+}
+
+func createDtbImgFilegroup(ctx android.LoadHookContext) dtbImg {
+ partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+ if !partitionVars.BoardIncludeDtbInBootimg {
+ return dtbImg{include: false}
+ }
+ for _, copyFilePair := range partitionVars.ProductCopyFiles {
+ srcDestList := strings.Split(copyFilePair, ":")
+ if len(srcDestList) < 2 {
+ ctx.ModuleErrorf("PRODUCT_COPY_FILES must follow the format \"src:dest\", got: %s", copyFilePair)
+ }
+ if srcDestList[1] == "dtb.img" {
+ moduleName := generatedModuleName(ctx.Config(), "dtb_img_filegroup")
+ ctx.CreateModuleInDirectory(
+ android.FileGroupFactory,
+ filepath.Dir(srcDestList[0]),
+ &struct {
+ Name *string
+ Srcs []string
+ }{
+ Name: proptools.StringPtr(moduleName),
+ Srcs: []string{filepath.Base(srcDestList[1])},
+ },
+ )
+ imgType := "vendor_boot"
+ if !buildingVendorBootImage(partitionVars) {
+ imgType = "boot"
+ }
+ return dtbImg{include: true, name: moduleName, imgType: imgType}
+ }
+ }
+ return dtbImg{include: false}
+}
+
+func createVendorBootConfigImg(ctx android.LoadHookContext) (string, bool) {
+ partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+ bootconfig := partitionVars.InternalBootconfig
+ bootconfigFile := partitionVars.InternalBootconfigFile
+ if len(bootconfig) == 0 && len(bootconfigFile) == 0 {
+ return "", false
+ }
+
+ vendorBootconfigImgModuleName := generatedModuleName(ctx.Config(), "vendor_bootconfig_image")
+
+ ctx.CreateModule(
+ filesystem.BootconfigModuleFactory,
+ &struct {
+ Name *string
+ Boot_config []string
+ Boot_config_file *string
+ }{
+ Name: proptools.StringPtr(vendorBootconfigImgModuleName),
+ Boot_config: bootconfig,
+ Boot_config_file: proptools.StringPtr(bootconfigFile),
+ },
+ )
+
+ return vendorBootconfigImgModuleName, true
+}
diff --git a/fsgen/config.go b/fsgen/config.go
new file mode 100644
index 0000000..a217600
--- /dev/null
+++ b/fsgen/config.go
@@ -0,0 +1,141 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package fsgen
+
+import (
+ "android/soong/filesystem"
+
+ "github.com/google/blueprint/proptools"
+)
+
+var (
+ // Most of the symlinks and directories listed here originate from create_root_structure.mk,
+ // but the handwritten generic system image also recreates them:
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/target/product/generic/Android.bp;l=33;drc=db08311f1b6ef6cb0a4fbcc6263b89849360ce04
+ // TODO(b/377734331): only generate the symlinks if the relevant partitions exist
+ commonSymlinksFromRoot = []filesystem.SymlinkDefinition{
+ {
+ Target: proptools.StringPtr("/system/bin/init"),
+ Name: proptools.StringPtr("init"),
+ },
+ {
+ Target: proptools.StringPtr("/system/etc"),
+ Name: proptools.StringPtr("etc"),
+ },
+ {
+ Target: proptools.StringPtr("/system/bin"),
+ Name: proptools.StringPtr("bin"),
+ },
+ {
+ Target: proptools.StringPtr("/data/user_de/0/com.android.shell/files/bugreports"),
+ Name: proptools.StringPtr("bugreports"),
+ },
+ {
+ Target: proptools.StringPtr("/sys/kernel/debug"),
+ Name: proptools.StringPtr("d"),
+ },
+ {
+ Target: proptools.StringPtr("/product/etc/security/adb_keys"),
+ Name: proptools.StringPtr("adb_keys"),
+ },
+ {
+ Target: proptools.StringPtr("/vendor/odm/app"),
+ Name: proptools.StringPtr("odm/app"),
+ },
+ {
+ Target: proptools.StringPtr("/vendor/odm/bin"),
+ Name: proptools.StringPtr("odm/bin"),
+ },
+ {
+ Target: proptools.StringPtr("/vendor/odm/etc"),
+ Name: proptools.StringPtr("odm/etc"),
+ },
+ {
+ Target: proptools.StringPtr("/vendor/odm/firmware"),
+ Name: proptools.StringPtr("odm/firmware"),
+ },
+ {
+ Target: proptools.StringPtr("/vendor/odm/framework"),
+ Name: proptools.StringPtr("odm/framework"),
+ },
+ {
+ Target: proptools.StringPtr("/vendor/odm/lib"),
+ Name: proptools.StringPtr("odm/lib"),
+ },
+ {
+ Target: proptools.StringPtr("/vendor/odm/lib64"),
+ Name: proptools.StringPtr("odm/lib64"),
+ },
+ {
+ Target: proptools.StringPtr("/vendor/odm/overlay"),
+ Name: proptools.StringPtr("odm/overlay"),
+ },
+ {
+ Target: proptools.StringPtr("/vendor/odm/priv-app"),
+ Name: proptools.StringPtr("odm/priv-app"),
+ },
+ {
+ Target: proptools.StringPtr("/vendor/odm/usr"),
+ Name: proptools.StringPtr("odm/usr"),
+ },
+ // For Treble Generic System Image (GSI), system-as-root GSI needs to work on
+ // both devices with and without /odm_dlkm partition. Those symlinks are for
+ // devices without /odm_dlkm partition. For devices with /odm_dlkm
+ // partition, mount odm_dlkm.img under /odm_dlkm will hide those symlinks.
+ // Note that /odm_dlkm/lib is omitted because odm DLKMs should be accessed
+ // via /odm/lib/modules directly. All of this also applies to the vendor_dlkm symlink
+ {
+ Target: proptools.StringPtr("/odm/odm_dlkm/etc"),
+ Name: proptools.StringPtr("odm_dlkm/etc"),
+ },
+ {
+ Target: proptools.StringPtr("/vendor/vendor_dlkm/etc"),
+ Name: proptools.StringPtr("vendor_dlkm/etc"),
+ },
+ }
+
+ // Common directories between partitions that may be listed as `Dirs` property in the
+ // filesystem module.
+ commonPartitionDirs = []string{
+ // From generic_rootdirs in build/make/target/product/generic/Android.bp
+ "apex",
+ "bootstrap-apex",
+ "config",
+ "data",
+ "data_mirror",
+ "debug_ramdisk",
+ "dev",
+ "linkerconfig",
+ "metadata",
+ "mnt",
+ "odm",
+ "odm_dlkm",
+ "oem",
+ "postinstall",
+ "proc",
+ "second_stage_resources",
+ "storage",
+ "sys",
+ "system",
+ "system_dlkm",
+ "tmp",
+ "vendor",
+ "vendor_dlkm",
+
+ // from android_rootdirs in build/make/target/product/generic/Android.bp
+ "system_ext",
+ "product",
+ }
+)
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
new file mode 100644
index 0000000..9dcbec1
--- /dev/null
+++ b/fsgen/filesystem_creator.go
@@ -0,0 +1,1253 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package fsgen
+
+import (
+ "crypto/sha256"
+ "fmt"
+ "path/filepath"
+ "slices"
+ "strconv"
+ "strings"
+
+ "android/soong/android"
+ "android/soong/filesystem"
+ "android/soong/kernel"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/parser"
+ "github.com/google/blueprint/proptools"
+)
+
+var pctx = android.NewPackageContext("android/soong/fsgen")
+
+func init() {
+ registerBuildComponents(android.InitRegistrationContext)
+}
+
+func registerBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("soong_filesystem_creator", filesystemCreatorFactory)
+ ctx.PreDepsMutators(RegisterCollectFileSystemDepsMutators)
+}
+
+type generatedPartitionData struct {
+ partitionType string
+ moduleName string
+ // supported is true if the module was created successfully, false if there was some problem
+ // and the module couldn't be created.
+ supported bool
+ handwritten bool
+}
+
+type allGeneratedPartitionData []generatedPartitionData
+
+func (d allGeneratedPartitionData) moduleNames() []string {
+ var result []string
+ for _, data := range d {
+ if data.supported {
+ result = append(result, data.moduleName)
+ }
+ }
+ return result
+}
+
+func (d allGeneratedPartitionData) types() []string {
+ var result []string
+ for _, data := range d {
+ if data.supported {
+ result = append(result, data.partitionType)
+ }
+ }
+ return result
+}
+
+func (d allGeneratedPartitionData) unsupportedTypes() []string {
+ var result []string
+ for _, data := range d {
+ if !data.supported {
+ result = append(result, data.partitionType)
+ }
+ }
+ return result
+}
+
+func (d allGeneratedPartitionData) names() []string {
+ var result []string
+ for _, data := range d {
+ if data.supported {
+ result = append(result, data.moduleName)
+ }
+ }
+ return result
+}
+
+func (d allGeneratedPartitionData) nameForType(ty string) string {
+ for _, data := range d {
+ if data.supported && data.partitionType == ty {
+ return data.moduleName
+ }
+ }
+ return ""
+}
+
+func (d allGeneratedPartitionData) typeForName(name string) string {
+ for _, data := range d {
+ if data.supported && data.moduleName == name {
+ return data.partitionType
+ }
+ }
+ return ""
+}
+
+func (d allGeneratedPartitionData) isHandwritten(name string) bool {
+ for _, data := range d {
+ if data.supported && data.moduleName == name {
+ return data.handwritten
+ }
+ }
+ return false
+}
+
+type filesystemCreatorProps struct {
+ Unsupported_partition_types []string `blueprint:"mutated"`
+
+ Vbmeta_module_names []string `blueprint:"mutated"`
+ Vbmeta_partition_names []string `blueprint:"mutated"`
+
+ Boot_image string `blueprint:"mutated" android:"path_device_first"`
+ Vendor_boot_image string `blueprint:"mutated" android:"path_device_first"`
+ Init_boot_image string `blueprint:"mutated" android:"path_device_first"`
+ Super_image string `blueprint:"mutated" android:"path_device_first"`
+}
+
+type filesystemCreator struct {
+ android.ModuleBase
+
+ properties filesystemCreatorProps
+}
+
+func filesystemCreatorFactory() android.Module {
+ module := &filesystemCreator{}
+
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ module.AddProperties(&module.properties)
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ generatedPrebuiltEtcModuleNames := createPrebuiltEtcModules(ctx)
+ avbpubkeyGenerated := createAvbpubkeyModule(ctx)
+ createFsGenState(ctx, generatedPrebuiltEtcModuleNames, avbpubkeyGenerated)
+ module.createAvbKeyFilegroups(ctx)
+ module.createMiscFilegroups(ctx)
+ module.createInternalModules(ctx)
+ })
+
+ return module
+}
+
+func generatedPartitions(ctx android.EarlyModuleContext) allGeneratedPartitionData {
+ partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+
+ var result allGeneratedPartitionData
+ addGenerated := func(ty string) {
+ result = append(result, generatedPartitionData{
+ partitionType: ty,
+ moduleName: generatedModuleNameForPartition(ctx.Config(), ty),
+ supported: true,
+ })
+ }
+
+ if ctx.Config().UseSoongSystemImage() {
+ if ctx.Config().SoongDefinedSystemImage() == "" {
+ panic("PRODUCT_SOONG_DEFINED_SYSTEM_IMAGE must be set if USE_SOONG_DEFINED_SYSTEM_IMAGE is true")
+ }
+ result = append(result, generatedPartitionData{
+ partitionType: "system",
+ moduleName: ctx.Config().SoongDefinedSystemImage(),
+ supported: true,
+ handwritten: true,
+ })
+ } else {
+ addGenerated("system")
+ }
+ if ctx.DeviceConfig().SystemExtPath() == "system_ext" {
+ addGenerated("system_ext")
+ }
+ if ctx.DeviceConfig().BuildingVendorImage() && ctx.DeviceConfig().VendorPath() == "vendor" {
+ addGenerated("vendor")
+ }
+ if ctx.DeviceConfig().BuildingProductImage() && ctx.DeviceConfig().ProductPath() == "product" {
+ addGenerated("product")
+ }
+ if ctx.DeviceConfig().BuildingOdmImage() && ctx.DeviceConfig().OdmPath() == "odm" {
+ addGenerated("odm")
+ }
+ if ctx.DeviceConfig().BuildingUserdataImage() && ctx.DeviceConfig().UserdataPath() == "data" {
+ addGenerated("userdata")
+ }
+ if partitionVars.BuildingSystemDlkmImage {
+ addGenerated("system_dlkm")
+ }
+ if partitionVars.BuildingVendorDlkmImage {
+ addGenerated("vendor_dlkm")
+ }
+ if partitionVars.BuildingOdmDlkmImage {
+ addGenerated("odm_dlkm")
+ }
+ if partitionVars.BuildingRamdiskImage {
+ addGenerated("ramdisk")
+ }
+ if buildingVendorBootImage(partitionVars) {
+ addGenerated("vendor_ramdisk")
+ }
+ if ctx.DeviceConfig().BuildingRecoveryImage() && ctx.DeviceConfig().RecoveryPath() == "recovery" {
+ addGenerated("recovery")
+ }
+ return result
+}
+
+func (f *filesystemCreator) createInternalModules(ctx android.LoadHookContext) {
+ partitions := generatedPartitions(ctx)
+ for i := range partitions {
+ f.createPartition(ctx, partitions, &partitions[i])
+ }
+ // Create android_info.prop
+ f.createAndroidInfo(ctx)
+
+ partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+ dtbImg := createDtbImgFilegroup(ctx)
+
+ if buildingBootImage(partitionVars) {
+ if createBootImage(ctx, dtbImg) {
+ f.properties.Boot_image = ":" + generatedModuleNameForPartition(ctx.Config(), "boot")
+ } else {
+ f.properties.Unsupported_partition_types = append(f.properties.Unsupported_partition_types, "boot")
+ }
+ }
+ if buildingVendorBootImage(partitionVars) {
+ if createVendorBootImage(ctx, dtbImg) {
+ f.properties.Vendor_boot_image = ":" + generatedModuleNameForPartition(ctx.Config(), "vendor_boot")
+ } else {
+ f.properties.Unsupported_partition_types = append(f.properties.Unsupported_partition_types, "vendor_boot")
+ }
+ }
+ if buildingInitBootImage(partitionVars) {
+ if createInitBootImage(ctx) {
+ f.properties.Init_boot_image = ":" + generatedModuleNameForPartition(ctx.Config(), "init_boot")
+ } else {
+ f.properties.Unsupported_partition_types = append(f.properties.Unsupported_partition_types, "init_boot")
+ }
+ }
+
+ var systemOtherImageName string
+ if buildingSystemOtherImage(partitionVars) {
+ systemModule := partitions.nameForType("system")
+ systemOtherImageName = generatedModuleNameForPartition(ctx.Config(), "system_other")
+ ctx.CreateModule(
+ filesystem.SystemOtherImageFactory,
+ &filesystem.SystemOtherImageProperties{
+ System_image: &systemModule,
+ Preinstall_dexpreopt_files_from: partitions.moduleNames(),
+ },
+ &struct {
+ Name *string
+ }{
+ Name: proptools.StringPtr(systemOtherImageName),
+ },
+ )
+ }
+
+ for _, x := range f.createVbmetaPartitions(ctx, partitions) {
+ f.properties.Vbmeta_module_names = append(f.properties.Vbmeta_module_names, x.moduleName)
+ f.properties.Vbmeta_partition_names = append(f.properties.Vbmeta_partition_names, x.partitionName)
+ }
+
+ var superImageSubpartitions []string
+ if buildingSuperImage(partitionVars) {
+ superImageSubpartitions = createSuperImage(ctx, partitions, partitionVars, systemOtherImageName)
+ f.properties.Super_image = ":" + generatedModuleNameForPartition(ctx.Config(), "super")
+ }
+
+ ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).soongGeneratedPartitions = partitions
+ f.createDeviceModule(ctx, partitions, f.properties.Vbmeta_module_names, superImageSubpartitions)
+}
+
+func generatedModuleName(cfg android.Config, suffix string) string {
+ prefix := "soong"
+ if cfg.HasDeviceProduct() {
+ prefix = cfg.DeviceProduct()
+ }
+ return fmt.Sprintf("%s_generated_%s", prefix, suffix)
+}
+
+func generatedModuleNameForPartition(cfg android.Config, partitionType string) string {
+ return generatedModuleName(cfg, fmt.Sprintf("%s_image", partitionType))
+}
+
+func buildingSystemOtherImage(partitionVars android.PartitionVariables) bool {
+ // TODO: Recreate this logic from make instead of just depending on the final result variable:
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/board_config.mk;l=429;drc=15a0df840e7093f65518003ab80cf24a3d9e8e6a
+ return partitionVars.BuildingSystemOtherImage
+}
+
+func (f *filesystemCreator) createBootloaderFilegroup(ctx android.LoadHookContext) (string, bool) {
+ bootloaderPath := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.PrebuiltBootloader
+ if len(bootloaderPath) == 0 {
+ return "", false
+ }
+
+ bootloaderFilegroupName := generatedModuleName(ctx.Config(), "bootloader")
+ filegroupProps := &struct {
+ Name *string
+ Srcs []string
+ Visibility []string
+ }{
+ Name: proptools.StringPtr(bootloaderFilegroupName),
+ Srcs: []string{bootloaderPath},
+ Visibility: []string{"//visibility:public"},
+ }
+ ctx.CreateModuleInDirectory(android.FileGroupFactory, ".", filegroupProps)
+ return bootloaderFilegroupName, true
+}
+
+func (f *filesystemCreator) createDeviceModule(
+ ctx android.LoadHookContext,
+ partitions allGeneratedPartitionData,
+ vbmetaPartitions []string,
+ superImageSubPartitions []string,
+) {
+ baseProps := &struct {
+ Name *string
+ Android_info *string
+ }{
+ Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "device")),
+ Android_info: proptools.StringPtr(":" + generatedModuleName(ctx.Config(), "android_info.prop{.txt}")),
+ }
+
+ // Currently, only the system and system_ext partition module is created.
+ partitionProps := &filesystem.PartitionNameProperties{}
+ if f.properties.Super_image != "" {
+ partitionProps.Super_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "super"))
+ }
+ if modName := partitions.nameForType("system"); modName != "" && !android.InList("system", superImageSubPartitions) {
+ partitionProps.System_partition_name = proptools.StringPtr(modName)
+ }
+ if modName := partitions.nameForType("system_ext"); modName != "" && !android.InList("system_ext", superImageSubPartitions) {
+ partitionProps.System_ext_partition_name = proptools.StringPtr(modName)
+ }
+ if modName := partitions.nameForType("vendor"); modName != "" && !android.InList("vendor", superImageSubPartitions) {
+ partitionProps.Vendor_partition_name = proptools.StringPtr(modName)
+ }
+ if modName := partitions.nameForType("product"); modName != "" && !android.InList("product", superImageSubPartitions) {
+ partitionProps.Product_partition_name = proptools.StringPtr(modName)
+ }
+ if modName := partitions.nameForType("odm"); modName != "" && !android.InList("odm", superImageSubPartitions) {
+ partitionProps.Odm_partition_name = proptools.StringPtr(modName)
+ }
+ if modName := partitions.nameForType("userdata"); modName != "" {
+ partitionProps.Userdata_partition_name = proptools.StringPtr(modName)
+ }
+ if modName := partitions.nameForType("recovery"); modName != "" {
+ partitionProps.Recovery_partition_name = proptools.StringPtr(modName)
+ }
+ if modName := partitions.nameForType("system_dlkm"); modName != "" && !android.InList("system_dlkm", superImageSubPartitions) {
+ partitionProps.System_dlkm_partition_name = proptools.StringPtr(modName)
+ }
+ if modName := partitions.nameForType("vendor_dlkm"); modName != "" && !android.InList("vendor_dlkm", superImageSubPartitions) {
+ partitionProps.Vendor_dlkm_partition_name = proptools.StringPtr(modName)
+ }
+ if modName := partitions.nameForType("odm_dlkm"); modName != "" && !android.InList("odm_dlkm", superImageSubPartitions) {
+ partitionProps.Odm_dlkm_partition_name = proptools.StringPtr(modName)
+ }
+ if f.properties.Boot_image != "" {
+ partitionProps.Boot_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "boot"))
+ }
+ if f.properties.Vendor_boot_image != "" {
+ partitionProps.Vendor_boot_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "vendor_boot"))
+ }
+ if f.properties.Init_boot_image != "" {
+ partitionProps.Init_boot_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "init_boot"))
+ }
+ partitionProps.Vbmeta_partitions = vbmetaPartitions
+
+ deviceProps := &filesystem.DeviceProperties{
+ Main_device: proptools.BoolPtr(true),
+ Ab_ota_updater: proptools.BoolPtr(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.AbOtaUpdater),
+ }
+ if bootloader, ok := f.createBootloaderFilegroup(ctx); ok {
+ deviceProps.Bootloader = proptools.StringPtr(":" + bootloader)
+ }
+
+ ctx.CreateModule(filesystem.AndroidDeviceFactory, baseProps, partitionProps, deviceProps)
+}
+
+func partitionSpecificFsProps(ctx android.EarlyModuleContext, partitions allGeneratedPartitionData, fsProps *filesystem.FilesystemProperties, partitionType string) {
+ partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+ switch partitionType {
+ case "system":
+ fsProps.Build_logtags = proptools.BoolPtr(true)
+ // https://source.corp.google.com/h/googleplex-android/platform/build//639d79f5012a6542ab1f733b0697db45761ab0f3:core/packaging/flags.mk;l=21;drc=5ba8a8b77507f93aa48cc61c5ba3f31a4d0cbf37;bpv=1;bpt=0
+ fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true)
+ // Identical to that of the aosp_shared_system_image
+ if partitionVars.ProductFsverityGenerateMetadata {
+ fsProps.Fsverity.Inputs = proptools.NewSimpleConfigurable([]string{
+ "etc/boot-image.prof",
+ "etc/dirty-image-objects",
+ "etc/preloaded-classes",
+ "etc/classpaths/*.pb",
+ "framework/*",
+ "framework/*/*", // framework/{arch}
+ "framework/oat/*/*", // framework/oat/{arch}
+ })
+ fsProps.Fsverity.Libs = proptools.NewSimpleConfigurable([]string{":framework-res{.export-package.apk}"})
+ }
+ fsProps.Symlinks = commonSymlinksFromRoot
+ fsProps.Symlinks = append(fsProps.Symlinks,
+ []filesystem.SymlinkDefinition{
+ {
+ Target: proptools.StringPtr("/data/cache"),
+ Name: proptools.StringPtr("cache"),
+ },
+ {
+ Target: proptools.StringPtr("/storage/self/primary"),
+ Name: proptools.StringPtr("sdcard"),
+ },
+ {
+ Target: proptools.StringPtr("/system_dlkm/lib/modules"),
+ Name: proptools.StringPtr("system/lib/modules"),
+ },
+ {
+ Target: proptools.StringPtr("/product"),
+ Name: proptools.StringPtr("system/product"),
+ },
+ {
+ Target: proptools.StringPtr("/system_ext"),
+ Name: proptools.StringPtr("system/system_ext"),
+ },
+ {
+ Target: proptools.StringPtr("/vendor"),
+ Name: proptools.StringPtr("system/vendor"),
+ },
+ }...,
+ )
+ fsProps.Base_dir = proptools.StringPtr("system")
+ fsProps.Dirs = proptools.NewSimpleConfigurable(commonPartitionDirs)
+ fsProps.Security_patch = proptools.StringPtr(ctx.Config().PlatformSecurityPatch())
+
+ if systemExtName := partitions.nameForType("system_ext"); systemExtName != "" {
+ fsProps.Import_aconfig_flags_from = []string{systemExtName}
+ }
+ fsProps.Stem = proptools.StringPtr("system.img")
+ case "system_ext":
+ if partitionVars.ProductFsverityGenerateMetadata {
+ fsProps.Fsverity.Inputs = proptools.NewSimpleConfigurable([]string{
+ "framework/*",
+ "framework/*/*", // framework/{arch}
+ "framework/oat/*/*", // framework/oat/{arch}
+ })
+ fsProps.Fsverity.Libs = proptools.NewSimpleConfigurable([]string{":framework-res{.export-package.apk}"})
+ }
+ fsProps.Security_patch = proptools.StringPtr(ctx.Config().PlatformSecurityPatch())
+ fsProps.Stem = proptools.StringPtr("system_ext.img")
+ case "product":
+ fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true)
+ fsProps.Android_filesystem_deps.System = proptools.StringPtr(partitions.nameForType("system"))
+ if systemExtName := partitions.nameForType("system_ext"); systemExtName != "" {
+ fsProps.Android_filesystem_deps.System_ext = proptools.StringPtr(systemExtName)
+ }
+ fsProps.Security_patch = proptools.StringPtr(ctx.Config().PlatformSecurityPatch())
+ fsProps.Stem = proptools.StringPtr("product.img")
+ case "vendor":
+ fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true)
+ fsProps.Symlinks = []filesystem.SymlinkDefinition{
+ filesystem.SymlinkDefinition{
+ Target: proptools.StringPtr("/odm"),
+ Name: proptools.StringPtr("odm"),
+ },
+ filesystem.SymlinkDefinition{
+ Target: proptools.StringPtr("/vendor_dlkm/lib/modules"),
+ Name: proptools.StringPtr("lib/modules"),
+ },
+ }
+ fsProps.Android_filesystem_deps.System = proptools.StringPtr(partitions.nameForType("system"))
+ if systemExtName := partitions.nameForType("system_ext"); systemExtName != "" {
+ fsProps.Android_filesystem_deps.System_ext = proptools.StringPtr(systemExtName)
+ }
+ fsProps.Security_patch = proptools.StringPtr(partitionVars.VendorSecurityPatch)
+ fsProps.Stem = proptools.StringPtr("vendor.img")
+ case "odm":
+ fsProps.Symlinks = []filesystem.SymlinkDefinition{
+ filesystem.SymlinkDefinition{
+ Target: proptools.StringPtr("/odm_dlkm/lib/modules"),
+ Name: proptools.StringPtr("lib/modules"),
+ },
+ }
+ fsProps.Security_patch = proptools.StringPtr(partitionVars.OdmSecurityPatch)
+ fsProps.Stem = proptools.StringPtr("odm.img")
+ case "userdata":
+ fsProps.Stem = proptools.StringPtr("userdata.img")
+ if vars, ok := partitionVars.PartitionQualifiedVariables["userdata"]; ok {
+ parsed, err := strconv.ParseInt(vars.BoardPartitionSize, 10, 64)
+ if err != nil {
+ panic(fmt.Sprintf("Partition size must be an int, got %s", vars.BoardPartitionSize))
+ }
+ fsProps.Partition_size = &parsed
+ // Disable avb for userdata partition
+ fsProps.Use_avb = nil
+ }
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=2265;drc=7f50a123045520f2c5e18e9eb4e83f92244a1459
+ if s, err := strconv.ParseBool(partitionVars.ProductFsCasefold); err == nil {
+ fsProps.Support_casefolding = proptools.BoolPtr(s)
+ } else if len(partitionVars.ProductFsCasefold) > 0 {
+ ctx.ModuleErrorf("Unrecognized PRODUCT_FS_CASEFOLD value %s", partitionVars.ProductFsCasefold)
+ }
+ if s, err := strconv.ParseBool(partitionVars.ProductQuotaProjid); err == nil {
+ fsProps.Support_project_quota = proptools.BoolPtr(s)
+ } else if len(partitionVars.ProductQuotaProjid) > 0 {
+ ctx.ModuleErrorf("Unrecognized PRODUCT_QUOTA_PROJID value %s", partitionVars.ProductQuotaProjid)
+ }
+ if s, err := strconv.ParseBool(partitionVars.ProductFsCompression); err == nil {
+ fsProps.Enable_compression = proptools.BoolPtr(s)
+ } else if len(partitionVars.ProductFsCompression) > 0 {
+ ctx.ModuleErrorf("Unrecognized PRODUCT_FS_COMPRESSION value %s", partitionVars.ProductFsCompression)
+ }
+
+ case "ramdisk":
+ // Following the logic in https://cs.android.com/android/platform/superproject/main/+/c3c5063df32748a8806ce5da5dd0db158eab9ad9:build/make/core/Makefile;l=1307
+ fsProps.Dirs = android.NewSimpleConfigurable([]string{
+ "debug_ramdisk",
+ "dev",
+ "metadata",
+ "mnt",
+ "proc",
+ "second_stage_resources",
+ "sys",
+ })
+ if partitionVars.BoardUsesGenericKernelImage {
+ fsProps.Dirs.AppendSimpleValue([]string{
+ "first_stage_ramdisk/debug_ramdisk",
+ "first_stage_ramdisk/dev",
+ "first_stage_ramdisk/metadata",
+ "first_stage_ramdisk/mnt",
+ "first_stage_ramdisk/proc",
+ "first_stage_ramdisk/second_stage_resources",
+ "first_stage_ramdisk/sys",
+ })
+ }
+ fsProps.Stem = proptools.StringPtr("ramdisk.img")
+ case "recovery":
+ dirs := append(commonPartitionDirs, []string{
+ "sdcard",
+ }...)
+
+ dirsWithRoot := make([]string, len(dirs))
+ for i, dir := range dirs {
+ dirsWithRoot[i] = filepath.Join("root", dir)
+ }
+
+ fsProps.Dirs = proptools.NewSimpleConfigurable(dirsWithRoot)
+ fsProps.Symlinks = symlinksWithNamePrefix(append(commonSymlinksFromRoot, filesystem.SymlinkDefinition{
+ Target: proptools.StringPtr("prop.default"),
+ Name: proptools.StringPtr("default.prop"),
+ }), "root")
+ fsProps.Stem = proptools.StringPtr("recovery.img")
+ case "system_dlkm":
+ fsProps.Security_patch = proptools.StringPtr(partitionVars.SystemDlkmSecurityPatch)
+ fsProps.Stem = proptools.StringPtr("system_dlkm.img")
+ case "vendor_dlkm":
+ fsProps.Security_patch = proptools.StringPtr(partitionVars.VendorDlkmSecurityPatch)
+ fsProps.Stem = proptools.StringPtr("vendor_dlkm.img")
+ case "odm_dlkm":
+ fsProps.Security_patch = proptools.StringPtr(partitionVars.OdmDlkmSecurityPatch)
+ fsProps.Stem = proptools.StringPtr("odm_dlkm.img")
+ case "vendor_ramdisk":
+ if recoveryName := partitions.nameForType("recovery"); recoveryName != "" {
+ fsProps.Include_files_of = []string{recoveryName}
+ }
+ fsProps.Stem = proptools.StringPtr("vendor_ramdisk.img")
+ }
+}
+
+var (
+ dlkmPartitions = []string{
+ "system_dlkm",
+ "vendor_dlkm",
+ "odm_dlkm",
+ }
+)
+
+// Creates a soong module to build the given partition.
+func (f *filesystemCreator) createPartition(ctx android.LoadHookContext, partitions allGeneratedPartitionData, partition *generatedPartitionData) {
+ // Nextgen team's handwritten soong system image, don't need to create anything ourselves
+ if partition.partitionType == "system" && ctx.Config().UseSoongSystemImage() {
+ return
+ }
+
+ baseProps := generateBaseProps(proptools.StringPtr(partition.moduleName))
+
+ fsProps, supported := generateFsProps(ctx, partitions, partition.partitionType)
+ if !supported {
+ partition.supported = false
+ return
+ }
+
+ partitionType := partition.partitionType
+ if partitionType == "vendor" || partitionType == "product" || partitionType == "system" {
+ fsProps.Linker_config.Gen_linker_config = proptools.BoolPtr(true)
+ if partitionType != "system" {
+ fsProps.Linker_config.Linker_config_srcs = f.createLinkerConfigSourceFilegroups(ctx, partitionType)
+ }
+ }
+
+ if android.InList(partitionType, append(dlkmPartitions, "vendor_ramdisk")) {
+ f.createPrebuiltKernelModules(ctx, partitionType)
+ }
+
+ var module android.Module
+ if partitionType == "system" {
+ module = ctx.CreateModule(filesystem.SystemImageFactory, baseProps, fsProps)
+ } else {
+ // Explicitly set the partition.
+ fsProps.Partition_type = proptools.StringPtr(partitionType)
+ module = ctx.CreateModule(filesystem.FilesystemFactory, baseProps, fsProps)
+ }
+ module.HideFromMake()
+ if partitionType == "vendor" {
+ f.createVendorBuildProp(ctx)
+ }
+}
+
+// Creates filegroups for the files specified in BOARD_(partition_)AVB_KEY_PATH
+func (f *filesystemCreator) createAvbKeyFilegroups(ctx android.LoadHookContext) {
+ partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+ var files []string
+
+ if len(partitionVars.BoardAvbKeyPath) > 0 {
+ files = append(files, partitionVars.BoardAvbKeyPath)
+ }
+ for _, partition := range android.SortedKeys(partitionVars.PartitionQualifiedVariables) {
+ specificPartitionVars := partitionVars.PartitionQualifiedVariables[partition]
+ if len(specificPartitionVars.BoardAvbKeyPath) > 0 {
+ files = append(files, specificPartitionVars.BoardAvbKeyPath)
+ }
+ }
+
+ fsGenState := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
+ for _, file := range files {
+ if _, ok := fsGenState.avbKeyFilegroups[file]; ok {
+ continue
+ }
+ if file == "external/avb/test/data/testkey_rsa4096.pem" {
+ // There already exists a checked-in filegroup for this commonly-used key, just use that
+ fsGenState.avbKeyFilegroups[file] = "avb_testkey_rsa4096"
+ continue
+ }
+ dir := filepath.Dir(file)
+ base := filepath.Base(file)
+ name := fmt.Sprintf("avb_key_%x", strings.ReplaceAll(file, "/", "_"))
+ ctx.CreateModuleInDirectory(
+ android.FileGroupFactory,
+ dir,
+ &struct {
+ Name *string
+ Srcs []string
+ Visibility []string
+ }{
+ Name: proptools.StringPtr(name),
+ Srcs: []string{base},
+ Visibility: []string{"//visibility:public"},
+ },
+ )
+ fsGenState.avbKeyFilegroups[file] = name
+ }
+}
+
+// Creates filegroups for miscellaneous other files
+func (f *filesystemCreator) createMiscFilegroups(ctx android.LoadHookContext) {
+ partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+
+ if partitionVars.BoardErofsCompressorHints != "" {
+ dir := filepath.Dir(partitionVars.BoardErofsCompressorHints)
+ base := filepath.Base(partitionVars.BoardErofsCompressorHints)
+ ctx.CreateModuleInDirectory(
+ android.FileGroupFactory,
+ dir,
+ &struct {
+ Name *string
+ Srcs []string
+ Visibility []string
+ }{
+ Name: proptools.StringPtr("soong_generated_board_erofs_compress_hints_filegroup"),
+ Srcs: []string{base},
+ Visibility: []string{"//visibility:public"},
+ },
+ )
+ }
+}
+
+// createPrebuiltKernelModules creates `prebuilt_kernel_modules`. These modules will be added to deps of the
+// autogenerated *_dlkm filsystem modules. Each _dlkm partition should have a single prebuilt_kernel_modules dependency.
+// This ensures that the depmod artifacts (modules.* installed in /lib/modules/) are generated with a complete view.
+func (f *filesystemCreator) createPrebuiltKernelModules(ctx android.LoadHookContext, partitionType string) {
+ fsGenState := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
+ name := generatedModuleName(ctx.Config(), fmt.Sprintf("%s-kernel-modules", partitionType))
+ props := &struct {
+ Name *string
+ Srcs []string
+ System_deps []string
+ System_dlkm_specific *bool
+ Vendor_dlkm_specific *bool
+ Odm_dlkm_specific *bool
+ Vendor_ramdisk *bool
+ Load_by_default *bool
+ Blocklist_file *string
+ Options_file *string
+ Strip_debug_symbols *bool
+ }{
+ Name: proptools.StringPtr(name),
+ Strip_debug_symbols: proptools.BoolPtr(false),
+ }
+ switch partitionType {
+ case "system_dlkm":
+ props.Srcs = android.ExistentPathsForSources(ctx, ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelModules).Strings()
+ props.System_dlkm_specific = proptools.BoolPtr(true)
+ if len(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelLoadModules) == 0 {
+ // Create empty modules.load file for system
+ // https://source.corp.google.com/h/googleplex-android/platform/build/+/ef55daac9954896161b26db4f3ef1781b5a5694c:core/Makefile;l=695-700;drc=549fe2a5162548bd8b47867d35f907eb22332023;bpv=1;bpt=0
+ props.Load_by_default = proptools.BoolPtr(false)
+ }
+ if blocklistFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelBlocklistFile; blocklistFile != "" {
+ props.Blocklist_file = proptools.StringPtr(blocklistFile)
+ }
+ case "vendor_dlkm":
+ props.Srcs = android.ExistentPathsForSources(ctx, ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorKernelModules).Strings()
+ if len(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelModules) > 0 {
+ props.System_deps = []string{":" + generatedModuleName(ctx.Config(), "system_dlkm-kernel-modules") + "{.modules}"}
+ }
+ props.Vendor_dlkm_specific = proptools.BoolPtr(true)
+ if blocklistFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorKernelBlocklistFile; blocklistFile != "" {
+ props.Blocklist_file = proptools.StringPtr(blocklistFile)
+ }
+ case "odm_dlkm":
+ props.Srcs = android.ExistentPathsForSources(ctx, ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.OdmKernelModules).Strings()
+ props.Odm_dlkm_specific = proptools.BoolPtr(true)
+ if blocklistFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.OdmKernelBlocklistFile; blocklistFile != "" {
+ props.Blocklist_file = proptools.StringPtr(blocklistFile)
+ }
+ case "vendor_ramdisk":
+ props.Srcs = android.ExistentPathsForSources(ctx, ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorRamdiskKernelModules).Strings()
+ props.Vendor_ramdisk = proptools.BoolPtr(true)
+ if blocklistFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorRamdiskKernelBlocklistFile; blocklistFile != "" {
+ props.Blocklist_file = proptools.StringPtr(blocklistFile)
+ }
+ if optionsFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorRamdiskKernelOptionsFile; optionsFile != "" {
+ props.Options_file = proptools.StringPtr(optionsFile)
+ }
+
+ default:
+ ctx.ModuleErrorf("DLKM is not supported for %s\n", partitionType)
+ }
+
+ if len(props.Srcs) == 0 {
+ return // do not generate `prebuilt_kernel_modules` if there are no sources
+ }
+
+ kernelModule := ctx.CreateModuleInDirectory(
+ kernel.PrebuiltKernelModulesFactory,
+ ".", // create in root directory for now
+ props,
+ )
+ kernelModule.HideFromMake()
+ // Add to deps
+ (*fsGenState.fsDeps[partitionType])[name] = defaultDepCandidateProps(ctx.Config())
+}
+
+// Create an android_info module. This will be used to create /vendor/build.prop
+func (f *filesystemCreator) createAndroidInfo(ctx android.LoadHookContext) {
+ // Create a android_info for vendor
+ // The board info files might be in a directory outside the root soong namespace, so create
+ // the module in "."
+ partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+ androidInfoProps := &struct {
+ Name *string
+ Board_info_files []string
+ Bootloader_board_name *string
+ Stem *string
+ }{
+ Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "android_info.prop")),
+ Board_info_files: partitionVars.BoardInfoFiles,
+ Stem: proptools.StringPtr("android-info.txt"),
+ }
+ if len(androidInfoProps.Board_info_files) == 0 {
+ androidInfoProps.Bootloader_board_name = proptools.StringPtr(partitionVars.BootLoaderBoardName)
+ }
+ androidInfoProp := ctx.CreateModuleInDirectory(
+ android.AndroidInfoFactory,
+ ".",
+ androidInfoProps,
+ )
+ androidInfoProp.HideFromMake()
+}
+
+func (f *filesystemCreator) createVendorBuildProp(ctx android.LoadHookContext) {
+ vendorBuildProps := &struct {
+ Name *string
+ Vendor *bool
+ Stem *string
+ Product_config *string
+ Android_info *string
+ Licenses []string
+ }{
+ Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "vendor-build.prop")),
+ Vendor: proptools.BoolPtr(true),
+ Stem: proptools.StringPtr("build.prop"),
+ Product_config: proptools.StringPtr(":product_config"),
+ Android_info: proptools.StringPtr(":" + generatedModuleName(ctx.Config(), "android_info.prop")),
+ Licenses: []string{"Android-Apache-2.0"},
+ }
+ vendorBuildProp := ctx.CreateModule(
+ android.BuildPropFactory,
+ vendorBuildProps,
+ )
+ vendorBuildProp.HideFromMake()
+}
+
+func createRecoveryBuildProp(ctx android.LoadHookContext) string {
+ moduleName := generatedModuleName(ctx.Config(), "recovery-prop.default")
+
+ var vendorBuildProp *string
+ if ctx.DeviceConfig().BuildingVendorImage() && ctx.DeviceConfig().VendorPath() == "vendor" {
+ vendorBuildProp = proptools.StringPtr(":" + generatedModuleName(ctx.Config(), "vendor-build.prop"))
+ }
+
+ recoveryBuildProps := &struct {
+ Name *string
+ System_build_prop *string
+ Vendor_build_prop *string
+ Odm_build_prop *string
+ Product_build_prop *string
+ System_ext_build_prop *string
+
+ Recovery *bool
+ No_full_install *bool
+ Visibility []string
+ }{
+ Name: proptools.StringPtr(moduleName),
+ System_build_prop: proptools.StringPtr(":system-build.prop"),
+ Vendor_build_prop: vendorBuildProp,
+ Odm_build_prop: proptools.StringPtr(":odm-build.prop"),
+ Product_build_prop: proptools.StringPtr(":product-build.prop"),
+ System_ext_build_prop: proptools.StringPtr(":system_ext-build.prop"),
+
+ Recovery: proptools.BoolPtr(true),
+ No_full_install: proptools.BoolPtr(true),
+ Visibility: []string{"//visibility:public"},
+ }
+
+ ctx.CreateModule(android.RecoveryBuildPropModuleFactory, recoveryBuildProps)
+
+ return moduleName
+}
+
+// createLinkerConfigSourceFilegroups creates filegroup modules to generate linker.config.pb for the following partitions
+// 1. vendor: Using PRODUCT_VENDOR_LINKER_CONFIG_FRAGMENTS (space separated file list)
+// 1. product: Using PRODUCT_PRODUCT_LINKER_CONFIG_FRAGMENTS (space separated file list)
+// It creates a filegroup for each file in the fragment list
+// The filegroup modules are then added to `linker_config_srcs` of the autogenerated vendor `android_filesystem`.
+func (f *filesystemCreator) createLinkerConfigSourceFilegroups(ctx android.LoadHookContext, partitionType string) []string {
+ ret := []string{}
+ partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+ var linkerConfigSrcs []string
+ if partitionType == "vendor" {
+ linkerConfigSrcs = android.FirstUniqueStrings(partitionVars.VendorLinkerConfigSrcs)
+ } else if partitionType == "product" {
+ linkerConfigSrcs = android.FirstUniqueStrings(partitionVars.ProductLinkerConfigSrcs)
+ } else {
+ ctx.ModuleErrorf("linker.config.pb is only supported for vendor and product partitions. For system partition, use `android_system_image`")
+ }
+
+ if len(linkerConfigSrcs) > 0 {
+ // Create a filegroup, and add `:<filegroup_name>` to ret.
+ for index, linkerConfigSrc := range linkerConfigSrcs {
+ dir := filepath.Dir(linkerConfigSrc)
+ base := filepath.Base(linkerConfigSrc)
+ fgName := generatedModuleName(ctx.Config(), fmt.Sprintf("%s-linker-config-src%s", partitionType, strconv.Itoa(index)))
+ srcs := []string{base}
+ fgProps := &struct {
+ Name *string
+ Srcs proptools.Configurable[[]string]
+ }{
+ Name: proptools.StringPtr(fgName),
+ Srcs: proptools.NewSimpleConfigurable(srcs),
+ }
+ ctx.CreateModuleInDirectory(
+ android.FileGroupFactory,
+ dir,
+ fgProps,
+ )
+ ret = append(ret, ":"+fgName)
+ }
+ }
+ return ret
+}
+
+type filesystemBaseProperty struct {
+ Name *string
+ Compile_multilib *string
+ Visibility []string
+}
+
+func generateBaseProps(namePtr *string) *filesystemBaseProperty {
+ return &filesystemBaseProperty{
+ Name: namePtr,
+ Compile_multilib: proptools.StringPtr("both"),
+ // The vbmeta modules are currently in the root directory and depend on the partitions
+ Visibility: []string{"//.", "//build/soong:__subpackages__"},
+ }
+}
+
+func generateFsProps(ctx android.EarlyModuleContext, partitions allGeneratedPartitionData, partitionType string) (*filesystem.FilesystemProperties, bool) {
+ fsProps := &filesystem.FilesystemProperties{}
+
+ partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+ var avbInfo avbInfo
+ var fsType string
+ if strings.Contains(partitionType, "ramdisk") {
+ fsType = "compressed_cpio"
+ } else {
+ specificPartitionVars := partitionVars.PartitionQualifiedVariables[partitionType]
+ fsType = specificPartitionVars.BoardFileSystemType
+ avbInfo = getAvbInfo(ctx.Config(), partitionType)
+ if fsType == "" {
+ fsType = "ext4" //default
+ }
+ }
+
+ fsProps.Type = proptools.StringPtr(fsType)
+ if filesystem.GetFsTypeFromString(ctx, *fsProps.Type).IsUnknown() {
+ // Currently the android_filesystem module type only supports a handful of FS types like ext4, erofs
+ return nil, false
+ }
+
+ if *fsProps.Type == "erofs" {
+ if partitionVars.BoardErofsCompressor != "" {
+ fsProps.Erofs.Compressor = proptools.StringPtr(partitionVars.BoardErofsCompressor)
+ }
+ if partitionVars.BoardErofsCompressorHints != "" {
+ fsProps.Erofs.Compress_hints = proptools.StringPtr(":soong_generated_board_erofs_compress_hints_filegroup")
+ }
+ }
+
+ // Don't build this module on checkbuilds, the soong-built partitions are still in-progress
+ // and sometimes don't build.
+ fsProps.Unchecked_module = proptools.BoolPtr(true)
+
+ // BOARD_AVB_ENABLE
+ fsProps.Use_avb = avbInfo.avbEnable
+ // BOARD_AVB_KEY_PATH
+ fsProps.Avb_private_key = avbInfo.avbkeyFilegroup
+ // BOARD_AVB_ALGORITHM
+ fsProps.Avb_algorithm = avbInfo.avbAlgorithm
+ // BOARD_AVB_SYSTEM_ROLLBACK_INDEX
+ fsProps.Rollback_index = avbInfo.avbRollbackIndex
+ // BOARD_AVB_SYSTEM_ROLLBACK_INDEX_LOCATION
+ fsProps.Rollback_index_location = avbInfo.avbRollbackIndexLocation
+ fsProps.Avb_hash_algorithm = avbInfo.avbHashAlgorithm
+
+ fsProps.Partition_name = proptools.StringPtr(partitionType)
+
+ switch partitionType {
+ // The partitions that support file_contexts came from here:
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=2270;drc=ad7cfb56010cb22c3aa0e70cf71c804352553526
+ case "system", "userdata", "cache", "vendor", "product", "system_ext", "odm", "vendor_dlkm", "odm_dlkm", "system_dlkm", "oem":
+ fsProps.Precompiled_file_contexts = proptools.StringPtr(":file_contexts_bin_gen")
+ }
+
+ fsProps.Is_auto_generated = proptools.BoolPtr(true)
+ if partitionType != "system" {
+ mountPoint := proptools.StringPtr(partitionType)
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/tools/releasetools/build_image.py;l=1012;drc=3f576a753594bad3fc838ccb8b1b72f7efac1d50
+ if partitionType == "userdata" {
+ mountPoint = proptools.StringPtr("data")
+ }
+ fsProps.Mount_point = mountPoint
+
+ }
+
+ partitionSpecificFsProps(ctx, partitions, fsProps, partitionType)
+
+ return fsProps, true
+}
+
+type avbInfo struct {
+ avbEnable *bool
+ avbKeyPath *string
+ avbkeyFilegroup *string
+ avbAlgorithm *string
+ avbRollbackIndex *int64
+ avbRollbackIndexLocation *int64
+ avbMode *string
+ avbHashAlgorithm *string
+}
+
+func getAvbInfo(config android.Config, partitionType string) avbInfo {
+ partitionVars := config.ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+ specificPartitionVars := partitionVars.PartitionQualifiedVariables[partitionType]
+ var result avbInfo
+ boardAvbEnable := partitionVars.BoardAvbEnable
+ if boardAvbEnable {
+ result.avbEnable = proptools.BoolPtr(true)
+ // There are "global" and "specific" copies of a lot of these variables. Sometimes they
+ // choose the specific and then fall back to the global one if it's not set, other times
+ // the global one actually only applies to the vbmeta partition.
+ if partitionType == "vbmeta" {
+ if partitionVars.BoardAvbKeyPath != "" {
+ result.avbKeyPath = proptools.StringPtr(partitionVars.BoardAvbKeyPath)
+ }
+ if partitionVars.BoardAvbRollbackIndex != "" {
+ parsed, err := strconv.ParseInt(partitionVars.BoardAvbRollbackIndex, 10, 64)
+ if err != nil {
+ panic(fmt.Sprintf("Rollback index must be an int, got %s", partitionVars.BoardAvbRollbackIndex))
+ }
+ result.avbRollbackIndex = &parsed
+ }
+ }
+ if specificPartitionVars.BoardAvbKeyPath != "" {
+ result.avbKeyPath = proptools.StringPtr(specificPartitionVars.BoardAvbKeyPath)
+ }
+ if specificPartitionVars.BoardAvbAlgorithm != "" {
+ result.avbAlgorithm = proptools.StringPtr(specificPartitionVars.BoardAvbAlgorithm)
+ } else if partitionVars.BoardAvbAlgorithm != "" {
+ result.avbAlgorithm = proptools.StringPtr(partitionVars.BoardAvbAlgorithm)
+ }
+ if specificPartitionVars.BoardAvbRollbackIndex != "" {
+ parsed, err := strconv.ParseInt(specificPartitionVars.BoardAvbRollbackIndex, 10, 64)
+ if err != nil {
+ panic(fmt.Sprintf("Rollback index must be an int, got %s", specificPartitionVars.BoardAvbRollbackIndex))
+ }
+ result.avbRollbackIndex = &parsed
+ }
+ if specificPartitionVars.BoardAvbRollbackIndex != "" {
+ parsed, err := strconv.ParseInt(specificPartitionVars.BoardAvbRollbackIndex, 10, 64)
+ if err != nil {
+ panic(fmt.Sprintf("Rollback index must be an int, got %s", specificPartitionVars.BoardAvbRollbackIndex))
+ }
+ result.avbRollbackIndex = &parsed
+ }
+ if specificPartitionVars.BoardAvbRollbackIndexLocation != "" {
+ parsed, err := strconv.ParseInt(specificPartitionVars.BoardAvbRollbackIndexLocation, 10, 64)
+ if err != nil {
+ panic(fmt.Sprintf("Rollback index location must be an int, got %s", specificPartitionVars.BoardAvbRollbackIndexLocation))
+ }
+ result.avbRollbackIndexLocation = &parsed
+ }
+
+ // Make allows you to pass arbitrary arguments to avbtool via this variable, but in practice
+ // it's only used for --hash_algorithm. The soong module has a dedicated property for the
+ // hashtree algorithm, and doesn't allow custom arguments, so just extract the hashtree
+ // algorithm out of the arbitrary arguments.
+ addHashtreeFooterArgs := strings.Split(specificPartitionVars.BoardAvbAddHashtreeFooterArgs, " ")
+ if i := slices.Index(addHashtreeFooterArgs, "--hash_algorithm"); i >= 0 {
+ result.avbHashAlgorithm = &addHashtreeFooterArgs[i+1]
+ }
+
+ result.avbMode = proptools.StringPtr("make_legacy")
+ }
+ if result.avbKeyPath != nil {
+ fsGenState := config.Get(fsGenStateOnceKey).(*FsGenState)
+ filegroup := fsGenState.avbKeyFilegroups[*result.avbKeyPath]
+ result.avbkeyFilegroup = proptools.StringPtr(":" + filegroup)
+ }
+ return result
+}
+
+func (f *filesystemCreator) createFileListDiffTest(ctx android.ModuleContext, partitionType string, partitionModuleName string) android.Path {
+ partitionImage := ctx.GetDirectDepWithTag(partitionModuleName, generatedFilesystemDepTag)
+ filesystemInfo, ok := android.OtherModuleProvider(ctx, partitionImage, filesystem.FilesystemProvider)
+ if !ok {
+ ctx.ModuleErrorf("Expected module %s to provide FileysystemInfo", partitionModuleName)
+ return nil
+ }
+ makeFileList := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/obj/PACKAGING/%s_intermediates/file_list.txt", ctx.Config().DeviceName(), partitionType))
+ diffTestResultFile := android.PathForModuleOut(ctx, fmt.Sprintf("diff_test_%s.txt", partitionModuleName))
+
+ builder := android.NewRuleBuilder(pctx, ctx)
+ builder.Command().BuiltTool("file_list_diff").
+ Input(makeFileList).
+ Input(filesystemInfo.FileListFile).
+ Text(partitionModuleName)
+ builder.Command().Text("touch").Output(diffTestResultFile)
+ builder.Build(partitionModuleName+" diff test", partitionModuleName+" diff test")
+ return diffTestResultFile
+}
+
+func createFailingCommand(ctx android.ModuleContext, message string) android.Path {
+ hasher := sha256.New()
+ hasher.Write([]byte(message))
+ filename := fmt.Sprintf("failing_command_%x.txt", hasher.Sum(nil))
+ file := android.PathForModuleOut(ctx, filename)
+ builder := android.NewRuleBuilder(pctx, ctx)
+ builder.Command().Textf("echo %s", proptools.NinjaAndShellEscape(message))
+ builder.Command().Text("exit 1 #").Output(file)
+ builder.Build("failing command "+filename, "failing command "+filename)
+ return file
+}
+
+func createVbmetaDiff(ctx android.ModuleContext, vbmetaModuleName string, vbmetaPartitionName string) android.Path {
+ vbmetaModule := ctx.GetDirectDepWithTag(vbmetaModuleName, generatedVbmetaPartitionDepTag)
+ outputFilesProvider, ok := android.OtherModuleProvider(ctx, vbmetaModule, android.OutputFilesProvider)
+ if !ok {
+ ctx.ModuleErrorf("Expected module %s to provide OutputFiles", vbmetaModule)
+ }
+ if len(outputFilesProvider.DefaultOutputFiles) != 1 {
+ ctx.ModuleErrorf("Expected 1 output file from module %s", vbmetaModule)
+ }
+ soongVbMetaFile := outputFilesProvider.DefaultOutputFiles[0]
+ makeVbmetaFile := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/%s.img", ctx.Config().DeviceName(), vbmetaPartitionName))
+
+ diffTestResultFile := android.PathForModuleOut(ctx, fmt.Sprintf("diff_test_%s.txt", vbmetaModuleName))
+ createDiffTest(ctx, diffTestResultFile, soongVbMetaFile, makeVbmetaFile)
+ return diffTestResultFile
+}
+
+func createDiffTest(ctx android.ModuleContext, diffTestResultFile android.WritablePath, file1 android.Path, file2 android.Path) {
+ builder := android.NewRuleBuilder(pctx, ctx)
+ builder.Command().Text("diff").
+ Input(file1).
+ Input(file2)
+ builder.Command().Text("touch").Output(diffTestResultFile)
+ builder.Build("diff test "+diffTestResultFile.String(), "diff test")
+}
+
+type imageDepTagType struct {
+ blueprint.BaseDependencyTag
+}
+
+var generatedFilesystemDepTag imageDepTagType
+var generatedVbmetaPartitionDepTag imageDepTagType
+
+func (f *filesystemCreator) DepsMutator(ctx android.BottomUpMutatorContext) {
+ for _, name := range ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).soongGeneratedPartitions.names() {
+ ctx.AddDependency(ctx.Module(), generatedFilesystemDepTag, name)
+ }
+ for _, vbmetaModule := range f.properties.Vbmeta_module_names {
+ ctx.AddDependency(ctx.Module(), generatedVbmetaPartitionDepTag, vbmetaModule)
+ }
+}
+
+func (f *filesystemCreator) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ if ctx.ModuleDir() != "build/soong/fsgen" {
+ ctx.ModuleErrorf("There can only be one soong_filesystem_creator in build/soong/fsgen")
+ }
+ f.HideFromMake()
+
+ partitions := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).soongGeneratedPartitions
+
+ var content strings.Builder
+ generatedBp := android.PathForModuleOut(ctx, "soong_generated_product_config.bp")
+ for _, partition := range partitions.types() {
+ content.WriteString(generateBpContent(ctx, partition))
+ content.WriteString("\n")
+ }
+ android.WriteFileRule(ctx, generatedBp, content.String())
+
+ ctx.Phony("product_config_to_bp", generatedBp)
+
+ var diffTestFiles []android.Path
+ for _, partitionType := range partitions.types() {
+ diffTestFile := f.createFileListDiffTest(ctx, partitionType, partitions.nameForType(partitionType))
+ diffTestFiles = append(diffTestFiles, diffTestFile)
+ ctx.Phony(fmt.Sprintf("soong_generated_%s_filesystem_test", partitionType), diffTestFile)
+ }
+ for _, partitionType := range slices.Concat(partitions.unsupportedTypes(), f.properties.Unsupported_partition_types) {
+ diffTestFile := createFailingCommand(ctx, fmt.Sprintf("Couldn't build %s partition", partitionType))
+ diffTestFiles = append(diffTestFiles, diffTestFile)
+ ctx.Phony(fmt.Sprintf("soong_generated_%s_filesystem_test", partitionType), diffTestFile)
+ }
+ for i, vbmetaModule := range f.properties.Vbmeta_module_names {
+ diffTestFile := createVbmetaDiff(ctx, vbmetaModule, f.properties.Vbmeta_partition_names[i])
+ diffTestFiles = append(diffTestFiles, diffTestFile)
+ ctx.Phony(fmt.Sprintf("soong_generated_%s_filesystem_test", f.properties.Vbmeta_partition_names[i]), diffTestFile)
+ }
+ if f.properties.Boot_image != "" {
+ diffTestFile := android.PathForModuleOut(ctx, "boot_diff_test.txt")
+ soongBootImg := android.PathForModuleSrc(ctx, f.properties.Boot_image)
+ makeBootImage := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/boot.img", ctx.Config().DeviceName()))
+ createDiffTest(ctx, diffTestFile, soongBootImg, makeBootImage)
+ diffTestFiles = append(diffTestFiles, diffTestFile)
+ ctx.Phony("soong_generated_boot_filesystem_test", diffTestFile)
+ }
+ if f.properties.Vendor_boot_image != "" {
+ diffTestFile := android.PathForModuleOut(ctx, "vendor_boot_diff_test.txt")
+ soongBootImg := android.PathForModuleSrc(ctx, f.properties.Vendor_boot_image)
+ makeBootImage := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/vendor_boot.img", ctx.Config().DeviceName()))
+ createDiffTest(ctx, diffTestFile, soongBootImg, makeBootImage)
+ diffTestFiles = append(diffTestFiles, diffTestFile)
+ ctx.Phony("soong_generated_vendor_boot_filesystem_test", diffTestFile)
+ }
+ if f.properties.Init_boot_image != "" {
+ diffTestFile := android.PathForModuleOut(ctx, "init_boot_diff_test.txt")
+ soongBootImg := android.PathForModuleSrc(ctx, f.properties.Init_boot_image)
+ makeBootImage := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/init_boot.img", ctx.Config().DeviceName()))
+ createDiffTest(ctx, diffTestFile, soongBootImg, makeBootImage)
+ diffTestFiles = append(diffTestFiles, diffTestFile)
+ ctx.Phony("soong_generated_init_boot_filesystem_test", diffTestFile)
+ }
+ if f.properties.Super_image != "" {
+ diffTestFile := android.PathForModuleOut(ctx, "super_diff_test.txt")
+ soongSuperImg := android.PathForModuleSrc(ctx, f.properties.Super_image)
+ makeSuperImage := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/super.img", ctx.Config().DeviceName()))
+ createDiffTest(ctx, diffTestFile, soongSuperImg, makeSuperImage)
+ diffTestFiles = append(diffTestFiles, diffTestFile)
+ ctx.Phony("soong_generated_super_filesystem_test", diffTestFile)
+ }
+ ctx.Phony("soong_generated_filesystem_tests", diffTestFiles...)
+}
+
+func generateBpContent(ctx android.EarlyModuleContext, partitionType string) string {
+ fsGenState := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
+ fsProps, fsTypeSupported := generateFsProps(ctx, fsGenState.soongGeneratedPartitions, partitionType)
+ if !fsTypeSupported {
+ return ""
+ }
+
+ baseProps := generateBaseProps(proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), partitionType)))
+ deps := fsGenState.fsDeps[partitionType]
+ highPriorityDeps := fsGenState.generatedPrebuiltEtcModuleNames
+ depProps := generateDepStruct(*deps, highPriorityDeps)
+
+ result, err := proptools.RepackProperties([]interface{}{baseProps, fsProps, depProps})
+ if err != nil {
+ ctx.ModuleErrorf("%s", err.Error())
+ return ""
+ }
+
+ moduleType := "android_filesystem"
+ if partitionType == "system" {
+ moduleType = "android_system_image"
+ }
+
+ file := &parser.File{
+ Defs: []parser.Definition{
+ &parser.Module{
+ Type: moduleType,
+ Map: *result,
+ },
+ },
+ }
+ bytes, err := parser.Print(file)
+ if err != nil {
+ ctx.ModuleErrorf(err.Error())
+ }
+ return strings.TrimSpace(string(bytes))
+}
diff --git a/fsgen/filesystem_creator_test.go b/fsgen/filesystem_creator_test.go
new file mode 100644
index 0000000..5657608
--- /dev/null
+++ b/fsgen/filesystem_creator_test.go
@@ -0,0 +1,383 @@
+// 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 fsgen
+
+import (
+ "android/soong/android"
+ "android/soong/etc"
+ "android/soong/filesystem"
+ "android/soong/java"
+ "testing"
+
+ "github.com/google/blueprint/proptools"
+)
+
+var prepareForTestWithFsgenBuildComponents = android.FixtureRegisterWithContext(registerBuildComponents)
+
+func TestFileSystemCreatorSystemImageProps(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ android.PrepareForIntegrationTestWithAndroid,
+ android.PrepareForTestWithAndroidBuildComponents,
+ android.PrepareForTestWithAllowMissingDependencies,
+ filesystem.PrepareForTestWithFilesystemBuildComponents,
+ prepareForTestWithFsgenBuildComponents,
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.BoardAvbEnable = true
+ config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.PartitionQualifiedVariables =
+ map[string]android.PartitionQualifiedVariablesType{
+ "system": {
+ BoardAvbKeyPath: "external/avb/test/data/testkey_rsa4096.pem",
+ BoardAvbAlgorithm: "SHA256_RSA4096",
+ BoardAvbRollbackIndex: "0",
+ BoardFileSystemType: "ext4",
+ },
+ }
+ }),
+ android.FixtureMergeMockFs(android.MockFS{
+ "external/avb/test/data/testkey_rsa4096.pem": nil,
+ "external/avb/test/Android.bp": []byte(`
+ filegroup {
+ name: "avb_testkey_rsa4096",
+ srcs: ["data/testkey_rsa4096.pem"],
+ }
+ `),
+ "build/soong/fsgen/Android.bp": []byte(`
+ soong_filesystem_creator {
+ name: "foo",
+ }
+ `),
+ }),
+ ).RunTest(t)
+
+ fooSystem := result.ModuleForTests("test_product_generated_system_image", "android_common").Module().(interface {
+ FsProps() filesystem.FilesystemProperties
+ })
+ android.AssertBoolEquals(
+ t,
+ "Property expected to match the product variable 'BOARD_AVB_ENABLE'",
+ true,
+ proptools.Bool(fooSystem.FsProps().Use_avb),
+ )
+ android.AssertStringEquals(
+ t,
+ "Property the avb_private_key property to be set to the existing filegroup",
+ ":avb_testkey_rsa4096",
+ proptools.String(fooSystem.FsProps().Avb_private_key),
+ )
+ android.AssertStringEquals(
+ t,
+ "Property expected to match the product variable 'BOARD_AVB_ALGORITHM'",
+ "SHA256_RSA4096",
+ proptools.String(fooSystem.FsProps().Avb_algorithm),
+ )
+ android.AssertIntEquals(
+ t,
+ "Property expected to match the product variable 'BOARD_AVB_SYSTEM_ROLLBACK_INDEX'",
+ 0,
+ proptools.Int(fooSystem.FsProps().Rollback_index),
+ )
+ android.AssertStringEquals(
+ t,
+ "Property expected to match the product variable 'BOARD_SYSTEMIMAGE_FILE_SYSTEM_TYPE'",
+ "ext4",
+ proptools.String(fooSystem.FsProps().Type),
+ )
+}
+
+func TestFileSystemCreatorSetPartitionDeps(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ android.PrepareForIntegrationTestWithAndroid,
+ android.PrepareForTestWithAndroidBuildComponents,
+ android.PrepareForTestWithAllowMissingDependencies,
+ filesystem.PrepareForTestWithFilesystemBuildComponents,
+ prepareForTestWithFsgenBuildComponents,
+ java.PrepareForTestWithJavaBuildComponents,
+ java.PrepareForTestWithJavaDefaultModules,
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductPackages = []string{"bar", "baz"}
+ config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.PartitionQualifiedVariables =
+ map[string]android.PartitionQualifiedVariablesType{
+ "system": {
+ BoardFileSystemType: "ext4",
+ },
+ }
+ }),
+ android.FixtureMergeMockFs(android.MockFS{
+ "external/avb/test/data/testkey_rsa4096.pem": nil,
+ "build/soong/fsgen/Android.bp": []byte(`
+ soong_filesystem_creator {
+ name: "foo",
+ }
+ `),
+ }),
+ ).RunTestWithBp(t, `
+ java_library {
+ name: "bar",
+ srcs: ["A.java"],
+ }
+ java_library {
+ name: "baz",
+ srcs: ["A.java"],
+ product_specific: true,
+ }
+ `)
+
+ android.AssertBoolEquals(
+ t,
+ "Generated system image expected to depend on system partition installed \"bar\"",
+ true,
+ java.CheckModuleHasDependency(t, result.TestContext, "test_product_generated_system_image", "android_common", "bar"),
+ )
+ android.AssertBoolEquals(
+ t,
+ "Generated system image expected to not depend on product partition installed \"baz\"",
+ false,
+ java.CheckModuleHasDependency(t, result.TestContext, "test_product_generated_system_image", "android_common", "baz"),
+ )
+}
+
+func TestFileSystemCreatorDepsWithNamespace(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ android.PrepareForIntegrationTestWithAndroid,
+ android.PrepareForTestWithAndroidBuildComponents,
+ android.PrepareForTestWithAllowMissingDependencies,
+ android.PrepareForTestWithNamespace,
+ android.PrepareForTestWithArchMutator,
+ filesystem.PrepareForTestWithFilesystemBuildComponents,
+ prepareForTestWithFsgenBuildComponents,
+ java.PrepareForTestWithJavaBuildComponents,
+ java.PrepareForTestWithJavaDefaultModules,
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductPackages = []string{"bar"}
+ config.TestProductVariables.NamespacesToExport = []string{"a/b"}
+ config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.PartitionQualifiedVariables =
+ map[string]android.PartitionQualifiedVariablesType{
+ "system": {
+ BoardFileSystemType: "ext4",
+ },
+ }
+ }),
+ android.PrepareForNativeBridgeEnabled,
+ android.FixtureMergeMockFs(android.MockFS{
+ "external/avb/test/data/testkey_rsa4096.pem": nil,
+ "build/soong/fsgen/Android.bp": []byte(`
+ soong_filesystem_creator {
+ name: "foo",
+ }
+ `),
+ "a/b/Android.bp": []byte(`
+ soong_namespace{
+ }
+ java_library {
+ name: "bar",
+ srcs: ["A.java"],
+ compile_multilib: "64",
+ }
+ `),
+ "c/d/Android.bp": []byte(`
+ soong_namespace{
+ }
+ java_library {
+ name: "bar",
+ srcs: ["A.java"],
+ }
+ `),
+ }),
+ ).RunTest(t)
+
+ var packagingProps android.PackagingProperties
+ for _, prop := range result.ModuleForTests("test_product_generated_system_image", "android_common").Module().GetProperties() {
+ if packagingPropStruct, ok := prop.(*android.PackagingProperties); ok {
+ packagingProps = *packagingPropStruct
+ }
+ }
+ moduleDeps := packagingProps.Multilib.Lib64.Deps
+
+ eval := result.ModuleForTests("test_product_generated_system_image", "android_common").Module().ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+ android.AssertStringListContains(
+ t,
+ "Generated system image expected to depend on \"bar\" defined in \"a/b\" namespace",
+ moduleDeps.GetOrDefault(eval, nil),
+ "//a/b:bar",
+ )
+ android.AssertStringListDoesNotContain(
+ t,
+ "Generated system image expected to not depend on \"bar\" defined in \"c/d\" namespace",
+ moduleDeps.GetOrDefault(eval, nil),
+ "//c/d:bar",
+ )
+}
+
+func TestRemoveOverriddenModulesFromDeps(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ android.PrepareForIntegrationTestWithAndroid,
+ android.PrepareForTestWithAndroidBuildComponents,
+ android.PrepareForTestWithAllowMissingDependencies,
+ prepareForTestWithFsgenBuildComponents,
+ java.PrepareForTestWithJavaBuildComponents,
+ android.FixtureMergeMockFs(android.MockFS{
+ "external/avb/test/data/testkey_rsa4096.pem": nil,
+ "build/soong/fsgen/Android.bp": []byte(`
+ soong_filesystem_creator {
+ name: "foo",
+ }
+ `),
+ }),
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductPackages = []string{"libfoo", "libbar"}
+ }),
+ ).RunTestWithBp(t, `
+java_library {
+ name: "libfoo",
+}
+java_library {
+ name: "libbar",
+ required: ["libbaz"],
+}
+java_library {
+ name: "libbaz",
+ overrides: ["libfoo"], // overrides libfoo
+}
+ `)
+ resolvedSystemDeps := result.TestContext.Config().Get(fsGenStateOnceKey).(*FsGenState).fsDeps["system"]
+ _, libFooInDeps := (*resolvedSystemDeps)["libfoo"]
+ android.AssertBoolEquals(t, "libfoo should not appear in deps because it has been overridden by libbaz. The latter is a required dep of libbar, which is listed in PRODUCT_PACKAGES", false, libFooInDeps)
+}
+
+func TestPrebuiltEtcModuleGen(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ android.PrepareForIntegrationTestWithAndroid,
+ android.PrepareForTestWithAndroidBuildComponents,
+ android.PrepareForTestWithAllowMissingDependencies,
+ filesystem.PrepareForTestWithFilesystemBuildComponents,
+ prepareForTestWithFsgenBuildComponents,
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductCopyFiles = []string{
+ "frameworks/base/config/preloaded-classes:system/etc/preloaded-classes",
+ "frameworks/base/data/keyboards/Vendor_0079_Product_0011.kl:system/usr/keylayout/subdir/Vendor_0079_Product_0011.kl",
+ "frameworks/base/data/keyboards/Vendor_0079_Product_18d4.kl:system/usr/keylayout/subdir/Vendor_0079_Product_18d4.kl",
+ "some/non/existing/file.txt:system/etc/file.txt",
+ "device/sample/etc/apns-full-conf.xml:product/etc/apns-conf.xml:google",
+ "device/sample/etc/apns-full-conf.xml:product/etc/apns-conf-2.xml",
+ }
+ config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.PartitionQualifiedVariables =
+ map[string]android.PartitionQualifiedVariablesType{
+ "system": {
+ BoardFileSystemType: "ext4",
+ },
+ }
+ }),
+ android.FixtureMergeMockFs(android.MockFS{
+ "external/avb/test/data/testkey_rsa4096.pem": nil,
+ "build/soong/fsgen/Android.bp": []byte(`
+ soong_filesystem_creator {
+ name: "foo",
+ }
+ `),
+ "frameworks/base/config/preloaded-classes": nil,
+ "frameworks/base/data/keyboards/Vendor_0079_Product_0011.kl": nil,
+ "frameworks/base/data/keyboards/Vendor_0079_Product_18d4.kl": nil,
+ "device/sample/etc/apns-full-conf.xml": nil,
+ }),
+ ).RunTest(t)
+
+ checkModuleProp := func(m android.Module, matcher func(actual interface{}) bool) bool {
+ for _, prop := range m.GetProperties() {
+
+ if matcher(prop) {
+ return true
+ }
+ }
+ return false
+ }
+
+ // check generated prebuilt_* module type install path and install partition
+ generatedModule := result.ModuleForTests("system-frameworks_base_config-etc-0", "android_arm64_armv8-a").Module()
+ etcModule, _ := generatedModule.(*etc.PrebuiltEtc)
+ android.AssertStringEquals(
+ t,
+ "module expected to have etc install path",
+ "etc",
+ etcModule.BaseDir(),
+ )
+ android.AssertBoolEquals(
+ t,
+ "module expected to be installed in system partition",
+ true,
+ !generatedModule.InstallInProduct() &&
+ !generatedModule.InstallInVendor() &&
+ !generatedModule.InstallInSystemExt(),
+ )
+
+ // check generated prebuilt_* module specifies correct relative_install_path property
+ generatedModule = result.ModuleForTests("system-frameworks_base_data_keyboards-usr_keylayout_subdir-0", "android_arm64_armv8-a").Module()
+ etcModule, _ = generatedModule.(*etc.PrebuiltEtc)
+ android.AssertStringEquals(
+ t,
+ "module expected to set correct relative_install_path properties",
+ "subdir",
+ etcModule.SubDir(),
+ )
+
+ // check that prebuilt_* module is not generated for non existing source file
+ android.AssertPanicMessageContains(
+ t,
+ "prebuilt_* module not generated for non existing source file",
+ "failed to find module \"system-some_non_existing-etc-0\"",
+ func() { result.ModuleForTests("system-some_non_existing-etc-0", "android_arm64_armv8-a") },
+ )
+
+ // check that duplicate src file can exist in PRODUCT_COPY_FILES and generates separate modules
+ generatedModule0 := result.ModuleForTests("product-device_sample_etc-etc-0", "android_arm64_armv8-a").Module()
+ generatedModule1 := result.ModuleForTests("product-device_sample_etc-etc-1", "android_arm64_armv8-a").Module()
+
+ // check that generated prebuilt_* module sets correct srcs and dsts property
+ eval := generatedModule0.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+ android.AssertBoolEquals(
+ t,
+ "module expected to set correct srcs and dsts properties",
+ true,
+ checkModuleProp(generatedModule0, func(actual interface{}) bool {
+ if p, ok := actual.(*etc.PrebuiltEtcProperties); ok {
+ srcs := p.Srcs.GetOrDefault(eval, nil)
+ dsts := p.Dsts.GetOrDefault(eval, nil)
+ return len(srcs) == 1 &&
+ srcs[0] == "apns-full-conf.xml" &&
+ len(dsts) == 1 &&
+ dsts[0] == "apns-conf.xml"
+ }
+ return false
+ }),
+ )
+
+ // check that generated prebuilt_* module sets correct srcs and dsts property
+ eval = generatedModule1.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+ android.AssertBoolEquals(
+ t,
+ "module expected to set correct srcs and dsts properties",
+ true,
+ checkModuleProp(generatedModule1, func(actual interface{}) bool {
+ if p, ok := actual.(*etc.PrebuiltEtcProperties); ok {
+ srcs := p.Srcs.GetOrDefault(eval, nil)
+ dsts := p.Dsts.GetOrDefault(eval, nil)
+ return len(srcs) == 1 &&
+ srcs[0] == "apns-full-conf.xml" &&
+ len(dsts) == 1 &&
+ dsts[0] == "apns-conf-2.xml"
+ }
+ return false
+ }),
+ )
+}
diff --git a/fsgen/fsgen_mutators.go b/fsgen/fsgen_mutators.go
new file mode 100644
index 0000000..9b25e77
--- /dev/null
+++ b/fsgen/fsgen_mutators.go
@@ -0,0 +1,393 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package fsgen
+
+import (
+ "fmt"
+ "slices"
+ "strings"
+ "sync"
+
+ "android/soong/android"
+
+ "github.com/google/blueprint/proptools"
+)
+
+func RegisterCollectFileSystemDepsMutators(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("fs_collect_deps", collectDepsMutator).MutatesGlobalState()
+ ctx.BottomUp("fs_set_deps", setDepsMutator)
+}
+
+var fsGenStateOnceKey = android.NewOnceKey("FsGenState")
+var fsGenRemoveOverridesOnceKey = android.NewOnceKey("FsGenRemoveOverrides")
+
+// Map of partition module name to its partition that may be generated by Soong.
+// Note that it is not guaranteed that all modules returned by this function are successfully
+// created.
+func getAllSoongGeneratedPartitionNames(config android.Config, partitions []string) map[string]string {
+ ret := map[string]string{}
+ for _, partition := range partitions {
+ ret[generatedModuleNameForPartition(config, partition)] = partition
+ }
+ return ret
+}
+
+type depCandidateProps struct {
+ Namespace string
+ Multilib string
+ Arch []android.ArchType
+}
+
+// Map of module name to depCandidateProps
+type multilibDeps map[string]*depCandidateProps
+
+// Information necessary to generate the filesystem modules, including details about their
+// dependencies
+type FsGenState struct {
+ // List of modules in `PRODUCT_PACKAGES` and `PRODUCT_PACKAGES_DEBUG`
+ depCandidates []string
+ // Map of names of partition to the information of modules to be added as deps
+ fsDeps map[string]*multilibDeps
+ // Information about the main soong-generated partitions
+ soongGeneratedPartitions allGeneratedPartitionData
+ // Mutex to protect the fsDeps
+ fsDepsMutex sync.Mutex
+ // Map of _all_ soong module names to their corresponding installation properties
+ moduleToInstallationProps map[string]installationProperties
+ // List of prebuilt_* modules that are autogenerated.
+ generatedPrebuiltEtcModuleNames []string
+ // Mapping from a path to an avb key to the name of a filegroup module that contains it
+ avbKeyFilegroups map[string]string
+}
+
+type installationProperties struct {
+ Required []string
+ Overrides []string
+}
+
+func defaultDepCandidateProps(config android.Config) *depCandidateProps {
+ return &depCandidateProps{
+ Namespace: ".",
+ Arch: []android.ArchType{config.BuildArch},
+ }
+}
+
+func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNames []string, avbpubkeyGenerated bool) *FsGenState {
+ return ctx.Config().Once(fsGenStateOnceKey, func() interface{} {
+ partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+ candidates := android.FirstUniqueStrings(android.Concat(partitionVars.ProductPackages, partitionVars.ProductPackagesDebug))
+ candidates = android.Concat(candidates, generatedPrebuiltEtcModuleNames)
+
+ fsGenState := FsGenState{
+ depCandidates: candidates,
+ fsDeps: map[string]*multilibDeps{
+ // These additional deps are added according to the cuttlefish system image bp.
+ "system": {
+ // keep-sorted start
+ "com.android.apex.cts.shim.v1_prebuilt": defaultDepCandidateProps(ctx.Config()),
+ "dex_bootjars": defaultDepCandidateProps(ctx.Config()),
+ "framework_compatibility_matrix.device.xml": defaultDepCandidateProps(ctx.Config()),
+ "init.environ.rc-soong": defaultDepCandidateProps(ctx.Config()),
+ "libcompiler_rt": defaultDepCandidateProps(ctx.Config()),
+ "libdmabufheap": defaultDepCandidateProps(ctx.Config()),
+ "libgsi": defaultDepCandidateProps(ctx.Config()),
+ "llndk.libraries.txt": defaultDepCandidateProps(ctx.Config()),
+ "logpersist.start": defaultDepCandidateProps(ctx.Config()),
+ "update_engine_sideload": defaultDepCandidateProps(ctx.Config()),
+ // keep-sorted end
+ },
+ "vendor": {
+ "fs_config_files_vendor": defaultDepCandidateProps(ctx.Config()),
+ "fs_config_dirs_vendor": defaultDepCandidateProps(ctx.Config()),
+ generatedModuleName(ctx.Config(), "vendor-build.prop"): defaultDepCandidateProps(ctx.Config()),
+ },
+ "odm": {
+ // fs_config_* files are automatically installed for all products with odm partitions.
+ // https://cs.android.com/android/_/android/platform/build/+/e4849e87ab660b59a6501b3928693db065ee873b:tools/fs_config/Android.mk;l=34;drc=8d6481b92c4b4e9b9f31a61545b6862090fcc14b;bpv=1;bpt=0
+ "fs_config_files_odm": defaultDepCandidateProps(ctx.Config()),
+ "fs_config_dirs_odm": defaultDepCandidateProps(ctx.Config()),
+ },
+ "product": {},
+ "system_ext": {
+ // VNDK apexes are automatically included.
+ // This hardcoded list will need to be updated if `PRODUCT_EXTRA_VNDK_VERSIONS` is updated.
+ // https://cs.android.com/android/_/android/platform/build/+/adba533072b00c53ac0f198c550a3cbd7a00e4cd:core/main.mk;l=984;bpv=1;bpt=0;drc=174db7b179592cf07cbfd2adb0119486fda911e7
+ "com.android.vndk.v30": defaultDepCandidateProps(ctx.Config()),
+ "com.android.vndk.v31": defaultDepCandidateProps(ctx.Config()),
+ "com.android.vndk.v32": defaultDepCandidateProps(ctx.Config()),
+ "com.android.vndk.v33": defaultDepCandidateProps(ctx.Config()),
+ "com.android.vndk.v34": defaultDepCandidateProps(ctx.Config()),
+ },
+ "userdata": {},
+ "system_dlkm": {
+ // these are phony required deps of the phony fs_config_dirs_nonsystem
+ "fs_config_dirs_system_dlkm": defaultDepCandidateProps(ctx.Config()),
+ "fs_config_files_system_dlkm": defaultDepCandidateProps(ctx.Config()),
+ // build props are automatically added to `ALL_DEFAULT_INSTALLED_MODULES`
+ "system_dlkm-build.prop": defaultDepCandidateProps(ctx.Config()),
+ },
+ "vendor_dlkm": {
+ "fs_config_dirs_vendor_dlkm": defaultDepCandidateProps(ctx.Config()),
+ "fs_config_files_vendor_dlkm": defaultDepCandidateProps(ctx.Config()),
+ "vendor_dlkm-build.prop": defaultDepCandidateProps(ctx.Config()),
+ },
+ "odm_dlkm": {
+ "fs_config_dirs_odm_dlkm": defaultDepCandidateProps(ctx.Config()),
+ "fs_config_files_odm_dlkm": defaultDepCandidateProps(ctx.Config()),
+ "odm_dlkm-build.prop": defaultDepCandidateProps(ctx.Config()),
+ },
+ "ramdisk": {},
+ "vendor_ramdisk": {},
+ "recovery": {
+ "sepolicy.recovery": defaultDepCandidateProps(ctx.Config()),
+ "plat_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
+ "plat_service_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
+ "plat_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
+ "system_ext_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
+ "system_ext_service_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
+ "system_ext_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
+ "vendor_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
+ "vendor_service_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
+ "vendor_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
+ "odm_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
+ "odm_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
+ "product_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
+ "product_service_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
+ "product_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
+ },
+ },
+ fsDepsMutex: sync.Mutex{},
+ moduleToInstallationProps: map[string]installationProperties{},
+ generatedPrebuiltEtcModuleNames: generatedPrebuiltEtcModuleNames,
+ avbKeyFilegroups: map[string]string{},
+ }
+
+ if avbpubkeyGenerated {
+ (*fsGenState.fsDeps["product"])["system_other_avbpubkey"] = defaultDepCandidateProps(ctx.Config())
+ }
+
+ // Add common resources `prebuilt_res` module as dep of recovery partition
+ (*fsGenState.fsDeps["recovery"])[fmt.Sprintf("recovery-resources-common-%s", getDpi(ctx))] = defaultDepCandidateProps(ctx.Config())
+ (*fsGenState.fsDeps["recovery"])[getRecoveryFontModuleName(ctx)] = defaultDepCandidateProps(ctx.Config())
+ (*fsGenState.fsDeps["recovery"])[createRecoveryBuildProp(ctx)] = defaultDepCandidateProps(ctx.Config())
+
+ return &fsGenState
+ }).(*FsGenState)
+}
+
+func checkDepModuleInMultipleNamespaces(mctx android.BottomUpMutatorContext, foundDeps multilibDeps, module string, partitionName string) {
+ otherNamespace := mctx.Namespace().Path
+ if val, found := foundDeps[module]; found && otherNamespace != "." && !android.InList(val.Namespace, []string{".", otherNamespace}) {
+ mctx.ModuleErrorf("found in multiple namespaces(%s and %s) when including in %s partition", val.Namespace, otherNamespace, partitionName)
+ }
+}
+
+func appendDepIfAppropriate(mctx android.BottomUpMutatorContext, deps *multilibDeps, installPartition string) {
+ moduleName := mctx.ModuleName()
+ checkDepModuleInMultipleNamespaces(mctx, *deps, moduleName, installPartition)
+ if _, ok := (*deps)[moduleName]; ok {
+ // Prefer the namespace-specific module over the platform module
+ if mctx.Namespace().Path != "." {
+ (*deps)[moduleName].Namespace = mctx.Namespace().Path
+ }
+ (*deps)[moduleName].Arch = append((*deps)[moduleName].Arch, mctx.Module().Target().Arch.ArchType)
+ } else {
+ multilib, _ := mctx.Module().DecodeMultilib(mctx)
+ (*deps)[moduleName] = &depCandidateProps{
+ Namespace: mctx.Namespace().Path,
+ Multilib: multilib,
+ Arch: []android.ArchType{mctx.Module().Target().Arch.ArchType},
+ }
+ }
+}
+
+func collectDepsMutator(mctx android.BottomUpMutatorContext) {
+ m := mctx.Module()
+ if m.Target().Os.Class != android.Device {
+ return
+ }
+ fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
+
+ fsGenState.fsDepsMutex.Lock()
+ defer fsGenState.fsDepsMutex.Unlock()
+
+ if slices.Contains(fsGenState.depCandidates, mctx.ModuleName()) {
+ installPartition := m.PartitionTag(mctx.DeviceConfig())
+ // Only add the module as dependency when:
+ // - its enabled
+ // - its namespace is included in PRODUCT_SOONG_NAMESPACES
+ if m.Enabled(mctx) && m.ExportedToMake() {
+ appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition)
+ }
+ }
+ // store the map of module to (required,overrides) even if the module is not in PRODUCT_PACKAGES.
+ // the module might be installed transitively.
+ if m.Enabled(mctx) && m.ExportedToMake() {
+ fsGenState.moduleToInstallationProps[m.Name()] = installationProperties{
+ Required: m.RequiredModuleNames(mctx),
+ Overrides: m.Overrides(),
+ }
+ }
+}
+
+type depsStruct struct {
+ Deps []string
+}
+
+type multilibDepsStruct struct {
+ Common depsStruct
+ Lib32 depsStruct
+ Lib64 depsStruct
+ Both depsStruct
+ Prefer32 depsStruct
+}
+
+type packagingPropsStruct struct {
+ High_priority_deps []string
+ Deps []string
+ Multilib multilibDepsStruct
+}
+
+func fullyQualifiedModuleName(moduleName, namespace string) string {
+ if namespace == "." {
+ return moduleName
+ }
+ return fmt.Sprintf("//%s:%s", namespace, moduleName)
+}
+
+func getBitness(archTypes []android.ArchType) (ret []string) {
+ for _, archType := range archTypes {
+ if archType.Multilib == "" {
+ ret = append(ret, android.COMMON_VARIANT)
+ } else {
+ ret = append(ret, archType.Bitness())
+ }
+ }
+ return ret
+}
+
+func setDepsMutator(mctx android.BottomUpMutatorContext) {
+ removeOverriddenDeps(mctx)
+ fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
+ fsDeps := fsGenState.fsDeps
+ m := mctx.Module()
+ if partition := fsGenState.soongGeneratedPartitions.typeForName(m.Name()); partition != "" {
+ if fsGenState.soongGeneratedPartitions.isHandwritten(m.Name()) {
+ // Handwritten image, don't modify it
+ return
+ }
+ depsStruct := generateDepStruct(*fsDeps[partition], fsGenState.generatedPrebuiltEtcModuleNames)
+ if err := proptools.AppendMatchingProperties(m.GetProperties(), depsStruct, nil); err != nil {
+ mctx.ModuleErrorf(err.Error())
+ }
+ }
+}
+
+// removeOverriddenDeps collects PRODUCT_PACKAGES and (transitive) required deps.
+// it then removes any modules which appear in `overrides` of the above list.
+func removeOverriddenDeps(mctx android.BottomUpMutatorContext) {
+ mctx.Config().Once(fsGenRemoveOverridesOnceKey, func() interface{} {
+ fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
+ fsDeps := fsGenState.fsDeps
+ overridden := map[string]bool{}
+ allDeps := []string{}
+
+ // Step 1: Initialization: Append PRODUCT_PACKAGES to the queue
+ for _, fsDep := range fsDeps {
+ for depName, _ := range *fsDep {
+ allDeps = append(allDeps, depName)
+ }
+ }
+
+ // Step 2: Process the queue, and add required modules to the queue.
+ i := 0
+ for {
+ if i == len(allDeps) {
+ break
+ }
+ depName := allDeps[i]
+ for _, overrides := range fsGenState.moduleToInstallationProps[depName].Overrides {
+ overridden[overrides] = true
+ }
+ // add required dep to the queue.
+ allDeps = append(allDeps, fsGenState.moduleToInstallationProps[depName].Required...)
+ i += 1
+ }
+
+ // Step 3: Delete all the overridden modules.
+ for overridden, _ := range overridden {
+ for partition, _ := range fsDeps {
+ delete(*fsDeps[partition], overridden)
+ }
+ }
+ return nil
+ })
+}
+
+var HighPriorityDeps = []string{}
+
+func isHighPriorityDep(depName string) bool {
+ for _, highPriorityDeps := range HighPriorityDeps {
+ if strings.HasPrefix(depName, highPriorityDeps) {
+ return true
+ }
+ }
+ return false
+}
+
+func generateDepStruct(deps map[string]*depCandidateProps, highPriorityDeps []string) *packagingPropsStruct {
+ depsStruct := packagingPropsStruct{}
+ for depName, depProps := range deps {
+ bitness := getBitness(depProps.Arch)
+ fullyQualifiedDepName := fullyQualifiedModuleName(depName, depProps.Namespace)
+ if android.InList(depName, highPriorityDeps) {
+ depsStruct.High_priority_deps = append(depsStruct.High_priority_deps, fullyQualifiedDepName)
+ } else if android.InList("32", bitness) && android.InList("64", bitness) {
+ // If both 32 and 64 bit variants are enabled for this module
+ switch depProps.Multilib {
+ case string(android.MultilibBoth):
+ depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
+ case string(android.MultilibCommon), string(android.MultilibFirst):
+ depsStruct.Deps = append(depsStruct.Deps, fullyQualifiedDepName)
+ case "32":
+ depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
+ case "64", "darwin_universal":
+ depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
+ case "prefer32", "first_prefer32":
+ depsStruct.Multilib.Prefer32.Deps = append(depsStruct.Multilib.Prefer32.Deps, fullyQualifiedDepName)
+ default:
+ depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
+ }
+ } else if android.InList("64", bitness) {
+ // If only 64 bit variant is enabled
+ depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
+ } else if android.InList("32", bitness) {
+ // If only 32 bit variant is enabled
+ depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
+ } else {
+ // If only common variant is enabled
+ depsStruct.Multilib.Common.Deps = append(depsStruct.Multilib.Common.Deps, fullyQualifiedDepName)
+ }
+ }
+ depsStruct.Deps = android.SortedUniqueStrings(depsStruct.Deps)
+ depsStruct.Multilib.Lib32.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Lib32.Deps)
+ depsStruct.Multilib.Lib64.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Lib64.Deps)
+ depsStruct.Multilib.Prefer32.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Prefer32.Deps)
+ depsStruct.Multilib.Both.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Both.Deps)
+ depsStruct.Multilib.Common.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Common.Deps)
+ depsStruct.High_priority_deps = android.SortedUniqueStrings(depsStruct.High_priority_deps)
+
+ return &depsStruct
+}
diff --git a/fsgen/prebuilt_etc_modules_gen.go b/fsgen/prebuilt_etc_modules_gen.go
new file mode 100644
index 0000000..e028b1d
--- /dev/null
+++ b/fsgen/prebuilt_etc_modules_gen.go
@@ -0,0 +1,412 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package fsgen
+
+import (
+ "android/soong/android"
+ "android/soong/etc"
+ "fmt"
+ "path/filepath"
+ "strings"
+
+ "github.com/google/blueprint/proptools"
+)
+
+type srcBaseFileInstallBaseFileTuple struct {
+ srcBaseFile string
+ installBaseFile string
+}
+
+// prebuilt src files grouped by the install partitions.
+// Each groups are a mapping of the relative install path to the name of the files
+type prebuiltSrcGroupByInstallPartition struct {
+ system map[string][]srcBaseFileInstallBaseFileTuple
+ system_ext map[string][]srcBaseFileInstallBaseFileTuple
+ product map[string][]srcBaseFileInstallBaseFileTuple
+ vendor map[string][]srcBaseFileInstallBaseFileTuple
+ recovery map[string][]srcBaseFileInstallBaseFileTuple
+}
+
+func newPrebuiltSrcGroupByInstallPartition() *prebuiltSrcGroupByInstallPartition {
+ return &prebuiltSrcGroupByInstallPartition{
+ system: map[string][]srcBaseFileInstallBaseFileTuple{},
+ system_ext: map[string][]srcBaseFileInstallBaseFileTuple{},
+ product: map[string][]srcBaseFileInstallBaseFileTuple{},
+ vendor: map[string][]srcBaseFileInstallBaseFileTuple{},
+ recovery: map[string][]srcBaseFileInstallBaseFileTuple{},
+ }
+}
+
+func isSubdirectory(parent, child string) bool {
+ rel, err := filepath.Rel(parent, child)
+ if err != nil {
+ return false
+ }
+ return !strings.HasPrefix(rel, "..")
+}
+
+func appendIfCorrectInstallPartition(partitionToInstallPathList []partitionToInstallPath, destPath, srcPath string, srcGroup *prebuiltSrcGroupByInstallPartition) {
+ for _, part := range partitionToInstallPathList {
+ partition := part.name
+ installPath := part.installPath
+
+ if isSubdirectory(installPath, destPath) {
+ relativeInstallPath, _ := filepath.Rel(installPath, destPath)
+ relativeInstallDir := filepath.Dir(relativeInstallPath)
+ var srcMap map[string][]srcBaseFileInstallBaseFileTuple
+ switch partition {
+ case "system":
+ srcMap = srcGroup.system
+ case "system_ext":
+ srcMap = srcGroup.system_ext
+ case "product":
+ srcMap = srcGroup.product
+ case "vendor":
+ srcMap = srcGroup.vendor
+ case "recovery":
+ srcMap = srcGroup.recovery
+ }
+ if srcMap != nil {
+ srcMap[relativeInstallDir] = append(srcMap[relativeInstallDir], srcBaseFileInstallBaseFileTuple{
+ srcBaseFile: filepath.Base(srcPath),
+ installBaseFile: filepath.Base(destPath),
+ })
+ }
+ return
+ }
+ }
+}
+
+// Create a map of source files to the list of destination files from PRODUCT_COPY_FILES entries.
+// Note that the value of the map is a list of string, given that a single source file can be
+// copied to multiple files.
+// This function also checks the existence of the source files, and validates that there is no
+// multiple source files copying to the same dest file.
+func uniqueExistingProductCopyFileMap(ctx android.LoadHookContext) map[string][]string {
+ seen := make(map[string]bool)
+ filtered := make(map[string][]string)
+
+ for _, copyFilePair := range ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.ProductCopyFiles {
+ srcDestList := strings.Split(copyFilePair, ":")
+ if len(srcDestList) < 2 {
+ ctx.ModuleErrorf("PRODUCT_COPY_FILES must follow the format \"src:dest\", got: %s", copyFilePair)
+ }
+ src, dest := srcDestList[0], srcDestList[1]
+
+ // Some downstream branches use absolute path as entries in PRODUCT_COPY_FILES.
+ // Convert them to relative path from top and check if they do not escape the tree root.
+ relSrc := android.ToRelativeSourcePath(ctx, src)
+
+ if _, ok := seen[dest]; !ok {
+ if optionalPath := android.ExistentPathForSource(ctx, relSrc); optionalPath.Valid() {
+ seen[dest] = true
+ filtered[relSrc] = append(filtered[relSrc], dest)
+ }
+ }
+ }
+
+ return filtered
+}
+
+type partitionToInstallPath struct {
+ name string
+ installPath string
+}
+
+func processProductCopyFiles(ctx android.LoadHookContext) map[string]*prebuiltSrcGroupByInstallPartition {
+ // Filter out duplicate dest entries and non existing src entries
+ productCopyFileMap := uniqueExistingProductCopyFileMap(ctx)
+
+ // System is intentionally added at the last to consider the scenarios where
+ // non-system partitions are installed as part of the system partition
+ partitionToInstallPathList := []partitionToInstallPath{
+ {name: "recovery", installPath: "recovery/root"},
+ {name: "vendor", installPath: ctx.DeviceConfig().VendorPath()},
+ {name: "product", installPath: ctx.DeviceConfig().ProductPath()},
+ {name: "system_ext", installPath: ctx.DeviceConfig().SystemExtPath()},
+ {name: "system", installPath: "system"},
+ }
+
+ groupedSources := map[string]*prebuiltSrcGroupByInstallPartition{}
+ for _, src := range android.SortedKeys(productCopyFileMap) {
+ destFiles := productCopyFileMap[src]
+ srcFileDir := filepath.Dir(src)
+ if _, ok := groupedSources[srcFileDir]; !ok {
+ groupedSources[srcFileDir] = newPrebuiltSrcGroupByInstallPartition()
+ }
+ for _, dest := range destFiles {
+ appendIfCorrectInstallPartition(partitionToInstallPathList, dest, filepath.Base(src), groupedSources[srcFileDir])
+ }
+ }
+
+ return groupedSources
+}
+
+type prebuiltModuleProperties struct {
+ Name *string
+
+ Soc_specific *bool
+ Product_specific *bool
+ System_ext_specific *bool
+ Recovery *bool
+ Ramdisk *bool
+
+ Srcs []string
+ Dsts []string
+
+ No_full_install *bool
+
+ NamespaceExportedToMake bool
+
+ Visibility []string
+}
+
+// Split relative_install_path to a separate struct, because it is not supported for every
+// modules listed in [etcInstallPathToFactoryMap]
+type prebuiltSubdirProperties struct {
+ // If the base file name of the src and dst all match, dsts property does not need to be
+ // set, and only relative_install_path can be set.
+ Relative_install_path *string
+}
+
+// Split install_in_root to a separate struct as it is part of rootProperties instead of
+// properties
+type prebuiltInstallInRootProperties struct {
+ Install_in_root *bool
+}
+
+var (
+ etcInstallPathToFactoryList = map[string]android.ModuleFactory{
+ "": etc.PrebuiltRootFactory,
+ "avb": etc.PrebuiltAvbFactory,
+ "bin": etc.PrebuiltBinaryFactory,
+ "bt_firmware": etc.PrebuiltBtFirmwareFactory,
+ "cacerts": etc.PrebuiltEtcCaCertsFactory,
+ "dsp": etc.PrebuiltDSPFactory,
+ "etc": etc.PrebuiltEtcFactory,
+ "etc/dsp": etc.PrebuiltDSPFactory,
+ "etc/firmware": etc.PrebuiltFirmwareFactory,
+ "firmware": etc.PrebuiltFirmwareFactory,
+ "first_stage_ramdisk": etc.PrebuiltFirstStageRamdiskFactory,
+ "fonts": etc.PrebuiltFontFactory,
+ "framework": etc.PrebuiltFrameworkFactory,
+ "lib": etc.PrebuiltRenderScriptBitcodeFactory,
+ "lib64": etc.PrebuiltRenderScriptBitcodeFactory,
+ "lib/rfsa": etc.PrebuiltRFSAFactory,
+ "media": etc.PrebuiltMediaFactory,
+ "odm": etc.PrebuiltOdmFactory,
+ "optee": etc.PrebuiltOpteeFactory,
+ "overlay": etc.PrebuiltOverlayFactory,
+ "priv-app": etc.PrebuiltPrivAppFactory,
+ "sbin": etc.PrebuiltSbinFactory,
+ "system": etc.PrebuiltSystemFactory,
+ "res": etc.PrebuiltResFactory,
+ "rfs": etc.PrebuiltRfsFactory,
+ "tts": etc.PrebuiltVoicepackFactory,
+ "tvconfig": etc.PrebuiltTvConfigFactory,
+ "tvservice": etc.PrebuiltTvServiceFactory,
+ "usr/share": etc.PrebuiltUserShareFactory,
+ "usr/hyphen-data": etc.PrebuiltUserHyphenDataFactory,
+ "usr/keylayout": etc.PrebuiltUserKeyLayoutFactory,
+ "usr/keychars": etc.PrebuiltUserKeyCharsFactory,
+ "usr/srec": etc.PrebuiltUserSrecFactory,
+ "usr/idc": etc.PrebuiltUserIdcFactory,
+ "vendor": etc.PrebuiltVendorFactory,
+ "vendor_dlkm": etc.PrebuiltVendorDlkmFactory,
+ "wallpaper": etc.PrebuiltWallpaperFactory,
+ "wlc_upt": etc.PrebuiltWlcUptFactory,
+ }
+)
+
+func generatedPrebuiltEtcModuleName(partition, srcDir, destDir string, count int) string {
+ // generated module name follows the pattern:
+ // <install partition>-<src file path>-<relative install path from partition root>-<number>
+ // Note that all path separators are replaced with "_" in the name
+ moduleName := partition
+ if !android.InList(srcDir, []string{"", "."}) {
+ moduleName += fmt.Sprintf("-%s", strings.ReplaceAll(srcDir, string(filepath.Separator), "_"))
+ }
+ if !android.InList(destDir, []string{"", "."}) {
+ moduleName += fmt.Sprintf("-%s", strings.ReplaceAll(destDir, string(filepath.Separator), "_"))
+ }
+ moduleName += fmt.Sprintf("-%d", count)
+
+ return moduleName
+}
+
+func groupDestFilesBySrc(destFiles []srcBaseFileInstallBaseFileTuple) (ret map[string][]srcBaseFileInstallBaseFileTuple, maxLen int) {
+ ret = map[string][]srcBaseFileInstallBaseFileTuple{}
+ maxLen = 0
+ for _, tuple := range destFiles {
+ if _, ok := ret[tuple.srcBaseFile]; !ok {
+ ret[tuple.srcBaseFile] = []srcBaseFileInstallBaseFileTuple{}
+ }
+ ret[tuple.srcBaseFile] = append(ret[tuple.srcBaseFile], tuple)
+ maxLen = max(maxLen, len(ret[tuple.srcBaseFile]))
+ }
+ return ret, maxLen
+}
+
+func prebuiltEtcModuleProps(ctx android.LoadHookContext, moduleName, partition, destDir string) prebuiltModuleProperties {
+ moduleProps := prebuiltModuleProperties{}
+ moduleProps.Name = proptools.StringPtr(moduleName)
+
+ // Set partition specific properties
+ switch partition {
+ case "system_ext":
+ moduleProps.System_ext_specific = proptools.BoolPtr(true)
+ case "product":
+ moduleProps.Product_specific = proptools.BoolPtr(true)
+ case "vendor":
+ moduleProps.Soc_specific = proptools.BoolPtr(true)
+ case "recovery":
+ // To match the logic in modulePartition() in android/paths.go
+ if ctx.DeviceConfig().BoardUsesRecoveryAsBoot() && strings.HasPrefix(destDir, "first_stage_ramdisk") {
+ moduleProps.Ramdisk = proptools.BoolPtr(true)
+ } else {
+ moduleProps.Recovery = proptools.BoolPtr(true)
+ }
+ }
+
+ moduleProps.No_full_install = proptools.BoolPtr(true)
+ moduleProps.NamespaceExportedToMake = true
+ moduleProps.Visibility = []string{"//visibility:public"}
+
+ return moduleProps
+}
+
+func createPrebuiltEtcModulesInDirectory(ctx android.LoadHookContext, partition, srcDir, destDir string, destFiles []srcBaseFileInstallBaseFileTuple) (moduleNames []string) {
+ groupedDestFiles, maxLen := groupDestFilesBySrc(destFiles)
+
+ // Find out the most appropriate module type to generate
+ var etcInstallPathKey string
+ for _, etcInstallPath := range android.SortedKeys(etcInstallPathToFactoryList) {
+ // Do not break when found but iterate until the end to find a module with more
+ // specific install path
+ if strings.HasPrefix(destDir, etcInstallPath) {
+ etcInstallPathKey = etcInstallPath
+ }
+ }
+ relDestDirFromInstallDirBase, _ := filepath.Rel(etcInstallPathKey, destDir)
+
+ for fileIndex := range maxLen {
+ srcTuple := []srcBaseFileInstallBaseFileTuple{}
+ for _, srcFile := range android.SortedKeys(groupedDestFiles) {
+ groupedDestFile := groupedDestFiles[srcFile]
+ if len(groupedDestFile) > fileIndex {
+ srcTuple = append(srcTuple, groupedDestFile[fileIndex])
+ }
+ }
+
+ moduleName := generatedPrebuiltEtcModuleName(partition, srcDir, destDir, fileIndex)
+ moduleProps := prebuiltEtcModuleProps(ctx, moduleName, partition, destDir)
+ modulePropsPtr := &moduleProps
+ propsList := []interface{}{modulePropsPtr}
+
+ allCopyFileNamesUnchanged := true
+ var srcBaseFiles, installBaseFiles []string
+ for _, tuple := range srcTuple {
+ if tuple.srcBaseFile != tuple.installBaseFile {
+ allCopyFileNamesUnchanged = false
+ }
+ srcBaseFiles = append(srcBaseFiles, tuple.srcBaseFile)
+ installBaseFiles = append(installBaseFiles, tuple.installBaseFile)
+ }
+
+ // Recovery partition-installed modules are installed to `recovery/root/system` by
+ // default (See modulePartition() in android/paths.go). If the destination file
+ // directory is not `recovery/root/system/...`, it should set install_in_root to true
+ // to prevent being installed in `recovery/root/system`.
+ if partition == "recovery" && !strings.HasPrefix(destDir, "system") {
+ propsList = append(propsList, &prebuiltInstallInRootProperties{
+ Install_in_root: proptools.BoolPtr(true),
+ })
+ }
+
+ // Set appropriate srcs, dsts, and releative_install_path based on
+ // the source and install file names
+ if allCopyFileNamesUnchanged {
+ modulePropsPtr.Srcs = srcBaseFiles
+
+ // Specify relative_install_path if it is not installed in the root directory of the
+ // partition
+ if !android.InList(relDestDirFromInstallDirBase, []string{"", "."}) {
+ propsList = append(propsList, &prebuiltSubdirProperties{
+ Relative_install_path: proptools.StringPtr(relDestDirFromInstallDirBase),
+ })
+ }
+ } else {
+ modulePropsPtr.Srcs = srcBaseFiles
+ dsts := []string{}
+ for _, installBaseFile := range installBaseFiles {
+ dsts = append(dsts, filepath.Join(relDestDirFromInstallDirBase, installBaseFile))
+ }
+ modulePropsPtr.Dsts = dsts
+ }
+
+ ctx.CreateModuleInDirectory(etcInstallPathToFactoryList[etcInstallPathKey], srcDir, propsList...)
+ moduleNames = append(moduleNames, moduleName)
+ }
+
+ return moduleNames
+}
+
+func createPrebuiltEtcModulesForPartition(ctx android.LoadHookContext, partition, srcDir string, destDirFilesMap map[string][]srcBaseFileInstallBaseFileTuple) (ret []string) {
+ for _, destDir := range android.SortedKeys(destDirFilesMap) {
+ ret = append(ret, createPrebuiltEtcModulesInDirectory(ctx, partition, srcDir, destDir, destDirFilesMap[destDir])...)
+ }
+ return ret
+}
+
+// Creates prebuilt_* modules based on the install paths and returns the list of generated
+// module names
+func createPrebuiltEtcModules(ctx android.LoadHookContext) (ret []string) {
+ groupedSources := processProductCopyFiles(ctx)
+ for _, srcDir := range android.SortedKeys(groupedSources) {
+ groupedSource := groupedSources[srcDir]
+ ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "system", srcDir, groupedSource.system)...)
+ ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "system_ext", srcDir, groupedSource.system_ext)...)
+ ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "product", srcDir, groupedSource.product)...)
+ ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "vendor", srcDir, groupedSource.vendor)...)
+ ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "recovery", srcDir, groupedSource.recovery)...)
+ }
+
+ return ret
+}
+
+func createAvbpubkeyModule(ctx android.LoadHookContext) bool {
+ avbKeyPath := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BoardAvbKeyPath
+ if avbKeyPath == "" {
+ return false
+ }
+ ctx.CreateModuleInDirectory(
+ etc.AvbpubkeyModuleFactory,
+ ".",
+ &struct {
+ Name *string
+ Product_specific *bool
+ Private_key *string
+ No_full_install *bool
+ Visibility []string
+ }{
+ Name: proptools.StringPtr("system_other_avbpubkey"),
+ Product_specific: proptools.BoolPtr(true),
+ Private_key: proptools.StringPtr(avbKeyPath),
+ No_full_install: proptools.BoolPtr(true),
+ Visibility: []string{"//visibility:public"},
+ },
+ )
+ return true
+}
diff --git a/fsgen/super_img.go b/fsgen/super_img.go
new file mode 100644
index 0000000..569f780
--- /dev/null
+++ b/fsgen/super_img.go
@@ -0,0 +1,132 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package fsgen
+
+import (
+ "strconv"
+
+ "android/soong/android"
+ "android/soong/filesystem"
+
+ "github.com/google/blueprint/proptools"
+)
+
+func buildingSuperImage(partitionVars android.PartitionVariables) bool {
+ return partitionVars.ProductBuildSuperPartition
+}
+
+func createSuperImage(
+ ctx android.LoadHookContext,
+ partitions allGeneratedPartitionData,
+ partitionVars android.PartitionVariables,
+ systemOtherImageName string,
+) []string {
+ baseProps := &struct {
+ Name *string
+ }{
+ Name: proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "super")),
+ }
+
+ superImageProps := &filesystem.SuperImageProperties{
+ Metadata_device: proptools.StringPtr(partitionVars.BoardSuperPartitionMetadataDevice),
+ Block_devices: partitionVars.BoardSuperPartitionBlockDevices,
+ Ab_update: proptools.BoolPtr(partitionVars.AbOtaUpdater),
+ Retrofit: proptools.BoolPtr(partitionVars.ProductRetrofitDynamicPartitions),
+ Use_dynamic_partitions: proptools.BoolPtr(partitionVars.ProductUseDynamicPartitions),
+ }
+ if partitionVars.ProductVirtualAbOta {
+ superImageProps.Virtual_ab.Enable = proptools.BoolPtr(true)
+ superImageProps.Virtual_ab.Retrofit = proptools.BoolPtr(partitionVars.ProductVirtualAbOtaRetrofit)
+ superImageProps.Virtual_ab.Compression = proptools.BoolPtr(partitionVars.ProductVirtualAbCompression)
+ if partitionVars.ProductVirtualAbCompressionMethod != "" {
+ superImageProps.Virtual_ab.Compression_method = proptools.StringPtr(partitionVars.ProductVirtualAbCompressionMethod)
+ }
+ if partitionVars.ProductVirtualAbCompressionFactor != "" {
+ factor, err := strconv.ParseInt(partitionVars.ProductVirtualAbCompressionFactor, 10, 32)
+ if err != nil {
+ ctx.ModuleErrorf("Compression factor must be an int, got %q", partitionVars.ProductVirtualAbCompressionFactor)
+ }
+ superImageProps.Virtual_ab.Compression_factor = proptools.Int64Ptr(factor)
+ }
+ if partitionVars.ProductVirtualAbCowVersion != "" {
+ version, err := strconv.ParseInt(partitionVars.ProductVirtualAbCowVersion, 10, 32)
+ if err != nil {
+ ctx.ModuleErrorf("COW version must be an int, got %q", partitionVars.ProductVirtualAbCowVersion)
+ }
+ superImageProps.Virtual_ab.Cow_version = proptools.Int64Ptr(version)
+ }
+ }
+ size, _ := strconv.ParseInt(partitionVars.BoardSuperPartitionSize, 10, 64)
+ superImageProps.Size = proptools.Int64Ptr(size)
+ sparse := !partitionVars.TargetUserimagesSparseExtDisabled && !partitionVars.TargetUserimagesSparseF2fsDisabled
+ superImageProps.Sparse = proptools.BoolPtr(sparse)
+
+ var partitionGroupsInfo []filesystem.PartitionGroupsInfo
+ for _, groupName := range android.SortedKeys(partitionVars.BoardSuperPartitionGroups) {
+ info := filesystem.PartitionGroupsInfo{
+ Name: groupName,
+ GroupSize: partitionVars.BoardSuperPartitionGroups[groupName].GroupSize,
+ PartitionList: partitionVars.BoardSuperPartitionGroups[groupName].PartitionList,
+ }
+ partitionGroupsInfo = append(partitionGroupsInfo, info)
+ }
+ superImageProps.Partition_groups = partitionGroupsInfo
+
+ if systemOtherImageName != "" {
+ superImageProps.System_other_partition = proptools.StringPtr(systemOtherImageName)
+ }
+
+ var superImageSubpartitions []string
+ partitionNameProps := &filesystem.SuperImagePartitionNameProperties{}
+ if modName := partitions.nameForType("system"); modName != "" {
+ partitionNameProps.System_partition = proptools.StringPtr(modName)
+ superImageSubpartitions = append(superImageSubpartitions, "system")
+ }
+ if modName := partitions.nameForType("system_ext"); modName != "" {
+ partitionNameProps.System_ext_partition = proptools.StringPtr(modName)
+ superImageSubpartitions = append(superImageSubpartitions, "system_ext")
+ }
+ if modName := partitions.nameForType("system_dlkm"); modName != "" {
+ partitionNameProps.System_dlkm_partition = proptools.StringPtr(modName)
+ superImageSubpartitions = append(superImageSubpartitions, "system_dlkm")
+ }
+ if modName := partitions.nameForType("system_other"); modName != "" {
+ partitionNameProps.System_other_partition = proptools.StringPtr(modName)
+ superImageSubpartitions = append(superImageSubpartitions, "system_other")
+ }
+ if modName := partitions.nameForType("product"); modName != "" {
+ partitionNameProps.Product_partition = proptools.StringPtr(modName)
+ superImageSubpartitions = append(superImageSubpartitions, "product")
+ }
+ if modName := partitions.nameForType("vendor"); modName != "" {
+ partitionNameProps.Vendor_partition = proptools.StringPtr(modName)
+ superImageSubpartitions = append(superImageSubpartitions, "vendor")
+ }
+ if modName := partitions.nameForType("vendor_dlkm"); modName != "" {
+ partitionNameProps.Vendor_dlkm_partition = proptools.StringPtr(modName)
+ superImageSubpartitions = append(superImageSubpartitions, "vendor_dlkm")
+ }
+ if modName := partitions.nameForType("odm"); modName != "" {
+ partitionNameProps.Odm_partition = proptools.StringPtr(modName)
+ superImageSubpartitions = append(superImageSubpartitions, "odm")
+ }
+ if modName := partitions.nameForType("odm_dlkm"); modName != "" {
+ partitionNameProps.Odm_dlkm_partition = proptools.StringPtr(modName)
+ superImageSubpartitions = append(superImageSubpartitions, "odm_dlkm")
+ }
+
+ ctx.CreateModule(filesystem.SuperImageFactory, baseProps, superImageProps, partitionNameProps)
+ return superImageSubpartitions
+}
diff --git a/fsgen/util.go b/fsgen/util.go
new file mode 100644
index 0000000..008f9fe
--- /dev/null
+++ b/fsgen/util.go
@@ -0,0 +1,79 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package fsgen
+
+import (
+ "android/soong/android"
+ "android/soong/filesystem"
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// Returns the appropriate dpi for recovery common resources selection. Replicates the logic in
+// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=2536;drc=a6af369e71ded123734523ea640b97b70a557cb9
+func getDpi(ctx android.LoadHookContext) string {
+ recoveryDensity := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.TargetScreenDensity
+ if len(recoveryDensity) == 0 {
+ aaptPreferredConfig := ctx.Config().ProductAAPTPreferredConfig()
+ if len(aaptPreferredConfig) > 0 {
+ recoveryDensity = aaptPreferredConfig
+ } else {
+ recoveryDensity = "mdpi"
+ }
+ }
+ if !android.InList(recoveryDensity, []string{"xxxhdpi", "xxhdpi", "xhdpi", "hdpi", "mdpi"}) {
+ recoveryDensity = strings.TrimSuffix(recoveryDensity, "dpi")
+ dpiInt, err := strconv.ParseInt(recoveryDensity, 10, 64)
+ if err != nil {
+ panic(fmt.Sprintf("Error in parsing recoveryDensity: %s", err.Error()))
+ }
+ if dpiInt >= 560 {
+ recoveryDensity = "xxxhdpi"
+ } else if dpiInt >= 400 {
+ recoveryDensity = "xxhdpi"
+ } else if dpiInt >= 280 {
+ recoveryDensity = "xhdpi"
+ } else if dpiInt >= 200 {
+ recoveryDensity = "hdpi"
+ } else {
+ recoveryDensity = "mdpi"
+ }
+ }
+
+ if p := android.ExistentPathForSource(ctx, fmt.Sprintf("bootable/recovery/res-%s", recoveryDensity)); !p.Valid() {
+ recoveryDensity = "xhdpi"
+ }
+
+ return recoveryDensity
+}
+
+// Returns the name of the appropriate prebuilt module for installing font.png file.
+// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=2536;drc=a6af369e71ded123734523ea640b97b70a557cb9
+func getRecoveryFontModuleName(ctx android.LoadHookContext) string {
+ if android.InList(getDpi(ctx), []string{"xxxhdpi", "xxhdpi", "xhdpi"}) {
+ return "recovery-fonts-18"
+ }
+ return "recovery-fonts-12"
+}
+
+// Returns a new list of symlinks with prefix added to the dest directory for all symlinks
+func symlinksWithNamePrefix(symlinks []filesystem.SymlinkDefinition, prefix string) []filesystem.SymlinkDefinition {
+ ret := make([]filesystem.SymlinkDefinition, len(symlinks))
+ for i, symlink := range symlinks {
+ ret[i] = symlink.CopyWithNamePrefix(prefix)
+ }
+ return ret
+}
diff --git a/fsgen/vbmeta_partitions.go b/fsgen/vbmeta_partitions.go
new file mode 100644
index 0000000..11f4bd0
--- /dev/null
+++ b/fsgen/vbmeta_partitions.go
@@ -0,0 +1,271 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package fsgen
+
+import (
+ "android/soong/android"
+ "android/soong/filesystem"
+ "strconv"
+
+ "github.com/google/blueprint/proptools"
+)
+
+type vbmetaModuleInfo struct {
+ // The name of the generated vbmeta module
+ moduleName string
+ // The name of the module that avb understands. This is the name passed to --chain_partition,
+ // and also the basename of the output file. (the output file is called partitionName + ".img")
+ partitionName string
+}
+
+// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4849;drc=62e20f0d218f60bae563b4ee742d88cca1fc1901
+var avbPartitions = []string{
+ "boot",
+ "init_boot",
+ "vendor_boot",
+ "vendor_kernel_boot",
+ "system",
+ "vendor",
+ "product",
+ "system_ext",
+ "odm",
+ "vendor_dlkm",
+ "odm_dlkm",
+ "system_dlkm",
+ "dtbo",
+ "pvmfw",
+ "recovery",
+ "vbmeta_system",
+ "vbmeta_vendor",
+}
+
+// Creates the vbmeta partition and the chained vbmeta partitions. Returns the list of module names
+// that the function created. May return nil if the product isn't using avb.
+//
+// AVB is Android Verified Boot: https://source.android.com/docs/security/features/verifiedboot
+// It works by signing all the partitions, but then also including an extra metadata paritition
+// called vbmeta that depends on all the other signed partitions. This creates a requirement
+// that you update all those partitions and the vbmeta partition together, so in order to relax
+// that requirement products can set up "chained" vbmeta partitions, where a chained partition
+// like vbmeta_system might contain the avb metadata for just a few products. In cuttlefish
+// vbmeta_system contains metadata about product, system, and system_ext. Using chained partitions,
+// that group of partitions can be updated independently from the other signed partitions.
+func (f *filesystemCreator) createVbmetaPartitions(ctx android.LoadHookContext, partitions allGeneratedPartitionData) []vbmetaModuleInfo {
+ partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+ // Some products seem to have BuildingVbmetaImage as true even when BoardAvbEnable is false
+ if !partitionVars.BuildingVbmetaImage || !partitionVars.BoardAvbEnable {
+ return nil
+ }
+
+ var result []vbmetaModuleInfo
+
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4593;drc=62e20f0d218f60bae563b4ee742d88cca1fc1901
+ var internalAvbPartitionsInChainedVbmetaImages []string
+ var chainedPartitionTypes []string
+ for _, chainedName := range android.SortedKeys(partitionVars.ChainedVbmetaPartitions) {
+ props := partitionVars.ChainedVbmetaPartitions[chainedName]
+ chainedName = "vbmeta_" + chainedName
+ if len(props.Partitions) == 0 {
+ continue
+ }
+ internalAvbPartitionsInChainedVbmetaImages = append(internalAvbPartitionsInChainedVbmetaImages, props.Partitions...)
+ if len(props.Key) == 0 {
+ ctx.ModuleErrorf("No key found for chained avb partition %q", chainedName)
+ continue
+ }
+ if len(props.Algorithm) == 0 {
+ ctx.ModuleErrorf("No algorithm found for chained avb partition %q", chainedName)
+ continue
+ }
+ if len(props.RollbackIndex) == 0 {
+ ctx.ModuleErrorf("No rollback index found for chained avb partition %q", chainedName)
+ continue
+ }
+ ril, err := strconv.ParseInt(props.RollbackIndexLocation, 10, 32)
+ if err != nil {
+ ctx.ModuleErrorf("Rollback index location must be an int, got %q", props.RollbackIndexLocation)
+ continue
+ }
+ // The default is to use the PlatformSecurityPatch, and a lot of product config files
+ // just set it to the platform security patch, so detect that and don't set the property
+ // in soong.
+ var rollbackIndex *int64
+ if props.RollbackIndex != ctx.Config().PlatformSecurityPatch() {
+ i, err := strconv.ParseInt(props.RollbackIndex, 10, 32)
+ if err != nil {
+ ctx.ModuleErrorf("Rollback index must be an int, got %q", props.RollbackIndex)
+ continue
+ }
+ rollbackIndex = &i
+ }
+
+ var partitionModules []string
+ for _, partition := range props.Partitions {
+ if modName := partitions.nameForType(partition); modName != "" {
+ partitionModules = append(partitionModules, modName)
+ }
+ }
+
+ name := generatedModuleNameForPartition(ctx.Config(), chainedName)
+ ctx.CreateModuleInDirectory(
+ filesystem.VbmetaFactory,
+ ".", // Create in the root directory for now so its easy to get the key
+ &filesystem.VbmetaProperties{
+ Partition_name: proptools.StringPtr(chainedName),
+ Stem: proptools.StringPtr(chainedName + ".img"),
+ Private_key: proptools.StringPtr(props.Key),
+ Algorithm: &props.Algorithm,
+ Rollback_index: rollbackIndex,
+ Rollback_index_location: &ril,
+ Partitions: proptools.NewSimpleConfigurable(partitionModules),
+ }, &struct {
+ Name *string
+ }{
+ Name: &name,
+ },
+ ).HideFromMake()
+
+ result = append(result, vbmetaModuleInfo{
+ moduleName: name,
+ partitionName: chainedName,
+ })
+
+ chainedPartitionTypes = append(chainedPartitionTypes, chainedName)
+ }
+
+ vbmetaModuleName := generatedModuleNameForPartition(ctx.Config(), "vbmeta")
+
+ var algorithm *string
+ var ri *int64
+ var key *string
+ if len(partitionVars.BoardAvbKeyPath) == 0 {
+ // Match make's defaults: https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4568;drc=5b55f926830963c02ab1d2d91e46442f04ba3af0
+ key = proptools.StringPtr("external/avb/test/data/testkey_rsa4096.pem")
+ algorithm = proptools.StringPtr("SHA256_RSA4096")
+ } else {
+ key = proptools.StringPtr(partitionVars.BoardAvbKeyPath)
+ algorithm = proptools.StringPtr(partitionVars.BoardAvbAlgorithm)
+ }
+ if len(partitionVars.BoardAvbRollbackIndex) > 0 {
+ parsedRi, err := strconv.ParseInt(partitionVars.BoardAvbRollbackIndex, 10, 32)
+ if err != nil {
+ ctx.ModuleErrorf("Rollback index location must be an int, got %q", partitionVars.BoardAvbRollbackIndex)
+ }
+ ri = &parsedRi
+ }
+
+ // --chain_partition argument is only set for partitions that set
+ // `BOARD_AVB_<partition name>_KEY_PATH` value and is not "recovery"
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4823;drc=62e20f0d218f60bae563b4ee742d88cca1fc1901
+ includeAsChainedPartitionInVbmeta := func(partition string) bool {
+ val, ok := partitionVars.PartitionQualifiedVariables[partition]
+ return ok && len(val.BoardAvbKeyPath) > 0 && partition != "recovery"
+ }
+
+ // --include_descriptors_from_image is passed if both conditions are met:
+ // - `BOARD_AVB_<partition name>_KEY_PATH` value is not set
+ // - not included in INTERNAL_AVB_PARTITIONS_IN_CHAINED_VBMETA_IMAGES
+ // for partitions that set INSTALLED_<partition name>IMAGE_TARGET
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4827;drc=62e20f0d218f60bae563b4ee742d88cca1fc1901
+ includeAsIncludedPartitionInVbmeta := func(partition string) bool {
+ if android.InList(partition, internalAvbPartitionsInChainedVbmetaImages) {
+ // Already handled by chained vbmeta partitions
+ return false
+ }
+ partitionQualifiedVars := partitionVars.PartitionQualifiedVariables[partition]
+
+ // The return logic in the switch cases below are identical to
+ // ifdef INSTALLED_<partition name>IMAGE_TARGET
+ switch partition {
+ case "boot":
+ return partitionQualifiedVars.BuildingImage || partitionQualifiedVars.PrebuiltImage || partitionVars.BoardUsesRecoveryAsBoot
+ case "vendor_kernel_boot", "dtbo":
+ return partitionQualifiedVars.PrebuiltImage
+ case "system":
+ return partitionQualifiedVars.BuildingImage
+ case "init_boot", "vendor_boot", "vendor", "product", "system_ext", "odm", "vendor_dlkm", "odm_dlkm", "system_dlkm":
+ return partitionQualifiedVars.BuildingImage || partitionQualifiedVars.PrebuiltImage
+ // TODO: Import BOARD_USES_PVMFWIMAGE
+ // ifeq ($(BOARD_USES_PVMFWIMAGE),true)
+ // case "pvmfw":
+ case "recovery":
+ // ifdef INSTALLED_RECOVERYIMAGE_TARGET
+ return !ctx.DeviceConfig().BoardUsesRecoveryAsBoot() && !ctx.DeviceConfig().BoardMoveRecoveryResourcesToVendorBoot()
+ // Technically these partitions are determined based on len(BOARD_AVB_VBMETA_SYSTEM) and
+ // len(BOARD_AVB_VBMETA_VENDOR) but if these are non empty these partitions are
+ // already included in the chained partitions.
+ case "vbmeta_system", "vbmeta_vendor":
+ return false
+ default:
+ return false
+ }
+ }
+
+ var chainedPartitionModules []string
+ var includePartitionModules []string
+ allGeneratedPartitionTypes := append(partitions.types(),
+ chainedPartitionTypes...,
+ )
+ if len(f.properties.Boot_image) > 0 {
+ allGeneratedPartitionTypes = append(allGeneratedPartitionTypes, "boot")
+ }
+ if len(f.properties.Init_boot_image) > 0 {
+ allGeneratedPartitionTypes = append(allGeneratedPartitionTypes, "init_boot")
+ }
+ if len(f.properties.Vendor_boot_image) > 0 {
+ allGeneratedPartitionTypes = append(allGeneratedPartitionTypes, "vendor_boot")
+ }
+
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4919;drc=62e20f0d218f60bae563b4ee742d88cca1fc1901
+ for _, partitionType := range android.SortedUniqueStrings(append(avbPartitions, chainedPartitionTypes...)) {
+ if !android.InList(partitionType, allGeneratedPartitionTypes) {
+ // Skip if the partition is not auto generated
+ continue
+ }
+ name := partitions.nameForType(partitionType)
+ if name == "" {
+ name = generatedModuleNameForPartition(ctx.Config(), partitionType)
+ }
+ if includeAsChainedPartitionInVbmeta(partitionType) {
+ chainedPartitionModules = append(chainedPartitionModules, name)
+ } else if includeAsIncludedPartitionInVbmeta(partitionType) {
+ includePartitionModules = append(includePartitionModules, name)
+ }
+ }
+
+ ctx.CreateModuleInDirectory(
+ filesystem.VbmetaFactory,
+ ".", // Create in the root directory for now so its easy to get the key
+ &filesystem.VbmetaProperties{
+ Stem: proptools.StringPtr("vbmeta.img"),
+ Algorithm: algorithm,
+ Private_key: key,
+ Rollback_index: ri,
+ Chained_partitions: chainedPartitionModules,
+ Partitions: proptools.NewSimpleConfigurable(includePartitionModules),
+ Partition_name: proptools.StringPtr("vbmeta"),
+ }, &struct {
+ Name *string
+ }{
+ Name: &vbmetaModuleName,
+ },
+ ).HideFromMake()
+
+ result = append(result, vbmetaModuleInfo{
+ moduleName: vbmetaModuleName,
+ partitionName: "vbmeta",
+ })
+ return result
+}
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index 306d65e..3fd79a7 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -44,6 +44,32 @@
UnknownFramework Framework = "unknownframework"
)
+func (f Framework) Variant() string {
+ switch f {
+ case AFL:
+ return "afl"
+ case LibFuzzer:
+ return "libfuzzer"
+ case Jazzer:
+ return "jazzer"
+ default:
+ panic(fmt.Errorf("unknown fuzzer %q when getting variant", f))
+ }
+}
+
+func FrameworkFromVariant(v string) Framework {
+ switch v {
+ case "afl":
+ return AFL
+ case "libfuzzer":
+ return LibFuzzer
+ case "jazzer":
+ return Jazzer
+ default:
+ panic(fmt.Errorf("unknown variant %q when getting fuzzer", v))
+ }
+}
+
var BoolDefault = proptools.BoolDefault
type FuzzModule struct {
@@ -385,9 +411,22 @@
// Optional list of seed files to be installed to the fuzz target's output
// directory.
Corpus []string `android:"path"`
+
+ // Same as corpus, but adds dependencies on module references using the device's os variant
+ // and the common arch variant.
+ Device_common_corpus []string `android:"path_device_common"`
+
// Optional list of data files to be installed to the fuzz target's output
// directory. Directory structure relative to the module is preserved.
Data []string `android:"path"`
+ // Same as data, but adds dependencies on modules using the device's os variant, and common
+ // architecture's variant. Can be useful to add device-built apps to the data of a host
+ // test.
+ Device_common_data []string `android:"path_device_common"`
+ // Same as data, but adds dependencies on modules using the device's os variant, and the
+ // device's first architecture's variant. Can be useful to add device-built apps to the data
+ // of a host test.
+ Device_first_data []string `android:"path_device_first"`
// Optional dictionary to be installed to the fuzz target's output directory.
Dictionary *string `android:"path"`
// Define the fuzzing frameworks this fuzz target can be built for. If
@@ -449,7 +488,7 @@
}
}
-func IsValid(ctx android.ConfigAndErrorContext, fuzzModule FuzzModule) bool {
+func IsValid(ctx android.ConfigurableEvaluatorContext, fuzzModule FuzzModule) bool {
// Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of
// fuzz targets we're going to package anyway.
if !fuzzModule.Enabled(ctx) || fuzzModule.InRamdisk() || fuzzModule.InVendorRamdisk() || fuzzModule.InRecovery() {
diff --git a/genrule/Android.bp b/genrule/Android.bp
index 7331741..49df480 100644
--- a/genrule/Android.bp
+++ b/genrule/Android.bp
@@ -22,4 +22,56 @@
"genrule_test.go",
],
pluginFor: ["soong_build"],
+ // Used by plugins
+ visibility: ["//visibility:public"],
+}
+
+genrule {
+ name: "nsjail_genrule_test_input",
+ cmd: "echo nsjail_genrule_test_input > $(out)",
+ out: ["nsjail_genrule_test_input.txt"],
+}
+
+// Pseudo-test that's run on checkbuilds to verify consistent directory
+// structure for genrules using sbox or nsjail.
+genrule_defaults {
+ name: "nsjail_genrule_test_gen_defaults",
+ // verify both relative paths and its contents
+ cmd: "(echo $(out) $(genDir) && sha256sum " +
+ "$(location get_clang_version) " +
+ "$(location py3-cmd) " +
+ "$(location genrule.go) " +
+ "$(location :nsjail_genrule_test_input) " +
+ "$(locations *.go)) | sed 's@\\./@@g' > $(out)",
+ tools: [
+ "get_clang_version", // random tool
+ "py3-cmd", // random prebuilt tool
+ ],
+ tool_files: ["genrule.go"], // random local file
+ srcs: [
+ ":nsjail_genrule_test_input", // random OutputFileProducer
+ "*.go", // random glob
+ ],
+ out: ["nsjail_genrule_test.txt"],
+}
+
+genrule {
+ name: "nsjail_genrule_test_gen_without_nsjail",
+ defaults: ["nsjail_genrule_test_gen_defaults"],
+}
+
+genrule {
+ name: "nsjail_genrule_test_gen_with_nsjail",
+ defaults: ["nsjail_genrule_test_gen_defaults"],
+ use_nsjail: true,
+}
+
+genrule {
+ name: "nsjail_genrule_test",
+ srcs: [
+ ":nsjail_genrule_test_gen_without_nsjail",
+ ":nsjail_genrule_test_gen_with_nsjail",
+ ],
+ cmd: "diff $(in) > $(out)",
+ out: ["nsjail_genrule_test"],
}
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
index 7c71b77..45a7f72 100644
--- a/genrule/allowlists.go
+++ b/genrule/allowlists.go
@@ -17,8 +17,6 @@
var (
SandboxingDenyModuleList = []string{
// go/keep-sorted start
- "aidl_camera_build_version",
- "com.google.pixel.camera.hal.manifest",
// go/keep-sorted end
}
)
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 9195643..65f74ce 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -21,11 +21,11 @@
import (
"fmt"
"io"
+ "path/filepath"
"strconv"
"strings"
"github.com/google/blueprint"
- "github.com/google/blueprint/bootstrap"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -63,7 +63,7 @@
ctx.RegisterModuleType("genrule", GenRuleFactory)
ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("genrule_tool_deps", toolDepsMutator).Parallel()
+ ctx.BottomUp("genrule_tool_deps", toolDepsMutator)
})
}
@@ -88,9 +88,7 @@
}
type SourceFileGenerator interface {
- GeneratedSourceFiles() android.Paths
- GeneratedHeaderDirs() android.Paths
- GeneratedDeps() android.Paths
+ android.SourceFileGenerator
}
// Alias for android.HostToolProvider
@@ -112,6 +110,12 @@
return target.IsReplacedByPrebuilt()
}
+func (t hostToolDependencyTag) AllowDisabledModuleDependencyProxy(
+ ctx android.OtherModuleProviderContext, target android.ModuleProxy) bool {
+ return android.OtherModuleProviderOrDefault(
+ ctx, target, android.CommonModuleInfoKey).ReplacedByPrebuilt
+}
+
var _ android.AllowDisabledModuleDependency = (*hostToolDependencyTag)(nil)
type generatorProperties struct {
@@ -139,8 +143,19 @@
Export_include_dirs []string
// list of input files
- Srcs proptools.Configurable[[]string] `android:"path,arch_variant"`
- ResolvedSrcs []string `blueprint:"mutated"`
+ Srcs proptools.Configurable[[]string] `android:"path,arch_variant"`
+
+ // Same as srcs, but will add dependencies on modules via a device os variation and the device's
+ // first supported arch's variation. Can be used to add a dependency from a host genrule to
+ // a device module.
+ Device_first_srcs proptools.Configurable[[]string] `android:"path_device_first"`
+
+ // Same as srcs, but will add dependencies on modules via a device os variation and the common
+ // arch variation. Can be used to add a dependency from a host genrule to a device module.
+ Device_common_srcs proptools.Configurable[[]string] `android:"path_device_common"`
+
+ // Same as srcs, but will add dependencies on modules via a common_os os variation.
+ Common_os_srcs proptools.Configurable[[]string] `android:"path_common_os"`
// input files to exclude
Exclude_srcs []string `android:"path,arch_variant"`
@@ -211,6 +226,11 @@
// For gensrsc sharding.
shard int
shards int
+
+ // For nsjail tasks
+ useNsjail bool
+ dirSrcs android.DirectoryPaths
+ keepGendir bool
}
func (g *Module) GeneratedSourceFiles() android.Paths {
@@ -243,13 +263,35 @@
}
}
+var buildNumberAllowlistKey = android.NewOnceKey("genruleBuildNumberAllowlistKey")
+
// This allowlist should be kept to the bare minimum, it's
// intended for things that existed before the build number
// was tightly controlled. Prefer using libbuildversion
// via the use_version_lib property of cc modules.
-var genrule_build_number_allowlist = map[string]bool{
- "build/soong/tests:gen": true,
- "tools/tradefederation/core:tradefed_zip": true,
+// This is a function instead of a global map so that
+// soong plugins cannot add entries to the allowlist
+func isModuleInBuildNumberAllowlist(ctx android.ModuleContext) bool {
+ allowlist := ctx.Config().Once(buildNumberAllowlistKey, func() interface{} {
+ // Define the allowlist as a list and then copy it into a map so that
+ // gofmt doesn't change unnecessary lines trying to align the values of the map.
+ allowlist := []string{
+ // go/keep-sorted start
+ "build/soong/tests:gen",
+ "hardware/google/camera/common/hal/aidl_service:aidl_camera_build_version",
+ "tools/tradefederation/core:tradefed_zip",
+ "vendor/google/services/LyricCameraHAL/src/apex:com.google.pixel.camera.hal.manifest",
+ // go/keep-sorted end
+ }
+ allowlistMap := make(map[string]bool, len(allowlist))
+ for _, a := range allowlist {
+ allowlistMap[a] = true
+ }
+ return allowlistMap
+ }).(map[string]bool)
+
+ _, ok := allowlist[ctx.ModuleDir()+":"+ctx.ModuleName()]
+ return ok
}
// generateCommonBuildActions contains build action generation logic
@@ -258,7 +300,15 @@
// approach zero; there should be no genrule action registration done directly
// by Soong logic in the mixed-build case.
func (g *Module) generateCommonBuildActions(ctx android.ModuleContext) {
- g.subName = ctx.ModuleSubDir()
+ // Add the variant as a suffix to the make modules to create, so that the make modules
+ // don't conflict because make doesn't know about variants. However, this causes issues with
+ // tracking required dependencies as the required property in soong is passed straight to make
+ // without accounting for these suffixes. To make it a little easier to work with, don't use
+ // a suffix for android_common variants so that java_genrules look like regular 1-variant
+ // genrules to make.
+ if ctx.ModuleSubDir() != "android_common" {
+ g.subName = ctx.ModuleSubDir()
+ }
if len(g.properties.Export_include_dirs) > 0 {
for _, dir := range g.properties.Export_include_dirs {
@@ -291,23 +341,18 @@
var packagedTools []android.PackagingSpec
if len(g.properties.Tools) > 0 {
seenTools := make(map[string]bool)
-
- ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
- switch tag := ctx.OtherModuleDependencyTag(module).(type) {
+ ctx.VisitDirectDepsProxyAllowDisabled(func(proxy android.ModuleProxy) {
+ switch tag := ctx.OtherModuleDependencyTag(proxy).(type) {
case hostToolDependencyTag:
+ // Necessary to retrieve any prebuilt replacement for the tool, since
+ // toolDepsMutator runs too late for the prebuilt mutators to have
+ // replaced the dependency.
+ module := android.PrebuiltGetPreferred(ctx, proxy)
tool := ctx.OtherModuleName(module)
- if m, ok := module.(android.Module); ok {
- // Necessary to retrieve any prebuilt replacement for the tool, since
- // toolDepsMutator runs too late for the prebuilt mutators to have
- // replaced the dependency.
- module = android.PrebuiltGetPreferred(ctx, m)
- }
-
- switch t := module.(type) {
- case android.HostToolProvider:
+ if h, ok := android.OtherModuleProvider(ctx, module, android.HostToolProviderInfoProvider); ok {
// A HostToolProvider provides the path to a tool, which will be copied
// into the sandbox.
- if !t.(android.Module).Enabled(ctx) {
+ if !android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey).Enabled {
if ctx.Config().AllowMissingDependencies() {
ctx.AddMissingDependencies([]string{tool})
} else {
@@ -315,12 +360,13 @@
}
return
}
- path := t.HostToolPath()
+ path := h.HostToolPath
if !path.Valid() {
ctx.ModuleErrorf("host tool %q missing output file", tool)
return
}
- if specs := t.TransitivePackagingSpecs(); specs != nil {
+ if specs := android.OtherModuleProviderOrDefault(
+ ctx, module, android.InstallFilesProvider).TransitivePackagingSpecs.ToList(); specs != nil {
// If the HostToolProvider has PackgingSpecs, which are definitions of the
// required relative locations of the tool and its dependencies, use those
// instead. They will be copied to those relative locations in the sbox
@@ -342,12 +388,7 @@
tools = append(tools, path.Path())
addLocationLabel(tag.label, toolLocation{android.Paths{path.Path()}})
}
- case bootstrap.GoBinaryTool:
- // A GoBinaryTool provides the install path to a tool, which will be copied.
- p := android.PathForGoBinary(ctx, t)
- tools = append(tools, p)
- addLocationLabel(tag.label, toolLocation{android.Paths{p}})
- default:
+ } else {
ctx.ModuleErrorf("%q is not a host tool provider", tool)
return
}
@@ -407,9 +448,11 @@
}
return srcFiles
}
- g.properties.ResolvedSrcs = g.properties.Srcs.GetOrDefault(ctx, nil)
- srcFiles := addLabelsForInputs("srcs", g.properties.ResolvedSrcs, g.properties.Exclude_srcs)
- android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcFiles.Strings()})
+ srcs := g.properties.Srcs.GetOrDefault(ctx, nil)
+ srcFiles := addLabelsForInputs("srcs", srcs, g.properties.Exclude_srcs)
+ srcFiles = append(srcFiles, addLabelsForInputs("device_first_srcs", g.properties.Device_first_srcs.GetOrDefault(ctx, nil), nil)...)
+ srcFiles = append(srcFiles, addLabelsForInputs("device_common_srcs", g.properties.Device_common_srcs.GetOrDefault(ctx, nil), nil)...)
+ srcFiles = append(srcFiles, addLabelsForInputs("common_os_srcs", g.properties.Common_os_srcs.GetOrDefault(ctx, nil), nil)...)
var copyFrom android.Paths
var outputFiles android.WritablePaths
@@ -437,21 +480,29 @@
// Pick a unique path outside the task.genDir for the sbox manifest textproto,
// a unique rule name, and the user-visible description.
- manifestName := "genrule.sbox.textproto"
+ var rule *android.RuleBuilder
desc := "generate"
name := "generator"
- if task.shards > 0 {
- manifestName = "genrule_" + strconv.Itoa(task.shard) + ".sbox.textproto"
- desc += " " + strconv.Itoa(task.shard)
- name += strconv.Itoa(task.shard)
- } else if len(task.out) == 1 {
- desc += " " + task.out[0].Base()
+ if task.useNsjail {
+ rule = android.NewRuleBuilder(pctx, ctx).Nsjail(task.genDir, android.PathForModuleOut(ctx, "nsjail_build_sandbox"))
+ if task.keepGendir {
+ rule.NsjailKeepGendir()
+ }
+ } else {
+ manifestName := "genrule.sbox.textproto"
+ if task.shards > 0 {
+ manifestName = "genrule_" + strconv.Itoa(task.shard) + ".sbox.textproto"
+ desc += " " + strconv.Itoa(task.shard)
+ name += strconv.Itoa(task.shard)
+ } else if len(task.out) == 1 {
+ desc += " " + task.out[0].Base()
+ }
+
+ manifestPath := android.PathForModuleOut(ctx, manifestName)
+
+ // Use a RuleBuilder to create a rule that runs the command inside an sbox sandbox.
+ rule = getSandboxedRuleBuilder(ctx, android.NewRuleBuilder(pctx, ctx).Sbox(task.genDir, manifestPath))
}
-
- manifestPath := android.PathForModuleOut(ctx, manifestName)
-
- // Use a RuleBuilder to create a rule that runs the command inside an sbox sandbox.
- rule := getSandboxedRuleBuilder(ctx, android.NewRuleBuilder(pctx, ctx).Sbox(task.genDir, manifestPath))
if Bool(g.properties.Write_if_changed) {
rule.Restat()
}
@@ -546,12 +597,24 @@
cmd.ImplicitTools(tools)
cmd.ImplicitPackagedTools(packagedTools)
if proptools.Bool(g.properties.Uses_order_only_build_number_file) {
- if _, ok := genrule_build_number_allowlist[ctx.ModuleDir()+":"+ctx.ModuleName()]; !ok {
+ if !isModuleInBuildNumberAllowlist(ctx) {
ctx.ModuleErrorf("Only allowlisted modules may use uses_order_only_build_number_file: true")
}
cmd.OrderOnly(ctx.Config().BuildNumberFile(ctx))
}
+ if task.useNsjail {
+ for _, input := range task.dirSrcs {
+ cmd.ImplicitDirectory(input)
+ // TODO(b/375551969): remove glob
+ if paths, err := ctx.GlobWithDeps(filepath.Join(input.String(), "**/*"), nil); err == nil {
+ rule.NsjailImplicits(android.PathsForSource(ctx, paths))
+ } else {
+ ctx.PropertyErrorf("dir_srcs", "can't glob %q", input.String())
+ }
+ }
+ }
+
// Create the rule to run the genrule command inside sbox.
rule.Build(name, desc)
@@ -610,6 +673,12 @@
}
g.setOutputFiles(ctx)
+
+ if ctx.Os() == android.Windows {
+ // Make doesn't support windows:
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/module_arch_supported.mk;l=66;drc=f264690860bb6ee7762784d6b7201aae057ba6f2
+ g.HideFromMake()
+ }
}
func (g *Module) setOutputFiles(ctx android.ModuleContext) {
@@ -624,9 +693,9 @@
}
// Collect information for opening IDE project files in java/jdeps.go.
-func (g *Module) IDEInfo(dpInfo *android.IdeInfo) {
+func (g *Module) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
dpInfo.Srcs = append(dpInfo.Srcs, g.Srcs().Strings()...)
- for _, src := range g.properties.ResolvedSrcs {
+ for _, src := range g.properties.Srcs.GetOrDefault(ctx, nil) {
if strings.HasPrefix(src, ":") {
src = strings.Trim(src, ":")
dpInfo.Deps = append(dpInfo.Deps, src)
@@ -679,16 +748,22 @@
type noopImageInterface struct{}
-func (x noopImageInterface) ImageMutatorBegin(android.BaseModuleContext) {}
-func (x noopImageInterface) VendorVariantNeeded(android.BaseModuleContext) bool { return false }
-func (x noopImageInterface) ProductVariantNeeded(android.BaseModuleContext) bool { return false }
-func (x noopImageInterface) CoreVariantNeeded(android.BaseModuleContext) bool { return false }
-func (x noopImageInterface) RamdiskVariantNeeded(android.BaseModuleContext) bool { return false }
-func (x noopImageInterface) VendorRamdiskVariantNeeded(android.BaseModuleContext) bool { return false }
-func (x noopImageInterface) DebugRamdiskVariantNeeded(android.BaseModuleContext) bool { return false }
-func (x noopImageInterface) RecoveryVariantNeeded(android.BaseModuleContext) bool { return false }
-func (x noopImageInterface) ExtraImageVariations(ctx android.BaseModuleContext) []string { return nil }
-func (x noopImageInterface) SetImageVariation(ctx android.BaseModuleContext, variation string) {
+func (x noopImageInterface) ImageMutatorBegin(android.ImageInterfaceContext) {}
+func (x noopImageInterface) VendorVariantNeeded(android.ImageInterfaceContext) bool { return false }
+func (x noopImageInterface) ProductVariantNeeded(android.ImageInterfaceContext) bool { return false }
+func (x noopImageInterface) CoreVariantNeeded(android.ImageInterfaceContext) bool { return false }
+func (x noopImageInterface) RamdiskVariantNeeded(android.ImageInterfaceContext) bool { return false }
+func (x noopImageInterface) VendorRamdiskVariantNeeded(android.ImageInterfaceContext) bool {
+ return false
+}
+func (x noopImageInterface) DebugRamdiskVariantNeeded(android.ImageInterfaceContext) bool {
+ return false
+}
+func (x noopImageInterface) RecoveryVariantNeeded(android.ImageInterfaceContext) bool { return false }
+func (x noopImageInterface) ExtraImageVariations(ctx android.ImageInterfaceContext) []string {
+ return nil
+}
+func (x noopImageInterface) SetImageVariation(ctx android.ImageInterfaceContext, variation string) {
}
func NewGenSrcs() *Module {
@@ -815,15 +890,32 @@
properties := &genRuleProperties{}
taskGenerator := func(ctx android.ModuleContext, rawCommand string, srcFiles android.Paths) []generateTask {
+ useNsjail := Bool(properties.Use_nsjail)
+
+ dirSrcs := android.DirectoryPathsForModuleSrc(ctx, properties.Dir_srcs)
+ if len(dirSrcs) > 0 && !useNsjail {
+ ctx.PropertyErrorf("dir_srcs", "can't use dir_srcs if use_nsjail is false")
+ return nil
+ }
+
+ keepGendir := Bool(properties.Keep_gendir)
+ if keepGendir && !useNsjail {
+ ctx.PropertyErrorf("keep_gendir", "can't use keep_gendir if use_nsjail is false")
+ return nil
+ }
+
outs := make(android.WritablePaths, len(properties.Out))
for i, out := range properties.Out {
outs[i] = android.PathForModuleGen(ctx, out)
}
return []generateTask{{
- in: srcFiles,
- out: outs,
- genDir: android.PathForModuleGen(ctx),
- cmd: rawCommand,
+ in: srcFiles,
+ out: outs,
+ genDir: android.PathForModuleGen(ctx),
+ cmd: rawCommand,
+ useNsjail: useNsjail,
+ dirSrcs: dirSrcs,
+ keepGendir: keepGendir,
}}
}
@@ -838,6 +930,16 @@
}
type genRuleProperties struct {
+ Use_nsjail *bool
+
+ // List of input directories. Can be set only when use_nsjail is true. Currently, usage of
+ // dir_srcs is limited only to Trusty build.
+ Dir_srcs []string `android:"path"`
+
+ // If set to true, $(genDir) is not truncated. Useful when this genrule can be incrementally
+ // built. Can be set only when use_nsjail is true.
+ Keep_gendir *bool
+
// names of the output files that will be generated
Out []string `android:"arch_variant"`
}
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 9278f15..688db07 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -693,9 +693,6 @@
expectedCmd := "cp in1 __SBOX_SANDBOX_DIR__/out/out"
android.AssertStringEquals(t, "cmd", expectedCmd, gen.rawCommands[0])
-
- expectedSrcs := []string{"in1"}
- android.AssertDeepEquals(t, "srcs", expectedSrcs, gen.properties.ResolvedSrcs)
}
func TestGenruleAllowMissingDependencies(t *testing.T) {
diff --git a/go.mod b/go.mod
index aa43066..57b59c0 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module android/soong
-go 1.22
+go 1.23
require (
github.com/google/blueprint v0.0.0
diff --git a/go.work b/go.work
index 46a135b..e538915 100644
--- a/go.work
+++ b/go.work
@@ -1,4 +1,4 @@
-go 1.22
+go 1.23
use (
.
diff --git a/golang/Android.bp b/golang/Android.bp
new file mode 100644
index 0000000..3eae94f
--- /dev/null
+++ b/golang/Android.bp
@@ -0,0 +1,22 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-golang",
+ pkgPath: "android/soong/golang",
+ deps: [
+ "blueprint",
+ "blueprint-pathtools",
+ "blueprint-bootstrap",
+ "soong",
+ "soong-android",
+ ],
+ srcs: [
+ "golang.go",
+ ],
+ testSrcs: [
+ "golang_test.go",
+ ],
+ pluginFor: ["soong_build"],
+}
diff --git a/golang/golang.go b/golang/golang.go
new file mode 100644
index 0000000..d33f5e0
--- /dev/null
+++ b/golang/golang.go
@@ -0,0 +1,137 @@
+// 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 golang wraps the blueprint blueprint_go_binary and bootstrap_go_binary module types in versions
+// that implement android.Module that are used when building in Soong. This simplifies the code in Soong
+// so it can always assume modules are an android.Module.
+// The original blueprint blueprint_go_binary and bootstrap_go_binary module types are still used during
+// bootstrapping, so the Android.bp entries for these module types must be compatible with both the
+// original blueprint module types and these wrapped module types.
+package golang
+
+import (
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/bootstrap"
+)
+
+func init() {
+ // Wrap the blueprint Go module types with Soong ones that interoperate with the rest of the Soong modules.
+ bootstrap.GoModuleTypesAreWrapped()
+ RegisterGoModuleTypes(android.InitRegistrationContext)
+}
+
+func RegisterGoModuleTypes(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("bootstrap_go_package", goPackageModuleFactory)
+ ctx.RegisterModuleType("blueprint_go_binary", goBinaryModuleFactory)
+}
+
+// A GoPackage is a module for building Go packages.
+type GoPackage struct {
+ android.ModuleBase
+ bootstrap.GoPackage
+}
+
+func goPackageModuleFactory() android.Module {
+ module := &GoPackage{}
+ module.AddProperties(module.Properties()...)
+ android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
+ return module
+}
+
+func (g *GoPackage) GenerateBuildActions(ctx blueprint.ModuleContext) {
+ // The embedded ModuleBase and bootstrap.GoPackage each implement GenerateBuildActions,
+ // the delegation has to be implemented manually to disambiguate. Call ModuleBase's
+ // GenerateBuildActions, which will call GenerateAndroidBuildActions, which will call
+ // bootstrap.GoPackage.GenerateBuildActions.
+ g.ModuleBase.GenerateBuildActions(ctx)
+}
+
+func (g *GoPackage) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ g.GoPackage.GenerateBuildActions(ctx.BlueprintModuleContext())
+}
+
+// A GoBinary is a module for building executable binaries from Go sources.
+type GoBinary struct {
+ android.ModuleBase
+ bootstrap.GoBinary
+
+ outputFile android.Path
+}
+
+func goBinaryModuleFactory() android.Module {
+ module := &GoBinary{}
+ module.AddProperties(module.Properties()...)
+ android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
+ return module
+}
+
+func (g *GoBinary) GenerateBuildActions(ctx blueprint.ModuleContext) {
+ // The embedded ModuleBase and bootstrap.GoBinary each implement GenerateBuildActions,
+ // the delegation has to be implemented manually to disambiguate. Call ModuleBase's
+ // GenerateBuildActions, which will call GenerateAndroidBuildActions, which will call
+ // bootstrap.GoBinary.GenerateBuildActions.
+ g.ModuleBase.GenerateBuildActions(ctx)
+}
+
+func (g *GoBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // Install the file in Soong instead of blueprint so that Soong knows about the install rules.
+ g.GoBinary.SetSkipInstall()
+
+ // Run the build actions from the wrapped blueprint bootstrap module.
+ g.GoBinary.GenerateBuildActions(ctx.BlueprintModuleContext())
+
+ // Translate the bootstrap module's string path into a Path
+ outputFile := android.PathForArbitraryOutput(ctx, android.Rel(ctx, ctx.Config().OutDir(), g.IntermediateFile())).WithoutRel()
+ g.outputFile = outputFile
+
+ // Don't create install rules for modules used by bootstrap, the install command line will differ from
+ // what was used during bootstrap, which will cause ninja to rebuild the module on the next run,
+ // triggering reanalysis.
+ if !usedByBootstrap(ctx.ModuleName()) {
+ installPath := ctx.InstallFile(android.PathForModuleInstall(ctx, "bin"), ctx.ModuleName(), outputFile)
+
+ // Modules in an unexported namespace have no install rule, only add modules in the exported namespaces
+ // to the blueprint_tools phony rules.
+ if !ctx.Config().KatiEnabled() || g.ExportedToMake() {
+ ctx.Phony("blueprint_tools", installPath)
+ }
+ }
+
+ ctx.SetOutputFiles(android.Paths{outputFile}, "")
+}
+
+func usedByBootstrap(name string) bool {
+ switch name {
+ case "loadplugins", "soong_build":
+ return true
+ default:
+ return false
+ }
+}
+
+func (g *GoBinary) HostToolPath() android.OptionalPath {
+ return android.OptionalPathForPath(g.outputFile)
+}
+
+func (g *GoBinary) AndroidMkEntries() []android.AndroidMkEntries {
+ return []android.AndroidMkEntries{
+ {
+ Class: "EXECUTABLES",
+ OutputFile: android.OptionalPathForPath(g.outputFile),
+ Include: "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk",
+ },
+ }
+}
diff --git a/golang/golang_test.go b/golang/golang_test.go
new file mode 100644
index 0000000..d555d14
--- /dev/null
+++ b/golang/golang_test.go
@@ -0,0 +1,58 @@
+// 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 golang
+
+import (
+ "android/soong/android"
+ "regexp"
+ "testing"
+
+ "github.com/google/blueprint/bootstrap"
+)
+
+func TestGolang(t *testing.T) {
+ bp := `
+ bootstrap_go_package {
+ name: "gopkg",
+ pkgPath: "test/pkg",
+ }
+
+ blueprint_go_binary {
+ name: "gobin",
+ deps: ["gopkg"],
+ }
+ `
+
+ result := android.GroupFixturePreparers(
+ android.PrepareForTestWithArchMutator,
+ android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+ RegisterGoModuleTypes(ctx)
+ ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUpBlueprint("bootstrap_deps", bootstrap.BootstrapDeps).UsesReverseDependencies()
+ })
+ }),
+ ).RunTestWithBp(t, bp)
+
+ bin := result.ModuleForTests("gobin", result.Config.BuildOSTarget.String())
+
+ expected := "^out/host/" + result.Config.PrebuiltOS() + "/bin/go/gobin/?[^/]*/obj/gobin$"
+ actual := android.PathsRelativeToTop(bin.OutputFiles(result.TestContext, t, ""))
+ if len(actual) != 1 {
+ t.Fatalf("Expected 1 output file, got %v", actual)
+ }
+ if match, err := regexp.Match(expected, []byte(actual[0])); err != nil || !match {
+ t.Fatalf("Expected output file to match %q, but got %q", expected, actual[0])
+ }
+}
diff --git a/java/Android.bp b/java/Android.bp
index 9603815..885e682 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -7,6 +7,7 @@
pkgPath: "android/soong/java",
deps: [
"blueprint",
+ "blueprint-depset",
"blueprint-pathtools",
"soong",
"soong-aconfig",
@@ -15,7 +16,6 @@
"soong-dexpreopt",
"soong-genrule",
"soong-java-config",
- "soong-testing",
"soong-provenance",
"soong-python",
"soong-remoteexec",
@@ -72,7 +72,7 @@
"rro.go",
"sdk.go",
"sdk_library.go",
- "sdk_library_external.go",
+ "sdk_library_internal.go",
"support_libraries.go",
"system_modules.go",
"systemserver_classpath_fragment.go",
@@ -86,7 +86,6 @@
"app_import_test.go",
"app_set_test.go",
"app_test.go",
- "code_metadata_test.go",
"container_test.go",
"bootclasspath_fragment_test.go",
"device_host_converter_test.go",
@@ -117,7 +116,7 @@
"sdk_version_test.go",
"system_modules_test.go",
"systemserver_classpath_fragment_test.go",
- "test_spec_test.go",
],
pluginFor: ["soong_build"],
+ visibility: ["//visibility:public"],
}
diff --git a/java/aapt2.go b/java/aapt2.go
index 61cf373..bae4d1e 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -15,7 +15,9 @@
package java
import (
+ "fmt"
"path/filepath"
+ "regexp"
"sort"
"strconv"
"strings"
@@ -31,19 +33,35 @@
return strings.HasPrefix(lastDir, "values")
}
+func isFlagsPath(subDir string) bool {
+ re := regexp.MustCompile(`flag\(!?([a-zA-Z_-]+\.)*[a-zA-Z0-9_-]+\)`)
+ lastDir := filepath.Base(subDir)
+ return re.MatchString(lastDir)
+}
+
// Convert input resource file path to output file path.
// values-[config]/<file>.xml -> values-[config]_<file>.arsc.flat;
+// flag(fully.qualified.flag_name)/values-[config]/<file>.xml -> /values-[config]_<file>.(fully.qualified.flag_name).arsc.flat;
// For other resource file, just replace the last "/" with "_" and add .flat extension.
func pathToAapt2Path(ctx android.ModuleContext, res android.Path) android.WritablePath {
- name := res.Base()
+ extension := filepath.Ext(res.Base())
+ name := strings.TrimSuffix(res.Base(), extension)
if isPathValueResource(res) {
- name = strings.TrimSuffix(name, ".xml") + ".arsc"
+ extension = ".arsc"
}
subDir := filepath.Dir(res.String())
subDir, lastDir := filepath.Split(subDir)
- name = lastDir + "_" + name + ".flat"
- return android.PathForModuleOut(ctx, "aapt2", subDir, name)
+ if isFlagsPath(subDir) {
+ var flag string
+ subDir, flag = filepath.Split(filepath.Dir(subDir))
+ flag = strings.TrimPrefix(flag, "flag")
+ name = fmt.Sprintf("%s_%s.%s%s.flat", lastDir, name, flag, extension)
+ } else {
+ name = fmt.Sprintf("%s_%s%s.flat", lastDir, name, extension)
+ }
+ out := android.PathForModuleOut(ctx, "aapt2", subDir, name)
+ return out
}
// pathsToAapt2Paths Calls pathToAapt2Path on each entry of the given Paths, i.e. []Path.
diff --git a/java/aar.go b/java/aar.go
index e6ad502..0a5a4c4 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -15,24 +15,25 @@
package java
import (
+ "crypto/sha256"
"fmt"
"path/filepath"
"slices"
- "strconv"
"strings"
"android/soong/android"
"android/soong/dexpreopt"
"github.com/google/blueprint"
+ "github.com/google/blueprint/depset"
"github.com/google/blueprint/proptools"
)
type AndroidLibraryDependency interface {
ExportPackage() android.Path
- ResourcesNodeDepSet() *android.DepSet[*resourcesNode]
- RRODirsDepSet() *android.DepSet[rroDir]
- ManifestsDepSet() *android.DepSet[android.Path]
+ ResourcesNodeDepSet() depset.DepSet[*resourcesNode]
+ RRODirsDepSet() depset.DepSet[rroDir]
+ ManifestsDepSet() depset.DepSet[android.Path]
SetRROEnforcedForDependent(enforce bool)
IsRROEnforced(ctx android.BaseModuleContext) bool
}
@@ -45,7 +46,7 @@
ctx.RegisterModuleType("android_library_import", AARImportFactory)
ctx.RegisterModuleType("android_library", AndroidLibraryFactory)
ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.TopDown("propagate_rro_enforcement", propagateRROEnforcementMutator)
+ ctx.Transition("propagate_rro_enforcement", &propagateRROEnforcementTransitionMutator{})
})
}
@@ -76,7 +77,7 @@
// list of directories relative to the Blueprints file containing
// Android resources. Defaults to ["res"] if a directory called res exists.
// Set to [] to disable the default.
- Resource_dirs []string `android:"path"`
+ Resource_dirs proptools.Configurable[[]string] `android:"path"`
// list of zip files containing Android resources.
Resource_zips []string `android:"path"`
@@ -136,9 +137,9 @@
aaptProperties aaptProperties
- resourcesNodesDepSet *android.DepSet[*resourcesNode]
- rroDirsDepSet *android.DepSet[rroDir]
- manifestsDepSet *android.DepSet[android.Path]
+ resourcesNodesDepSet depset.DepSet[*resourcesNode]
+ rroDirsDepSet depset.DepSet[rroDir]
+ manifestsDepSet depset.DepSet[android.Path]
manifestValues struct {
applicationId string
@@ -151,15 +152,67 @@
path android.Path
}
-// Propagate RRO enforcement flag to static lib dependencies transitively.
-func propagateRROEnforcementMutator(ctx android.TopDownMutatorContext) {
+// Propagate RRO enforcement flag to static lib dependencies transitively. If EnforceRROGlobally is set then
+// all modules will use the "" variant. If specific modules have RRO enforced, then modules (usually apps) with
+// RRO enabled will use the "" variation for themselves, but use the "rro" variant of direct and transitive static
+// android_library dependencies.
+type propagateRROEnforcementTransitionMutator struct{}
+
+func (p propagateRROEnforcementTransitionMutator) Split(ctx android.BaseModuleContext) []string {
+ // Never split modules, apps with or without RRO enabled use the "" variant, static android_library dependencies
+ // will use create the "rro" variant from incoming tranisitons.
+ return []string{""}
+}
+
+func (p propagateRROEnforcementTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+ // Non-static dependencies are not involved in RRO and always use the empty variant.
+ if ctx.DepTag() != staticLibTag {
+ return ""
+ }
+
m := ctx.Module()
- if d, ok := m.(AndroidLibraryDependency); ok && d.IsRROEnforced(ctx) {
- ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
- if a, ok := d.(AndroidLibraryDependency); ok {
- a.SetRROEnforcedForDependent(true)
- }
- })
+ if _, ok := m.(AndroidLibraryDependency); ok {
+ // If RRO is enforced globally don't bother using "rro" variants, the empty variant will have RRO enabled.
+ if ctx.Config().EnforceRROGlobally() {
+ return ""
+ }
+
+ // If RRO is enabled for this module use the "rro" variants of static dependencies. IncomingTransition will
+ // rewrite this back to "" if the dependency is not an android_library.
+ if ctx.Config().EnforceRROForModule(ctx.Module().Name()) {
+ return "rro"
+ }
+ }
+
+ return sourceVariation
+}
+
+func (p propagateRROEnforcementTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+ // Propagate the "rro" variant to android_library modules, but use the empty variant for everything else.
+ if incomingVariation == "rro" {
+ m := ctx.Module()
+ if _, ok := m.(AndroidLibraryDependency); ok {
+ return "rro"
+ }
+ return ""
+ }
+
+ return ""
+}
+
+func (p propagateRROEnforcementTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
+ m := ctx.Module()
+ if d, ok := m.(AndroidLibraryDependency); ok {
+ if variation == "rro" {
+ // This is the "rro" variant of a module that has both variants, mark this one as RRO enabled and
+ // hide it from make to avoid collisions with the non-RRO empty variant.
+ d.SetRROEnforcedForDependent(true)
+ m.HideFromMake()
+ } else if ctx.Config().EnforceRROGlobally() {
+ // RRO is enabled globally, mark it enabled for this module, but there is only one variant so no
+ // need to hide it from make.
+ d.SetRROEnforcedForDependent(true)
+ }
}
}
@@ -180,15 +233,15 @@
func (a *aapt) ExportPackage() android.Path {
return a.exportPackage
}
-func (a *aapt) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] {
+func (a *aapt) ResourcesNodeDepSet() depset.DepSet[*resourcesNode] {
return a.resourcesNodesDepSet
}
-func (a *aapt) RRODirsDepSet() *android.DepSet[rroDir] {
+func (a *aapt) RRODirsDepSet() depset.DepSet[rroDir] {
return a.rroDirsDepSet
}
-func (a *aapt) ManifestsDepSet() *android.DepSet[android.Path] {
+func (a *aapt) ManifestsDepSet() depset.DepSet[android.Path] {
return a.manifestsDepSet
}
@@ -204,7 +257,7 @@
}
func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkContext,
- manifestPath android.Path) (compileFlags, linkFlags []string, linkDeps android.Paths,
+ manifestPath android.Path, doNotIncludeAssetDirImplicitly bool) (compileFlags, linkFlags []string, linkDeps android.Paths,
resDirs, overlayDirs []globbedResourceDir, rroDirs []rroDir, resZips android.Paths) {
hasVersionCode := android.PrefixInList(a.aaptProperties.Aaptflags, "--version-code")
@@ -221,8 +274,13 @@
Paths: a.aaptProperties.Assets,
IncludeDirs: false,
})
- assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets")
- resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res")
+ var assetDirs android.Paths
+ if doNotIncludeAssetDirImplicitly {
+ assetDirs = android.PathsForModuleSrc(ctx, a.aaptProperties.Asset_dirs)
+ } else {
+ assetDirs = android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets")
+ }
+ resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs.GetOrDefault(ctx, nil), "res")
resourceZips := android.PathsForModuleSrc(ctx, a.aaptProperties.Resource_zips)
// Glob directories into lists of paths
@@ -236,18 +294,20 @@
rroDirs = append(rroDirs, resRRODirs...)
}
+ assetDirsHasher := sha256.New()
var assetDeps android.Paths
- for i, dir := range assetDirs {
+ for _, dir := range assetDirs {
// Add a dependency on every file in the asset directory. This ensures the aapt2
// rule will be rerun if one of the files in the asset directory is modified.
- assetDeps = append(assetDeps, androidResourceGlob(ctx, dir)...)
+ dirContents := androidResourceGlob(ctx, dir)
+ assetDeps = append(assetDeps, dirContents...)
- // Add a dependency on a file that contains a list of all the files in the asset directory.
+ // Add a hash of all the files in the asset directory to the command line.
// This ensures the aapt2 rule will be run if a file is removed from the asset directory,
// or a file is added whose timestamp is older than the output of aapt2.
- assetFileListFile := android.PathForModuleOut(ctx, "asset_dir_globs", strconv.Itoa(i)+".glob")
- androidResourceGlobList(ctx, dir, assetFileListFile)
- assetDeps = append(assetDeps, assetFileListFile)
+ for _, path := range dirContents.Strings() {
+ assetDirsHasher.Write([]byte(path))
+ }
}
assetDirStrings := assetDirs.Strings()
@@ -282,6 +342,7 @@
linkDeps = append(linkDeps, manifestPath)
linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirStrings, "-A "))
+ linkFlags = append(linkFlags, fmt.Sprintf("$$(: %x)", assetDirsHasher.Sum(nil)))
linkDeps = append(linkDeps, assetDeps...)
// Returns the effective version for {min|target}_sdk_version
@@ -330,8 +391,9 @@
versionName = proptools.NinjaEscape(versionName)
linkFlags = append(linkFlags, "--version-name ", versionName)
}
-
- linkFlags, compileFlags = android.FilterList(linkFlags, []string{"--legacy"})
+ // Split the flags by prefix, as --png-compression-level has the "=value" suffix.
+ linkFlags, compileFlags = android.FilterListByPrefix(linkFlags,
+ []string{"--legacy", "--png-compression-level"})
// Always set --pseudo-localize, it will be stripped out later for release
// builds that don't want it.
@@ -361,6 +423,25 @@
extraLinkFlags []string
aconfigTextFiles android.Paths
usesLibrary *usesLibrary
+ // If rroDirs is provided, it will be used to generate package-res.apk
+ rroDirs *android.Paths
+ // If manifestForAapt is not nil, it will be used for aapt instead of the default source manifest.
+ manifestForAapt android.Path
+}
+
+func filterRRO(rroDirsDepSet depset.DepSet[rroDir], filter overlayType) android.Paths {
+ var paths android.Paths
+ seen := make(map[android.Path]bool)
+ for _, d := range rroDirsDepSet.ToList() {
+ if d.overlayType == filter {
+ if seen[d.path] {
+ continue
+ }
+ seen[d.path] = true
+ paths = append(paths, d.path)
+ }
+ }
+ return paths
}
func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptions) {
@@ -372,10 +453,15 @@
opts.classLoaderContexts = opts.classLoaderContexts.ExcludeLibs(opts.excludedLibs)
// App manifest file
- manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
- manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
+ var manifestFilePath android.Path
+ if opts.manifestForAapt != nil {
+ manifestFilePath = opts.manifestForAapt
+ } else {
+ manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
+ manifestFilePath = android.PathForModuleSrc(ctx, manifestFile)
+ }
- manifestPath := ManifestFixer(ctx, manifestSrcPath, ManifestFixerParams{
+ manifestPath := ManifestFixer(ctx, manifestFilePath, ManifestFixerParams{
SdkContext: opts.sdkContext,
ClassLoaderContexts: opts.classLoaderContexts,
IsLibrary: a.isLibrary,
@@ -403,6 +489,7 @@
packageName: a.manifestValues.applicationId,
}
a.mergedManifestFile = manifestMerger(ctx, transitiveManifestPaths[0], manifestMergerParams)
+ ctx.CheckbuildFile(a.mergedManifestFile)
if !a.isLibrary {
// Only use the merged manifest for applications. For libraries, the transitive closure of manifests
// will be propagated to the final application and merged there. The merged manifest for libraries is
@@ -413,7 +500,12 @@
a.mergedManifestFile = manifestPath
}
- compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, opts.sdkContext, manifestPath)
+ // do not include assets in autogenerated RRO.
+ compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, opts.sdkContext, manifestPath, opts.rroDirs != nil)
+
+ a.rroDirsDepSet = depset.NewBuilder[rroDir](depset.TOPOLOGICAL).
+ Direct(rroDirs...).
+ Transitive(staticRRODirsDepSet).Build()
linkFlags = append(linkFlags, libFlags...)
linkDeps = append(linkDeps, sharedExportPackages...)
@@ -427,9 +519,9 @@
}
linkFlags = append(linkFlags, "--no-static-lib-packages")
- if a.isLibrary && a.useResourceProcessorBusyBox(ctx) {
- // When building an android_library using ResourceProcessorBusyBox pass --merge-only to skip resource
- // references validation until the final app link step when all static libraries are present.
+ if a.isLibrary {
+ // Pass --merge-only to skip resource references validation until the final
+ // app link step when when all static libraries are present.
linkFlags = append(linkFlags, "--merge-only")
}
@@ -503,9 +595,16 @@
}
}
- for _, dir := range overlayDirs {
- compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files,
- compileFlags, a.filterProduct(), opts.aconfigTextFiles).Paths()...)
+ var compiledRro, compiledRroOverlay android.Paths
+ if opts.rroDirs != nil {
+ compiledRro, compiledRroOverlay = a.compileResInDir(ctx, *opts.rroDirs, compileFlags, opts.aconfigTextFiles)
+ } else {
+ // RRO enforcement is done based on module name. Compile the overlayDirs only if rroDirs is nil.
+ // This ensures that the autogenerated RROs do not compile the overlay dirs twice.
+ for _, dir := range overlayDirs {
+ compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files,
+ compileFlags, a.filterProduct(), opts.aconfigTextFiles).Paths()...)
+ }
}
var splitPackages android.WritablePaths
@@ -534,9 +633,21 @@
if !a.isLibrary {
transitiveAssets = android.ReverseSliceInPlace(staticDeps.assets())
}
- aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt,
- linkFlags, linkDeps, compiledRes, compiledOverlay, transitiveAssets, splitPackages,
- opts.aconfigTextFiles)
+ if opts.rroDirs == nil { // link resources and overlay
+ aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt,
+ linkFlags, linkDeps, compiledRes, compiledOverlay, transitiveAssets, splitPackages,
+ opts.aconfigTextFiles)
+ ctx.CheckbuildFile(packageRes)
+ } else { // link autogenerated rro
+ if len(compiledRro) == 0 {
+ return
+ }
+ aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt,
+ linkFlags, linkDeps, compiledRro, compiledRroOverlay, nil, nil,
+ opts.aconfigTextFiles)
+ ctx.CheckbuildFile(packageRes)
+ }
+
// Extract assets from the resource package output so that they can be used later in aapt2link
// for modules that depend on this one.
if android.PrefixInList(linkFlags, "-A ") {
@@ -581,7 +692,7 @@
a.extraAaptPackagesFile = extraPackages
a.rTxt = rTxt
a.splits = splits
- a.resourcesNodesDepSet = android.NewDepSetBuilder[*resourcesNode](android.TOPOLOGICAL).
+ a.resourcesNodesDepSet = depset.NewBuilder[*resourcesNode](depset.TOPOLOGICAL).
Direct(&resourcesNode{
resPackage: a.exportPackage,
manifest: a.manifestPath,
@@ -593,15 +704,46 @@
usedResourceProcessor: a.useResourceProcessorBusyBox(ctx),
}).
Transitive(staticResourcesNodesDepSet).Build()
- a.rroDirsDepSet = android.NewDepSetBuilder[rroDir](android.TOPOLOGICAL).
- Direct(rroDirs...).
- Transitive(staticRRODirsDepSet).Build()
- a.manifestsDepSet = android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).
+ a.manifestsDepSet = depset.NewBuilder[android.Path](depset.TOPOLOGICAL).
Direct(a.manifestPath).
DirectSlice(additionalManifests).
Transitive(staticManifestsDepSet).Build()
}
+// comileResInDir finds the resource files in dirs by globbing and then compiles them using aapt2
+// returns the file paths of compiled resources
+// dirs[0] is used as compileRes
+// dirs[1:] is used as compileOverlay
+func (a *aapt) compileResInDir(ctx android.ModuleContext, dirs android.Paths, compileFlags []string, aconfig android.Paths) (android.Paths, android.Paths) {
+ filesInDir := func(dir android.Path) android.Paths {
+ files, err := ctx.GlobWithDeps(filepath.Join(dir.String(), "**/*"), androidResourceIgnoreFilenames)
+ if err != nil {
+ ctx.ModuleErrorf("failed to glob overlay resource dir %q: %s", dir, err.Error())
+ return nil
+ }
+ var filePaths android.Paths
+ for _, file := range files {
+ if strings.HasSuffix(file, "/") {
+ continue // ignore directories
+ }
+ filePaths = append(filePaths, android.PathForSource(ctx, file))
+ }
+ return filePaths
+ }
+
+ var compiledRes, compiledOverlay android.Paths
+ if len(dirs) == 0 {
+ return nil, nil
+ }
+ compiledRes = append(compiledRes, aapt2Compile(ctx, dirs[0], filesInDir(dirs[0]), compileFlags, a.filterProduct(), aconfig).Paths()...)
+ if len(dirs) > 0 {
+ for _, dir := range dirs[1:] {
+ compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir, filesInDir(dir), compileFlags, a.filterProduct(), aconfig).Paths()...)
+ }
+ }
+ return compiledRes, compiledOverlay
+}
+
var resourceProcessorBusyBox = pctx.AndroidStaticRule("resourceProcessorBusyBox",
blueprint.RuleParams{
Command: "${config.JavaCmd} -cp ${config.ResourceProcessorBusyBox} " +
@@ -715,8 +857,8 @@
// aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext,
classLoaderContexts dexpreopt.ClassLoaderContextMap, usesLibrary *usesLibrary) (
- staticResourcesNodes, sharedResourcesNodes *android.DepSet[*resourcesNode], staticRRODirs *android.DepSet[rroDir],
- staticManifests *android.DepSet[android.Path], sharedLibs android.Paths, flags []string) {
+ staticResourcesNodes, sharedResourcesNodes depset.DepSet[*resourcesNode], staticRRODirs depset.DepSet[rroDir],
+ staticManifests depset.DepSet[android.Path], sharedLibs android.Paths, flags []string) {
if classLoaderContexts == nil {
// Not all callers need to compute class loader context, those who don't just pass nil.
@@ -729,26 +871,28 @@
sharedLibs = append(sharedLibs, sdkDep.jars...)
}
- var staticResourcesNodeDepSets []*android.DepSet[*resourcesNode]
- var sharedResourcesNodeDepSets []*android.DepSet[*resourcesNode]
- rroDirsDepSetBuilder := android.NewDepSetBuilder[rroDir](android.TOPOLOGICAL)
- manifestsDepSetBuilder := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL)
+ var staticResourcesNodeDepSets []depset.DepSet[*resourcesNode]
+ var sharedResourcesNodeDepSets []depset.DepSet[*resourcesNode]
+ rroDirsDepSetBuilder := depset.NewBuilder[rroDir](depset.TOPOLOGICAL)
+ manifestsDepSetBuilder := depset.NewBuilder[android.Path](depset.TOPOLOGICAL)
- ctx.VisitDirectDeps(func(module android.Module) {
+ ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) {
depTag := ctx.OtherModuleDependencyTag(module)
var exportPackage android.Path
- aarDep, _ := module.(AndroidLibraryDependency)
- if aarDep != nil {
- exportPackage = aarDep.ExportPackage()
+ var aarDep *AndroidLibraryDependencyInfo
+ javaInfo, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider)
+ if ok && javaInfo.AndroidLibraryDependencyInfo != nil {
+ aarDep = javaInfo.AndroidLibraryDependencyInfo
+ exportPackage = aarDep.ExportPackage
}
switch depTag {
case instrumentationForTag:
// Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2.
- case sdkLibTag, libTag:
+ case sdkLibTag, libTag, rroDepTag:
if exportPackage != nil {
- sharedResourcesNodeDepSets = append(sharedResourcesNodeDepSets, aarDep.ResourcesNodeDepSet())
+ sharedResourcesNodeDepSets = append(sharedResourcesNodeDepSets, aarDep.ResourcesNodeDepSet)
sharedLibs = append(sharedLibs, exportPackage)
}
case frameworkResTag:
@@ -757,9 +901,9 @@
}
case staticLibTag:
if exportPackage != nil {
- staticResourcesNodeDepSets = append(staticResourcesNodeDepSets, aarDep.ResourcesNodeDepSet())
- rroDirsDepSetBuilder.Transitive(aarDep.RRODirsDepSet())
- manifestsDepSetBuilder.Transitive(aarDep.ManifestsDepSet())
+ staticResourcesNodeDepSets = append(staticResourcesNodeDepSets, aarDep.ResourcesNodeDepSet)
+ rroDirsDepSetBuilder.Transitive(aarDep.RRODirsDepSet)
+ manifestsDepSetBuilder.Transitive(aarDep.ManifestsDepSet)
}
}
@@ -776,9 +920,9 @@
// dependencies) the highest priority dependency is listed first, but for resources the highest priority
// dependency has to be listed last. This is also inconsistent with the way manifests from the same
// transitive dependencies are merged.
- staticResourcesNodes = android.NewDepSet(android.TOPOLOGICAL, nil,
+ staticResourcesNodes = depset.New(depset.TOPOLOGICAL, nil,
android.ReverseSliceInPlace(staticResourcesNodeDepSets))
- sharedResourcesNodes = android.NewDepSet(android.TOPOLOGICAL, nil,
+ sharedResourcesNodes = depset.New(depset.TOPOLOGICAL, nil,
android.ReverseSliceInPlace(sharedResourcesNodeDepSets))
staticRRODirs = rroDirsDepSetBuilder.Build()
@@ -795,6 +939,12 @@
return staticResourcesNodes, sharedResourcesNodes, staticRRODirs, staticManifests, sharedLibs, flags
}
+type AndroidLibraryInfo struct {
+ // Empty for now
+}
+
+var AndroidLibraryInfoProvider = blueprint.NewProvider[AndroidLibraryInfo]()
+
type AndroidLibrary struct {
Library
aapt
@@ -881,17 +1031,16 @@
extraSrcJars = android.Paths{a.aapt.aaptSrcJar}
}
- a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
+ javaInfo := a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars, nil)
a.aarFile = android.PathForModuleOut(ctx, ctx.ModuleName()+".aar")
var res android.Paths
if a.androidLibraryProperties.BuildAAR {
BuildAAR(ctx, a.aarFile, a.outputFile, a.manifestPath, a.rTxt, res)
- ctx.CheckbuildFile(a.aarFile)
}
prebuiltJniPackages := android.Paths{}
- ctx.VisitDirectDeps(func(module android.Module) {
+ ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) {
if info, ok := android.OtherModuleProvider(ctx, module, JniPackageProvider); ok {
prebuiltJniPackages = append(prebuiltJniPackages, info.JniPackages...)
}
@@ -906,7 +1055,16 @@
AconfigTextFiles: aconfigTextFilePaths,
})
+ android.SetProvider(ctx, AndroidLibraryInfoProvider, AndroidLibraryInfo{})
+
+ if javaInfo != nil {
+ setExtraJavaInfo(ctx, a, javaInfo)
+ android.SetProvider(ctx, JavaInfoProvider, javaInfo)
+ }
+
a.setOutputFiles(ctx)
+
+ buildComplianceMetadata(ctx)
}
func (a *AndroidLibrary) setOutputFiles(ctx android.ModuleContext) {
@@ -914,12 +1072,12 @@
setOutputFiles(ctx, a.Library.Module)
}
-func (a *AndroidLibrary) IDEInfo(dpInfo *android.IdeInfo) {
- a.Library.IDEInfo(dpInfo)
- a.aapt.IDEInfo(dpInfo)
+func (a *AndroidLibrary) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
+ a.Library.IDEInfo(ctx, dpInfo)
+ a.aapt.IDEInfo(ctx, dpInfo)
}
-func (a *aapt) IDEInfo(dpInfo *android.IdeInfo) {
+func (a *aapt) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
if a.rJar != nil {
dpInfo.Jars = append(dpInfo.Jars, a.rJar.String())
}
@@ -968,7 +1126,7 @@
// Defaults to sdk_version if not set. See sdk_version for possible values.
Min_sdk_version *string
// List of java static libraries that the included ARR (android library prebuilts) has dependencies to.
- Static_libs []string
+ Static_libs proptools.Configurable[[]string]
// List of java libraries that the included ARR (android library prebuilts) has dependencies to.
Libs []string
// If set to true, run Jetifier against .aar file. Defaults to false.
@@ -991,7 +1149,7 @@
// Functionality common to Module and Import.
embeddableInModuleAndImport
- providesTransitiveHeaderJars
+ providesTransitiveHeaderJarsForR8
properties AARImportProperties
@@ -1007,8 +1165,8 @@
rTxt android.Path
rJar android.Path
- resourcesNodesDepSet *android.DepSet[*resourcesNode]
- manifestsDepSet *android.DepSet[android.Path]
+ resourcesNodesDepSet depset.DepSet[*resourcesNode]
+ manifestsDepSet depset.DepSet[android.Path]
hideApexVariantFromMake bool
@@ -1054,15 +1212,15 @@
func (a *AARImport) ExportPackage() android.Path {
return a.exportPackage
}
-func (a *AARImport) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] {
+func (a *AARImport) ResourcesNodeDepSet() depset.DepSet[*resourcesNode] {
return a.resourcesNodesDepSet
}
-func (a *AARImport) RRODirsDepSet() *android.DepSet[rroDir] {
- return android.NewDepSet[rroDir](android.TOPOLOGICAL, nil, nil)
+func (a *AARImport) RRODirsDepSet() depset.DepSet[rroDir] {
+ return depset.New[rroDir](depset.TOPOLOGICAL, nil, nil)
}
-func (a *AARImport) ManifestsDepSet() *android.DepSet[android.Path] {
+func (a *AARImport) ManifestsDepSet() depset.DepSet[android.Path] {
return a.manifestsDepSet
}
@@ -1098,7 +1256,7 @@
}
ctx.AddVariationDependencies(nil, libTag, a.properties.Libs...)
- ctx.AddVariationDependencies(nil, staticLibTag, a.properties.Static_libs...)
+ ctx.AddVariationDependencies(nil, staticLibTag, a.properties.Static_libs.GetOrDefault(ctx, nil)...)
a.usesLibrary.deps(ctx, false)
}
@@ -1176,13 +1334,13 @@
proguardFlags := extractedAARDir.Join(ctx, "proguard.txt")
transitiveProguardFlags, transitiveUnconditionalExportedFlags := collectDepProguardSpecInfo(ctx)
android.SetProvider(ctx, ProguardSpecInfoProvider, ProguardSpecInfo{
- ProguardFlagsFiles: android.NewDepSet[android.Path](
- android.POSTORDER,
+ ProguardFlagsFiles: depset.New[android.Path](
+ depset.POSTORDER,
android.Paths{proguardFlags},
transitiveProguardFlags,
),
- UnconditionallyExportedProguardFlags: android.NewDepSet[android.Path](
- android.POSTORDER,
+ UnconditionallyExportedProguardFlags: depset.New[android.Path](
+ depset.POSTORDER,
nil,
transitiveUnconditionalExportedFlags,
),
@@ -1252,16 +1410,18 @@
transitiveAssets := android.ReverseSliceInPlace(staticDeps.assets())
aapt2Link(ctx, exportPackage, nil, proguardOptionsFile, aaptRTxt,
linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil, nil)
+ ctx.CheckbuildFile(exportPackage)
a.exportPackage = exportPackage
rJar := android.PathForModuleOut(ctx, "busybox/R.jar")
resourceProcessorBusyBoxGenerateBinaryR(ctx, a.rTxt, a.manifest, rJar, nil, true, nil, false)
+ ctx.CheckbuildFile(rJar)
a.rJar = rJar
aapt2ExtractExtraPackages(ctx, extraAaptPackagesFile, a.rJar)
a.extraAaptPackagesFile = extraAaptPackagesFile
- resourcesNodesDepSetBuilder := android.NewDepSetBuilder[*resourcesNode](android.TOPOLOGICAL)
+ resourcesNodesDepSetBuilder := depset.NewBuilder[*resourcesNode](depset.TOPOLOGICAL)
resourcesNodesDepSetBuilder.Direct(&resourcesNode{
resPackage: a.exportPackage,
manifest: a.manifest,
@@ -1274,7 +1434,7 @@
resourcesNodesDepSetBuilder.Transitive(staticResourcesNodesDepSet)
a.resourcesNodesDepSet = resourcesNodesDepSetBuilder.Build()
- manifestDepSetBuilder := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(a.manifest)
+ manifestDepSetBuilder := depset.NewBuilder[android.Path](depset.TOPOLOGICAL).Direct(a.manifest)
manifestDepSetBuilder.Transitive(staticManifestsDepSet)
a.manifestsDepSet = manifestDepSetBuilder.Build()
@@ -1286,14 +1446,18 @@
android.WriteFileRule(ctx, transitiveAaptResourcePackagesFile, strings.Join(transitiveAaptResourcePackages, "\n"))
a.transitiveAaptResourcePackagesFile = transitiveAaptResourcePackagesFile
- a.collectTransitiveHeaderJars(ctx)
+ a.collectTransitiveHeaderJarsForR8(ctx)
a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
var staticJars android.Paths
var staticHeaderJars android.Paths
var staticResourceJars android.Paths
- ctx.VisitDirectDeps(func(module android.Module) {
+ var transitiveStaticLibsHeaderJars []depset.DepSet[android.Path]
+ var transitiveStaticLibsImplementationJars []depset.DepSet[android.Path]
+ var transitiveStaticLibsResourceJars []depset.DepSet[android.Path]
+
+ ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) {
if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
tag := ctx.OtherModuleDependencyTag(module)
switch tag {
@@ -1301,65 +1465,109 @@
staticJars = append(staticJars, dep.ImplementationJars...)
staticHeaderJars = append(staticHeaderJars, dep.HeaderJars...)
staticResourceJars = append(staticResourceJars, dep.ResourceJars...)
+ transitiveStaticLibsHeaderJars = append(transitiveStaticLibsHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+ transitiveStaticLibsImplementationJars = append(transitiveStaticLibsImplementationJars, dep.TransitiveStaticLibsImplementationJars)
+ transitiveStaticLibsResourceJars = append(transitiveStaticLibsResourceJars, dep.TransitiveStaticLibsResourceJars)
}
}
addCLCFromDep(ctx, module, a.classLoaderContexts)
addMissingOptionalUsesLibsFromDep(ctx, module, &a.usesLibrary)
})
+ completeStaticLibsHeaderJars := depset.New(depset.PREORDER, android.Paths{classpathFile}, transitiveStaticLibsHeaderJars)
+ completeStaticLibsImplementationJars := depset.New(depset.PREORDER, android.Paths{classpathFile}, transitiveStaticLibsImplementationJars)
+ completeStaticLibsResourceJars := depset.New(depset.PREORDER, nil, transitiveStaticLibsResourceJars)
+
var implementationJarFile android.Path
- if len(staticJars) > 0 {
- combineJars := append(android.Paths{classpathFile}, staticJars...)
- combinedImplementationJar := android.PathForModuleOut(ctx, "combined", jarName).OutputPath
- TransformJarsToJar(ctx, combinedImplementationJar, "combine", combineJars, android.OptionalPath{}, false, nil, nil)
- implementationJarFile = combinedImplementationJar
+ var combineJars android.Paths
+ if ctx.Config().UseTransitiveJarsInClasspath() {
+ combineJars = completeStaticLibsImplementationJars.ToList()
+ } else {
+ combineJars = append(android.Paths{classpathFile}, staticJars...)
+ }
+
+ if len(combineJars) > 1 {
+ implementationJarOutputPath := android.PathForModuleOut(ctx, "combined", jarName)
+ TransformJarsToJar(ctx, implementationJarOutputPath, "combine", combineJars, android.OptionalPath{}, false, nil, nil)
+ implementationJarFile = implementationJarOutputPath
} else {
implementationJarFile = classpathFile
}
var resourceJarFile android.Path
- if len(staticResourceJars) > 1 {
+ var resourceJars android.Paths
+ if ctx.Config().UseTransitiveJarsInClasspath() {
+ resourceJars = completeStaticLibsResourceJars.ToList()
+ } else {
+ resourceJars = staticResourceJars
+ }
+ if len(resourceJars) > 1 {
combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
- TransformJarsToJar(ctx, combinedJar, "for resources", staticResourceJars, android.OptionalPath{},
+ TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{},
false, nil, nil)
resourceJarFile = combinedJar
- } else if len(staticResourceJars) == 1 {
- resourceJarFile = staticResourceJars[0]
+ } else if len(resourceJars) == 1 {
+ resourceJarFile = resourceJars[0]
}
// merge implementation jar with resources if necessary
- implementationAndResourcesJar := implementationJarFile
- if resourceJarFile != nil {
- jars := android.Paths{resourceJarFile, implementationAndResourcesJar}
+ var implementationAndResourcesJars android.Paths
+ if ctx.Config().UseTransitiveJarsInClasspath() {
+ implementationAndResourcesJars = append(slices.Clone(resourceJars), combineJars...)
+ } else {
+ implementationAndResourcesJars = android.PathsIfNonNil(resourceJarFile, implementationJarFile)
+ }
+ var implementationAndResourcesJar android.Path
+ if len(implementationAndResourcesJars) > 1 {
combinedJar := android.PathForModuleOut(ctx, "withres", jarName)
- TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{},
+ TransformJarsToJar(ctx, combinedJar, "for resources", implementationAndResourcesJars, android.OptionalPath{},
false, nil, nil)
implementationAndResourcesJar = combinedJar
+ } else {
+ implementationAndResourcesJar = implementationAndResourcesJars[0]
}
a.implementationJarFile = implementationJarFile
// Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource
a.implementationAndResourcesJarFile = implementationAndResourcesJar.WithoutRel()
- if len(staticHeaderJars) > 0 {
- combineJars := append(android.Paths{classpathFile}, staticHeaderJars...)
+ var headerJars android.Paths
+ if ctx.Config().UseTransitiveJarsInClasspath() {
+ headerJars = completeStaticLibsHeaderJars.ToList()
+ } else {
+ headerJars = append(android.Paths{classpathFile}, staticHeaderJars...)
+ }
+ if len(headerJars) > 1 {
headerJarFile := android.PathForModuleOut(ctx, "turbine-combined", jarName)
- TransformJarsToJar(ctx, headerJarFile, "combine header jars", combineJars, android.OptionalPath{}, false, nil, nil)
+ TransformJarsToJar(ctx, headerJarFile, "combine header jars", headerJars, android.OptionalPath{}, false, nil, nil)
a.headerJarFile = headerJarFile
} else {
- a.headerJarFile = classpathFile
+ a.headerJarFile = headerJars[0]
}
- android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
- HeaderJars: android.PathsIfNonNil(a.headerJarFile),
- ResourceJars: android.PathsIfNonNil(resourceJarFile),
- TransitiveLibsHeaderJars: a.transitiveLibsHeaderJars,
- TransitiveStaticLibsHeaderJars: a.transitiveStaticLibsHeaderJars,
- ImplementationAndResourcesJars: android.PathsIfNonNil(a.implementationAndResourcesJarFile),
- ImplementationJars: android.PathsIfNonNil(a.implementationJarFile),
- StubsLinkType: Implementation,
+ if ctx.Config().UseTransitiveJarsInClasspath() {
+ ctx.CheckbuildFile(classpathFile)
+ } else {
+ ctx.CheckbuildFile(a.headerJarFile)
+ ctx.CheckbuildFile(a.implementationJarFile)
+ }
+
+ javaInfo := &JavaInfo{
+ HeaderJars: android.PathsIfNonNil(a.headerJarFile),
+ LocalHeaderJars: android.PathsIfNonNil(classpathFile),
+ TransitiveStaticLibsHeaderJars: completeStaticLibsHeaderJars,
+ TransitiveStaticLibsImplementationJars: completeStaticLibsImplementationJars,
+ TransitiveStaticLibsResourceJars: completeStaticLibsResourceJars,
+ ResourceJars: android.PathsIfNonNil(resourceJarFile),
+ TransitiveLibsHeaderJarsForR8: a.transitiveLibsHeaderJarsForR8,
+ TransitiveStaticLibsHeaderJarsForR8: a.transitiveStaticLibsHeaderJarsForR8,
+ ImplementationAndResourcesJars: android.PathsIfNonNil(a.implementationAndResourcesJarFile),
+ ImplementationJars: android.PathsIfNonNil(a.implementationJarFile),
+ StubsLinkType: Implementation,
// TransitiveAconfigFiles: // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
- })
+ }
+ setExtraJavaInfo(ctx, a, javaInfo)
+ android.SetProvider(ctx, JavaInfoProvider, javaInfo)
if proptools.Bool(a.properties.Extract_jni) {
for _, t := range ctx.MultiTargets() {
@@ -1388,6 +1596,8 @@
ctx.SetOutputFiles([]android.Path{a.implementationAndResourcesJarFile}, "")
ctx.SetOutputFiles([]android.Path{a.aarPath}, ".aar")
+
+ buildComplianceMetadata(ctx)
}
func (a *AARImport) HeaderJars() android.Paths {
@@ -1415,8 +1625,8 @@
var _ android.ApexModule = (*AARImport)(nil)
// Implements android.ApexModule
-func (a *AARImport) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
- return a.depIsInSameApex(ctx, dep)
+func (a *AARImport) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
+ return a.depIsInSameApex(tag)
}
// Implements android.ApexModule
@@ -1451,6 +1661,6 @@
return module
}
-func (a *AARImport) IDEInfo(dpInfo *android.IdeInfo) {
- dpInfo.Jars = append(dpInfo.Jars, a.headerJarFile.String(), a.rJar.String())
+func (a *AARImport) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
+ dpInfo.Jars = append(dpInfo.Jars, a.implementationJarFile.String(), a.rJar.String())
}
diff --git a/java/aar_test.go b/java/aar_test.go
index aa4f0af..3ac228d 100644
--- a/java/aar_test.go
+++ b/java/aar_test.go
@@ -21,6 +21,7 @@
)
func TestAarImportProducesJniPackages(t *testing.T) {
+ t.Parallel()
ctx := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
).RunTestWithBp(t, `
@@ -50,6 +51,7 @@
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
appMod := ctx.Module(tc.name, "android_common")
appTestMod := ctx.ModuleForTests(tc.name, "android_common")
@@ -84,6 +86,7 @@
}
func TestLibraryFlagsPackages(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
).RunTestWithBp(t, `
@@ -133,6 +136,7 @@
}
func TestAndroidLibraryOutputFilesRel(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
).RunTestWithBp(t, `
diff --git a/java/android_manifest_test.go b/java/android_manifest_test.go
index 7c91884..edb22fc 100644
--- a/java/android_manifest_test.go
+++ b/java/android_manifest_test.go
@@ -21,6 +21,7 @@
)
func TestManifestMerger(t *testing.T) {
+ t.Parallel()
bp := `
android_app {
name: "app",
@@ -100,6 +101,7 @@
}
func TestManifestValuesApplicationIdSetsPackageName(t *testing.T) {
+ t.Parallel()
bp := `
android_test {
name: "test",
diff --git a/java/android_resources.go b/java/android_resources.go
index 038a260..3bb3eb5 100644
--- a/java/android_resources.go
+++ b/java/android_resources.go
@@ -39,15 +39,6 @@
return ctx.GlobFiles(filepath.Join(dir.String(), "**/*"), androidResourceIgnoreFilenames)
}
-// androidResourceGlobList creates a rule to write the list of files in the given directory, using
-// the standard exclusion patterns for Android resources, to the given output file.
-func androidResourceGlobList(ctx android.ModuleContext, dir android.Path,
- fileListFile android.WritablePath) {
-
- android.GlobToListFileRule(ctx, filepath.Join(dir.String(), "**/*"),
- androidResourceIgnoreFilenames, fileListFile)
-}
-
type overlayType int
const (
diff --git a/java/androidmk.go b/java/androidmk.go
index a1bc904..fe3c7a2 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -23,13 +23,12 @@
"github.com/google/blueprint/proptools"
)
-func (library *Library) AndroidMkEntriesHostDex() android.AndroidMkEntries {
- hostDexNeeded := Bool(library.deviceProperties.Hostdex) && !library.Host()
- if library.hideApexVariantFromMake {
- hostDexNeeded = false
- }
+func (library *Library) hostDexNeeded() bool {
+ return Bool(library.deviceProperties.Hostdex) && !library.Host() && !library.hideApexVariantFromMake
+}
- if hostDexNeeded {
+func (library *Library) AndroidMkEntriesHostDex() android.AndroidMkEntries {
+ if library.hostDexNeeded() {
var output android.Path
if library.dexJarFile.IsSet() {
output = library.dexJarFile.Path()
@@ -281,49 +280,24 @@
return nil
}
- if !binary.isWrapperVariant {
- return []android.AndroidMkEntries{android.AndroidMkEntries{
- Class: "JAVA_LIBRARIES",
- OutputFile: android.OptionalPathForPath(binary.outputFile),
- Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
- ExtraEntries: []android.AndroidMkExtraEntriesFunc{
- func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetPath("LOCAL_SOONG_HEADER_JAR", binary.headerJarFile)
- entries.SetPath("LOCAL_SOONG_CLASSES_JAR", binary.implementationAndResourcesJar)
- if binary.dexJarFile.IsSet() {
- entries.SetPath("LOCAL_SOONG_DEX_JAR", binary.dexJarFile.Path())
- }
- if len(binary.dexpreopter.builtInstalled) > 0 {
- entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", binary.dexpreopter.builtInstalled)
- }
- },
+ return []android.AndroidMkEntries{{
+ Class: "JAVA_LIBRARIES",
+ OutputFile: android.OptionalPathForPath(binary.outputFile),
+ Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.SetPath("LOCAL_SOONG_HEADER_JAR", binary.headerJarFile)
+ entries.SetPath("LOCAL_SOONG_CLASSES_JAR", binary.implementationAndResourcesJar)
+ if binary.dexJarFile.IsSet() {
+ entries.SetPath("LOCAL_SOONG_DEX_JAR", binary.dexJarFile.Path())
+ }
+ if len(binary.dexpreopter.builtInstalled) > 0 {
+ entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", binary.dexpreopter.builtInstalled)
+ }
+ entries.AddStrings("LOCAL_REQUIRED_MODULES", binary.androidMkNamesOfJniLibs...)
},
- ExtraFooters: []android.AndroidMkExtraFootersFunc{
- func(w io.Writer, name, prefix, moduleDir string) {
- fmt.Fprintln(w, "jar_installed_module := $(LOCAL_INSTALLED_MODULE)")
- },
- },
- }}
- } else {
- outputFile := binary.wrapperFile
-
- return []android.AndroidMkEntries{android.AndroidMkEntries{
- Class: "EXECUTABLES",
- OutputFile: android.OptionalPathForPath(outputFile),
- ExtraEntries: []android.AndroidMkExtraEntriesFunc{
- func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetBool("LOCAL_STRIP_MODULE", false)
- },
- },
- ExtraFooters: []android.AndroidMkExtraFootersFunc{
- func(w io.Writer, name, prefix, moduleDir string) {
- // Ensure that the wrapper script timestamp is always updated when the jar is updated
- fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): $(jar_installed_module)")
- fmt.Fprintln(w, "jar_installed_module :=")
- },
- },
- }}
- }
+ },
+ }}
}
func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries {
@@ -332,15 +306,11 @@
Disabled: true,
}}
}
- var required []string
- if proptools.Bool(app.appProperties.Generate_product_characteristics_rro) {
- required = []string{app.productCharacteristicsRROPackageName()}
- }
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "APPS",
OutputFile: android.OptionalPathForPath(app.outputFile),
Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
- Required: required,
+ Required: app.requiredModuleNames,
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
// App module names can be overridden.
@@ -375,31 +345,6 @@
entries.SetBoolIfTrue("LOCAL_NO_STANDARD_LIBRARIES", true)
}
- filterRRO := func(filter overlayType) android.Paths {
- var paths android.Paths
- seen := make(map[android.Path]bool)
- for _, d := range app.rroDirsDepSet.ToList() {
- if d.overlayType == filter {
- if seen[d.path] {
- continue
- }
- seen[d.path] = true
- paths = append(paths, d.path)
- }
- }
- // Reverse the order, Soong stores rroDirs in aapt2 order (low to high priority), but Make
- // expects it in LOCAL_RESOURCE_DIRS order (high to low priority).
- return android.ReversePaths(paths)
- }
- deviceRRODirs := filterRRO(device)
- if len(deviceRRODirs) > 0 {
- entries.AddStrings("LOCAL_SOONG_DEVICE_RRO_DIRS", deviceRRODirs.Strings()...)
- }
- productRRODirs := filterRRO(product)
- if len(productRRODirs) > 0 {
- entries.AddStrings("LOCAL_SOONG_PRODUCT_RRO_DIRS", productRRODirs.Strings()...)
- }
-
entries.SetBoolIfTrue("LOCAL_EXPORT_PACKAGE_RESOURCES", Bool(app.appProperties.Export_package_resources))
entries.SetPath("LOCAL_FULL_MANIFEST_FILE", app.manifestPath)
@@ -415,7 +360,7 @@
} else {
var names []string
for _, jniLib := range app.jniLibs {
- names = append(names, jniLib.name)
+ names = append(names, jniLib.name+":"+jniLib.target.Arch.ArchType.Bitness())
}
entries.AddStrings("LOCAL_REQUIRED_MODULES", names...)
}
@@ -450,6 +395,24 @@
}
}
+func (a *AutogenRuntimeResourceOverlay) AndroidMkEntries() []android.AndroidMkEntries {
+ if a.IsHideFromMake() || a.outputFile == nil {
+ return []android.AndroidMkEntries{android.AndroidMkEntries{
+ Disabled: true,
+ }}
+ }
+ return []android.AndroidMkEntries{android.AndroidMkEntries{
+ Class: "APPS",
+ OutputFile: android.OptionalPathForPath(a.outputFile),
+ Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_CERTIFICATE", a.certificate.AndroidMkString())
+ },
+ },
+ }}
+}
+
func (a *AndroidApp) getOverriddenPackages() []string {
var overridden []string
if len(a.overridableAppProperties.Overrides) > 0 {
@@ -591,73 +554,13 @@
},
ExtraFooters: []android.AndroidMkExtraFootersFunc{
func(w io.Writer, name, prefix, moduleDir string) {
- if dstubs.apiFile != nil {
- fmt.Fprintf(w, ".PHONY: %s %s.txt\n", dstubs.Name(), dstubs.Name())
- fmt.Fprintf(w, "%s %s.txt: %s\n", dstubs.Name(), dstubs.Name(), dstubs.apiFile)
- }
- if dstubs.removedApiFile != nil {
- fmt.Fprintf(w, ".PHONY: %s %s.txt\n", dstubs.Name(), dstubs.Name())
- fmt.Fprintf(w, "%s %s.txt: %s\n", dstubs.Name(), dstubs.Name(), dstubs.removedApiFile)
- }
- if dstubs.checkCurrentApiTimestamp != nil {
- fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-check-current-api")
- fmt.Fprintln(w, dstubs.Name()+"-check-current-api:",
- dstubs.checkCurrentApiTimestamp.String())
-
- fmt.Fprintln(w, ".PHONY: checkapi")
- fmt.Fprintln(w, "checkapi:",
- dstubs.checkCurrentApiTimestamp.String())
-
- fmt.Fprintln(w, ".PHONY: droidcore")
- fmt.Fprintln(w, "droidcore: checkapi")
- }
- if dstubs.updateCurrentApiTimestamp != nil {
- fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-update-current-api")
- fmt.Fprintln(w, dstubs.Name()+"-update-current-api:",
- dstubs.updateCurrentApiTimestamp.String())
-
- fmt.Fprintln(w, ".PHONY: update-api")
- fmt.Fprintln(w, "update-api:",
- dstubs.updateCurrentApiTimestamp.String())
- }
- if dstubs.checkLastReleasedApiTimestamp != nil {
- fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-check-last-released-api")
- fmt.Fprintln(w, dstubs.Name()+"-check-last-released-api:",
- dstubs.checkLastReleasedApiTimestamp.String())
-
- fmt.Fprintln(w, ".PHONY: checkapi")
- fmt.Fprintln(w, "checkapi:",
- dstubs.checkLastReleasedApiTimestamp.String())
-
- fmt.Fprintln(w, ".PHONY: droidcore")
- fmt.Fprintln(w, "droidcore: checkapi")
- }
if dstubs.apiLintTimestamp != nil {
- fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-api-lint")
- fmt.Fprintln(w, dstubs.Name()+"-api-lint:",
- dstubs.apiLintTimestamp.String())
-
- fmt.Fprintln(w, ".PHONY: checkapi")
- fmt.Fprintln(w, "checkapi:",
- dstubs.Name()+"-api-lint")
-
- fmt.Fprintln(w, ".PHONY: droidcore")
- fmt.Fprintln(w, "droidcore: checkapi")
-
if dstubs.apiLintReport != nil {
fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n", dstubs.Name()+"-api-lint",
dstubs.apiLintReport.String(), "apilint/"+dstubs.Name()+"-lint-report.txt")
fmt.Fprintf(w, "$(call declare-0p-target,%s)\n", dstubs.apiLintReport.String())
}
}
- if dstubs.checkNullabilityWarningsTimestamp != nil {
- fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-check-nullability-warnings")
- fmt.Fprintln(w, dstubs.Name()+"-check-nullability-warnings:",
- dstubs.checkNullabilityWarningsTimestamp.String())
-
- fmt.Fprintln(w, ".PHONY:", "droidcore")
- fmt.Fprintln(w, "droidcore: ", dstubs.Name()+"-check-nullability-warnings")
- }
},
},
}}
diff --git a/java/androidmk_test.go b/java/androidmk_test.go
index 243a279..9306e72 100644
--- a/java/androidmk_test.go
+++ b/java/androidmk_test.go
@@ -23,6 +23,7 @@
)
func TestRequired(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
@@ -42,6 +43,7 @@
}
func TestHostdex(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
@@ -72,6 +74,7 @@
}
func TestHostdexRequired(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
@@ -103,6 +106,7 @@
}
func TestHostdexSpecificRequired(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
@@ -136,6 +140,7 @@
}
func TestJavaSdkLibrary_RequireXmlPermissionFile(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -173,6 +178,7 @@
}
func TestImportSoongDexJar(t *testing.T) {
+ t.Parallel()
result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, `
java_import {
name: "my-java-import",
@@ -191,6 +197,7 @@
}
func TestAndroidTestHelperApp_LocalDisableTestConfig(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
android_test_helper_app {
name: "foo",
@@ -209,6 +216,7 @@
}
func TestGetOverriddenPackages(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(
t, `
android_app {
@@ -255,6 +263,7 @@
}
func TestJniAsRequiredDeps(t *testing.T) {
+ t.Parallel()
ctx := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
cc.PrepareForTestWithCcDefaultModules,
@@ -286,7 +295,7 @@
}{
{
name: "app",
- expected: []string{"libjni"},
+ expected: []string{"libjni:64"},
},
{
name: "app_embedded",
diff --git a/java/app.go b/java/app.go
index 1ebf658..abbf034 100644
--- a/java/app.go
+++ b/java/app.go
@@ -22,15 +22,13 @@
"path/filepath"
"strings"
- "android/soong/testing"
-
"github.com/google/blueprint"
+ "github.com/google/blueprint/depset"
"github.com/google/blueprint/proptools"
"android/soong/android"
"android/soong/cc"
"android/soong/dexpreopt"
- "android/soong/genrule"
"android/soong/tradefed"
)
@@ -63,6 +61,21 @@
ctx.RegisterModuleType("override_android_test", OverrideAndroidTestModuleFactory)
}
+type AppInfo struct {
+ // Updatable is set to the value of the updatable property
+ Updatable bool
+
+ // TestHelperApp is true if the module is a android_test_helper_app
+ TestHelperApp bool
+
+ // EmbeddedJNILibs is the list of paths to JNI libraries that were embedded in the APK.
+ EmbeddedJNILibs android.Paths
+
+ MergedManifestFile android.Path
+}
+
+var AppInfoProvider = blueprint.NewProvider[*AppInfo]()
+
// AndroidManifest.xml merging
// package splits
@@ -83,7 +96,7 @@
Package_splits []string
// list of native libraries that will be provided in or alongside the resulting jar
- Jni_libs []string `android:"arch_variant"`
+ Jni_libs proptools.Configurable[[]string] `android:"arch_variant"`
// if true, use JNI libraries that link against platform APIs even if this module sets
// sdk_version.
@@ -153,7 +166,7 @@
type overridableAppProperties struct {
// The name of a certificate in the default certificate directory, blank to use the default product certificate,
// or an android_app_certificate module name in the form ":module".
- Certificate *string
+ Certificate proptools.Configurable[string] `android:"replace_instead_of_append"`
// Name of the signing certificate lineage file or filegroup module.
Lineage *string `android:"path"`
@@ -162,7 +175,7 @@
RotationMinSdkVersion *string
// the package name of this app. The package name in the manifest file is used if one was not given.
- Package_name *string
+ Package_name proptools.Configurable[string]
// the logging parent of this app.
Logging_parent *string
@@ -212,13 +225,15 @@
javaApiUsedByOutputFile android.ModuleOutPath
privAppAllowlist android.OptionalPath
+
+ requiredModuleNames []string
}
func (a *AndroidApp) IsInstallable() bool {
return Bool(a.properties.Installable)
}
-func (a *AndroidApp) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] {
+func (a *AndroidApp) ResourcesNodeDepSet() depset.DepSet[*resourcesNode] {
return a.aapt.resourcesNodesDepSet
}
@@ -311,7 +326,7 @@
} else {
tag = jniInstallTag
}
- ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...)
+ ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs.GetOrDefault(ctx, nil)...)
}
for _, aconfig_declaration := range a.aaptProperties.Flags_packages {
ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration)
@@ -376,7 +391,8 @@
checkMinSdkVersionMts(ctx, a.MinSdkVersion(ctx))
applicationId := a.appTestHelperAppProperties.Manifest_values.ApplicationId
if applicationId != nil {
- if a.overridableAppProperties.Package_name != nil {
+ packageName := a.overridableAppProperties.Package_name.Get(ctx)
+ if packageName.IsPresent() {
ctx.PropertyErrorf("manifest_values.applicationId", "property is not supported when property package_name is set.")
}
a.aapt.manifestValues.applicationId = *applicationId
@@ -385,7 +401,18 @@
android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{
TestOnly: true,
})
+ android.SetProvider(ctx, AppInfoProvider, &AppInfo{
+ Updatable: Bool(a.appProperties.Updatable),
+ TestHelperApp: true,
+ })
+ moduleInfoJSON := ctx.ModuleInfoJSON()
+ moduleInfoJSON.Tags = append(moduleInfoJSON.Tags, "tests")
+ if len(a.appTestHelperAppProperties.Test_suites) > 0 {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, a.appTestHelperAppProperties.Test_suites...)
+ } else {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite")
+ }
}
func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -393,6 +420,38 @@
a.checkEmbedJnis(ctx)
a.generateAndroidBuildActions(ctx)
a.generateJavaUsedByApex(ctx)
+
+ var embeddedJniLibs []android.Path
+
+ if a.embeddedJniLibs {
+ for _, jni := range a.jniLibs {
+ embeddedJniLibs = append(embeddedJniLibs, jni.path)
+ }
+ }
+ android.SetProvider(ctx, AppInfoProvider, &AppInfo{
+ Updatable: Bool(a.appProperties.Updatable),
+ TestHelperApp: false,
+ EmbeddedJNILibs: embeddedJniLibs,
+ MergedManifestFile: a.mergedManifest,
+ })
+
+ a.requiredModuleNames = a.getRequiredModuleNames(ctx)
+}
+
+func (a *AndroidApp) getRequiredModuleNames(ctx android.ModuleContext) []string {
+ var required []string
+ if proptools.Bool(a.appProperties.Generate_product_characteristics_rro) {
+ required = []string{a.productCharacteristicsRROPackageName()}
+ }
+ // Install the vendor overlay variant if this app is installed.
+ if len(filterRRO(a.rroDirsDepSet, device)) > 0 {
+ required = append(required, AutogeneratedRroModuleName(ctx, ctx.Module().Name(), "vendor"))
+ }
+ // Install the product overlay variant if this app is installed.
+ if len(filterRRO(a.rroDirsDepSet, product)) > 0 {
+ required = append(required, AutogeneratedRroModuleName(ctx, ctx.Module().Name(), "product"))
+ }
+ return required
}
func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
@@ -428,7 +487,7 @@
func (a *AndroidApp) checkEmbedJnis(ctx android.BaseModuleContext) {
apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
apkInApex := !apexInfo.IsForPlatform()
- hasJnis := len(a.appProperties.Jni_libs) > 0
+ hasJnis := len(a.appProperties.Jni_libs.GetOrDefault(ctx, nil)) > 0
if apkInApex && hasJnis && !Bool(a.appProperties.Use_embedded_native_libs) {
ctx.ModuleErrorf("APK in APEX should have use_embedded_native_libs: true")
@@ -439,18 +498,24 @@
// This check is enforced for "updatable" APKs (including APK-in-APEX).
func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVersion android.ApiLevel) {
// It's enough to check direct JNI deps' sdk_version because all transitive deps from JNI deps are checked in cc.checkLinkType()
- ctx.VisitDirectDeps(func(m android.Module) {
+ ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) {
if !IsJniDepTag(ctx.OtherModuleDependencyTag(m)) {
return
}
- dep, _ := m.(*cc.Module)
+ if _, ok := android.OtherModuleProvider(ctx, m, cc.CcInfoProvider); !ok {
+ panic(fmt.Errorf("jni dependency is not a cc module: %v", m))
+ }
+ commonInfo, ok := android.OtherModuleProvider(ctx, m, android.CommonModuleInfoKey)
+ if !ok {
+ panic(fmt.Errorf("jni dependency doesn't have CommonModuleInfo provider: %v", m))
+ }
// The domain of cc.sdk_version is "current" and <number>
// We can rely on android.SdkSpec to convert it to <number> so that "current" is
// handled properly regardless of sdk finalization.
- jniSdkVersion, err := android.SdkSpecFrom(ctx, dep.MinSdkVersion()).EffectiveVersion(ctx)
+ jniSdkVersion, err := android.SdkSpecFrom(ctx, commonInfo.MinSdkVersion).EffectiveVersion(ctx)
if err != nil || minSdkVersion.LessThan(jniSdkVersion) {
- ctx.OtherModuleErrorf(dep, "min_sdk_version(%v) is higher than min_sdk_version(%v) of the containing android_app(%v)",
- dep.MinSdkVersion(), minSdkVersion, ctx.ModuleName())
+ ctx.OtherModuleErrorf(m, "min_sdk_version(%v) is higher than min_sdk_version(%v) of the containing android_app(%v)",
+ commonInfo.MinSdkVersion, minSdkVersion, ctx.ModuleName())
return
}
@@ -513,7 +578,7 @@
}
func getAconfigFilePaths(ctx android.ModuleContext) (aconfigTextFilePaths android.Paths) {
- ctx.VisitDirectDeps(func(dep android.Module) {
+ ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) {
tag := ctx.OtherModuleDependencyTag(dep)
switch tag {
case staticLibTag:
@@ -569,10 +634,11 @@
}
manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName())
- if overridden || a.overridableAppProperties.Package_name != nil {
+ packageNameProp := a.overridableAppProperties.Package_name.Get(ctx)
+ if overridden || packageNameProp.IsPresent() {
// The product override variable has a priority over the package_name property.
if !overridden {
- manifestPackageName = *a.overridableAppProperties.Package_name
+ manifestPackageName = packageNameProp.Get()
}
aaptLinkFlags = append(aaptLinkFlags, generateAaptRenamePackageFlags(manifestPackageName, a.renameResourcesPackage())...)
a.overriddenManifestPackageName = manifestPackageName
@@ -586,7 +652,7 @@
if override := ctx.Config().Getenv("OVERRIDE_APEX_MANIFEST_DEFAULT_VERSION"); override != "" {
a.aapt.defaultManifestVersion = override
} else {
- a.aapt.defaultManifestVersion = android.DefaultUpdatableModuleVersion
+ a.aapt.defaultManifestVersion = ctx.Config().ReleaseDefaultUpdatableModuleVersion()
}
}
@@ -618,7 +684,7 @@
func (a *AndroidApp) proguardBuildActions(ctx android.ModuleContext) {
var staticLibProguardFlagFiles android.Paths
- ctx.VisitDirectDeps(func(m android.Module) {
+ ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) {
depProguardInfo, _ := android.OtherModuleProvider(ctx, m, ProguardSpecInfoProvider)
staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, depProguardInfo.UnconditionallyExportedProguardFlags.ToList()...)
if ctx.OtherModuleDependencyTag(m) == staticLibTag {
@@ -652,7 +718,7 @@
return android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk")
}
-func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) (android.Path, android.Path) {
+func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) (android.Path, android.Path, *JavaInfo) {
a.dexpreopter.installPath = a.installPath(ctx)
a.dexpreopter.isApp = true
if a.dexProperties.Uncompress_dex == nil {
@@ -660,13 +726,14 @@
a.dexProperties.Uncompress_dex = proptools.BoolPtr(a.shouldUncompressDex(ctx))
}
a.dexpreopter.uncompressedDex = *a.dexProperties.Uncompress_dex
- a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
+ a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries(ctx)
a.dexpreopter.classLoaderContexts = a.classLoaderContexts
a.dexpreopter.manifestFile = a.mergedManifestFile
a.dexpreopter.preventInstall = a.appProperties.PreventInstall
var packageResources = a.exportPackage
+ javaInfo := &JavaInfo{}
if ctx.ModuleName() != "framework-res" {
if a.dexProperties.resourceShrinkingEnabled(ctx) {
protoFile := android.PathForModuleOut(ctx, packageResources.Base()+".proto.apk")
@@ -690,7 +757,7 @@
extraSrcJars = android.Paths{a.aapt.aaptSrcJar}
}
- a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
+ javaInfo = a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars, nil)
if a.dexProperties.resourceShrinkingEnabled(ctx) {
binaryResources := android.PathForModuleOut(ctx, packageResources.Base()+".binary.out.apk")
aapt2Convert(ctx, binaryResources, a.dexer.resourcesOutput.Path(), "binary")
@@ -698,7 +765,7 @@
}
}
- return a.dexJarFile.PathOrNil(), packageResources
+ return a.dexJarFile.PathOrNil(), packageResources, javaInfo
}
func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, prebuiltJniPackages android.Paths, ctx android.ModuleContext) android.WritablePath {
@@ -812,13 +879,14 @@
return android.PathForModuleSrc(ctx, *a.appProperties.Privapp_allowlist)
}
- if a.overridableAppProperties.Package_name == nil {
+ packageNameProp := a.overridableAppProperties.Package_name.Get(ctx)
+ if packageNameProp.IsEmpty() {
ctx.PropertyErrorf("privapp_allowlist", "package_name must be set to use privapp_allowlist")
}
- packageName := *a.overridableAppProperties.Package_name
+ packageName := packageNameProp.Get()
fileName := "privapp_allowlist_" + packageName + ".xml"
- outPath := android.PathForModuleOut(ctx, fileName).OutputPath
+ outPath := android.PathForModuleOut(ctx, fileName)
ctx.Build(pctx, android.BuildParams{
Rule: modifyAllowlist,
Input: android.PathForModuleSrc(ctx, *a.appProperties.Privapp_allowlist),
@@ -827,7 +895,7 @@
"packageName": packageName,
},
})
- return &outPath
+ return outPath
}
func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
@@ -888,10 +956,10 @@
// Process all building blocks, from AAPT to certificates.
a.aaptBuildActions(ctx)
// The decision to enforce <uses-library> checks is made before adding implicit SDK libraries.
- a.usesLibrary.freezeEnforceUsesLibraries()
+ a.usesLibrary.freezeEnforceUsesLibraries(ctx)
// Check that the <uses-library> list is coherent with the manifest.
- if a.usesLibrary.enforceUsesLibraries() {
+ if a.usesLibrary.enforceUsesLibraries(ctx) {
manifestCheckFile := a.usesLibrary.verifyUsesLibrariesManifest(
ctx, a.mergedManifestFile, &a.classLoaderContexts)
apkDeps = append(apkDeps, manifestCheckFile)
@@ -904,7 +972,7 @@
a.linter.resources = a.aapt.resourceFiles
a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps()
- dexJarFile, packageResources := a.dexBuildActions(ctx)
+ dexJarFile, packageResources, javaInfo := a.dexBuildActions(ctx)
// No need to check the SDK version of the JNI deps unless we embed them
checkNativeSdkVersion := a.shouldEmbedJnis(ctx) && !Bool(a.appProperties.Jni_uses_platform_apis)
@@ -1009,6 +1077,8 @@
ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile, extraInstalledPaths...)
}
+ ctx.CheckbuildFile(a.outputFile)
+
a.buildAppDependencyInfo(ctx)
providePrebuiltInfo(ctx,
@@ -1018,7 +1088,23 @@
},
)
+ if javaInfo != nil {
+ javaInfo.OutputFile = a.outputFile
+ setExtraJavaInfo(ctx, a, javaInfo)
+ android.SetProvider(ctx, JavaInfoProvider, javaInfo)
+ }
+
+ moduleInfoJSON := ctx.ModuleInfoJSON()
+ moduleInfoJSON.Class = []string{"APPS"}
+ if !a.embeddedJniLibs {
+ for _, jniLib := range a.jniLibs {
+ moduleInfoJSON.ExtraRequired = append(moduleInfoJSON.ExtraRequired, jniLib.name)
+ }
+ }
+
a.setOutputFiles(ctx)
+
+ buildComplianceMetadata(ctx)
}
func (a *AndroidApp) setOutputFiles(ctx android.ModuleContext) {
@@ -1050,46 +1136,77 @@
app.SdkVersion(ctx).Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx)
}
jniLib, prebuiltJniPackages := collectJniDeps(ctx, shouldCollectRecursiveNativeDeps,
- checkNativeSdkVersion, func(dep cc.LinkableInterface) bool {
- return !dep.IsNdk(ctx.Config()) && !dep.IsStubs()
+ checkNativeSdkVersion, func(parent, child android.ModuleProxy) bool {
+ apkInApex := ctx.Module().(android.ApexModule).NotInPlatform()
+ childLinkable, _ := android.OtherModuleProvider(ctx, child, cc.LinkableInfoProvider)
+ parentIsLinkable := false
+ if ctx.EqualModules(ctx.Module(), parent) {
+ parentLinkable, _ := ctx.Module().(cc.LinkableInterface)
+ parentIsLinkable = parentLinkable != nil
+ } else {
+ _, parentIsLinkable = android.OtherModuleProvider(ctx, parent, cc.LinkableInfoProvider)
+ }
+ useStubsOfDep := childLinkable.IsStubs
+ if apkInApex && parentIsLinkable {
+ // APK-in-APEX
+ // If the parent is a linkable interface, use stubs if the dependency edge crosses an apex boundary.
+ useStubsOfDep = useStubsOfDep || (childLinkable.HasStubsVariants && cc.ShouldUseStubForApex(ctx, parent, child))
+ }
+ return !childLinkable.IsNdk && !useStubsOfDep
})
var certificates []Certificate
- ctx.VisitDirectDeps(func(module android.Module) {
+ var directImplementationDeps android.Paths
+ var transitiveImplementationDeps []depset.DepSet[android.Path]
+ ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) {
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
if tag == certificateTag {
- if dep, ok := module.(*AndroidAppCertificate); ok {
+ if dep, ok := android.OtherModuleProvider(ctx, module, AndroidAppCertificateInfoProvider); ok {
certificates = append(certificates, dep.Certificate)
} else {
ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", otherName)
}
}
+
+ if IsJniDepTag(tag) {
+ directImplementationDeps = append(directImplementationDeps, android.OutputFileForModule(ctx, module, ""))
+ if info, ok := android.OtherModuleProvider(ctx, module, cc.ImplementationDepInfoProvider); ok {
+ transitiveImplementationDeps = append(transitiveImplementationDeps, info.ImplementationDeps)
+ }
+ }
})
+ android.SetProvider(ctx, cc.ImplementationDepInfoProvider, &cc.ImplementationDepInfo{
+ ImplementationDeps: depset.New(depset.PREORDER, directImplementationDeps, transitiveImplementationDeps),
+ })
+
return jniLib, prebuiltJniPackages, certificates
}
func collectJniDeps(ctx android.ModuleContext,
shouldCollectRecursiveNativeDeps bool,
checkNativeSdkVersion bool,
- filter func(cc.LinkableInterface) bool) ([]jniLib, android.Paths) {
+ filter func(parent, child android.ModuleProxy) bool) ([]jniLib, android.Paths) {
var jniLibs []jniLib
var prebuiltJniPackages android.Paths
seenModulePaths := make(map[string]bool)
- ctx.WalkDeps(func(module android.Module, parent android.Module) bool {
+ ctx.WalkDepsProxy(func(module, parent android.ModuleProxy) bool {
+ if !android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey).Enabled {
+ return false
+ }
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
if IsJniDepTag(tag) || cc.IsSharedDepTag(tag) {
- if dep, ok := module.(cc.LinkableInterface); ok {
- if filter != nil && !filter(dep) {
+ if dep, ok := android.OtherModuleProvider(ctx, module, cc.LinkableInfoProvider); ok {
+ if filter != nil && !filter(parent, module) {
return false
}
- lib := dep.OutputFile()
+ lib := dep.OutputFile
if lib.Valid() {
path := lib.Path()
if seenModulePaths[path.String()] {
@@ -1097,7 +1214,8 @@
}
seenModulePaths[path.String()] = true
- if checkNativeSdkVersion && dep.SdkVersion() == "" {
+ commonInfo := android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey)
+ if checkNativeSdkVersion && commonInfo.SdkVersion == "" {
ctx.PropertyErrorf("jni_libs", "JNI dependency %q uses platform APIs, but this module does not",
otherName)
}
@@ -1105,11 +1223,11 @@
jniLibs = append(jniLibs, jniLib{
name: ctx.OtherModuleName(module),
path: path,
- target: module.Target(),
- coverageFile: dep.CoverageOutputFile(),
- unstrippedFile: dep.UnstrippedOutputFile(),
- partition: dep.Partition(),
- installPaths: android.OtherModuleProviderOrDefault(ctx, dep, android.InstallFilesProvider).InstallFiles,
+ target: commonInfo.Target,
+ coverageFile: dep.CoverageOutputFile,
+ unstrippedFile: dep.UnstrippedOutputFile,
+ partition: dep.Partition,
+ installPaths: android.OtherModuleProviderOrDefault(ctx, module, android.InstallFilesProvider).InstallFiles,
})
} else if ctx.Config().AllowMissingDependencies() {
ctx.AddMissingDependencies([]string{otherName})
@@ -1133,9 +1251,12 @@
return jniLibs, prebuiltJniPackages
}
-func (a *AndroidApp) WalkPayloadDeps(ctx android.ModuleContext, do android.PayloadDepsCallback) {
+func (a *AndroidApp) WalkPayloadDeps(ctx android.BaseModuleContext, do android.PayloadDepsCallback) {
ctx.WalkDeps(func(child, parent android.Module) bool {
- isExternal := !a.DepIsInSameApex(ctx, child)
+ // TODO(ccross): Should this use android.DepIsInSameApex? Right now it is applying the android app
+ // heuristics to every transitive dependency, when it should probably be using the heuristics of the
+ // immediate parent.
+ isExternal := !a.OutgoingDepIsInSameApex(ctx.OtherModuleDependencyTag(child))
if am, ok := child.(android.ApexModule); ok {
if !do(ctx, parent, am, isExternal) {
return false
@@ -1151,7 +1272,7 @@
}
depsInfo := android.DepNameToDepInfoMap{}
- a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from android.Module, to android.ApexModule, externalDep bool) bool {
depName := to.Name()
// Skip dependencies that are only available to APEXes; they are developed with updatability
@@ -1204,23 +1325,19 @@
return Bool(a.appProperties.Updatable)
}
-func (a *AndroidApp) SetUpdatable(val bool) {
- a.appProperties.Updatable = &val
-}
-
func (a *AndroidApp) getCertString(ctx android.BaseModuleContext) string {
certificate, overridden := ctx.DeviceConfig().OverrideCertificateFor(ctx.ModuleName())
if overridden {
return ":" + certificate
}
- return String(a.overridableAppProperties.Certificate)
+ return a.overridableAppProperties.Certificate.GetOrDefault(ctx, "")
}
-func (a *AndroidApp) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
- if IsJniDepTag(ctx.OtherModuleDependencyTag(dep)) {
+func (a *AndroidApp) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
+ if IsJniDepTag(tag) {
return true
}
- return a.Library.DepIsInSameApex(ctx, dep)
+ return a.Library.OutgoingDepIsInSameApex(tag)
}
func (a *AndroidApp) Privileged() bool {
@@ -1243,9 +1360,9 @@
var _ cc.Coverage = (*AndroidApp)(nil)
-func (a *AndroidApp) IDEInfo(dpInfo *android.IdeInfo) {
- a.Library.IDEInfo(dpInfo)
- a.aapt.IDEInfo(dpInfo)
+func (a *AndroidApp) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
+ a.Library.IDEInfo(ctx, dpInfo)
+ a.aapt.IDEInfo(ctx, dpInfo)
}
func (a *AndroidApp) productCharacteristicsRROPackageName() string {
@@ -1315,20 +1432,22 @@
Srcs: []string{":" + a.Name() + "{.apk}"},
Cmd: proptools.StringPtr("$(location characteristics_rro_generator) $$($(location aapt2) dump packagename $(in)) $(out)"),
}
- ctx.CreateModule(genrule.GenRuleFactory, &rroManifestProperties)
+ ctx.CreateModule(GenRuleFactory, &rroManifestProperties)
rroProperties := struct {
Name *string
Filter_product *string
Aaptflags []string
Manifest *string
- Resource_dirs []string
+ Resource_dirs proptools.Configurable[[]string]
+ Flags_packages []string
}{
Name: proptools.StringPtr(rroPackageName),
Filter_product: proptools.StringPtr(characteristics),
Aaptflags: []string{"--auto-add-overlay"},
Manifest: proptools.StringPtr(":" + rroManifestName),
Resource_dirs: a.aaptProperties.Resource_dirs,
+ Flags_packages: a.aaptProperties.Flags_packages,
}
if !Bool(a.aaptProperties.Aapt_include_all_resources) {
for _, aaptConfig := range ctx.Config().ProductAAPTConfig() {
@@ -1336,11 +1455,82 @@
}
}
ctx.CreateModule(RuntimeResourceOverlayFactory, &rroProperties)
+
+ })
+
+ module.SetDefaultableHook(func(ctx android.DefaultableHookContext) {
+ createInternalRuntimeOverlays(ctx, module.ModuleBase)
})
return module
}
+func AutogeneratedRroModuleName(ctx android.EarlyModuleContext, moduleName, partition string) string {
+ return fmt.Sprintf("%s__%s__auto_generated_rro_%s", moduleName, ctx.Config().DeviceProduct(), partition)
+}
+
+type createModuleContext interface {
+ android.EarlyModuleContext
+ CreateModule(android.ModuleFactory, ...interface{}) android.Module
+}
+
+func createInternalRuntimeOverlays(ctx createModuleContext, a android.ModuleBase) {
+ if !ctx.Config().HasDeviceProduct() {
+ return
+ }
+ // vendor
+ vendorOverlayProps := struct {
+ Name *string
+ Base *string
+ Vendor *bool
+ Product_specific *bool
+ System_ext_specific *bool
+ Manifest *string
+ Sdk_version *string
+ Compile_multilib *string
+ Enabled proptools.Configurable[bool]
+ }{
+ Name: proptools.StringPtr(AutogeneratedRroModuleName(ctx, a.Name(), "vendor")),
+ Base: proptools.StringPtr(a.Name()),
+ Vendor: proptools.BoolPtr(true),
+ Product_specific: proptools.BoolPtr(false),
+ System_ext_specific: proptools.BoolPtr(false),
+ Manifest: proptools.StringPtr(":" + a.Name() + "{.manifest.xml}"),
+ Sdk_version: proptools.StringPtr("current"),
+ Compile_multilib: proptools.StringPtr("first"),
+ Enabled: a.EnabledProperty().Clone(),
+ }
+ ctx.CreateModule(AutogenRuntimeResourceOverlayFactory, &vendorOverlayProps)
+
+ // product
+ productOverlayProps := struct {
+ Name *string
+ Base *string
+ Vendor *bool
+ Proprietary *bool
+ Soc_specific *bool
+ Product_specific *bool
+ System_ext_specific *bool
+ Manifest *string
+ Sdk_version *string
+ Compile_multilib *string
+ Enabled proptools.Configurable[bool]
+ }{
+ Name: proptools.StringPtr(AutogeneratedRroModuleName(ctx, a.Name(), "product")),
+ Base: proptools.StringPtr(a.Name()),
+ Vendor: proptools.BoolPtr(false),
+ Proprietary: proptools.BoolPtr(false),
+ Soc_specific: proptools.BoolPtr(false),
+ Product_specific: proptools.BoolPtr(true),
+ System_ext_specific: proptools.BoolPtr(false),
+ Manifest: proptools.StringPtr(":" + a.Name() + "{.manifest.xml}"),
+ Sdk_version: proptools.StringPtr("current"),
+ Compile_multilib: proptools.StringPtr("first"),
+ Enabled: a.EnabledProperty().Clone(),
+ }
+ ctx.CreateModule(AutogenRuntimeResourceOverlayFactory, &productOverlayProps)
+}
+
// A dictionary of values to be overridden in the manifest.
type Manifest_values struct {
// Overrides the value of package_name in the manifest
@@ -1403,25 +1593,46 @@
}
applicationId := a.appTestProperties.Manifest_values.ApplicationId
if applicationId != nil {
- if a.overridableAppProperties.Package_name != nil {
+ packageNameProp := a.overridableAppProperties.Package_name.Get(ctx)
+ if packageNameProp.IsPresent() {
ctx.PropertyErrorf("manifest_values.applicationId", "property is not supported when property package_name is set.")
}
a.aapt.manifestValues.applicationId = *applicationId
}
a.generateAndroidBuildActions(ctx)
+ for _, c := range a.testProperties.Test_options.Tradefed_options {
+ configs = append(configs, c)
+ }
for _, module := range a.testProperties.Test_mainline_modules {
configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: "mainline-param", Value: module})
}
testConfig := tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config,
- a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites, a.testProperties.Auto_gen_config, configs)
+ a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites,
+ a.testProperties.Auto_gen_config, configs, a.testProperties.Test_options.Test_runner_options)
a.testConfig = a.FixTestConfig(ctx, testConfig)
a.extraTestConfigs = android.PathsForModuleSrc(ctx, a.testProperties.Test_options.Extra_test_configs)
a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
- android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+ a.data = append(a.data, android.PathsForModuleSrc(ctx, a.testProperties.Device_common_data)...)
+ a.data = append(a.data, android.PathsForModuleSrc(ctx, a.testProperties.Device_first_data)...)
+ a.data = append(a.data, android.PathsForModuleSrc(ctx, a.testProperties.Device_first_prefer32_data)...)
+
+ // Install test deps
+ if !ctx.Config().KatiEnabled() {
+ pathInTestCases := android.PathForModuleInstall(ctx, ctx.Module().Name())
+ if a.testConfig != nil {
+ ctx.InstallFile(pathInTestCases, ctx.Module().Name()+".config", a.testConfig)
+ }
+ testDeps := append(a.data, a.extraTestConfigs...)
+ for _, data := range android.SortedUniquePaths(testDeps) {
+ dataPath := android.DataPath{SrcPath: data}
+ ctx.InstallTestData(pathInTestCases, []android.DataPath{dataPath})
+ }
+ }
+
android.SetProvider(ctx, tradefed.BaseTestProviderKey, tradefed.BaseTestProviderData{
- InstalledFiles: a.data,
+ TestcaseRelDataFiles: testcaseRel(a.data),
OutputFile: a.OutputFile(),
TestConfig: a.testConfig,
HostRequiredModuleNames: a.HostRequiredModuleNames(),
@@ -1429,12 +1640,38 @@
IsHost: false,
LocalCertificate: a.certificate.AndroidMkString(),
IsUnitTest: Bool(a.testProperties.Test_options.Unit_test),
+ MkInclude: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
+ MkAppClass: "APPS",
})
android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{
TestOnly: true,
TopLevelTarget: true,
})
+ moduleInfoJSON := ctx.ModuleInfoJSON()
+ moduleInfoJSON.Tags = append(moduleInfoJSON.Tags, "tests")
+ if a.testConfig != nil {
+ moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, a.testConfig.String())
+ }
+ moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, a.extraTestConfigs.Strings()...)
+ if len(a.testProperties.Test_suites) > 0 {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, a.testProperties.Test_suites...)
+ } else {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite")
+ }
+
+ if _, ok := testConfig.(android.WritablePath); ok {
+ moduleInfoJSON.AutoTestConfig = []string{"true"}
+ }
+ moduleInfoJSON.TestMainlineModules = append(moduleInfoJSON.TestMainlineModules, a.testProperties.Test_mainline_modules...)
+}
+
+func testcaseRel(paths android.Paths) []string {
+ relPaths := []string{}
+ for _, p := range paths {
+ relPaths = append(relPaths, p.Rel())
+ }
+ return relPaths
}
func (a *AndroidTest) FixTestConfig(ctx android.ModuleContext, testConfig android.Path) android.Path {
@@ -1453,10 +1690,11 @@
command.FlagWithArg("--test-file-name ", a.installApkName+".apk")
}
- if a.overridableAppProperties.Package_name != nil {
+ packageNameProp := a.overridableAppProperties.Package_name.Get(ctx)
+ if packageNameProp.IsPresent() {
fixNeeded = true
command.FlagWithInput("--manifest ", a.manifestPath).
- FlagWithArg("--package-name ", *a.overridableAppProperties.Package_name)
+ FlagWithArg("--package-name ", packageNameProp.Get())
}
if a.appTestProperties.Mainline_package_name != nil {
@@ -1471,7 +1709,23 @@
return testConfig
}
+func (a *AndroidTestHelperApp) DepsMutator(ctx android.BottomUpMutatorContext) {
+ if len(a.ApexProperties.Apex_available) == 0 && ctx.Config().IsEnvTrue("EMMA_API_MAPPER") {
+ // Instrument the android_test_helper target to log potential API calls at the run time.
+ // Contact android-xts-infra team before using the environment var EMMA_API_MAPPER.
+ ctx.AddVariationDependencies(nil, staticLibTag, "apimapper-helper-device-lib")
+ a.setApiMapper(true)
+ }
+ a.AndroidApp.DepsMutator(ctx)
+}
+
func (a *AndroidTest) DepsMutator(ctx android.BottomUpMutatorContext) {
+ if len(a.ApexProperties.Apex_available) == 0 && ctx.Config().IsEnvTrue("EMMA_API_MAPPER") {
+ // Instrument the android_test_helper target to log potential API calls at the run time.
+ // Contact android-xts-infra team before using the environment var EMMA_API_MAPPER.
+ ctx.AddVariationDependencies(nil, staticLibTag, "apimapper-helper-device-lib")
+ a.setApiMapper(true)
+ }
a.AndroidApp.DepsMutator(ctx)
}
@@ -1498,7 +1752,7 @@
module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
module.appProperties.AlwaysPackageNativeLibs = true
module.Module.dexpreopter.isTest = true
- module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
+ module.Module.linter.properties.Lint.Test_module_type = proptools.BoolPtr(true)
module.addHostAndDeviceProperties()
module.AddProperties(
@@ -1549,12 +1803,14 @@
// TODO(b/192032291): Disable by default after auditing downstream usage.
module.Module.dexProperties.Optimize.EnabledByDefault = true
+ module.Module.dexProperties.Optimize.Ignore_library_extends_program = proptools.BoolPtr(true)
+ module.Module.dexProperties.Optimize.Proguard_compatibility = proptools.BoolPtr(false)
module.Module.properties.Installable = proptools.BoolPtr(true)
module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
module.appProperties.AlwaysPackageNativeLibs = true
module.Module.dexpreopter.isTest = true
- module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
+ module.Module.linter.properties.Lint.Test_module_type = proptools.BoolPtr(true)
module.addHostAndDeviceProperties()
module.AddProperties(
@@ -1581,6 +1837,12 @@
Certificate *string
}
+type AndroidAppCertificateInfo struct {
+ Certificate Certificate
+}
+
+var AndroidAppCertificateInfoProvider = blueprint.NewProvider[AndroidAppCertificateInfo]()
+
// android_app_certificate modules can be referenced by the certificates property of android_app modules to select
// the signing key.
func AndroidAppCertificateFactory() android.Module {
@@ -1596,6 +1858,10 @@
Pem: android.PathForModuleSrc(ctx, cert+".x509.pem"),
Key: android.PathForModuleSrc(ctx, cert+".pk8"),
}
+
+ android.SetProvider(ctx, AndroidAppCertificateInfoProvider, AndroidAppCertificateInfo{
+ Certificate: c.Certificate,
+ })
}
type OverrideAndroidApp struct {
@@ -1619,6 +1885,10 @@
android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon)
android.InitOverrideModule(m)
+ android.AddLoadHookWithPriority(m, func(ctx android.LoadHookContext) {
+ createInternalRuntimeOverlays(ctx, m.ModuleBase)
+ }, 1) // Run after soong config load hoook
+
return m
}
@@ -1650,11 +1920,11 @@
type UsesLibraryProperties struct {
// A list of shared library modules that will be listed in uses-library tags in the AndroidManifest.xml file.
- Uses_libs []string
+ Uses_libs proptools.Configurable[[]string]
// A list of shared library modules that will be listed in uses-library tags in the AndroidManifest.xml file with
// required=false.
- Optional_uses_libs []string
+ Optional_uses_libs proptools.Configurable[[]string]
// If true, the list of uses_libs and optional_uses_libs modules must match the AndroidManifest.xml file. Defaults
// to true if either uses_libs or optional_uses_libs is set. Will unconditionally default to true in the future.
@@ -1702,7 +1972,7 @@
func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, addCompatDeps bool) {
if !ctx.Config().UnbundledBuild() || ctx.Config().UnbundledBuildImage() {
- ctx.AddVariationDependencies(nil, usesLibReqTag, u.usesLibraryProperties.Uses_libs...)
+ ctx.AddVariationDependencies(nil, usesLibReqTag, u.usesLibraryProperties.Uses_libs.GetOrDefault(ctx, nil)...)
presentOptionalUsesLibs := u.presentOptionalUsesLibs(ctx)
ctx.AddVariationDependencies(nil, usesLibOptTag, presentOptionalUsesLibs...)
// Only add these extra dependencies if the module is an app that depends on framework
@@ -1715,17 +1985,17 @@
ctx.AddVariationDependencies(nil, usesLibCompat28OptTag, dexpreopt.OptionalCompatUsesLibs28...)
ctx.AddVariationDependencies(nil, usesLibCompat30OptTag, dexpreopt.OptionalCompatUsesLibs30...)
}
- _, diff, _ := android.ListSetDifference(u.usesLibraryProperties.Optional_uses_libs, presentOptionalUsesLibs)
+ _, diff, _ := android.ListSetDifference(u.usesLibraryProperties.Optional_uses_libs.GetOrDefault(ctx, nil), presentOptionalUsesLibs)
u.usesLibraryProperties.Missing_optional_uses_libs = diff
} else {
- ctx.AddVariationDependencies(nil, r8LibraryJarTag, u.usesLibraryProperties.Uses_libs...)
+ ctx.AddVariationDependencies(nil, r8LibraryJarTag, u.usesLibraryProperties.Uses_libs.GetOrDefault(ctx, nil)...)
ctx.AddVariationDependencies(nil, r8LibraryJarTag, u.presentOptionalUsesLibs(ctx)...)
}
}
// presentOptionalUsesLibs returns optional_uses_libs after filtering out libraries that don't exist in the source tree.
func (u *usesLibrary) presentOptionalUsesLibs(ctx android.BaseModuleContext) []string {
- optionalUsesLibs := android.FilterListPred(u.usesLibraryProperties.Optional_uses_libs, func(s string) bool {
+ optionalUsesLibs := android.FilterListPred(u.usesLibraryProperties.Optional_uses_libs.GetOrDefault(ctx, nil), func(s string) bool {
exists := ctx.OtherModuleExists(s)
if !exists && !android.InList(ctx.ModuleName(), ctx.Config().BuildWarningBadOptionalUsesLibsAllowlist()) {
fmt.Printf("Warning: Module '%s' depends on non-existing optional_uses_libs '%s'\n", ctx.ModuleName(), s)
@@ -1746,7 +2016,7 @@
return clcMap
}
- ctx.VisitDirectDeps(func(m android.Module) {
+ ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) {
tag, isUsesLibTag := ctx.OtherModuleDependencyTag(m).(usesLibraryDependencyTag)
if !isUsesLibTag {
return
@@ -1754,32 +2024,35 @@
dep := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(m))
+ javaInfo, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider)
+ if !ok {
+ return
+ }
// Skip stub libraries. A dependency on the implementation library has been added earlier,
// so it will be added to CLC, but the stub shouldn't be. Stub libraries can be distingushed
// from implementation libraries by their name, which is different as it has a suffix.
- if comp, ok := m.(SdkLibraryComponentDependency); ok {
- if impl := comp.OptionalSdkLibraryImplementation(); impl != nil && *impl != dep {
+ if comp := javaInfo.SdkLibraryComponentDependencyInfo; comp != nil {
+ if impl := comp.OptionalSdkLibraryImplementation; impl != nil && *impl != dep {
return
}
}
- // Skip java_sdk_library dependencies that provide stubs, but not an implementation.
- // This will be restricted to optional_uses_libs
- if sdklib, ok := m.(SdkLibraryDependency); ok {
- if tag == usesLibOptTag && sdklib.DexJarBuildPath(ctx).PathOrNil() == nil {
- u.shouldDisableDexpreopt = true
- return
+ if lib := javaInfo.UsesLibraryDependencyInfo; lib != nil {
+ if _, ok := android.OtherModuleProvider(ctx, m, SdkLibraryInfoProvider); ok {
+ // Skip java_sdk_library dependencies that provide stubs, but not an implementation.
+ // This will be restricted to optional_uses_libs
+ if tag == usesLibOptTag && lib.DexJarBuildPath.PathOrNil() == nil {
+ u.shouldDisableDexpreopt = true
+ return
+ }
}
- }
-
- if lib, ok := m.(UsesLibraryDependency); ok {
libName := dep
- if ulib, ok := m.(ProvidesUsesLib); ok && ulib.ProvidesUsesLib() != nil {
- libName = *ulib.ProvidesUsesLib()
+ if ulib := javaInfo.ProvidesUsesLibInfo; ulib != nil && ulib.ProvidesUsesLib != nil {
+ libName = *ulib.ProvidesUsesLib
}
clcMap.AddContext(ctx, tag.sdkVersion, libName, tag.optional,
- lib.DexJarBuildPath(ctx).PathOrNil(), lib.DexJarInstallPath(),
- lib.ClassLoaderContexts())
+ lib.DexJarBuildPath.PathOrNil(), lib.DexJarInstallPath,
+ lib.ClassLoaderContexts)
} else if ctx.Config().AllowMissingDependencies() {
ctx.AddMissingDependencies([]string{dep})
} else {
@@ -1792,15 +2065,15 @@
// enforceUsesLibraries returns true of <uses-library> tags should be checked against uses_libs and optional_uses_libs
// properties. Defaults to true if either of uses_libs or optional_uses_libs is specified. Will default to true
// unconditionally in the future.
-func (u *usesLibrary) enforceUsesLibraries() bool {
- defaultEnforceUsesLibs := len(u.usesLibraryProperties.Uses_libs) > 0 ||
- len(u.usesLibraryProperties.Optional_uses_libs) > 0
+func (u *usesLibrary) enforceUsesLibraries(ctx android.ModuleContext) bool {
+ defaultEnforceUsesLibs := len(u.usesLibraryProperties.Uses_libs.GetOrDefault(ctx, nil)) > 0 ||
+ len(u.usesLibraryProperties.Optional_uses_libs.GetOrDefault(ctx, nil)) > 0
return BoolDefault(u.usesLibraryProperties.Enforce_uses_libs, u.enforce || defaultEnforceUsesLibs)
}
// Freeze the value of `enforce_uses_libs` based on the current values of `uses_libs` and `optional_uses_libs`.
-func (u *usesLibrary) freezeEnforceUsesLibraries() {
- enforce := u.enforceUsesLibraries()
+func (u *usesLibrary) freezeEnforceUsesLibraries(ctx android.ModuleContext) {
+ enforce := u.enforceUsesLibraries(ctx)
u.usesLibraryProperties.Enforce_uses_libs = &enforce
}
diff --git a/java/app_import.go b/java/app_import.go
index 045a89a..352e995 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -43,6 +43,12 @@
Description: "Uncompress embedded JNI libs",
})
+ stripEmbeddedJniLibsUnusedArchRule = pctx.AndroidStaticRule("strip-embedded-jni-libs-from-unused-arch", blueprint.RuleParams{
+ Command: `${config.Zip2ZipCmd} -i $in -o $out -x 'lib/**/*.so' $extraArgs`,
+ CommandDeps: []string{"${config.Zip2ZipCmd}"},
+ Description: "Remove all JNI libs from unused architectures",
+ }, "extraArgs")
+
uncompressDexRule = pctx.AndroidStaticRule("uncompress-dex", blueprint.RuleParams{
Command: `if (zipinfo $in '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then ` +
`${config.Zip2ZipCmd} -i $in -o $out -0 'classes*.dex'` +
@@ -56,11 +62,26 @@
CommandDeps: []string{"build/soong/scripts/check_prebuilt_presigned_apk.py", "${config.Aapt2Cmd}", "${config.ZipAlign}"},
Description: "Check presigned apk",
}, "extraArgs")
+
+ extractApkRule = pctx.AndroidStaticRule("extract-apk", blueprint.RuleParams{
+ Command: "unzip -p $in $extract_apk > $out",
+ Description: "Extract specific sub apk",
+ }, "extract_apk")
+
+ gzipRule = pctx.AndroidStaticRule("gzip",
+ blueprint.RuleParams{
+ Command: "prebuilts/build-tools/path/linux-x86/gzip -9 -c $in > $out",
+ CommandDeps: []string{"prebuilts/build-tools/path/linux-x86/gzip"},
+ Description: "gzip $out",
+ })
)
func RegisterAppImportBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("android_app_import", AndroidAppImportFactory)
ctx.RegisterModuleType("android_test_import", AndroidTestImportFactory)
+ ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("disable_prebuilts_without_apk", disablePrebuiltsWithoutApkMutator)
+ })
}
type AndroidAppImport struct {
@@ -85,16 +106,16 @@
hideApexVariantFromMake bool
- provenanceMetaDataFile android.OutputPath
+ provenanceMetaDataFile android.Path
}
type AndroidAppImportProperties struct {
// A prebuilt apk to import
- Apk *string `android:"path"`
+ Apk proptools.Configurable[string] `android:"path,replace_instead_of_append"`
// The name of a certificate in the default certificate directory or an android_app_certificate
// module name in the form ":module". Should be empty if presigned or default_dev_cert is set.
- Certificate *string
+ Certificate proptools.Configurable[string] `android:"replace_instead_of_append"`
// Names of extra android_app_certificate modules to sign the apk with in the form ":module".
Additional_certificates []string
@@ -147,10 +168,19 @@
// the prebuilt is Name() without "prebuilt_" prefix
Source_module_name *string
+ // Whether stripping all libraries from unused architectures.
+ Strip_unused_jni_arch *bool
+
// Path to the .prebuilt_info file of the prebuilt app.
// In case of mainline modules, the .prebuilt_info file contains the build_id that was used
// to generate the prebuilt.
Prebuilt_info *string `android:"path"`
+
+ // Path of extracted apk which is extracted from prebuilt apk. Use this extracted to import.
+ Extract_apk *string
+
+ // Compress the output APK using gzip. Defaults to false.
+ Compress_apk proptools.Configurable[bool] `android:"arch_variant,replace_instead_of_append"`
}
func (a *AndroidAppImport) IsInstallable() bool {
@@ -193,13 +223,6 @@
}
}
}
-
- if String(a.properties.Apk) == "" {
- // Disable this module since the apk property is still empty after processing all matching
- // variants. This likely means there is no matching variant, and the default variant doesn't
- // have an apk property value either.
- a.Disable()
- }
}
func MergePropertiesFromVariant(ctx android.EarlyModuleContext,
@@ -219,8 +242,32 @@
}
}
+// disablePrebuiltsWithoutApkMutator is a pre-arch mutator that disables AndroidAppImport or
+// AndroidTestImport modules that don't have an apk set. We need this separate mutator instead
+// of doing it in processVariants because processVariants is a defaultable hook, and configurable
+// properties can only be evaluated after the defaults (and eventually, base configurabtion)
+// mutators.
+func disablePrebuiltsWithoutApkMutator(ctx android.BottomUpMutatorContext) {
+ switch a := ctx.Module().(type) {
+ case *AndroidAppImport:
+ if a.properties.Apk.GetOrDefault(ctx, "") == "" {
+ // Disable this module since the apk property is still empty after processing all
+ // matching variants. This likely means there is no matching variant, and the default
+ // variant doesn't have an apk property value either.
+ a.Disable()
+ }
+ case *AndroidTestImport:
+ if a.properties.Apk.GetOrDefault(ctx, "") == "" {
+ // Disable this module since the apk property is still empty after processing all
+ // matching variants. This likely means there is no matching variant, and the default
+ // variant doesn't have an apk property value either.
+ a.Disable()
+ }
+ }
+}
+
func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) {
- cert := android.SrcIsModule(String(a.properties.Certificate))
+ cert := android.SrcIsModule(a.properties.Certificate.GetOrDefault(ctx, ""))
if cert != "" {
ctx.AddDependency(ctx.Module(), certificateTag, cert)
}
@@ -239,7 +286,7 @@
}
func (a *AndroidAppImport) uncompressEmbeddedJniLibs(
- ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
+ ctx android.ModuleContext, inputPath android.Path, outputPath android.WritablePath) {
// Test apps don't need their JNI libraries stored uncompressed. As a matter of fact, messing
// with them may invalidate pre-existing signature data.
if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || Bool(a.properties.Preprocessed)) {
@@ -258,6 +305,19 @@
})
}
+func (a *AndroidAppImport) extractSubApk(
+ ctx android.ModuleContext, inputPath android.Path, outputPath android.WritablePath) {
+ extractApkPath := *a.properties.Extract_apk
+ ctx.Build(pctx, android.BuildParams{
+ Rule: extractApkRule,
+ Input: inputPath,
+ Output: outputPath,
+ Args: map[string]string{
+ "extract_apk": extractApkPath,
+ },
+ })
+}
+
// Returns whether this module should have the dex file stored uncompressed in the APK.
func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool {
if ctx.Config().UnbundledBuild() || proptools.Bool(a.properties.Preprocessed) {
@@ -272,6 +332,26 @@
return shouldUncompressDex(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), &a.dexpreopter)
}
+func (a *AndroidAppImport) stripEmbeddedJniLibsUnusedArch(
+ ctx android.ModuleContext, inputPath android.Path, outputPath android.WritablePath) {
+ var wantedJniLibSlice []string
+ for _, target := range ctx.MultiTargets() {
+ supported_abis := target.Arch.Abi
+ for _, arch := range supported_abis {
+ wantedJniLibSlice = append(wantedJniLibSlice, " -X lib/"+arch+"/*.so")
+ }
+ }
+ wantedJniLibString := strings.Join(wantedJniLibSlice, " ")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: stripEmbeddedJniLibsUnusedArchRule,
+ Input: inputPath,
+ Output: outputPath,
+ Args: map[string]string{
+ "extraArgs": wantedJniLibString,
+ },
+ })
+}
+
func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
a.generateAndroidBuildActions(ctx)
}
@@ -303,7 +383,7 @@
}
numCertPropsSet := 0
- if String(a.properties.Certificate) != "" {
+ if a.properties.Certificate.GetOrDefault(ctx, "") != "" {
numCertPropsSet++
}
if Bool(a.properties.Presigned) {
@@ -316,16 +396,27 @@
ctx.ModuleErrorf("One and only one of certficate, presigned (implied by preprocessed), and default_dev_cert properties must be set")
}
- // TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
// TODO: LOCAL_PACKAGE_SPLITS
srcApk := a.prebuilt.SingleSourcePath(ctx)
+ if a.properties.Extract_apk != nil {
+ extract_apk := android.PathForModuleOut(ctx, "extract-apk", ctx.ModuleName()+".apk")
+ a.extractSubApk(ctx, srcApk, extract_apk)
+ srcApk = extract_apk
+ }
// TODO: Install or embed JNI libraries
// Uncompress JNI libraries in the apk
jnisUncompressed := android.PathForModuleOut(ctx, "jnis-uncompressed", ctx.ModuleName()+".apk")
- a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed.OutputPath)
+ a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed)
+
+ // Strip all embedded JNI libs and include only required ones accordingly to the module's compile_multilib
+ if Bool(a.properties.Strip_unused_jni_arch) {
+ jnisStripped := android.PathForModuleOut(ctx, "jnis-stripped", ctx.ModuleName()+".apk")
+ a.stripEmbeddedJniLibsUnusedArch(ctx, jnisUncompressed, jnisStripped)
+ jnisUncompressed = jnisStripped
+ }
var pathFragments []string
relInstallPath := String(a.properties.Relative_install_path)
@@ -344,13 +435,15 @@
a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
- a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
+ a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries(ctx)
a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
- if a.usesLibrary.shouldDisableDexpreopt {
+
+ // Disable Dexpreopt if Compress_apk is true. It follows the build/make/core/app_prebuilt_internal.mk
+ if a.usesLibrary.shouldDisableDexpreopt || a.properties.Compress_apk.GetOrDefault(ctx, false) {
a.dexpreopter.disableDexpreopt()
}
- if a.usesLibrary.enforceUsesLibraries() {
+ if a.usesLibrary.enforceUsesLibraries(ctx) {
a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk, &a.dexpreopter.classLoaderContexts)
}
@@ -365,7 +458,13 @@
jnisUncompressed = dexUncompressed
}
- apkFilename := proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".apk")
+ defaultApkFilename := a.BaseModuleName()
+ if a.properties.Compress_apk.GetOrDefault(ctx, false) {
+ defaultApkFilename += ".apk.gz"
+ } else {
+ defaultApkFilename += ".apk"
+ }
+ apkFilename := proptools.StringDefault(a.properties.Filename, defaultApkFilename)
// TODO: Handle EXTERNAL
@@ -386,7 +485,7 @@
// If the certificate property is empty at this point, default_dev_cert must be set to true.
// Which makes processMainCert's behavior for the empty cert string WAI.
_, _, certificates := collectAppDeps(ctx, a, false, false)
- a.certificate, certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx)
+ a.certificate, certificates = processMainCert(a.ModuleBase, a.properties.Certificate.GetOrDefault(ctx, ""), certificates, ctx)
signed := android.PathForModuleOut(ctx, "signed", apkFilename)
var lineageFile android.Path
if lineage := String(a.properties.Lineage); lineage != "" {
@@ -405,11 +504,20 @@
a.certificate = PresignedCertificate
}
- // TODO: Optionally compress the output apk.
+ if a.properties.Compress_apk.GetOrDefault(ctx, false) {
+ outputFile := android.PathForModuleOut(ctx, "compressed_apk", apkFilename)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: gzipRule,
+ Input: a.outputFile,
+ Output: outputFile,
+ Description: "Compressing " + a.outputFile.Base(),
+ })
+ a.outputFile = outputFile
+ }
if apexInfo.IsForPlatform() {
a.installPath = ctx.InstallFile(installDir, apkFilename, a.outputFile)
- artifactPath := android.PathForModuleSrc(ctx, *a.properties.Apk)
+ artifactPath := android.PathForModuleSrc(ctx, a.properties.Apk.GetOrDefault(ctx, ""))
a.provenanceMetaDataFile = provenance.GenerateArtifactProvenanceMetaData(ctx, artifactPath, a.installPath)
}
@@ -423,6 +531,8 @@
ctx.SetOutputFiles([]android.Path{a.outputFile}, "")
+ buildComplianceMetadata(ctx)
+
// TODO: androidmk converter jni libs
}
@@ -473,7 +583,7 @@
return a.certificate
}
-func (a *AndroidAppImport) ProvenanceMetaDataFile() android.OutputPath {
+func (a *AndroidAppImport) ProvenanceMetaDataFile() android.Path {
return a.provenanceMetaDataFile
}
@@ -518,7 +628,7 @@
return Bool(a.properties.Privileged)
}
-func (a *AndroidAppImport) DepIsInSameApex(_ android.BaseModuleContext, _ android.Module) bool {
+func (a *AndroidAppImport) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
// android_app_import might have extra dependencies via uses_libs property.
// Don't track the dependency as we don't automatically add those libraries
// to the classpath. It should be explicitly added to java_libs property of APEX
@@ -533,10 +643,6 @@
return android.SdkSpecPrivate.ApiLevel
}
-func (a *AndroidAppImport) LintDepSets() LintDepSets {
- return LintDepSets{}
-}
-
var _ android.ApexModule = (*AndroidAppImport)(nil)
// Implements android.ApexModule
@@ -637,7 +743,7 @@
android.InitApexModule(module)
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
- android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk")
+ android.InitConfigurablePrebuiltModuleString(module, &module.properties.Apk, "Apk")
module.usesLibrary.enforce = true
@@ -690,7 +796,7 @@
android.InitApexModule(module)
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
- android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk")
+ android.InitConfigurablePrebuiltModuleString(module, &module.properties.Apk, "Apk")
return module
}
diff --git a/java/app_import_test.go b/java/app_import_test.go
index 54a5e75..52ae719 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -26,6 +26,7 @@
)
func TestAndroidAppImport(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
android_app_import {
name: "foo",
@@ -59,7 +60,48 @@
android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"])
}
+func TestAndroidAppImportWithDefaults(t *testing.T) {
+ t.Parallel()
+ ctx, _ := testJava(t, `
+ android_app_import {
+ name: "foo",
+ defaults: ["foo_defaults"],
+ }
+
+ java_defaults {
+ name: "foo_defaults",
+ apk: "prebuilts/apk/app.apk",
+ certificate: "platform",
+ dex_preopt: {
+ enabled: true,
+ },
+ }
+ `)
+
+ variant := ctx.ModuleForTests("foo", "android_common")
+
+ // Check dexpreopt outputs.
+ if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule == nil ||
+ variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule == nil {
+ t.Errorf("can't find dexpreopt outputs")
+ }
+
+ // Check cert signing flag.
+ signedApk := variant.Output("signed/foo.apk")
+ signingFlag := signedApk.Args["certificates"]
+ expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8"
+ if expected != signingFlag {
+ t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
+ }
+ rule := variant.Rule("genProvenanceMetaData")
+ android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String())
+ android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String())
+ android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"])
+ android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"])
+}
+
func TestAndroidAppImport_NoDexPreopt(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
android_app_import {
name: "foo",
@@ -87,6 +129,7 @@
}
func TestAndroidAppImport_Presigned(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
android_app_import {
name: "foo",
@@ -121,6 +164,7 @@
}
func TestAndroidAppImport_SigningLineage(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
android_app_import {
name: "foo",
@@ -164,6 +208,7 @@
}
func TestAndroidAppImport_SigningLineageFilegroup(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
android_app_import {
name: "foo",
@@ -196,6 +241,7 @@
}
func TestAndroidAppImport_DefaultDevCert(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
android_app_import {
name: "foo",
@@ -231,6 +277,7 @@
}
func TestAndroidAppImport_DpiVariants(t *testing.T) {
+ t.Parallel()
bp := `
android_app_import {
name: "foo",
@@ -317,6 +364,7 @@
}
func TestAndroidAppImport_Filename(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
android_app_import {
name: "foo",
@@ -325,10 +373,25 @@
}
android_app_import {
+ name: "foo_compressed",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ compress_apk: true,
+ }
+
+ android_app_import {
name: "bar",
apk: "prebuilts/apk/app.apk",
presigned: true,
- filename: "bar_sample.apk"
+ filename: "bar_sample.apk",
+ }
+
+ android_app_import {
+ name: "compressed_bar",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ filename: "bar_sample.apk",
+ compress_apk: true,
}
`)
@@ -347,12 +410,26 @@
expectedMetaDataPath: "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto",
},
{
+ name: "foo_compressed",
+ expected: "foo_compressed.apk.gz",
+ onDevice: "/system/app/foo_compressed/foo_compressed.apk.gz",
+ expectedArtifactPath: "prebuilts/apk/app.apk",
+ expectedMetaDataPath: "out/soong/.intermediates/provenance_metadata/foo_compressed/provenance_metadata.textproto",
+ },
+ {
name: "bar",
expected: "bar_sample.apk",
onDevice: "/system/app/bar/bar_sample.apk",
expectedArtifactPath: "prebuilts/apk/app.apk",
expectedMetaDataPath: "out/soong/.intermediates/provenance_metadata/bar/provenance_metadata.textproto",
},
+ {
+ name: "compressed_bar",
+ expected: "bar_sample.apk",
+ onDevice: "/system/app/compressed_bar/bar_sample.apk",
+ expectedArtifactPath: "prebuilts/apk/app.apk",
+ expectedMetaDataPath: "out/soong/.intermediates/provenance_metadata/compressed_bar/provenance_metadata.textproto",
+ },
}
for _, test := range testCases {
@@ -380,6 +457,7 @@
}
func TestAndroidAppImport_ArchVariants(t *testing.T) {
+ t.Parallel()
// The test config's target arch is ARM64.
testCases := []struct {
name string
@@ -505,6 +583,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, test.bp)
variant := ctx.ModuleForTests("foo", "android_common")
@@ -530,6 +609,7 @@
}
func TestAndroidAppImport_SoongConfigVariables(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
bp string
@@ -572,6 +652,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
ctx := android.GroupFixturePreparers(
prepareForJavaTest,
android.PrepareForTestWithSoongConfigModuleBuildComponents,
@@ -607,6 +688,7 @@
}
func TestAndroidAppImport_overridesDisabledAndroidApp(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
android_app {
name: "foo",
@@ -635,6 +717,7 @@
}
func TestAndroidAppImport_relativeInstallPath(t *testing.T) {
+ t.Parallel()
bp := `
android_app_import {
name: "no_relative_install_path",
@@ -664,28 +747,49 @@
}{
{
name: "no_relative_install_path",
- expectedInstallPath: "out/soong/target/product/test_device/system/app/no_relative_install_path/no_relative_install_path.apk",
+ expectedInstallPath: "out/target/product/test_device/system/app/no_relative_install_path/no_relative_install_path.apk",
errorMessage: "Install path is not correct when relative_install_path is missing",
},
{
name: "relative_install_path",
- expectedInstallPath: "out/soong/target/product/test_device/system/app/my/path/relative_install_path/relative_install_path.apk",
+ expectedInstallPath: "out/target/product/test_device/system/app/my/path/relative_install_path/relative_install_path.apk",
errorMessage: "Install path is not correct for app when relative_install_path is present",
},
{
name: "privileged_relative_install_path",
- expectedInstallPath: "out/soong/target/product/test_device/system/priv-app/my/path/privileged_relative_install_path/privileged_relative_install_path.apk",
+ expectedInstallPath: "out/target/product/test_device/system/priv-app/my/path/privileged_relative_install_path/privileged_relative_install_path.apk",
errorMessage: "Install path is not correct for privileged app when relative_install_path is present",
},
}
for _, testCase := range testCases {
- ctx, _ := testJava(t, bp)
- mod := ctx.ModuleForTests(testCase.name, "android_common").Module().(*AndroidAppImport)
- android.AssertPathRelativeToTopEquals(t, testCase.errorMessage, testCase.expectedInstallPath, mod.installPath)
+ t.Run(testCase.name, func(t *testing.T) {
+ t.Parallel()
+ ctx, _ := testJava(t, bp)
+ mod := ctx.ModuleForTests(testCase.name, "android_common").Module().(*AndroidAppImport)
+ android.AssertPathRelativeToTopEquals(t, testCase.errorMessage, testCase.expectedInstallPath, mod.installPath)
+ })
}
}
+func TestAndroidAppImport_ExtractApk(t *testing.T) {
+ t.Parallel()
+ ctx, _ := testJava(t, `
+ android_app_import {
+ name: "foo",
+ apk: "prebuilts/apk/app.apk",
+ certificate: "platform",
+ extract_apk: "extract_path/sub_app.apk"
+ }
+ `)
+
+ variant := ctx.ModuleForTests("foo", "android_common")
+ extractRuleArgs := variant.Output("extract-apk/foo.apk").BuildParams.Args
+ if extractRuleArgs["extract_apk"] != "extract_path/sub_app.apk" {
+ t.Errorf("Unexpected extract apk args: %s", extractRuleArgs["extract_apk"])
+ }
+}
func TestAndroidTestImport(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
android_test_import {
name: "foo",
@@ -714,6 +818,7 @@
}
func TestAndroidTestImport_NoJinUncompressForPresigned(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
android_test_import {
name: "foo",
@@ -737,13 +842,13 @@
variant := ctx.ModuleForTests("foo", "android_common")
jniRule := variant.Output("jnis-uncompressed/foo.apk").BuildParams.Rule.String()
if jniRule == android.Cp.String() {
- t.Errorf("Unexpected JNI uncompress rule command: " + jniRule)
+ t.Errorf("Unexpected JNI uncompress rule command: %s", jniRule)
}
variant = ctx.ModuleForTests("foo_presigned", "android_common")
jniRule = variant.Output("jnis-uncompressed/foo_presigned.apk").BuildParams.Rule.String()
if jniRule != android.Cp.String() {
- t.Errorf("Unexpected JNI uncompress rule: " + jniRule)
+ t.Errorf("Unexpected JNI uncompress rule: %s", jniRule)
}
if variant.MaybeOutput("zip-aligned/foo_presigned.apk").Rule == nil {
t.Errorf("Presigned test apk should be aligned")
@@ -751,6 +856,7 @@
}
func TestAndroidTestImport_Preprocessed(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
android_test_import {
name: "foo",
@@ -764,7 +870,7 @@
variant := ctx.ModuleForTests("foo", "android_common")
jniRule := variant.Output("jnis-uncompressed/" + apkName).BuildParams.Rule.String()
if jniRule != android.Cp.String() {
- t.Errorf("Unexpected JNI uncompress rule: " + jniRule)
+ t.Errorf("Unexpected JNI uncompress rule: %s", jniRule)
}
// Make sure signing and aligning were skipped.
@@ -777,9 +883,11 @@
}
func TestAndroidAppImport_Preprocessed(t *testing.T) {
+ t.Parallel()
for _, dontUncompressPrivAppDexs := range []bool{false, true} {
name := fmt.Sprintf("dontUncompressPrivAppDexs:%t", dontUncompressPrivAppDexs)
t.Run(name, func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
@@ -807,7 +915,7 @@
variant := result.ModuleForTests("foo", "android_common")
outputBuildParams := variant.Output(apkName).BuildParams
if outputBuildParams.Rule.String() != android.Cp.String() {
- t.Errorf("Unexpected prebuilt android_app_import rule: " + outputBuildParams.Rule.String())
+ t.Errorf("Unexpected prebuilt android_app_import rule: %s", outputBuildParams.Rule.String())
}
// Make sure compression and aligning were validated.
@@ -817,7 +925,7 @@
validationBuildParams := variant.Output("validated-prebuilt/check.stamp").BuildParams
if validationBuildParams.Rule.String() != checkPresignedApkRule.String() {
- t.Errorf("Unexpected validation rule: " + validationBuildParams.Rule.String())
+ t.Errorf("Unexpected validation rule: %s", validationBuildParams.Rule.String())
}
expectedScriptArgs := "--preprocessed"
@@ -829,7 +937,7 @@
variant = result.ModuleForTests("bar", "android_common")
outputBuildParams = variant.Output(apkName).BuildParams
if outputBuildParams.Rule.String() != android.Cp.String() {
- t.Errorf("Unexpected prebuilt android_app_import rule: " + outputBuildParams.Rule.String())
+ t.Errorf("Unexpected prebuilt android_app_import rule: %s", outputBuildParams.Rule.String())
}
// Make sure compression and aligning were validated.
@@ -839,7 +947,7 @@
validationBuildParams = variant.Output("validated-prebuilt/check.stamp").BuildParams
if validationBuildParams.Rule.String() != checkPresignedApkRule.String() {
- t.Errorf("Unexpected validation rule: " + validationBuildParams.Rule.String())
+ t.Errorf("Unexpected validation rule: %s", validationBuildParams.Rule.String())
}
expectedScriptArgs = "--privileged"
@@ -854,6 +962,7 @@
}
func TestAndroidTestImport_UncompressDex(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
bp string
@@ -917,6 +1026,7 @@
name := fmt.Sprintf("%s,unbundled:%t,dontUncompressPrivAppDexs:%t",
tt.name, unbundled, dontUncompressPrivAppDexs)
t.Run(name, func(t *testing.T) {
+ t.Parallel()
test(t, tt.bp, unbundled, dontUncompressPrivAppDexs)
})
}
@@ -925,6 +1035,7 @@
}
func TestAppImportMissingCertificateAllowMissingDependencies(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
android.PrepareForTestWithAllowMissingDependencies,
diff --git a/java/app_set_test.go b/java/app_set_test.go
index c02b359..cc7af04 100644
--- a/java/app_set_test.go
+++ b/java/app_set_test.go
@@ -24,6 +24,7 @@
)
func TestAndroidAppSet(t *testing.T) {
+ t.Parallel()
result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, `
android_app_set {
name: "foo",
@@ -65,6 +66,7 @@
}
func TestAndroidAppSet_Variants(t *testing.T) {
+ t.Parallel()
bp := `
android_app_set {
name: "foo",
@@ -113,24 +115,24 @@
}
for _, test := range testCases {
- ctx := android.GroupFixturePreparers(
- PrepareForTestWithJavaDefaultModules,
- android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI
- variables.Platform_sdk_version = &test.sdkVersion
- }),
- android.FixtureModifyConfig(func(config android.Config) {
- config.Targets[android.Android] = test.targets
- }),
- ).RunTestWithBp(t, bp)
+ t.Run(test.name, func(t *testing.T) {
+ ctx := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI
+ variables.Platform_sdk_version = &test.sdkVersion
+ }),
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.Targets[android.Android] = test.targets
+ }),
+ ).RunTestWithBp(t, bp)
- module := ctx.ModuleForTests("foo", "android_common")
- const packedSplitApks = "foo.zip"
- params := module.Output(packedSplitApks)
- for k, v := range test.expected {
- t.Run(test.name, func(t *testing.T) {
+ module := ctx.ModuleForTests("foo", "android_common")
+ const packedSplitApks = "foo.zip"
+ params := module.Output(packedSplitApks)
+ for k, v := range test.expected {
android.AssertStringEquals(t, fmt.Sprintf("arg value for `%s`", k), v, params.Args[k])
- })
- }
+ }
+ })
}
}
diff --git a/java/app_test.go b/java/app_test.go
index ec97a55..701fc35 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -18,6 +18,7 @@
"fmt"
"path/filepath"
"reflect"
+ "regexp"
"sort"
"strings"
"testing"
@@ -41,6 +42,7 @@
}
func TestApp(t *testing.T) {
+ t.Parallel()
resourceFiles := []string{
"res/layout/layout.xml",
"res/values/strings.xml",
@@ -55,6 +57,7 @@
for _, moduleType := range []string{"android_app", "android_library"} {
t.Run(moduleType, func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
android.FixtureModifyMockFS(func(fs android.MockFS) {
@@ -100,6 +103,7 @@
}
func TestAppSplits(t *testing.T) {
+ t.Parallel()
ctx := testApp(t, `
android_app {
name: "foo",
@@ -124,6 +128,7 @@
}
func TestPlatformAPIs(t *testing.T) {
+ t.Parallel()
testJava(t, `
android_app {
name: "foo",
@@ -158,6 +163,7 @@
}
func TestAndroidAppLinkType(t *testing.T) {
+ t.Parallel()
testJava(t, `
android_app {
name: "foo",
@@ -247,6 +253,7 @@
}
func TestUpdatableApps(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
bp string
@@ -358,6 +365,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
errorHandler := android.FixtureExpectsNoErrors
if test.expectedError != "" {
errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(test.expectedError)
@@ -372,6 +380,7 @@
}
func TestUpdatableApps_TransitiveDepsShouldSetMinSdkVersion(t *testing.T) {
+ t.Parallel()
testJavaError(t, `module "bar".*: should support min_sdk_version\(29\)`, cc.GatherRequiredDepsForTest(android.Android)+`
android_app {
name: "foo",
@@ -390,6 +399,7 @@
}
func TestUpdatableApps_JniLibsShouldShouldSupportMinSdkVersion(t *testing.T) {
+ t.Parallel()
testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
android_app {
name: "foo",
@@ -410,6 +420,7 @@
}
func TestUpdatableApps_JniLibShouldBeBuiltAgainstMinSdkVersion(t *testing.T) {
+ t.Parallel()
bp := cc.GatherRequiredDepsForTest(android.Android) + `
android_app {
name: "foo",
@@ -465,6 +476,7 @@
}
func TestUpdatableApps_ErrorIfJniLibDoesntSupportMinSdkVersion(t *testing.T) {
+ t.Parallel()
bp := cc.GatherRequiredDepsForTest(android.Android) + `
android_app {
name: "foo",
@@ -486,6 +498,7 @@
}
func TestUpdatableApps_ErrorIfDepMinSdkVersionIsHigher(t *testing.T) {
+ t.Parallel()
bp := cc.GatherRequiredDepsForTest(android.Android) + `
android_app {
name: "foo",
@@ -517,6 +530,7 @@
}
func TestUpdatableApps_ApplyDefaultUpdatableModuleVersion(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
).RunTestWithBp(t, `
@@ -530,13 +544,14 @@
`)
foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer")
android.AssertStringDoesContain(t,
- "com.android.foo: expected manifest fixer to set override-placeholder-version to android.DefaultUpdatableModuleVersion",
+ "com.android.foo: expected manifest fixer to set override-placeholder-version to RELEASE_DEFAULT_UPDATABLE_MODULE_VERSION",
foo.BuildParams.Args["args"],
- fmt.Sprintf("--override-placeholder-version %s", android.DefaultUpdatableModuleVersion),
+ fmt.Sprintf("--override-placeholder-version %s", testDefaultUpdatableModuleVersion),
)
}
func TestUpdatableApps_ApplyOverrideApexManifestDefaultVersion(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
android.FixtureMergeEnv(map[string]string{
@@ -560,6 +575,7 @@
}
func TestResourceDirs(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
prop string
@@ -596,6 +612,7 @@
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
fs.AddToFixture(),
@@ -617,6 +634,7 @@
}
func TestLibraryAssets(t *testing.T) {
+ t.Parallel()
bp := `
android_app {
name: "foo",
@@ -711,6 +729,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
m := ctx.ModuleForTests(test.name, "android_common")
// Check asset flag in aapt2 link flags
@@ -746,6 +765,7 @@
}
func TestAppJavaResources(t *testing.T) {
+ t.Parallel()
bp := `
android_app {
name: "foo",
@@ -791,6 +811,7 @@
}
func TestAndroidResourceProcessor(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
appUsesRP bool
@@ -1223,6 +1244,7 @@
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
+ t.Parallel()
bp := fmt.Sprintf(`
android_app {
name: "app",
@@ -1419,26 +1441,32 @@
}
func TestAndroidResourceOverlays(t *testing.T) {
+ t.Parallel()
+ type moduleAndVariant struct {
+ module string
+ variant string
+ }
+
testCases := []struct {
name string
enforceRROTargets []string
enforceRROExcludedOverlays []string
- resourceFiles map[string][]string
- overlayFiles map[string][]string
- rroDirs map[string][]string
+ resourceFiles map[moduleAndVariant][]string
+ overlayFiles map[moduleAndVariant][]string
+ rroDirs map[moduleAndVariant][]string
}{
{
name: "no RRO",
enforceRROTargets: nil,
enforceRROExcludedOverlays: nil,
- resourceFiles: map[string][]string{
- "foo": nil,
- "bar": {"bar/res/res/values/strings.xml"},
- "lib": nil,
- "lib2": {"lib2/res/res/values/strings.xml"},
+ resourceFiles: map[moduleAndVariant][]string{
+ {"foo", "android_common"}: nil,
+ {"bar", "android_common"}: {"bar/res/res/values/strings.xml"},
+ {"lib", "android_common"}: nil,
+ {"lib2", "android_common"}: {"lib2/res/res/values/strings.xml"},
},
- overlayFiles: map[string][]string{
- "foo": {
+ overlayFiles: map[moduleAndVariant][]string{
+ {"foo", "android_common"}: {
"out/soong/.intermediates/lib2/android_common/package-res.apk",
"out/soong/.intermediates/lib/android_common/package-res.apk",
"out/soong/.intermediates/lib3/android_common/package-res.apk",
@@ -1447,57 +1475,65 @@
"device/vendor/blah/overlay/foo/res/values/strings.xml",
"product/vendor/blah/overlay/foo/res/values/strings.xml",
},
- "bar": {
+ {"bar", "android_common"}: {
"device/vendor/blah/static_overlay/bar/res/values/strings.xml",
"device/vendor/blah/overlay/bar/res/values/strings.xml",
},
- "lib": {
+ {"lib", "android_common"}: {
"out/soong/.intermediates/lib2/android_common/package-res.apk",
"lib/res/res/values/strings.xml",
"device/vendor/blah/overlay/lib/res/values/strings.xml",
},
},
- rroDirs: map[string][]string{
- "foo": nil,
- "bar": nil,
+ rroDirs: map[moduleAndVariant][]string{
+ {"foo", "android_common"}: nil,
+ {"bar", "android_common"}: nil,
},
},
{
name: "enforce RRO on foo",
enforceRROTargets: []string{"foo"},
enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"},
- resourceFiles: map[string][]string{
- "foo": nil,
- "bar": {"bar/res/res/values/strings.xml"},
- "lib": nil,
- "lib2": {"lib2/res/res/values/strings.xml"},
+ resourceFiles: map[moduleAndVariant][]string{
+ {"foo", "android_common"}: nil,
+ {"bar", "android_common"}: {"bar/res/res/values/strings.xml"},
+ {"lib", "android_common"}: nil,
+ {"lib", "android_common_rro"}: nil,
+ {"lib2", "android_common"}: {"lib2/res/res/values/strings.xml"},
+ {"lib2", "android_common_rro"}: {"lib2/res/res/values/strings.xml"},
},
- overlayFiles: map[string][]string{
- "foo": {
- "out/soong/.intermediates/lib2/android_common/package-res.apk",
- "out/soong/.intermediates/lib/android_common/package-res.apk",
- "out/soong/.intermediates/lib3/android_common/package-res.apk",
+ overlayFiles: map[moduleAndVariant][]string{
+ {"foo", "android_common"}: {
+ "out/soong/.intermediates/lib2/android_common_rro/package-res.apk",
+ "out/soong/.intermediates/lib/android_common_rro/package-res.apk",
+ "out/soong/.intermediates/lib3/android_common_rro/package-res.apk",
"foo/res/res/values/strings.xml",
"device/vendor/blah/static_overlay/foo/res/values/strings.xml",
},
- "bar": {
+ {"bar", "android_common"}: {
"device/vendor/blah/static_overlay/bar/res/values/strings.xml",
"device/vendor/blah/overlay/bar/res/values/strings.xml",
},
- "lib": {
+ {"lib", "android_common"}: {
"out/soong/.intermediates/lib2/android_common/package-res.apk",
"lib/res/res/values/strings.xml",
+ "device/vendor/blah/overlay/lib/res/values/strings.xml",
+ },
+ {"lib", "android_common_rro"}: {
+ "out/soong/.intermediates/lib2/android_common_rro/package-res.apk",
+ "lib/res/res/values/strings.xml",
},
},
- rroDirs: map[string][]string{
- "foo": {
+ rroDirs: map[moduleAndVariant][]string{
+ {"foo", "android_common"}: {
"device:device/vendor/blah/overlay/foo/res",
"product:product/vendor/blah/overlay/foo/res",
"device:device/vendor/blah/overlay/lib/res",
},
- "bar": nil,
- "lib": {"device:device/vendor/blah/overlay/lib/res"},
+ {"bar", "android_common"}: nil,
+ {"lib", "android_common"}: nil,
+ {"lib", "android_common_rro"}: {"device:device/vendor/blah/overlay/lib/res"},
},
},
{
@@ -1508,35 +1544,35 @@
"device/vendor/blah/static_overlay/foo",
"device/vendor/blah/static_overlay/bar/res",
},
- resourceFiles: map[string][]string{
- "foo": nil,
- "bar": {"bar/res/res/values/strings.xml"},
- "lib": nil,
- "lib2": {"lib2/res/res/values/strings.xml"},
+ resourceFiles: map[moduleAndVariant][]string{
+ {"foo", "android_common"}: nil,
+ {"bar", "android_common"}: {"bar/res/res/values/strings.xml"},
+ {"lib", "android_common"}: nil,
+ {"lib2", "android_common"}: {"lib2/res/res/values/strings.xml"},
},
- overlayFiles: map[string][]string{
- "foo": {
+ overlayFiles: map[moduleAndVariant][]string{
+ {"foo", "android_common"}: {
"out/soong/.intermediates/lib2/android_common/package-res.apk",
"out/soong/.intermediates/lib/android_common/package-res.apk",
"out/soong/.intermediates/lib3/android_common/package-res.apk",
"foo/res/res/values/strings.xml",
"device/vendor/blah/static_overlay/foo/res/values/strings.xml",
},
- "bar": {"device/vendor/blah/static_overlay/bar/res/values/strings.xml"},
- "lib": {
+ {"bar", "android_common"}: {"device/vendor/blah/static_overlay/bar/res/values/strings.xml"},
+ {"lib", "android_common"}: {
"out/soong/.intermediates/lib2/android_common/package-res.apk",
"lib/res/res/values/strings.xml",
},
},
- rroDirs: map[string][]string{
- "foo": {
+ rroDirs: map[moduleAndVariant][]string{
+ {"foo", "android_common"}: {
"device:device/vendor/blah/overlay/foo/res",
"product:product/vendor/blah/overlay/foo/res",
// Lib dep comes after the direct deps
"device:device/vendor/blah/overlay/lib/res",
},
- "bar": {"device:device/vendor/blah/overlay/bar/res"},
- "lib": {"device:device/vendor/blah/overlay/lib/res"},
+ {"bar", "android_common"}: {"device:device/vendor/blah/overlay/bar/res"},
+ {"lib", "android_common"}: {"device:device/vendor/blah/overlay/lib/res"},
},
},
}
@@ -1602,6 +1638,7 @@
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
fs.AddToFixture(),
@@ -1621,19 +1658,19 @@
for _, o := range list {
res := module.MaybeOutput(o)
if res.Rule != nil {
- // If the overlay is compiled as part of this module (i.e. a .arsc.flat file),
+ // If the overlay is compiled as part of this moduleAndVariant (i.e. a .arsc.flat file),
// verify the inputs to the .arsc.flat rule.
files = append(files, res.Inputs.Strings()...)
} else {
- // Otherwise, verify the full path to the output of the other module
+ // Otherwise, verify the full path to the output of the other moduleAndVariant
files = append(files, o)
}
}
return files
}
- getResources := func(moduleName string) (resourceFiles, overlayFiles, rroDirs []string) {
- module := result.ModuleForTests(moduleName, "android_common")
+ getResources := func(moduleName, variantName string) (resourceFiles, overlayFiles, rroDirs []string) {
+ module := result.ModuleForTests(moduleName, variantName)
resourceList := module.MaybeOutput("aapt2/res.list")
if resourceList.Rule != nil {
resourceFiles = resourceListToFiles(module, android.PathsRelativeToTop(resourceList.Inputs))
@@ -1658,21 +1695,33 @@
return resourceFiles, overlayFiles, rroDirs
}
- modules := []string{"foo", "bar", "lib", "lib2"}
- for _, module := range modules {
- resourceFiles, overlayFiles, rroDirs := getResources(module)
+ modules := []moduleAndVariant{
+ {"foo", "android_common"},
+ {"foo", "android_common_rro"},
+ {"bar", "android_common"},
+ {"bar", "android_common_rro"},
+ {"lib", "android_common"},
+ {"lib", "android_common_rro"},
+ {"lib2", "android_common"},
+ {"lib2", "android_common_rro"},
+ }
+ for _, moduleAndVariant := range modules {
+ if _, exists := testCase.resourceFiles[moduleAndVariant]; !exists {
+ continue
+ }
+ resourceFiles, overlayFiles, rroDirs := getResources(moduleAndVariant.module, moduleAndVariant.variant)
- if !reflect.DeepEqual(resourceFiles, testCase.resourceFiles[module]) {
+ if !reflect.DeepEqual(resourceFiles, testCase.resourceFiles[moduleAndVariant]) {
t.Errorf("expected %s resource files:\n %#v\n got:\n %#v",
- module, testCase.resourceFiles[module], resourceFiles)
+ moduleAndVariant, testCase.resourceFiles[moduleAndVariant], resourceFiles)
}
- if !reflect.DeepEqual(overlayFiles, testCase.overlayFiles[module]) {
+ if !reflect.DeepEqual(overlayFiles, testCase.overlayFiles[moduleAndVariant]) {
t.Errorf("expected %s overlay files:\n %#v\n got:\n %#v",
- module, testCase.overlayFiles[module], overlayFiles)
+ moduleAndVariant, testCase.overlayFiles[moduleAndVariant], overlayFiles)
}
- if !reflect.DeepEqual(rroDirs, testCase.rroDirs[module]) {
+ if !reflect.DeepEqual(rroDirs, testCase.rroDirs[moduleAndVariant]) {
t.Errorf("expected %s rroDirs: %#v\n got:\n %#v",
- module, testCase.rroDirs[module], rroDirs)
+ moduleAndVariant, testCase.rroDirs[moduleAndVariant], rroDirs)
}
}
})
@@ -1699,6 +1748,7 @@
}
func TestAppSdkVersion(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
sdkVersion string
@@ -1766,6 +1816,7 @@
for _, moduleType := range []string{"android_app", "android_library"} {
for _, test := range testCases {
t.Run(moduleType+" "+test.name, func(t *testing.T) {
+ t.Parallel()
platformApiProp := ""
if test.platformApis {
platformApiProp = "platform_apis: true,"
@@ -1802,6 +1853,7 @@
}
func TestVendorAppSdkVersion(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
sdkVersion string
@@ -1844,6 +1896,7 @@
for _, sdkKind := range []string{"", "system_"} {
for _, test := range testCases {
t.Run(moduleType+" "+test.name, func(t *testing.T) {
+ t.Parallel()
bp := fmt.Sprintf(`%s {
name: "foo",
srcs: ["a.java"],
@@ -1875,6 +1928,7 @@
}
func TestJNIABI(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
cc_library {
name: "libjni",
@@ -1931,6 +1985,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
app := ctx.ModuleForTests(test.name, "android_common")
jniLibZip := app.Output("jnilibs.zip")
var abis []string
@@ -1949,6 +2004,7 @@
}
func TestAppSdkVersionByPartition(t *testing.T) {
+ t.Parallel()
testJavaError(t, "sdk_version must have a value when the module is located at vendor or product", `
android_app {
name: "foo",
@@ -1993,6 +2049,7 @@
}
func TestJNIPackaging(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
cc_library {
name: "libjni",
@@ -2064,6 +2121,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
app := ctx.ModuleForTests(test.name, "android_common")
jniLibZip := app.MaybeOutput("jnilibs.zip")
if g, w := (jniLibZip.Rule != nil), test.packaged; g != w {
@@ -2084,6 +2142,7 @@
}
func TestJNISDK(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
cc_library {
name: "libjni",
@@ -2154,6 +2213,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
app := ctx.ModuleForTests(test.name, "android_common")
jniLibZip := app.MaybeOutput("jnilibs.zip")
@@ -2179,6 +2239,7 @@
}
t.Run("jni_uses_platform_apis_error", func(t *testing.T) {
+ t.Parallel()
testJavaError(t, `jni_uses_platform_apis: can only be set for modules that set sdk_version`, `
android_test {
name: "app_platform",
@@ -2189,6 +2250,7 @@
})
t.Run("jni_uses_sdk_apis_error", func(t *testing.T) {
+ t.Parallel()
testJavaError(t, `jni_uses_sdk_apis: can only be set for modules that do not set sdk_version`, `
android_test {
name: "app_sdk",
@@ -2201,6 +2263,7 @@
}
func TestCertificates(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
bp string
@@ -2338,6 +2401,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
@@ -2375,6 +2439,7 @@
}
func TestRequestV4SigningFlag(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
bp string
@@ -2419,6 +2484,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
).RunTestWithBp(t, test.bp)
@@ -2433,6 +2499,7 @@
}
func TestPackageNameOverride(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
bp string
@@ -2451,7 +2518,7 @@
packageNameOverride: "",
expected: []string{
"out/soong/.intermediates/foo/android_common/foo.apk",
- "out/soong/target/product/test_device/system/app/foo/foo.apk",
+ "out/target/product/test_device/system/app/foo/foo.apk",
},
},
{
@@ -2467,7 +2534,7 @@
expected: []string{
// The package apk should be still be the original name for test dependencies.
"out/soong/.intermediates/foo/android_common/bar.apk",
- "out/soong/target/product/test_device/system/app/bar/bar.apk",
+ "out/target/product/test_device/system/app/bar/bar.apk",
},
},
{
@@ -2483,13 +2550,14 @@
packageNameOverride: "",
expected: []string{
"out/soong/.intermediates/foo/android_common/bar.apk",
- "out/soong/target/product/test_device/system/app/bar/bar.apk",
+ "out/target/product/test_device/system/app/bar/bar.apk",
},
},
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
@@ -2518,6 +2586,7 @@
}
func TestInstrumentationTargetOverridden(t *testing.T) {
+ t.Parallel()
bp := `
android_app {
name: "foo",
@@ -2549,6 +2618,7 @@
}
func TestOverrideAndroidApp(t *testing.T) {
+ t.Parallel()
result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(
t, `
android_app {
@@ -2626,7 +2696,7 @@
name: "foo",
moduleName: "foo",
variantName: "android_common",
- apkPath: "out/soong/target/product/test_device/system/app/foo/foo.apk",
+ apkPath: "out/target/product/test_device/system/app/foo/foo.apk",
certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
certSigningFlags: "",
overrides: []string{"qux"},
@@ -2638,7 +2708,7 @@
name: "foo",
moduleName: "bar",
variantName: "android_common_bar",
- apkPath: "out/soong/target/product/test_device/system/app/bar/bar.apk",
+ apkPath: "out/target/product/test_device/system/app/bar/bar.apk",
certFlag: "cert/new_cert.x509.pem cert/new_cert.pk8",
certSigningFlags: "--lineage lineage.bin --rotation-min-sdk-version 32",
overrides: []string{"qux", "foo"},
@@ -2650,7 +2720,7 @@
name: "foo",
moduleName: "baz",
variantName: "android_common_baz",
- apkPath: "out/soong/target/product/test_device/system/app/baz/baz.apk",
+ apkPath: "out/target/product/test_device/system/app/baz/baz.apk",
certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
certSigningFlags: "",
overrides: []string{"qux", "foo"},
@@ -2662,7 +2732,7 @@
name: "foo",
moduleName: "baz_no_rename_resources",
variantName: "android_common_baz_no_rename_resources",
- apkPath: "out/soong/target/product/test_device/system/app/baz_no_rename_resources/baz_no_rename_resources.apk",
+ apkPath: "out/target/product/test_device/system/app/baz_no_rename_resources/baz_no_rename_resources.apk",
certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
certSigningFlags: "",
overrides: []string{"qux", "foo"},
@@ -2674,7 +2744,7 @@
name: "foo_no_rename_resources",
moduleName: "baz_base_no_rename_resources",
variantName: "android_common_baz_base_no_rename_resources",
- apkPath: "out/soong/target/product/test_device/system/app/baz_base_no_rename_resources/baz_base_no_rename_resources.apk",
+ apkPath: "out/target/product/test_device/system/app/baz_base_no_rename_resources/baz_base_no_rename_resources.apk",
certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
certSigningFlags: "",
overrides: []string{"qux", "foo_no_rename_resources"},
@@ -2686,7 +2756,7 @@
name: "foo_no_rename_resources",
moduleName: "baz_override_base_rename_resources",
variantName: "android_common_baz_override_base_rename_resources",
- apkPath: "out/soong/target/product/test_device/system/app/baz_override_base_rename_resources/baz_override_base_rename_resources.apk",
+ apkPath: "out/target/product/test_device/system/app/baz_override_base_rename_resources/baz_override_base_rename_resources.apk",
certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
certSigningFlags: "",
overrides: []string{"qux", "foo_no_rename_resources"},
@@ -2731,6 +2801,7 @@
}
func TestOverrideAndroidAppOverrides(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(
t, `
android_app {
@@ -2789,6 +2860,7 @@
}
func TestOverrideAndroidAppWithPrebuilt(t *testing.T) {
+ t.Parallel()
result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(
t, `
android_app {
@@ -2824,6 +2896,7 @@
}
func TestOverrideAndroidAppStem(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
android_app {
name: "foo",
@@ -2863,33 +2936,33 @@
{
moduleName: "foo",
variantName: "android_common",
- apkPath: "out/soong/target/product/test_device/system/app/foo/foo.apk",
+ apkPath: "out/target/product/test_device/system/app/foo/foo.apk",
},
{
moduleName: "foo",
variantName: "android_common_bar",
- apkPath: "out/soong/target/product/test_device/system/app/bar/bar.apk",
+ apkPath: "out/target/product/test_device/system/app/bar/bar.apk",
},
{
moduleName: "foo",
variantName: "android_common_baz",
- apkPath: "out/soong/target/product/test_device/system/app/baz_stem/baz_stem.apk",
+ apkPath: "out/target/product/test_device/system/app/baz_stem/baz_stem.apk",
},
{
moduleName: "foo2",
variantName: "android_common",
- apkPath: "out/soong/target/product/test_device/system/app/foo2_stem/foo2_stem.apk",
+ apkPath: "out/target/product/test_device/system/app/foo2_stem/foo2_stem.apk",
},
{
moduleName: "foo2",
variantName: "android_common_bar2",
// Note that this may cause the duplicate output error.
- apkPath: "out/soong/target/product/test_device/system/app/foo2_stem/foo2_stem.apk",
+ apkPath: "out/target/product/test_device/system/app/foo2_stem/foo2_stem.apk",
},
{
moduleName: "foo2",
variantName: "android_common_baz2",
- apkPath: "out/soong/target/product/test_device/system/app/baz2_stem/baz2_stem.apk",
+ apkPath: "out/target/product/test_device/system/app/baz2_stem/baz2_stem.apk",
},
} {
variant := ctx.ModuleForTests(expected.moduleName, expected.variantName)
@@ -2898,6 +2971,7 @@
}
func TestOverrideAndroidAppDependency(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
android_app {
name: "foo",
@@ -2999,7 +3073,7 @@
variant := ctx.ModuleForTests("foo_test", expected.variantName)
// Check the final apk name
- variant.Output("out/soong" + expected.apkPath)
+ variant.Output("out" + expected.apkPath)
// Check if the overrides field values are correctly aggregated.
mod := variant.Module().(*AndroidTest)
@@ -3133,6 +3207,7 @@
}
func TestStl(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
cc_library {
name: "libjni",
@@ -3175,6 +3250,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
app := ctx.ModuleForTests(test.name, "android_common")
jniLibZip := app.Output("jnilibs.zip")
var jnis []string
@@ -3241,7 +3317,7 @@
java_library {
name: "static-runtime-helper",
srcs: ["a.java"],
- libs: ["runtime-library"],
+ libs: ["runtime-library.impl"],
sdk_version: "current",
}
@@ -3305,7 +3381,7 @@
name: "app",
srcs: ["a.java"],
libs: [
- "qux",
+ "qux.impl",
"quuz.stubs"
],
static_libs: [
@@ -3405,6 +3481,7 @@
}
func TestDexpreoptBcp(t *testing.T) {
+ t.Parallel()
bp := `
java_sdk_library {
name: "foo",
@@ -3447,6 +3524,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -3465,6 +3543,7 @@
}
func TestCodelessApp(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
bp string
@@ -3529,6 +3608,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
ctx := testApp(t, test.bp)
foo := ctx.ModuleForTests("foo", "android_common")
@@ -3541,6 +3621,7 @@
}
func TestUncompressDex(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
bp string
@@ -3640,10 +3721,13 @@
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
+ t.Parallel()
t.Run("platform", func(t *testing.T) {
+ t.Parallel()
test(t, tt.bp, tt.uncompressedPlatform, false)
})
t.Run("unbundled", func(t *testing.T) {
+ t.Parallel()
test(t, tt.bp, tt.uncompressedUnbundled, true)
})
})
@@ -3665,6 +3749,7 @@
}
func TestExportedProguardFlagFiles(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
android_app {
name: "foo",
@@ -3726,6 +3811,7 @@
}
func TestTargetSdkVersionManifestFixer(t *testing.T) {
+ t.Parallel()
platform_sdk_codename := "Tiramisu"
platform_sdk_version := 33
testCases := []struct {
@@ -3778,43 +3864,47 @@
},
}
for _, testCase := range testCases {
- targetSdkVersionTemplate := ""
- if testCase.targetSdkVersionInBp != "" {
- targetSdkVersionTemplate = fmt.Sprintf(`target_sdk_version: "%s",`, testCase.targetSdkVersionInBp)
- }
- bp := fmt.Sprintf(`
+ t.Run(testCase.name, func(t *testing.T) {
+ t.Parallel()
+ targetSdkVersionTemplate := ""
+ if testCase.targetSdkVersionInBp != "" {
+ targetSdkVersionTemplate = fmt.Sprintf(`target_sdk_version: "%s",`, testCase.targetSdkVersionInBp)
+ }
+ bp := fmt.Sprintf(`
android_app {
name: "foo",
sdk_version: "current",
%s
}
`, targetSdkVersionTemplate)
- fixture := android.GroupFixturePreparers(
- prepareForJavaTest,
- android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- if testCase.platformSdkFinal {
- variables.Platform_sdk_final = proptools.BoolPtr(true)
- }
- // explicitly set platform_sdk_codename to make the test deterministic
- variables.Platform_sdk_codename = &platform_sdk_codename
- variables.Platform_sdk_version = &platform_sdk_version
- variables.Platform_version_active_codenames = []string{platform_sdk_codename}
- // create a non-empty list if unbundledBuild==true
- if testCase.unbundledBuild {
- variables.Unbundled_build_apps = []string{"apex_a", "apex_b"}
- }
- }),
- )
+ fixture := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ if testCase.platformSdkFinal {
+ variables.Platform_sdk_final = proptools.BoolPtr(true)
+ }
+ // explicitly set platform_sdk_codename to make the test deterministic
+ variables.Platform_sdk_codename = &platform_sdk_codename
+ variables.Platform_sdk_version = &platform_sdk_version
+ variables.Platform_version_active_codenames = []string{platform_sdk_codename}
+ // create a non-empty list if unbundledBuild==true
+ if testCase.unbundledBuild {
+ variables.Unbundled_build_apps = []string{"apex_a", "apex_b"}
+ }
+ }),
+ )
- result := fixture.RunTestWithBp(t, bp)
- foo := result.ModuleForTests("foo", "android_common")
+ result := fixture.RunTestWithBp(t, bp)
+ foo := result.ModuleForTests("foo", "android_common")
- manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
- android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected)
+ manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
+ android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected)
+ })
}
}
func TestDefaultAppTargetSdkVersionForUpdatableModules(t *testing.T) {
+ t.Parallel()
platform_sdk_codename := "Tiramisu"
platform_sdk_version := 33
testCases := []struct {
@@ -3870,11 +3960,13 @@
},
}
for _, testCase := range testCases {
- targetSdkVersionTemplate := ""
- if testCase.targetSdkVersionInBp != nil {
- targetSdkVersionTemplate = fmt.Sprintf(`target_sdk_version: "%s",`, *testCase.targetSdkVersionInBp)
- }
- bp := fmt.Sprintf(`
+ t.Run(testCase.name, func(t *testing.T) {
+ t.Parallel()
+ targetSdkVersionTemplate := ""
+ if testCase.targetSdkVersionInBp != nil {
+ targetSdkVersionTemplate = fmt.Sprintf(`target_sdk_version: "%s",`, *testCase.targetSdkVersionInBp)
+ }
+ bp := fmt.Sprintf(`
android_app {
name: "foo",
sdk_version: "current",
@@ -3885,30 +3977,32 @@
}
`, targetSdkVersionTemplate, testCase.updatable, testCase.updatable) // enforce default target sdk version if app is updatable
- fixture := android.GroupFixturePreparers(
- PrepareForTestWithJavaDefaultModules,
- android.PrepareForTestWithAllowMissingDependencies,
- android.PrepareForTestWithAndroidMk,
- android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- // explicitly set following platform variables to make the test deterministic
- variables.Platform_sdk_final = &testCase.platform_sdk_final
- variables.Platform_sdk_version = &platform_sdk_version
- variables.Platform_sdk_codename = &platform_sdk_codename
- variables.Platform_version_active_codenames = []string{platform_sdk_codename}
- variables.Unbundled_build = proptools.BoolPtr(true)
- variables.Unbundled_build_apps = []string{"sampleModule"}
- }),
- )
+ fixture := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ android.PrepareForTestWithAllowMissingDependencies,
+ android.PrepareForTestWithAndroidMk,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ // explicitly set following platform variables to make the test deterministic
+ variables.Platform_sdk_final = &testCase.platform_sdk_final
+ variables.Platform_sdk_version = &platform_sdk_version
+ variables.Platform_sdk_codename = &platform_sdk_codename
+ variables.Platform_version_active_codenames = []string{platform_sdk_codename}
+ variables.Unbundled_build = proptools.BoolPtr(true)
+ variables.Unbundled_build_apps = []string{"sampleModule"}
+ }),
+ )
- result := fixture.RunTestWithBp(t, bp)
- foo := result.ModuleForTests("foo", "android_common")
+ result := fixture.RunTestWithBp(t, bp)
+ foo := result.ModuleForTests("foo", "android_common")
- manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
- android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+*testCase.targetSdkVersionExpected)
+ manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
+ android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+*testCase.targetSdkVersionExpected)
+ })
}
}
func TestEnforceDefaultAppTargetSdkVersionFlag(t *testing.T) {
+ t.Parallel()
platform_sdk_codename := "Tiramisu"
platform_sdk_version := 33
testCases := []struct {
@@ -3953,8 +4047,10 @@
},
}
for _, testCase := range testCases {
- errExpected := testCase.expectedError != ""
- bp := fmt.Sprintf(`
+ t.Run(testCase.name, func(t *testing.T) {
+ t.Parallel()
+ errExpected := testCase.expectedError != ""
+ bp := fmt.Sprintf(`
android_app {
name: "foo",
enforce_default_target_sdk_version: %t,
@@ -3965,35 +4061,37 @@
}
`, testCase.enforceDefaultTargetSdkVersion, testCase.targetSdkVersionInBp, testCase.updatable)
- fixture := android.GroupFixturePreparers(
- PrepareForTestWithJavaDefaultModules,
- android.PrepareForTestWithAllowMissingDependencies,
- android.PrepareForTestWithAndroidMk,
- android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- // explicitly set following platform variables to make the test deterministic
- variables.Platform_sdk_final = &testCase.platform_sdk_final
- variables.Platform_sdk_version = &platform_sdk_version
- variables.Platform_sdk_codename = &platform_sdk_codename
- variables.Unbundled_build = proptools.BoolPtr(true)
- variables.Unbundled_build_apps = []string{"sampleModule"}
- }),
- )
+ fixture := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ android.PrepareForTestWithAllowMissingDependencies,
+ android.PrepareForTestWithAndroidMk,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ // explicitly set following platform variables to make the test deterministic
+ variables.Platform_sdk_final = &testCase.platform_sdk_final
+ variables.Platform_sdk_version = &platform_sdk_version
+ variables.Platform_sdk_codename = &platform_sdk_codename
+ variables.Unbundled_build = proptools.BoolPtr(true)
+ variables.Unbundled_build_apps = []string{"sampleModule"}
+ }),
+ )
- errorHandler := android.FixtureExpectsNoErrors
- if errExpected {
- errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(testCase.expectedError)
- }
- result := fixture.ExtendWithErrorHandler(errorHandler).RunTestWithBp(t, bp)
+ errorHandler := android.FixtureExpectsNoErrors
+ if errExpected {
+ errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(testCase.expectedError)
+ }
+ result := fixture.ExtendWithErrorHandler(errorHandler).RunTestWithBp(t, bp)
- if !errExpected {
- foo := result.ModuleForTests("foo", "android_common")
- manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
- android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected)
- }
+ if !errExpected {
+ foo := result.ModuleForTests("foo", "android_common")
+ manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
+ android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected)
+ }
+ })
}
}
func TestEnforceDefaultAppTargetSdkVersionFlagForTests(t *testing.T) {
+ t.Parallel()
platform_sdk_codename := "Tiramisu"
platform_sdk_version := 33
testCases := []struct {
@@ -4026,8 +4124,10 @@
},
}
for _, testCase := range testCases {
- errExpected := testCase.expectedError != ""
- bp := fmt.Sprintf(`
+ t.Run(testCase.name, func(t *testing.T) {
+ t.Parallel()
+ errExpected := testCase.expectedError != ""
+ bp := fmt.Sprintf(`
android_test {
name: "foo",
enforce_default_target_sdk_version: %t,
@@ -4036,35 +4136,37 @@
}
`, testCase.enforceDefaultTargetSdkVersion, testCase.targetSdkVersionInBp)
- fixture := android.GroupFixturePreparers(
- PrepareForTestWithJavaDefaultModules,
- android.PrepareForTestWithAllowMissingDependencies,
- android.PrepareForTestWithAndroidMk,
- android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- // explicitly set following platform variables to make the test deterministic
- variables.Platform_sdk_final = &testCase.platform_sdk_final
- variables.Platform_sdk_version = &platform_sdk_version
- variables.Platform_sdk_codename = &platform_sdk_codename
- variables.Unbundled_build = proptools.BoolPtr(true)
- variables.Unbundled_build_apps = []string{"sampleModule"}
- }),
- )
+ fixture := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ android.PrepareForTestWithAllowMissingDependencies,
+ android.PrepareForTestWithAndroidMk,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ // explicitly set following platform variables to make the test deterministic
+ variables.Platform_sdk_final = &testCase.platform_sdk_final
+ variables.Platform_sdk_version = &platform_sdk_version
+ variables.Platform_sdk_codename = &platform_sdk_codename
+ variables.Unbundled_build = proptools.BoolPtr(true)
+ variables.Unbundled_build_apps = []string{"sampleModule"}
+ }),
+ )
- errorHandler := android.FixtureExpectsNoErrors
- if errExpected {
- errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(testCase.expectedError)
- }
- result := fixture.ExtendWithErrorHandler(errorHandler).RunTestWithBp(t, bp)
+ errorHandler := android.FixtureExpectsNoErrors
+ if errExpected {
+ errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(testCase.expectedError)
+ }
+ result := fixture.ExtendWithErrorHandler(errorHandler).RunTestWithBp(t, bp)
- if !errExpected {
- foo := result.ModuleForTests("foo", "android_common")
- manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
- android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected)
- }
+ if !errExpected {
+ foo := result.ModuleForTests("foo", "android_common")
+ manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
+ android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected)
+ }
+ })
}
}
func TestAppMissingCertificateAllowMissingDependencies(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
android.PrepareForTestWithAllowMissingDependencies,
@@ -4094,6 +4196,7 @@
}
func TestAppIncludesJniPackages(t *testing.T) {
+ t.Parallel()
ctx := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
).RunTestWithBp(t, `
@@ -4156,6 +4259,7 @@
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
app := ctx.ModuleForTests(tc.name, "android_common")
outputFile := "jnilibs.zip"
@@ -4180,6 +4284,7 @@
}
func TestTargetSdkVersionMtsTests(t *testing.T) {
+ t.Parallel()
platformSdkCodename := "Tiramisu"
android_test := "android_test"
android_test_helper_app := "android_test_helper_app"
@@ -4235,14 +4340,18 @@
}),
)
for _, testCase := range testCases {
- result := fixture.RunTestWithBp(t, fmt.Sprintf(bpTemplate, testCase.moduleType, testCase.targetSdkVersionInBp, testCase.testSuites))
- mytest := result.ModuleForTests("mytest", "android_common")
- manifestFixerArgs := mytest.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
- android.AssertStringDoesContain(t, testCase.desc, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected)
+ t.Run(testCase.desc, func(t *testing.T) {
+ t.Parallel()
+ result := fixture.RunTestWithBp(t, fmt.Sprintf(bpTemplate, testCase.moduleType, testCase.targetSdkVersionInBp, testCase.testSuites))
+ mytest := result.ModuleForTests("mytest", "android_common")
+ manifestFixerArgs := mytest.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
+ android.AssertStringDoesContain(t, testCase.desc, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected)
+ })
}
}
func TestPrivappAllowlist(t *testing.T) {
+ t.Parallel()
testJavaError(t, "privileged must be set in order to use privapp_allowlist", `
android_app {
name: "foo",
@@ -4280,11 +4389,12 @@
}
// verify that permissions are copied to device
- app.Output("out/soong/target/product/test_device/system/etc/permissions/foo.xml")
- overrideApp.Output("out/soong/target/product/test_device/system/etc/permissions/bar.xml")
+ app.Output("out/target/product/test_device/system/etc/permissions/foo.xml")
+ overrideApp.Output("out/target/product/test_device/system/etc/permissions/bar.xml")
}
func TestPrivappAllowlistAndroidMk(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
android.PrepareForTestWithAndroidMk,
@@ -4364,6 +4474,7 @@
}
func TestAppFlagsPackages(t *testing.T) {
+ t.Parallel()
ctx := android.GroupFixturePreparers(
prepareForJavaTest,
android.FixtureMergeMockFs(
@@ -4428,6 +4539,7 @@
}
func TestAppFlagsPackagesPropagation(t *testing.T) {
+ t.Parallel()
ctx := testApp(t, `
aconfig_declarations {
name: "foo",
@@ -4505,6 +4617,7 @@
// Test that dexpreopt is disabled if an optional_uses_libs exists, but does not provide an implementation.
func TestNoDexpreoptOptionalUsesLibDoesNotHaveImpl(t *testing.T) {
+ t.Parallel()
bp := `
java_sdk_library_import {
name: "sdklib_noimpl",
@@ -4564,7 +4677,77 @@
assertTestOnlyAndTopLevel(t, ctx, expectedTestOnly, expectedTopLevel)
}
+func TestTestConfigTemplate(t *testing.T) {
+ t.Parallel()
+ ctx := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ ).RunTestWithBp(t, `
+ android_test {
+ name: "android-test",
+ test_config_template: "AndroidTestTemplate.xml",
+ test_options: {
+ tradefed_options: [
+ {
+ name: "name1",
+ key: "key1",
+ value: "value1",
+ },
+ {
+ name: "name2",
+ key: "key2",
+ value: "value2",
+ },
+ ],
+ test_runner_options: [
+ {
+ name: "name3",
+ key: "key3",
+ value: "value3",
+ },
+ {
+ name: "name4",
+ key: "key4",
+ value: "value4",
+ },
+ ],
+ },
+ }
+ `)
+ type option struct {
+ name string
+ key string
+ value string
+ }
+ re := regexp.MustCompile(`<option name="(.*)" key="(.*)" value="(.*)" />`)
+ parse_options := func(optionsString string) []option {
+ lines := strings.Split(optionsString, `\n`)
+ var ret []option
+ for _, l := range lines {
+ sm := re.FindStringSubmatch(l)
+ if sm == nil {
+ continue
+ }
+ ret = append(ret, option{sm[1], sm[2], sm[3]})
+ }
+ return ret
+ }
+ rule := ctx.ModuleForTests("android-test", "android_common").Rule("autogenInstrumentationTest")
+ android.AssertSameArray(t, "extraConfigs mismatch",
+ []option{
+ {"name1", "key1", "value1"},
+ {"name2", "key2", "value2"},
+ },
+ parse_options(rule.Args["extraConfigs"]))
+ android.AssertSameArray(t, "extraTestRunnerConfigs mismatch",
+ []option{
+ {"name3", "key3", "value3"},
+ {"name4", "key4", "value4"},
+ },
+ parse_options(rule.Args["extraTestRunnerConfigs"]))
+}
+
func TestAppStem(t *testing.T) {
+ t.Parallel()
ctx := testApp(t, `
android_app {
name: "foo",
@@ -4582,6 +4765,7 @@
}
func TestAppMinSdkVersionOverride(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
).RunTestWithBp(t, `
@@ -4615,6 +4799,7 @@
}
func TestNotApplyDefaultUpdatableModuleVersion(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
).RunTestWithBp(t, `
@@ -4634,6 +4819,7 @@
}
func TestNotApplyOverrideApexManifestDefaultVersion(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
android.FixtureMergeEnv(map[string]string{
@@ -4654,3 +4840,202 @@
"--override-placeholder-version",
)
}
+
+func TestResourcesWithFlagDirectories(t *testing.T) {
+ t.Parallel()
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ android.FixtureMergeMockFs(android.MockFS{
+ "res/flag(test.package.flag1)/values/bools.xml": nil,
+ "res/flag(!test.package.flag2)/values/bools.xml": nil,
+ "res/flag(test.package.flag1)/values-config/strings_google_services.xml": nil,
+ "res/flags(test.package.flag1)/values/strings.xml": nil,
+ }),
+ ).RunTestWithBp(t, `
+ android_library {
+ name: "foo",
+ srcs: ["a.java"],
+ use_resource_processor: true,
+ resource_dirs: [
+ "res",
+ ],
+ }
+ `)
+ fooModule := result.ModuleForTests("foo", "android_common")
+ compileOutputPaths := fooModule.Rule("aapt2Compile").Outputs.Strings()
+
+ android.AssertStringListContains(
+ t,
+ "Expected to generate flag path",
+ compileOutputPaths,
+ "out/soong/.intermediates/foo/android_common/aapt2/res/values_bools.(test.package.flag1).arsc.flat",
+ )
+ android.AssertStringListContains(
+ t,
+ "Expected to generate flag path with ! prefix in name",
+ compileOutputPaths,
+ "out/soong/.intermediates/foo/android_common/aapt2/res/values_bools.(!test.package.flag2).arsc.flat",
+ )
+ android.AssertStringListContains(
+ t,
+ "Expected to generate flag path with configs",
+ compileOutputPaths,
+ "out/soong/.intermediates/foo/android_common/aapt2/res/values-config_strings_google_services.(test.package.flag1).arsc.flat",
+ )
+ android.AssertStringListDoesNotContain(
+ t,
+ "Expected to not generate flag path with non-flag(flag_name) pattern",
+ compileOutputPaths,
+ "out/soong/.intermediates/foo/android_common/aapt2/res/values_strings.(test.package.flag1).arsc.flat",
+ )
+}
+
+func TestAutogeneratedStaticRro(t *testing.T) {
+ t.Parallel()
+ bp := `
+android_app {
+ name: "foo",
+ srcs: ["foo.java"],
+ platform_apis: true,
+}
+override_android_app {
+ name: "override_foo",
+ base: "foo",
+}
+`
+ testCases := []struct {
+ desc string
+ preparer android.FixturePreparer
+ overlayApkExpected bool
+ }{
+ {
+ desc: "No DEVICE_PACKAGE_OVERLAYS, no overlay .apk file",
+ overlayApkExpected: false,
+ },
+ {
+ desc: "DEVICE_PACKAGE_OVERLAYS exists, but the directory is empty",
+ overlayApkExpected: false,
+ preparer: android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.DeviceResourceOverlays = []string{"device/company/test_product"}
+ }),
+ },
+ {
+ desc: "DEVICE_PACKAGE_OVERLAYS exists, directory is non-empty, but does not contain a matching resource dir",
+ overlayApkExpected: false,
+ preparer: android.GroupFixturePreparers(
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.DeviceResourceOverlays = []string{"device/company/test_product"}
+ }),
+ android.MockFS{
+ "res/foo.xml": nil,
+ "device/company/test_product/different_res/foo.xml": nil, // different dir
+ }.AddToFixture(),
+ ),
+ },
+ {
+ desc: "DEVICE_PACKAGE_OVERLAYS and the directory contain a matching resource dir",
+ overlayApkExpected: true,
+ preparer: android.GroupFixturePreparers(
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.DeviceResourceOverlays = []string{"device/company/test_product"}
+ }),
+ android.MockFS{
+ "res/foo.xml": nil,
+ "device/company/test_product/res/foo.xml": nil,
+ }.AddToFixture(),
+ ),
+ },
+ }
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ t.Parallel()
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.EnforceRROTargets = []string{"*"}
+ }),
+ android.OptionalFixturePreparer(tc.preparer),
+ ).RunTestWithBp(t, bp)
+ vendorOverlayApk := result.ModuleForTests("foo__test_product__auto_generated_rro_vendor", "android_arm64_armv8-a").MaybeOutput("foo__test_product__auto_generated_rro_vendor.apk")
+ android.AssertBoolEquals(t, tc.desc, tc.overlayApkExpected, vendorOverlayApk.Rule != nil)
+ overrideVendorOverlayApk := result.ModuleForTests("override_foo__test_product__auto_generated_rro_vendor", "android_arm64_armv8-a").MaybeOutput("override_foo__test_product__auto_generated_rro_vendor.apk")
+ android.AssertBoolEquals(t, tc.desc, tc.overlayApkExpected, overrideVendorOverlayApk.Rule != nil)
+ })
+ }
+}
+
+func TestNoAutogeneratedStaticRroForDisabledOverrideApps(t *testing.T) {
+ t.Parallel()
+ bp := `
+soong_config_module_type {
+ name: "my_custom_override_android_app",
+ module_type: "override_android_app",
+ config_namespace: "my_namespace",
+ value_variables: ["my_app_enabled"],
+ properties: ["enabled"],
+}
+soong_config_bool_variable {
+ name: "my_app_enabled",
+}
+android_app {
+ name: "foo",
+ srcs: ["foo.java"],
+ platform_apis: true,
+}
+my_custom_override_android_app {
+ name: "override_foo",
+ base: "foo",
+ soong_config_variables: {
+ my_app_enabled: {
+ enabled: true,
+ conditions_default: {
+ enabled: false
+ },
+ },
+ }
+}
+`
+ testCases := []struct {
+ desc string
+ preparer android.FixturePreparer
+ overlayApkExpected bool
+ }{
+ {
+ desc: "my_app_enabled is empty",
+ overlayApkExpected: false,
+ },
+ {
+ desc: "my_app_enabled is true",
+ overlayApkExpected: true,
+ preparer: android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.VendorVars = map[string]map[string]string{
+ "my_namespace": {
+ "my_app_enabled": "true",
+ },
+ }
+ }),
+ },
+ }
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ t.Parallel()
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ android.PrepareForTestWithSoongConfigModuleBuildComponents,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.EnforceRROTargets = []string{"*"}
+ }),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.DeviceResourceOverlays = []string{"device/company/test_product"}
+ }),
+ android.MockFS{
+ "res/foo.xml": nil,
+ "device/company/test_product/res/foo.xml": nil,
+ }.AddToFixture(),
+ android.OptionalFixturePreparer(tc.preparer),
+ ).RunTestWithBp(t, bp)
+ overrideVendorOverlayApk := result.ModuleForTests("override_foo__test_product__auto_generated_rro_vendor", "android_arm64_armv8-a").Module().(*AutogenRuntimeResourceOverlay)
+ android.AssertBoolEquals(t, tc.desc, tc.overlayApkExpected, overrideVendorOverlayApk.exportPackage != nil)
+ })
+ }
+}
diff --git a/java/base.go b/java/base.go
index 4ab82c5..d89c324 100644
--- a/java/base.go
+++ b/java/base.go
@@ -15,6 +15,7 @@
package java
import (
+ "encoding/gob"
"fmt"
"path/filepath"
"reflect"
@@ -23,6 +24,7 @@
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/depset"
"github.com/google/blueprint/pathtools"
"github.com/google/blueprint/proptools"
@@ -58,6 +60,9 @@
// This is most useful in the arch/multilib variants to remove non-common files
Exclude_srcs []string `android:"path,arch_variant"`
+ // list of Kotlin source files that should excluded from the list of common_srcs.
+ Exclude_common_srcs []string `android:"path,arch_variant"`
+
// list of directories containing Java resources
Java_resource_dirs []string `android:"arch_variant"`
@@ -65,25 +70,35 @@
Exclude_java_resource_dirs []string `android:"arch_variant"`
// list of files to use as Java resources
- Java_resources []string `android:"path,arch_variant"`
+ Java_resources proptools.Configurable[[]string] `android:"path,arch_variant"`
// list of files that should be excluded from java_resources and java_resource_dirs
Exclude_java_resources []string `android:"path,arch_variant"`
+ // Same as java_resources, but modules added here will use the device variant. Can be useful
+ // for making a host test that tests the contents of a device built app.
+ Device_common_java_resources proptools.Configurable[[]string] `android:"path_device_common"`
+
+ // Same as java_resources, but modules added here will use the device's os variant and the
+ // device's first architecture variant. Can be useful for making a host test that tests the
+ // contents of a native device built app.
+ Device_first_java_resources proptools.Configurable[[]string] `android:"path_device_first"`
+
// list of module-specific flags that will be used for javac compiles
Javacflags []string `android:"arch_variant"`
// list of module-specific flags that will be used for kotlinc compiles
Kotlincflags []string `android:"arch_variant"`
+ // Kotlin language version to target. Currently only 1.9 and 2 are supported.
+ // See kotlinc's `-language-version` flag.
+ Kotlin_lang_version *string
+
// list of java libraries that will be in the classpath
Libs []string `android:"arch_variant"`
// list of java libraries that will be compiled into the resulting jar
- Static_libs []string `android:"arch_variant"`
-
- // list of java libraries that should not be used to build this module
- Exclude_static_libs []string `android:"arch_variant"`
+ Static_libs proptools.Configurable[[]string] `android:"arch_variant"`
// manifest file to be included in resulting jar
Manifest *string `android:"path"`
@@ -98,8 +113,9 @@
// if not blank, used as prefix to generate repackage rule
Jarjar_prefix *string
- // if set to true, skip the jarjar repackaging
- Skip_jarjar_repackage *bool
+ // Number of shards for jarjar. It needs to be an integer represented as a string.
+ // TODO(b/383559945) change it to int, once Configurable supports the type.
+ Jarjar_shards proptools.Configurable[string]
// If not blank, set the java version passed to javac as -source and -target
Java_version *string
@@ -118,6 +134,9 @@
// List of modules to use as annotation processors
Plugins []string
+ // List of modules to use as kotlin plugin
+ Kotlin_plugins []string
+
// List of modules to export to libraries that directly depend on this library as annotation
// processors. Note that if the plugins set generates_api: true this will disable the turbine
// optimization on modules that depend on this module, which will reduce parallelism and cause
@@ -223,12 +242,24 @@
// the stubs via static libs.
Is_stubs_module *bool
- // If true, enable the "Ravenizer" tool on the output jar.
- // "Ravenizer" is a tool for Ravenwood tests, but it can also be enabled on other kinds
- // of java targets.
Ravenizer struct {
+ // If true, enable the "Ravenizer" tool on the output jar.
+ // "Ravenizer" is a tool for Ravenwood tests, but it can also be enabled on other kinds
+ // of java targets.
Enabled *bool
+
+ // If true, the "Ravenizer" tool will remove all Mockito and DexMaker
+ // classes from the output jar.
+ Strip_mockito *bool
}
+
+ // Contributing api surface of the stub module. Is not visible to bp modules, and should
+ // only be set for stub submodules generated by the java_sdk_library
+ Stub_contributing_api *string `blueprint:"mutated"`
+
+ // If true, enable the "ApiMapper" tool on the output jar. "ApiMapper" is a tool to inject
+ // bytecode to log API calls.
+ ApiMapper bool `blueprint:"mutated"`
}
// Properties that are specific to device modules. Host module factories should not add these when
@@ -342,13 +373,13 @@
e.initSdkLibraryComponent(module)
}
-// Module/Import's DepIsInSameApex(...) delegates to this method.
+// Module/Import's OutgoingDepIsInSameApex(...) delegates to this method.
//
-// This cannot implement DepIsInSameApex(...) directly as that leads to ambiguity with
+// This cannot implement OutgoingDepIsInSameApex(...) directly as that leads to ambiguity with
// the one provided by ApexModuleBase.
-func (e *embeddableInModuleAndImport) depIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+func (e *embeddableInModuleAndImport) depIsInSameApex(tag blueprint.DependencyTag) bool {
// dependencies other than the static linkage are all considered crossing APEX boundary
- if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
+ if tag == staticLibTag {
return true
}
return false
@@ -455,21 +486,16 @@
// inserting into the bootclasspath/classpath of another compile
headerJarFile android.Path
- repackagedHeaderJarFile android.Path
-
// jar file containing implementation classes including static library dependencies but no
// resources
implementationJarFile android.Path
- // jar file containing only resources including from static library dependencies
- resourceJar android.Path
-
// args and dependencies to package source files into a srcjar
srcJarArgs []string
srcJarDeps android.Paths
// the source files of this module and all its static dependencies
- transitiveSrcFiles *android.DepSet[android.Path]
+ transitiveSrcFiles depset.DepSet[android.Path]
// jar file containing implementation classes and resources including static library
// dependencies
@@ -534,7 +560,8 @@
linter
// list of the xref extraction files
- kytheFiles android.Paths
+ kytheFiles android.Paths
+ kytheKotlinFiles android.Paths
hideApexVariantFromMake bool
@@ -589,21 +616,31 @@
return j.ProductSpecific()
}
-func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
- sdkVersion := j.SdkVersion(ctx)
- if sdkVersion.Stable() {
- return nil
- }
- if sdkVersion.Kind == android.SdkCorePlatform {
- if useLegacyCorePlatformApi(ctx, j.BaseModuleName()) {
- return fmt.Errorf("non stable SDK %v - uses legacy core platform", sdkVersion)
- } else {
- // Treat stable core platform as stable.
+var _ android.StubsAvailableModule = (*Module)(nil)
+
+// To safisfy the StubsAvailableModule interface
+func (j *Module) IsStubsModule() bool {
+ return proptools.Bool(j.properties.Is_stubs_module)
+}
+
+func CheckStableSdkVersion(ctx android.BaseModuleContext, module android.ModuleProxy) error {
+ if info, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
+ if info.SdkVersion.Stable() {
return nil
}
- } else {
- return fmt.Errorf("non stable SDK %v", sdkVersion)
+ if info.SdkVersion.Kind == android.SdkCorePlatform {
+ if useLegacyCorePlatformApi(ctx, android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey).BaseModuleName) {
+ return fmt.Errorf("non stable SDK %v - uses legacy core platform", info.SdkVersion)
+ } else {
+ // Treat stable core platform as stable.
+ return nil
+ }
+ } else {
+ return fmt.Errorf("non stable SDK %v", info.SdkVersion)
+ }
}
+
+ return nil
}
// checkSdkVersions enforces restrictions around SDK dependencies.
@@ -619,14 +656,17 @@
// Make sure this module doesn't statically link to modules with lower-ranked SDK link type.
// See rank() for details.
- ctx.VisitDirectDeps(func(module android.Module) {
+ ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) {
tag := ctx.OtherModuleDependencyTag(module)
- switch module.(type) {
- // TODO(satayev): cover other types as well, e.g. imports
- case *Library, *AndroidLibrary:
+ _, isJavaLibrary := android.OtherModuleProvider(ctx, module, JavaLibraryInfoProvider)
+ _, isAndroidLibrary := android.OtherModuleProvider(ctx, module, AndroidLibraryInfoProvider)
+ _, isJavaAconfigLibrary := android.OtherModuleProvider(ctx, module, android.CodegenInfoProvider)
+ // Exclude java_aconfig_library modules to maintain consistency with existing behavior.
+ if (isJavaLibrary && !isJavaAconfigLibrary) || isAndroidLibrary {
+ // TODO(satayev): cover other types as well, e.g. imports
switch tag {
case bootClasspathTag, sdkLibTag, libTag, staticLibTag, java9LibTag:
- j.checkSdkLinkType(ctx, module.(moduleWithSdkDep), tag.(dependencyTag))
+ j.checkSdkLinkType(ctx, module)
}
}
})
@@ -691,17 +731,14 @@
// helper method for java modules to set OutputFilesProvider
func setOutputFiles(ctx android.ModuleContext, m Module) {
- ctx.SetOutputFiles(append(android.Paths{m.outputFile}, m.extraOutputFiles...), "")
- ctx.SetOutputFiles(android.Paths{m.outputFile}, android.DefaultDistTag)
- ctx.SetOutputFiles(android.Paths{m.implementationAndResourcesJar}, ".jar")
- ctx.SetOutputFiles(android.Paths{m.headerJarFile}, ".hjar")
+ ctx.SetOutputFiles(append(android.PathsIfNonNil(m.outputFile), m.extraOutputFiles...), "")
+ ctx.SetOutputFiles(android.PathsIfNonNil(m.outputFile), android.DefaultDistTag)
+ ctx.SetOutputFiles(android.PathsIfNonNil(m.implementationAndResourcesJar), ".jar")
+ ctx.SetOutputFiles(android.PathsIfNonNil(m.headerJarFile), ".hjar")
if m.dexer.proguardDictionary.Valid() {
ctx.SetOutputFiles(android.Paths{m.dexer.proguardDictionary.Path()}, ".proguard_map")
}
ctx.SetOutputFiles(m.properties.Generated_srcjars, ".generated_srcjars")
- if m.linter.outputs.xml != nil {
- ctx.SetOutputFiles(android.Paths{m.linter.outputs.xml}, ".lint")
- }
}
func InitJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
@@ -728,6 +765,10 @@
ctx.DeviceConfig().JavaCoverageEnabledForPath(ctx.ModuleDir())
}
+func (j *Module) shouldApiMapper() bool {
+ return j.properties.ApiMapper
+}
+
func (j *Module) shouldInstrumentStatic(ctx android.BaseModuleContext) bool {
return j.properties.Supports_static_instrumentation &&
j.shouldInstrument(ctx) &&
@@ -742,7 +783,8 @@
apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
isJacocoAgent := ctx.ModuleName() == "jacocoagent"
- if j.DirectlyInAnyApex() && !isJacocoAgent && !apexInfo.IsForPlatform() {
+ compileDex := Bool(j.dexProperties.Compile_dex) || Bool(j.properties.Installable)
+ if compileDex && !isJacocoAgent && !apexInfo.IsForPlatform() {
if !inList(ctx.ModuleName(), config.InstrumentFrameworkModules) {
return true
} else if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
@@ -756,6 +798,10 @@
j.properties.Instrument = value
}
+func (j *Module) setApiMapper(value bool) {
+ j.properties.ApiMapper = value
+}
+
func (j *Module) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
return android.SdkSpecFrom(ctx, String(j.deviceProperties.Sdk_version))
}
@@ -803,13 +849,22 @@
}
func (j *Module) AvailableFor(what string) bool {
- if what == android.AvailableToPlatform && Bool(j.deviceProperties.Hostdex) {
+ return android.CheckAvailableForApex(what, j.ApexAvailableFor())
+}
+
+func (j *Module) ApexAvailableFor() []string {
+ list := j.ApexModuleBase.ApexAvailable()
+ if Bool(j.deviceProperties.Hostdex) {
// Exception: for hostdex: true libraries, the platform variant is created
// even if it's not marked as available to platform. In that case, the platform
// variant is used only for the hostdex and not installed to the device.
- return true
+ list = append(list, android.AvailableToPlatform)
}
- return j.ApexModuleBase.AvailableFor(what)
+ return android.FirstUniqueStrings(list)
+}
+
+func (j *Module) staticLibs(ctx android.BaseModuleContext) []string {
+ return j.properties.Static_libs.GetOrDefault(ctx, nil)
}
func (j *Module) deps(ctx android.BottomUpMutatorContext) {
@@ -828,39 +883,11 @@
libDeps := ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
- j.properties.Static_libs = android.RemoveListFromList(j.properties.Static_libs, j.properties.Exclude_static_libs)
- ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs...)
+ ctx.AddVariationDependencies(nil, staticLibTag, j.staticLibs(ctx)...)
// Add dependency on libraries that provide additional hidden api annotations.
ctx.AddVariationDependencies(nil, hiddenApiAnnotationsTag, j.properties.Hiddenapi_additional_annotations...)
- if ctx.Config().EnforceInterPartitionJavaSdkLibrary() {
- // Require java_sdk_library at inter-partition java dependency to ensure stable
- // interface between partitions. If inter-partition java_library dependency is detected,
- // raise build error because java_library doesn't have a stable interface.
- //
- // Inputs:
- // PRODUCT_ENFORCE_INTER_PARTITION_JAVA_SDK_LIBRARY
- // if true, enable enforcement
- // PRODUCT_INTER_PARTITION_JAVA_LIBRARY_ALLOWLIST
- // exception list of java_library names to allow inter-partition dependency
- for idx := range j.properties.Libs {
- if libDeps[idx] == nil {
- continue
- }
-
- if javaDep, ok := libDeps[idx].(javaSdkLibraryEnforceContext); ok {
- // java_sdk_library is always allowed at inter-partition dependency.
- // So, skip check.
- if _, ok := javaDep.(*SdkLibrary); ok {
- continue
- }
-
- j.checkPartitionsForJavaDependency(ctx, "libs", javaDep)
- }
- }
- }
-
// For library dependencies that are component libraries (like stubs), add the implementation
// as a dependency (dexpreopt needs to be against the implementation library, not stubs).
for _, dep := range libDeps {
@@ -871,7 +898,7 @@
// explicitly listed in the optional_uses_libs property.
tag := usesLibReqTag
if android.InList(*lib, dexpreopt.OptionalCompatUsesLibs) ||
- android.InList(*lib, j.usesLibrary.usesLibraryProperties.Optional_uses_libs) {
+ android.InList(*lib, j.usesLibrary.usesLibraryProperties.Optional_uses_libs.GetOrDefault(ctx, nil)) {
tag = usesLibOptTag
}
ctx.AddVariationDependencies(nil, tag, *lib)
@@ -881,6 +908,7 @@
}
ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), pluginTag, j.properties.Plugins...)
+ ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), kotlinPluginTag, j.properties.Kotlin_plugins...)
ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), errorpronePluginTag, j.properties.Errorprone.Extra_check_modules...)
ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), exportedPluginTag, j.properties.Exported_plugins...)
@@ -911,9 +939,9 @@
ctx.AddVariationDependencies(nil, staticLibTag, "jacocoagent")
}
- if j.useCompose() {
+ if j.useCompose(ctx) {
ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), kotlinPluginTag,
- "androidx.compose.compiler_compiler-hosted")
+ "kotlin-compose-compiler-plugin")
}
}
@@ -1132,25 +1160,24 @@
j.properties.Generated_srcjars = append(j.properties.Generated_srcjars, path)
}
-func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars android.Paths) {
+func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars, extraDepCombinedJars android.Paths) *JavaInfo {
// Auto-propagating jarjar rules
jarjarProviderData := j.collectJarJarRules(ctx)
if jarjarProviderData != nil {
android.SetProvider(ctx, JarJarProvider, *jarjarProviderData)
- if !proptools.Bool(j.properties.Skip_jarjar_repackage) {
- text := getJarJarRuleText(jarjarProviderData)
- if text != "" {
- ruleTextFile := android.PathForModuleOut(ctx, "repackaged-jarjar", "repackaging.txt")
- android.WriteFileRule(ctx, ruleTextFile, text)
- j.repackageJarjarRules = ruleTextFile
- }
+ text := getJarJarRuleText(jarjarProviderData)
+ if text != "" {
+ ruleTextFile := android.PathForModuleOut(ctx, "repackaged-jarjar", "repackaging.txt")
+ android.WriteFileRule(ctx, ruleTextFile, text)
+ j.repackageJarjarRules = ruleTextFile
}
}
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
- if re := proptools.Bool(j.properties.Ravenizer.Enabled); re {
- j.ravenizer.enabled = re
+ // Only override the original value if explicitly set
+ if j.properties.Ravenizer.Enabled != nil {
+ j.ravenizer.enabled = *j.properties.Ravenizer.Enabled
}
deps := j.collectDeps(ctx)
@@ -1174,7 +1201,7 @@
flags = protoFlags(ctx, &j.properties, &j.protoProperties, flags)
}
- kotlinCommonSrcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Common_srcs, nil)
+ kotlinCommonSrcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Common_srcs, j.properties.Exclude_common_srcs)
if len(kotlinCommonSrcFiles.FilterOutByExt(".kt")) > 0 {
ctx.PropertyErrorf("common_srcs", "common_srcs must be .kt files")
}
@@ -1221,7 +1248,6 @@
uniqueSrcFiles = append(uniqueSrcFiles, uniqueJavaFiles...)
uniqueSrcFiles = append(uniqueSrcFiles, uniqueKtFiles...)
j.uniqueSrcFiles = uniqueSrcFiles
- android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: uniqueSrcFiles.Strings()})
// We don't currently run annotation processors in turbine, which means we can't use turbine
// generated header jars when an annotation processor that generates API is enabled. One
@@ -1232,7 +1258,6 @@
// Collect .java and .kt files for AIDEGen
j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, uniqueSrcFiles.Strings()...)
- var kotlinJars android.Paths
var kotlinHeaderJars android.Paths
// Prepend extraClasspathJars to classpath so that the resource processor R.jar comes before
@@ -1242,6 +1267,8 @@
j.aconfigCacheFiles = append(deps.aconfigProtoFiles, j.properties.Aconfig_Cache_files...)
+ var localImplementationJars android.Paths
+
// If compiling headers then compile them and skip the rest
if proptools.Bool(j.properties.Headers_only) {
if srcFiles.HasExt(".kt") {
@@ -1251,30 +1278,52 @@
ctx.ModuleErrorf("headers_only is enabled but Turbine is disabled.")
}
- _, combinedHeaderJarFile := j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName,
+ transitiveStaticLibsHeaderJars := deps.transitiveStaticLibsHeaderJars
+
+ localHeaderJars, combinedHeaderJarFile := j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName,
extraCombinedJars)
- combinedHeaderJarFile = j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine")
- combinedHeaderJarFile = j.repackageFlagsIfNecessary(ctx, combinedHeaderJarFile, jarName, "repackage-turbine")
+ combinedHeaderJarFile, jarjared := j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine", false)
+ if jarjared {
+ localHeaderJars = android.Paths{combinedHeaderJarFile}
+ transitiveStaticLibsHeaderJars = nil
+ }
+ combinedHeaderJarFile, repackaged := j.repackageFlagsIfNecessary(ctx, combinedHeaderJarFile, jarName, "repackage-turbine")
+ if repackaged {
+ localHeaderJars = android.Paths{combinedHeaderJarFile}
+ transitiveStaticLibsHeaderJars = nil
+ }
if ctx.Failed() {
- return
+ return nil
}
j.headerJarFile = combinedHeaderJarFile
- android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
+ if ctx.Config().UseTransitiveJarsInClasspath() {
+ if len(localHeaderJars) > 0 {
+ ctx.CheckbuildFile(localHeaderJars...)
+ } else {
+ // There are no local sources or resources in this module, so there is nothing to checkbuild.
+ ctx.UncheckedModule()
+ }
+ } else {
+ ctx.CheckbuildFile(j.headerJarFile)
+ }
+
+ j.outputFile = j.headerJarFile
+ return &JavaInfo{
HeaderJars: android.PathsIfNonNil(j.headerJarFile),
- TransitiveLibsHeaderJars: j.transitiveLibsHeaderJars,
- TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
+ LocalHeaderJars: localHeaderJars,
+ TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, localHeaderJars, transitiveStaticLibsHeaderJars),
+ TransitiveLibsHeaderJarsForR8: j.transitiveLibsHeaderJarsForR8,
+ TransitiveStaticLibsHeaderJarsForR8: j.transitiveStaticLibsHeaderJarsForR8,
AidlIncludeDirs: j.exportAidlIncludeDirs,
ExportedPlugins: j.exportedPluginJars,
ExportedPluginClasses: j.exportedPluginClasses,
ExportedPluginDisableTurbine: j.exportedDisableTurbine,
StubsLinkType: j.stubsLinkType,
AconfigIntermediateCacheOutputPaths: deps.aconfigProtoFiles,
- })
-
- j.outputFile = j.headerJarFile
- return
+ SdkVersion: j.SdkVersion(ctx),
+ }
}
if srcFiles.HasExt(".kt") {
@@ -1287,6 +1336,26 @@
kotlincFlags := j.properties.Kotlincflags
CheckKotlincFlags(ctx, kotlincFlags)
+ // Available kotlin versions can be found at
+ // https://github.com/JetBrains/kotlin/blob/master/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt#L560
+ // in the `LanguageVersion` class.
+ // For now, avoid targeting language versions directly, as we'd like to kee our source
+ // code version aligned as much as possible. Ideally, after defaulting to "2", we
+ // can remove the "1.9" option entirely, or at least make it emit a warning.
+ kotlin_default_lang_version := "1.9"
+ if build_flag_lang_version, ok := ctx.Config().GetBuildFlag("RELEASE_KOTLIN_LANG_VERSION"); ok {
+ kotlin_default_lang_version = build_flag_lang_version
+ }
+ kotlin_lang_version := proptools.StringDefault(j.properties.Kotlin_lang_version, kotlin_default_lang_version)
+ switch kotlin_lang_version {
+ case "1.9":
+ kotlincFlags = append(kotlincFlags, "-language-version 1.9")
+ case "2":
+ kotlincFlags = append(kotlincFlags, "-Xsuppress-version-warnings", "-Xconsistent-data-class-copy-visibility")
+ default:
+ ctx.PropertyErrorf("kotlin_lang_version", "Must be one of `1.9` or `2`")
+ }
+
// Workaround for KT-46512
kotlincFlags = append(kotlincFlags, "-Xsam-conversions=class")
@@ -1321,7 +1390,7 @@
kaptResJar := android.PathForModuleOut(ctx, "kapt", "kapt-res.jar")
kotlinKapt(ctx, kaptSrcJar, kaptResJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags)
srcJars = append(srcJars, kaptSrcJar)
- kotlinJars = append(kotlinJars, kaptResJar)
+ localImplementationJars = append(localImplementationJars, kaptResJar)
// Disable annotation processing in javac, it's already been handled by kapt
flags.processorPath = nil
flags.processors = nil
@@ -1329,26 +1398,29 @@
kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName)
kotlinHeaderJar := android.PathForModuleOut(ctx, "kotlin_headers", jarName)
- kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags)
+ j.kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags)
if ctx.Failed() {
- return
+ return nil
}
- kotlinJarPath := j.repackageFlagsIfNecessary(ctx, kotlinJar, jarName, "kotlinc")
+ kotlinJarPath, _ := j.repackageFlagsIfNecessary(ctx, kotlinJar, jarName, "kotlinc")
// Make javac rule depend on the kotlinc rule
flags.classpath = append(classpath{kotlinHeaderJar}, flags.classpath...)
- kotlinJars = append(kotlinJars, kotlinJarPath)
+ localImplementationJars = append(localImplementationJars, kotlinJarPath)
+
kotlinHeaderJars = append(kotlinHeaderJars, kotlinHeaderJar)
}
- jars := slices.Clone(kotlinJars)
-
j.compiledSrcJars = srcJars
+ transitiveStaticLibsHeaderJars := deps.transitiveStaticLibsHeaderJars
+
enableSharding := false
- var headerJarFileWithoutDepsOrJarjar android.Path
+ var localHeaderJars android.Paths
+ var shardingHeaderJars android.Paths
+ var repackagedHeaderJarFile android.Path
if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !disableTurbine {
if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 {
enableSharding = true
@@ -1361,11 +1433,26 @@
extraJars := slices.Clone(kotlinHeaderJars)
extraJars = append(extraJars, extraCombinedJars...)
var combinedHeaderJarFile android.Path
- headerJarFileWithoutDepsOrJarjar, combinedHeaderJarFile =
- j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars)
+ localHeaderJars, combinedHeaderJarFile = j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars)
+ shardingHeaderJars = localHeaderJars
- j.headerJarFile = j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine")
- j.repackagedHeaderJarFile = j.repackageFlagsIfNecessary(ctx, j.headerJarFile, jarName, "turbine")
+ var jarjared bool
+ j.headerJarFile, jarjared = j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine", false)
+ if jarjared {
+ // jarjar modifies transitive static dependencies, use the combined header jar and drop the transitive
+ // static libs header jars.
+ localHeaderJars = android.Paths{j.headerJarFile}
+ transitiveStaticLibsHeaderJars = nil
+ }
+ var repackaged bool
+ repackagedHeaderJarFile, repackaged = j.repackageFlagsIfNecessary(ctx, j.headerJarFile, jarName, "turbine")
+ if repackaged {
+ // repackage modifies transitive static dependencies, use the combined header jar and drop the transitive
+ // static libs header jars.
+ // TODO(b/356688296): this shouldn't export both the unmodified and repackaged header jars
+ localHeaderJars = android.Paths{j.headerJarFile, repackagedHeaderJarFile}
+ transitiveStaticLibsHeaderJars = nil
+ }
}
if len(uniqueJavaFiles) > 0 || len(srcJars) > 0 {
hasErrorproneableFiles := false
@@ -1383,25 +1470,32 @@
// build.
flags = enableErrorproneFlags(flags)
} else if hasErrorproneableFiles && ctx.Config().RunErrorProne() && j.properties.Errorprone.Enabled == nil {
- // Otherwise, if the RUN_ERROR_PRONE environment variable is set, create
- // a new jar file just for compiling with the errorprone compiler to.
- // This is because we don't want to cause the java files to get completely
- // rebuilt every time the state of the RUN_ERROR_PRONE variable changes.
- // We also don't want to run this if errorprone is enabled by default for
- // this module, or else we could have duplicated errorprone messages.
- errorproneFlags := enableErrorproneFlags(flags)
- errorprone := android.PathForModuleOut(ctx, "errorprone", jarName)
- errorproneAnnoSrcJar := android.PathForModuleOut(ctx, "errorprone", "anno.srcjar")
+ if ctx.Config().RunErrorProneInline() {
+ // On CI, we're not going to toggle back/forth between errorprone and non-errorprone
+ // builds, so it's faster if we don't compile the module twice and instead always
+ // compile the module with errorprone.
+ flags = enableErrorproneFlags(flags)
+ } else {
+ // Otherwise, if the RUN_ERROR_PRONE environment variable is set, create
+ // a new jar file just for compiling with the errorprone compiler to.
+ // This is because we don't want to cause the java files to get completely
+ // rebuilt every time the state of the RUN_ERROR_PRONE variable changes.
+ // We also don't want to run this if errorprone is enabled by default for
+ // this module, or else we could have duplicated errorprone messages.
+ errorproneFlags := enableErrorproneFlags(flags)
+ errorprone := android.PathForModuleOut(ctx, "errorprone", jarName)
+ errorproneAnnoSrcJar := android.PathForModuleOut(ctx, "errorprone", "anno.srcjar")
- transformJavaToClasses(ctx, errorprone, -1, uniqueJavaFiles, srcJars, errorproneAnnoSrcJar, errorproneFlags, nil,
- "errorprone", "errorprone")
+ transformJavaToClasses(ctx, errorprone, -1, uniqueJavaFiles, srcJars, errorproneAnnoSrcJar, errorproneFlags, nil,
+ "errorprone", "errorprone")
- extraJarDeps = append(extraJarDeps, errorprone)
+ extraJarDeps = append(extraJarDeps, errorprone)
+ }
}
if enableSharding {
- if headerJarFileWithoutDepsOrJarjar != nil {
- flags.classpath = append(classpath{headerJarFileWithoutDepsOrJarjar}, flags.classpath...)
+ if len(shardingHeaderJars) > 0 {
+ flags.classpath = append(classpath(slices.Clone(shardingHeaderJars)), flags.classpath...)
}
shardSize := int(*(j.properties.Javac_shard_size))
var shardSrcs []android.Paths
@@ -1410,8 +1504,8 @@
for idx, shardSrc := range shardSrcs {
classes := j.compileJavaClasses(ctx, jarName, idx, shardSrc,
nil, flags, extraJarDeps)
- classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(idx))
- jars = append(jars, classes)
+ classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(idx))
+ localImplementationJars = append(localImplementationJars, classes)
}
}
// Assume approximately 5 sources per srcjar.
@@ -1423,21 +1517,21 @@
for idx, shardSrcJars := range shardSrcJarsList {
classes := j.compileJavaClasses(ctx, jarName, startIdx+idx,
nil, shardSrcJars, flags, extraJarDeps)
- classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(startIdx+idx))
- jars = append(jars, classes)
+ classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(startIdx+idx))
+ localImplementationJars = append(localImplementationJars, classes)
}
}
} else {
classes := j.compileJavaClasses(ctx, jarName, -1, uniqueJavaFiles, srcJars, flags, extraJarDeps)
- classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac")
- jars = append(jars, classes)
+ classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac")
+ localImplementationJars = append(localImplementationJars, classes)
}
if ctx.Failed() {
- return
+ return nil
}
}
- jars = append(jars, extraCombinedJars...)
+ localImplementationJars = append(localImplementationJars, extraCombinedJars...)
j.srcJarArgs, j.srcJarDeps = resourcePathsToJarArgs(srcFiles), srcFiles
@@ -1449,7 +1543,11 @@
dirArgs, dirDeps := ResourceDirsToJarArgs(ctx, j.properties.Java_resource_dirs,
j.properties.Exclude_java_resource_dirs, j.properties.Exclude_java_resources)
- fileArgs, fileDeps := ResourceFilesToJarArgs(ctx, j.properties.Java_resources, j.properties.Exclude_java_resources)
+ fileArgs, fileDeps := ResourceFilesToJarArgs(ctx, j.properties.Java_resources.GetOrDefault(ctx, nil), j.properties.Exclude_java_resources)
+ fileArgs2, fileDeps2 := ResourceFilesToJarArgs(ctx, j.properties.Device_common_java_resources.GetOrDefault(ctx, nil), nil)
+ fileArgs3, fileDeps3 := ResourceFilesToJarArgs(ctx, j.properties.Device_first_java_resources.GetOrDefault(ctx, nil), nil)
+ fileArgs = slices.Concat(fileArgs, fileArgs2, fileArgs3)
+ fileDeps = slices.Concat(fileDeps, fileDeps2, fileDeps3)
extraArgs, extraDeps := resourcePathsToJarArgs(j.extraResources), j.extraResources
var resArgs []string
@@ -1464,40 +1562,18 @@
resArgs = append(resArgs, extraArgs...)
resDeps = append(resDeps, extraDeps...)
+ var localResourceJars android.Paths
if len(resArgs) > 0 {
resourceJar := android.PathForModuleOut(ctx, "res", jarName)
TransformResourcesToJar(ctx, resourceJar, resArgs, resDeps)
- j.resourceJar = resourceJar
if ctx.Failed() {
- return
+ return nil
}
+ localResourceJars = append(localResourceJars, resourceJar)
}
- var resourceJars android.Paths
- if j.resourceJar != nil {
- resourceJars = append(resourceJars, j.resourceJar)
- }
if Bool(j.properties.Include_srcs) {
- resourceJars = append(resourceJars, includeSrcJar)
- }
- resourceJars = append(resourceJars, deps.staticResourceJars...)
-
- if len(resourceJars) > 1 {
- combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
- TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{},
- false, nil, nil)
- j.resourceJar = combinedJar
- } else if len(resourceJars) == 1 {
- j.resourceJar = resourceJars[0]
- }
-
- if len(deps.staticJars) > 0 {
- jars = append(jars, deps.staticJars...)
- }
-
- manifest := j.overrideManifest
- if !manifest.Valid() && j.properties.Manifest != nil {
- manifest = android.OptionalPathForPath(android.PathForModuleSrc(ctx, *j.properties.Manifest))
+ localResourceJars = append(localResourceJars, includeSrcJar)
}
services := android.PathsForModuleSrc(ctx, j.properties.Services)
@@ -1522,35 +1598,68 @@
Implicits: services,
Args: args,
})
- jars = append(jars, servicesJar)
+ localResourceJars = append(localResourceJars, servicesJar)
+ }
+
+ completeStaticLibsResourceJars := depset.New(depset.PREORDER, localResourceJars, deps.transitiveStaticLibsResourceJars)
+
+ var combinedResourceJar android.Path
+ var resourceJars android.Paths
+ if ctx.Config().UseTransitiveJarsInClasspath() {
+ resourceJars = completeStaticLibsResourceJars.ToList()
+ } else {
+ resourceJars = append(slices.Clone(localResourceJars), deps.staticResourceJars...)
+ }
+ if len(resourceJars) == 1 {
+ combinedResourceJar = resourceJars[0]
+ } else if len(resourceJars) > 0 {
+ combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
+ TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{},
+ false, nil, nil)
+ combinedResourceJar = combinedJar
+ }
+
+ manifest := j.overrideManifest
+ if !manifest.Valid() && j.properties.Manifest != nil {
+ manifest = android.OptionalPathForPath(android.PathForModuleSrc(ctx, *j.properties.Manifest))
}
// Combine the classes built from sources, any manifests, and any static libraries into
// classes.jar. If there is only one input jar this step will be skipped.
var outputFile android.Path
+ completeStaticLibsImplementationJars := depset.New(depset.PREORDER, localImplementationJars, deps.transitiveStaticLibsImplementationJars)
+
+ var jars android.Paths
+ if ctx.Config().UseTransitiveJarsInClasspath() {
+ jars = completeStaticLibsImplementationJars.ToList()
+ } else {
+ jars = append(slices.Clone(localImplementationJars), deps.staticJars...)
+ }
+
+ jars = append(jars, extraDepCombinedJars...)
+
if len(jars) == 1 && !manifest.Valid() {
// Optimization: skip the combine step as there is nothing to do
// TODO(ccross): this leaves any module-info.class files, but those should only come from
// prebuilt dependencies until we support modules in the platform build, so there shouldn't be
- // any if len(jars) == 1.
+ // any if len(extraJars) == 0.
// moduleStubLinkType determines if the module is the TopLevelStubLibrary generated
// from sdk_library. The TopLevelStubLibrary contains only one static lib,
// either with .from-source or .from-text suffix.
// outputFile should be agnostic to the build configuration,
- // thus "combine" the single static lib in order to prevent the static lib from being exposed
+ // thus copy the single input static lib in order to prevent the static lib from being exposed
// to the copy rules.
- stub, _ := moduleStubLinkType(ctx.ModuleName())
-
- if stub {
- combinedJar := android.PathForModuleOut(ctx, "combined", jarName)
+ if stub, _ := moduleStubLinkType(j); stub {
+ copiedJar := android.PathForModuleOut(ctx, "combined", jarName)
ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
Input: jars[0],
- Output: combinedJar,
+ Output: copiedJar,
})
- outputFile = combinedJar
+ completeStaticLibsImplementationJars = depset.New(depset.PREORDER, android.Paths{copiedJar}, nil)
+ outputFile = copiedJar
} else {
outputFile = jars[0]
}
@@ -1562,29 +1671,60 @@
}
// jarjar implementation jar if necessary
- jarjarFile := j.jarjarIfNecessary(ctx, outputFile, jarName, "")
+ jarjarFile, jarjarred := j.jarjarIfNecessary(ctx, outputFile, jarName, "", true)
+ if jarjarred {
+ localImplementationJars = android.Paths{jarjarFile}
+ completeStaticLibsImplementationJars = depset.New(depset.PREORDER, localImplementationJars, nil)
+ }
outputFile = jarjarFile
// jarjar resource jar if necessary
- if j.resourceJar != nil {
- resourceJarJarFile := j.jarjarIfNecessary(ctx, j.resourceJar, jarName, "resource")
- j.resourceJar = resourceJarJarFile
+ if combinedResourceJar != nil {
+ resourceJarJarFile, jarjarred := j.jarjarIfNecessary(ctx, combinedResourceJar, jarName, "resource", false)
+ combinedResourceJar = resourceJarJarFile
+ if jarjarred {
+ localResourceJars = android.Paths{resourceJarJarFile}
+ completeStaticLibsResourceJars = depset.New(depset.PREORDER, localResourceJars, nil)
+ }
}
if ctx.Failed() {
- return
+ return nil
}
if j.ravenizer.enabled {
ravenizerInput := outputFile
- ravenizerOutput := android.PathForModuleOut(ctx, "ravenizer", jarName)
- ctx.Build(pctx, android.BuildParams{
- Rule: ravenizer,
- Description: "ravenizer",
- Input: ravenizerInput,
- Output: ravenizerOutput,
- })
+ ravenizerOutput := android.PathForModuleOut(ctx, "ravenizer", "", jarName)
+ ravenizerArgs := ""
+ if proptools.Bool(j.properties.Ravenizer.Strip_mockito) {
+ ravenizerArgs = "--strip-mockito"
+ }
+ TransformRavenizer(ctx, ravenizerOutput, ravenizerInput, ravenizerArgs)
outputFile = ravenizerOutput
+ localImplementationJars = android.Paths{ravenizerOutput}
+ completeStaticLibsImplementationJars = depset.New(depset.PREORDER, localImplementationJars, nil)
+ if combinedResourceJar != nil {
+ ravenizerInput = combinedResourceJar
+ ravenizerOutput = android.PathForModuleOut(ctx, "ravenizer", "resources", jarName)
+ TransformRavenizer(ctx, ravenizerOutput, ravenizerInput, ravenizerArgs)
+ combinedResourceJar = ravenizerOutput
+ localResourceJars = android.Paths{ravenizerOutput}
+ completeStaticLibsResourceJars = depset.New(depset.PREORDER, localResourceJars, nil)
+ }
+ }
+
+ if j.shouldApiMapper() {
+ inputFile := outputFile
+ apiMapperFile := android.PathForModuleOut(ctx, "apimapper", jarName)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: apimapper,
+ Description: "apimapper",
+ Input: inputFile,
+ Output: apiMapperFile,
+ })
+ outputFile = apiMapperFile
+ localImplementationJars = android.Paths{apiMapperFile}
+ completeStaticLibsImplementationJars = depset.New(depset.PREORDER, localImplementationJars, nil)
}
// Check package restrictions if necessary.
@@ -1606,12 +1746,14 @@
Validation: pkgckFile,
})
outputFile = packageCheckOutputFile
+ localImplementationJars = android.Paths{packageCheckOutputFile}
+ completeStaticLibsImplementationJars = depset.New(depset.PREORDER, localImplementationJars, nil)
// Check packages and create a timestamp file when complete.
CheckJarPackages(ctx, pkgckFile, outputFile, j.properties.Permitted_packages)
if ctx.Failed() {
- return
+ return nil
}
}
@@ -1624,43 +1766,58 @@
headerJarFile := android.PathForModuleOut(ctx, "javac-header", jarName)
convertImplementationJarToHeaderJar(ctx, j.implementationJarFile, headerJarFile)
j.headerJarFile = headerJarFile
+ if len(localImplementationJars) == 1 && ctx.Config().UseTransitiveJarsInClasspath() {
+ localHeaderJarFile := android.PathForModuleOut(ctx, "local-javac-header", jarName)
+ convertImplementationJarToHeaderJar(ctx, localImplementationJars[0], localHeaderJarFile)
+ localHeaderJars = append(localHeaderJars, localHeaderJarFile)
+ } else {
+ localHeaderJars = append(localHeaderJars, headerJarFile)
+ }
}
// enforce syntax check to jacoco filters for any build (http://b/183622051)
specs := j.jacocoModuleToZipCommand(ctx)
if ctx.Failed() {
- return
+ return nil
}
- if j.shouldInstrument(ctx) {
- outputFile = j.instrument(ctx, flags, outputFile, jarName, specs)
+ completeStaticLibsImplementationJarsToCombine := completeStaticLibsImplementationJars
+
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+
+ // Enable dex compilation for the APEX variants, unless it is disabled explicitly
+ compileDex := Bool(j.dexProperties.Compile_dex) || Bool(j.properties.Installable)
+
+ if j.shouldInstrument(ctx) && (!ctx.Device() || compileDex) {
+ instrumentedOutputFile := j.instrument(ctx, flags, outputFile, jarName, specs)
+ completeStaticLibsImplementationJarsToCombine = depset.New(depset.PREORDER, android.Paths{instrumentedOutputFile}, nil)
+ outputFile = instrumentedOutputFile
}
// merge implementation jar with resources if necessary
- implementationAndResourcesJar := outputFile
- if j.resourceJar != nil {
- jars := android.Paths{j.resourceJar, implementationAndResourcesJar}
+ var implementationAndResourcesJarsToCombine android.Paths
+ if ctx.Config().UseTransitiveJarsInClasspath() {
+ resourceJars := completeStaticLibsResourceJars.ToList()
+ if len(resourceJars) > 0 {
+ implementationAndResourcesJarsToCombine = append(resourceJars, completeStaticLibsImplementationJarsToCombine.ToList()...)
+ implementationAndResourcesJarsToCombine = append(implementationAndResourcesJarsToCombine, extraDepCombinedJars...)
+ }
+ } else {
+ if combinedResourceJar != nil {
+ implementationAndResourcesJarsToCombine = android.Paths{combinedResourceJar, outputFile}
+ }
+ }
+
+ if len(implementationAndResourcesJarsToCombine) > 0 {
combinedJar := android.PathForModuleOut(ctx, "withres", jarName)
- TransformJarsToJar(ctx, combinedJar, "for resources", jars, manifest,
+ TransformJarsToJar(ctx, combinedJar, "for resources", implementationAndResourcesJarsToCombine, manifest,
false, nil, nil)
- implementationAndResourcesJar = combinedJar
+ outputFile = combinedJar
}
- j.implementationAndResourcesJar = implementationAndResourcesJar
+ j.implementationAndResourcesJar = outputFile
- // Enable dex compilation for the APEX variants, unless it is disabled explicitly
- compileDex := j.dexProperties.Compile_dex
- apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
- if j.DirectlyInAnyApex() && !apexInfo.IsForPlatform() {
- if compileDex == nil {
- compileDex = proptools.BoolPtr(true)
- }
- if j.deviceProperties.Hostdex == nil {
- j.deviceProperties.Hostdex = proptools.BoolPtr(true)
- }
- }
-
- if ctx.Device() && (Bool(j.properties.Installable) || Bool(compileDex)) {
+ if ctx.Device() && compileDex {
if j.hasCode(ctx) {
if j.shouldInstrumentStatic(ctx) {
j.dexer.extraProguardFlagsFiles = append(j.dexer.extraProguardFlagsFiles,
@@ -1672,24 +1829,24 @@
flags: flags,
sdkVersion: j.SdkVersion(ctx),
minSdkVersion: j.MinSdkVersion(ctx),
- classesJar: implementationAndResourcesJar,
+ classesJar: outputFile,
jarName: jarName,
}
- if j.GetProfileGuided() && j.optimizeOrObfuscateEnabled() && !j.EnableProfileRewriting() {
+ if j.GetProfileGuided(ctx) && j.optimizeOrObfuscateEnabled() && !j.EnableProfileRewriting(ctx) {
ctx.PropertyErrorf("enable_profile_rewriting",
"Enable_profile_rewriting must be true when profile_guided dexpreopt and R8 optimization/obfuscation is turned on. The attached profile should be sourced from an unoptimized/unobfuscated APK.",
)
}
- if j.EnableProfileRewriting() {
- profile := j.GetProfile()
- if profile == "" || !j.GetProfileGuided() {
+ if j.EnableProfileRewriting(ctx) {
+ profile := j.GetProfile(ctx)
+ if profile == "" || !j.GetProfileGuided(ctx) {
ctx.PropertyErrorf("enable_profile_rewriting", "Profile and Profile_guided must be set when enable_profile_rewriting is true")
}
params.artProfileInput = &profile
}
dexOutputFile, dexArtProfileOutput := j.dexer.compileDex(ctx, params)
if ctx.Failed() {
- return
+ return nil
}
// If r8/d8 provides a profile that matches the optimized dex, use that for dexpreopt.
@@ -1698,10 +1855,20 @@
}
// merge dex jar with resources if necessary
- if j.resourceJar != nil {
- jars := android.Paths{dexOutputFile, j.resourceJar}
+ var dexAndResourceJarsToCombine android.Paths
+ if ctx.Config().UseTransitiveJarsInClasspath() {
+ resourceJars := completeStaticLibsResourceJars.ToList()
+ if len(resourceJars) > 0 {
+ dexAndResourceJarsToCombine = append(android.Paths{dexOutputFile}, resourceJars...)
+ }
+ } else {
+ if combinedResourceJar != nil {
+ dexAndResourceJarsToCombine = android.Paths{dexOutputFile, combinedResourceJar}
+ }
+ }
+ if len(dexAndResourceJarsToCombine) > 0 {
combinedJar := android.PathForModuleOut(ctx, "dex-withres", jarName)
- TransformJarsToJar(ctx, combinedJar, "for dex resources", jars, android.OptionalPath{},
+ TransformJarsToJar(ctx, combinedJar, "for dex resources", dexAndResourceJarsToCombine, android.OptionalPath{},
false, nil, nil)
if *j.dexProperties.Uncompress_dex {
combinedAlignedJar := android.PathForModuleOut(ctx, "dex-withres-aligned", jarName)
@@ -1729,18 +1896,17 @@
j.dexpreopt(ctx, libName, dexOutputFile)
outputFile = dexOutputFile
+
+ ctx.CheckbuildFile(dexOutputFile)
} else {
// There is no code to compile into a dex jar, make sure the resources are propagated
// to the APK if this is an app.
- outputFile = implementationAndResourcesJar
- j.dexJarFile = makeDexJarPathFromPath(j.resourceJar)
+ j.dexJarFile = makeDexJarPathFromPath(combinedResourceJar)
}
if ctx.Failed() {
- return
+ return nil
}
- } else {
- outputFile = implementationAndResourcesJar
}
if ctx.Device() {
@@ -1772,16 +1938,37 @@
j.collectTransitiveSrcFiles(ctx, srcFiles)
- ctx.CheckbuildFile(outputFile)
+ if ctx.Config().UseTransitiveJarsInClasspath() {
+ if len(localImplementationJars) > 0 || len(localResourceJars) > 0 || len(localHeaderJars) > 0 {
+ ctx.CheckbuildFile(localImplementationJars...)
+ ctx.CheckbuildFile(localResourceJars...)
+ ctx.CheckbuildFile(localHeaderJars...)
+ } else {
+ // There are no local sources or resources in this module, so there is nothing to checkbuild.
+ ctx.UncheckedModule()
+ }
+ } else {
+ ctx.CheckbuildFile(j.implementationJarFile)
+ ctx.CheckbuildFile(j.headerJarFile)
+ }
- android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
- HeaderJars: android.PathsIfNonNil(j.headerJarFile),
- RepackagedHeaderJars: android.PathsIfNonNil(j.repackagedHeaderJarFile),
- TransitiveLibsHeaderJars: j.transitiveLibsHeaderJars,
- TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
+ // Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource
+ j.outputFile = outputFile.WithoutRel()
+
+ return &JavaInfo{
+ HeaderJars: android.PathsIfNonNil(j.headerJarFile),
+ RepackagedHeaderJars: android.PathsIfNonNil(repackagedHeaderJarFile),
+
+ LocalHeaderJars: localHeaderJars,
+ TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, localHeaderJars, transitiveStaticLibsHeaderJars),
+ TransitiveStaticLibsImplementationJars: completeStaticLibsImplementationJars,
+ TransitiveStaticLibsResourceJars: completeStaticLibsResourceJars,
+
+ TransitiveLibsHeaderJarsForR8: j.transitiveLibsHeaderJarsForR8,
+ TransitiveStaticLibsHeaderJarsForR8: j.transitiveStaticLibsHeaderJarsForR8,
ImplementationAndResourcesJars: android.PathsIfNonNil(j.implementationAndResourcesJar),
ImplementationJars: android.PathsIfNonNil(j.implementationJarFile),
- ResourceJars: android.PathsIfNonNil(j.resourceJar),
+ ResourceJars: android.PathsIfNonNil(combinedResourceJar),
AidlIncludeDirs: j.exportAidlIncludeDirs,
SrcJarArgs: j.srcJarArgs,
SrcJarDeps: j.srcJarDeps,
@@ -1792,27 +1979,24 @@
JacocoReportClassesFile: j.jacocoReportClassesFile,
StubsLinkType: j.stubsLinkType,
AconfigIntermediateCacheOutputPaths: j.aconfigCacheFiles,
- })
-
- // Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource
- j.outputFile = outputFile.WithoutRel()
+ SdkVersion: j.SdkVersion(ctx),
+ OutputFile: j.outputFile,
+ }
}
-func (j *Module) useCompose() bool {
- return android.InList("androidx.compose.runtime_runtime", j.properties.Static_libs)
+func (j *Module) useCompose(ctx android.BaseModuleContext) bool {
+ return android.InList("androidx.compose.runtime_runtime", j.staticLibs(ctx))
}
-func collectDepProguardSpecInfo(ctx android.ModuleContext) (transitiveProguardFlags, transitiveUnconditionalExportedFlags []*android.DepSet[android.Path]) {
- ctx.VisitDirectDeps(func(m android.Module) {
+func collectDepProguardSpecInfo(ctx android.ModuleContext) (transitiveProguardFlags, transitiveUnconditionalExportedFlags []depset.DepSet[android.Path]) {
+ ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) {
depProguardInfo, _ := android.OtherModuleProvider(ctx, m, ProguardSpecInfoProvider)
depTag := ctx.OtherModuleDependencyTag(m)
- if depProguardInfo.UnconditionallyExportedProguardFlags != nil {
- transitiveUnconditionalExportedFlags = append(transitiveUnconditionalExportedFlags, depProguardInfo.UnconditionallyExportedProguardFlags)
- transitiveProguardFlags = append(transitiveProguardFlags, depProguardInfo.UnconditionallyExportedProguardFlags)
- }
+ transitiveUnconditionalExportedFlags = append(transitiveUnconditionalExportedFlags, depProguardInfo.UnconditionallyExportedProguardFlags)
+ transitiveProguardFlags = append(transitiveProguardFlags, depProguardInfo.UnconditionallyExportedProguardFlags)
- if depTag == staticLibTag && depProguardInfo.ProguardFlagsFiles != nil {
+ if depTag == staticLibTag {
transitiveProguardFlags = append(transitiveProguardFlags, depProguardInfo.ProguardFlagsFiles)
}
})
@@ -1834,13 +2018,13 @@
return ProguardSpecInfo{
Export_proguard_flags_files: exportUnconditionally,
- ProguardFlagsFiles: android.NewDepSet[android.Path](
- android.POSTORDER,
+ ProguardFlagsFiles: depset.New[android.Path](
+ depset.POSTORDER,
proguardFlagsForThisModule,
transitiveProguardFlags,
),
- UnconditionallyExportedProguardFlags: android.NewDepSet[android.Path](
- android.POSTORDER,
+ UnconditionallyExportedProguardFlags: depset.New[android.Path](
+ depset.POSTORDER,
directUnconditionalExportedFlags,
transitiveUnconditionalExportedFlags,
),
@@ -1901,7 +2085,9 @@
} else if strings.HasPrefix(flag, "-Xintellij-plugin-root") {
ctx.PropertyErrorf("kotlincflags",
"Bad flag: `%s`, only use internal compiler for consistency.", flag)
- } else if inList(flag, config.KotlincIllegalFlags) {
+ } else if slices.ContainsFunc(config.KotlincIllegalFlags, func(f string) bool {
+ return strings.HasPrefix(flag, f)
+ }) {
ctx.PropertyErrorf("kotlincflags", "Flag `%s` already used by build system", flag)
} else if flag == "-include-runtime" {
ctx.PropertyErrorf("kotlincflags", "Bad flag: `%s`, do not include runtime.", flag)
@@ -1917,22 +2103,26 @@
func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths,
deps deps, flags javaBuilderFlags, jarName string,
- extraJars android.Paths) (headerJar android.Path, combinedHeaderJar android.Path) {
+ extraJars android.Paths) (localHeaderJars android.Paths, combinedHeaderJar android.Path) {
- var jars android.Paths
if len(srcFiles) > 0 || len(srcJars) > 0 {
// Compile java sources into turbine.jar.
turbineJar := android.PathForModuleOut(ctx, "turbine", jarName)
TransformJavaToHeaderClasses(ctx, turbineJar, srcFiles, srcJars, flags)
- jars = append(jars, turbineJar)
- headerJar = turbineJar
+ localHeaderJars = append(localHeaderJars, turbineJar)
}
- jars = append(jars, extraJars...)
+ localHeaderJars = append(localHeaderJars, extraJars...)
// Combine any static header libraries into classes-header.jar. If there is only
// one input jar this step will be skipped.
- jars = append(jars, deps.staticHeaderJars...)
+ var jars android.Paths
+ if ctx.Config().UseTransitiveJarsInClasspath() {
+ depSet := depset.New(depset.PREORDER, localHeaderJars, deps.transitiveStaticLibsHeaderJars)
+ jars = depSet.ToList()
+ } else {
+ jars = append(slices.Clone(localHeaderJars), deps.staticHeaderJars...)
+ }
// we cannot skip the combine step for now if there is only one jar
// since we have to strip META-INF/TRANSITIVE dir from turbine.jar
@@ -1940,7 +2130,7 @@
TransformJarsToJar(ctx, combinedHeaderJarOutputPath, "for turbine", jars, android.OptionalPath{},
false, nil, []string{"META-INF/TRANSITIVE"})
- return headerJar, combinedHeaderJarOutputPath
+ return localHeaderJars, combinedHeaderJarOutputPath
}
func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
@@ -1956,27 +2146,23 @@
return instrumentedJar
}
-type providesTransitiveHeaderJars struct {
+type providesTransitiveHeaderJarsForR8 struct {
// set of header jars for all transitive libs deps
- transitiveLibsHeaderJars *android.DepSet[android.Path]
+ transitiveLibsHeaderJarsForR8 depset.DepSet[android.Path]
// set of header jars for all transitive static libs deps
- transitiveStaticLibsHeaderJars *android.DepSet[android.Path]
+ transitiveStaticLibsHeaderJarsForR8 depset.DepSet[android.Path]
}
-func (j *providesTransitiveHeaderJars) TransitiveLibsHeaderJars() *android.DepSet[android.Path] {
- return j.transitiveLibsHeaderJars
-}
-
-func (j *providesTransitiveHeaderJars) TransitiveStaticLibsHeaderJars() *android.DepSet[android.Path] {
- return j.transitiveStaticLibsHeaderJars
-}
-
-func (j *providesTransitiveHeaderJars) collectTransitiveHeaderJars(ctx android.ModuleContext) {
+// collectTransitiveHeaderJarsForR8 visits direct dependencies and collects all transitive libs and static_libs
+// header jars. The semantics of the collected jars are odd (it collects combined jars that contain the static
+// libs, but also the static libs, and it collects transitive libs dependencies of static_libs), so these
+// are only used to expand the --lib arguments to R8.
+func (j *providesTransitiveHeaderJarsForR8) collectTransitiveHeaderJarsForR8(ctx android.ModuleContext) {
directLibs := android.Paths{}
directStaticLibs := android.Paths{}
- transitiveLibs := []*android.DepSet[android.Path]{}
- transitiveStaticLibs := []*android.DepSet[android.Path]{}
- ctx.VisitDirectDeps(func(module android.Module) {
+ transitiveLibs := []depset.DepSet[android.Path]{}
+ transitiveStaticLibs := []depset.DepSet[android.Path]{}
+ ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) {
// don't add deps of the prebuilt version of the same library
if ctx.ModuleName() == android.RemoveOptionalPrebuiltPrefix(module.Name()) {
return
@@ -1994,16 +2180,12 @@
return
}
- if dep.TransitiveLibsHeaderJars != nil {
- transitiveLibs = append(transitiveLibs, dep.TransitiveLibsHeaderJars)
- }
- if dep.TransitiveStaticLibsHeaderJars != nil {
- transitiveStaticLibs = append(transitiveStaticLibs, dep.TransitiveStaticLibsHeaderJars)
- }
+ transitiveLibs = append(transitiveLibs, dep.TransitiveLibsHeaderJarsForR8)
+ transitiveStaticLibs = append(transitiveStaticLibs, dep.TransitiveStaticLibsHeaderJarsForR8)
}
})
- j.transitiveLibsHeaderJars = android.NewDepSet(android.POSTORDER, directLibs, transitiveLibs)
- j.transitiveStaticLibsHeaderJars = android.NewDepSet(android.POSTORDER, directStaticLibs, transitiveStaticLibs)
+ j.transitiveLibsHeaderJarsForR8 = depset.New(depset.POSTORDER, directLibs, transitiveLibs)
+ j.transitiveStaticLibsHeaderJarsForR8 = depset.New(depset.POSTORDER, directStaticLibs, transitiveStaticLibs)
}
func (j *Module) HeaderJars() android.Paths {
@@ -2045,20 +2227,20 @@
}
// Collect information for opening IDE project files in java/jdeps.go.
-func (j *Module) IDEInfo(dpInfo *android.IdeInfo) {
- // jarjar rules will repackage the sources. To prevent misleading results, IdeInfo should contain the
- // repackaged jar instead of the input sources.
+func (j *Module) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
if j.expandJarjarRules != nil {
dpInfo.Jarjar_rules = append(dpInfo.Jarjar_rules, j.expandJarjarRules.String())
- dpInfo.Jars = append(dpInfo.Jars, j.headerJarFile.String())
- } else {
- dpInfo.Srcs = append(dpInfo.Srcs, j.expandIDEInfoCompiledSrcs...)
- dpInfo.SrcJars = append(dpInfo.SrcJars, j.compiledSrcJars.Strings()...)
- dpInfo.SrcJars = append(dpInfo.SrcJars, j.annoSrcJars.Strings()...)
}
+ if j.headerJarFile != nil {
+ // Add the header jar so that the rdeps can be resolved to the repackaged classes.
+ dpInfo.Jars = append(dpInfo.Jars, j.headerJarFile.String())
+ }
+ dpInfo.Srcs = append(dpInfo.Srcs, j.expandIDEInfoCompiledSrcs...)
+ dpInfo.SrcJars = append(dpInfo.SrcJars, j.compiledSrcJars.Strings()...)
+ dpInfo.SrcJars = append(dpInfo.SrcJars, j.annoSrcJars.Strings()...)
dpInfo.Deps = append(dpInfo.Deps, j.CompilerDeps()...)
dpInfo.Aidl_include_dirs = append(dpInfo.Aidl_include_dirs, j.deviceProperties.Aidl.Include_dirs...)
- dpInfo.Static_libs = append(dpInfo.Static_libs, j.properties.Static_libs...)
+ dpInfo.Static_libs = append(dpInfo.Static_libs, j.staticLibs(ctx)...)
dpInfo.Libs = append(dpInfo.Libs, j.properties.Libs...)
}
@@ -2068,12 +2250,12 @@
func (j *Module) hasCode(ctx android.ModuleContext) bool {
srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
- return len(srcFiles) > 0 || len(ctx.GetDirectDepsWithTag(staticLibTag)) > 0
+ return len(srcFiles) > 0 || len(ctx.GetDirectDepsProxyWithTag(staticLibTag)) > 0
}
// Implements android.ApexModule
-func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
- return j.depIsInSameApex(ctx, dep)
+func (j *Module) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
+ return j.depIsInSameApex(tag)
}
// Implements android.ApexModule
@@ -2105,19 +2287,17 @@
}
func (j *Module) collectTransitiveSrcFiles(ctx android.ModuleContext, mine android.Paths) {
- var fromDeps []*android.DepSet[android.Path]
- ctx.VisitDirectDeps(func(module android.Module) {
+ var fromDeps []depset.DepSet[android.Path]
+ ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) {
tag := ctx.OtherModuleDependencyTag(module)
if tag == staticLibTag {
if depInfo, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
- if depInfo.TransitiveSrcFiles != nil {
- fromDeps = append(fromDeps, depInfo.TransitiveSrcFiles)
- }
+ fromDeps = append(fromDeps, depInfo.TransitiveSrcFiles)
}
}
})
- j.transitiveSrcFiles = android.NewDepSet(android.POSTORDER, mine, fromDeps)
+ j.transitiveSrcFiles = depset.New(depset.POSTORDER, mine, fromDeps)
}
func (j *Module) IsInstallable() bool {
@@ -2169,6 +2349,25 @@
getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool)
}
+func sdkLinkTypeFromSdkKind(k android.SdkKind) sdkLinkType {
+ switch k {
+ case android.SdkCore:
+ return javaCore
+ case android.SdkSystem:
+ return javaSystem
+ case android.SdkPublic:
+ return javaSdk
+ case android.SdkModule:
+ return javaModule
+ case android.SdkSystemServer:
+ return javaSystemServer
+ case android.SdkPrivate, android.SdkNone, android.SdkCorePlatform, android.SdkTest:
+ return javaPlatform
+ default:
+ return javaSdk
+ }
+}
+
func (m *Module) getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool) {
switch name {
case android.SdkCore.DefaultJavaLibraryName(),
@@ -2176,7 +2375,10 @@
"stable.core.platform.api.stubs",
"stub-annotations", "private-stub-annotations-jar",
"core-lambda-stubs",
- "core-generated-annotation-stubs":
+ "core-generated-annotation-stubs",
+ // jacocoagent only uses core APIs, but has to specify a non-core sdk_version so it can use
+ // a prebuilt SDK to avoid circular dependencies when it statically included in the bootclasspath.
+ "jacocoagent":
return javaCore, true
case android.SdkPublic.DefaultJavaLibraryName():
return javaSdk, true
@@ -2190,36 +2392,22 @@
return javaSystem, true
}
- if stub, linkType := moduleStubLinkType(name); stub {
+ if stub, linkType := moduleStubLinkType(m); stub {
return linkType, true
}
ver := m.SdkVersion(ctx)
- switch ver.Kind {
- case android.SdkCore:
- return javaCore, false
- case android.SdkSystem:
- return javaSystem, false
- case android.SdkPublic:
- return javaSdk, false
- case android.SdkModule:
- return javaModule, false
- case android.SdkSystemServer:
- return javaSystemServer, false
- case android.SdkPrivate, android.SdkNone, android.SdkCorePlatform, android.SdkTest:
- return javaPlatform, false
- }
-
if !ver.Valid() {
panic(fmt.Errorf("sdk_version is invalid. got %q", ver.Raw))
}
- return javaSdk, false
+
+ return sdkLinkTypeFromSdkKind(ver.Kind), false
}
// checkSdkLinkType make sures the given dependency doesn't have a lower SDK link type rank than
// this module's. See the comment on rank() for details and an example.
func (j *Module) checkSdkLinkType(
- ctx android.ModuleContext, dep moduleWithSdkDep, tag dependencyTag) {
+ ctx android.ModuleContext, dep android.ModuleProxy) {
if ctx.Host() {
return
}
@@ -2228,7 +2416,12 @@
if stubs {
return
}
- depLinkType, _ := dep.getSdkLinkType(ctx, ctx.OtherModuleName(dep))
+ info, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider)
+ if !ok || info.ModuleWithSdkDepInfo == nil {
+ panic(fmt.Errorf("dependency doesn't have ModuleWithSdkDepInfo: %v", dep))
+ }
+
+ depLinkType := info.ModuleWithSdkDepInfo.SdkLinkType
if myLinkType.rank() < depLinkType.rank() {
ctx.ModuleErrorf("compiles against %v, but dependency %q is compiling against %v. "+
@@ -2242,30 +2435,18 @@
func (j *Module) collectDeps(ctx android.ModuleContext) deps {
var deps deps
- if ctx.Device() {
- sdkDep := decodeSdkDep(ctx, android.SdkContext(j))
- if sdkDep.invalidVersion {
- ctx.AddMissingDependencies(sdkDep.bootclasspath)
- ctx.AddMissingDependencies(sdkDep.java9Classpath)
- } else if sdkDep.useFiles {
- // sdkDep.jar is actually equivalent to turbine header.jar.
- deps.classpath = append(deps.classpath, sdkDep.jars...)
- deps.dexClasspath = append(deps.dexClasspath, sdkDep.jars...)
- deps.aidlPreprocess = sdkDep.aidl
- // Add the sdk module dependency to `compileDepNames`.
- // This ensures that the dependency is reported in `module_bp_java_deps.json`
- // TODO (b/358608607): Move this to decodeSdkDep
- sdkSpec := android.SdkContext(j).SdkVersion(ctx)
- j.compileDepNames = append(j.compileDepNames, fmt.Sprintf("sdk_%s_%s_android", sdkSpec.Kind.String(), sdkSpec.ApiLevel.String()))
- } else {
- deps.aidlPreprocess = sdkDep.aidl
- }
- }
-
sdkLinkType, _ := j.getSdkLinkType(ctx, ctx.ModuleName())
- j.collectTransitiveHeaderJars(ctx)
- ctx.VisitDirectDeps(func(module android.Module) {
+ j.collectTransitiveHeaderJarsForR8(ctx)
+
+ var transitiveBootClasspathHeaderJars []depset.DepSet[android.Path]
+ var transitiveClasspathHeaderJars []depset.DepSet[android.Path]
+ var transitiveJava9ClasspathHeaderJars []depset.DepSet[android.Path]
+ var transitiveStaticJarsHeaderLibs []depset.DepSet[android.Path]
+ var transitiveStaticJarsImplementationLibs []depset.DepSet[android.Path]
+ var transitiveStaticJarsResourceLibs []depset.DepSet[android.Path]
+
+ ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) {
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
@@ -2278,14 +2459,12 @@
return
}
- if dep, ok := module.(SdkLibraryDependency); ok {
+ if sdkInfo, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok {
switch tag {
- case sdkLibTag, libTag:
- depHeaderJars := dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))
- deps.classpath = append(deps.classpath, depHeaderJars...)
- deps.dexClasspath = append(deps.dexClasspath, depHeaderJars...)
- case staticLibTag:
- ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
+ case sdkLibTag, libTag, staticLibTag:
+ generatingLibsString := android.PrettyConcat(
+ getGeneratingLibs(ctx, j.SdkVersion(ctx), module.Name(), sdkInfo), true, "or")
+ ctx.ModuleErrorf("cannot depend directly on java_sdk_library %q; try depending on %s instead", module.Name(), generatingLibsString)
}
} else if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
if sdkLinkType != javaPlatform {
@@ -2299,8 +2478,9 @@
switch tag {
case bootClasspathTag:
deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars...)
+ transitiveBootClasspathHeaderJars = append(transitiveBootClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
case sdkLibTag, libTag, instrumentationForTag:
- if _, ok := module.(*Plugin); ok {
+ if _, ok := android.OtherModuleProvider(ctx, module, JavaPluginInfoProvider); ok {
ctx.ModuleErrorf("a java_plugin (%s) cannot be used as a libs dependency", otherName)
}
deps.classpath = append(deps.classpath, dep.HeaderJars...)
@@ -2312,10 +2492,13 @@
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...)
deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine
+
+ transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
case java9LibTag:
deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...)
+ transitiveJava9ClasspathHeaderJars = append(transitiveJava9ClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
case staticLibTag:
- if _, ok := module.(*Plugin); ok {
+ if _, ok := android.OtherModuleProvider(ctx, module, JavaPluginInfoProvider); ok {
ctx.ModuleErrorf("a java_plugin (%s) cannot be used as a static_libs dependency", otherName)
}
deps.classpath = append(deps.classpath, dep.HeaderJars...)
@@ -2329,41 +2512,50 @@
// optimization.
deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine
deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...)
+
+ transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+ transitiveStaticJarsHeaderLibs = append(transitiveStaticJarsHeaderLibs, dep.TransitiveStaticLibsHeaderJars)
+ transitiveStaticJarsImplementationLibs = append(transitiveStaticJarsImplementationLibs, dep.TransitiveStaticLibsImplementationJars)
+ transitiveStaticJarsResourceLibs = append(transitiveStaticJarsResourceLibs, dep.TransitiveStaticLibsResourceJars)
case pluginTag:
- if plugin, ok := module.(*Plugin); ok {
- if plugin.pluginProperties.Processor_class != nil {
- addPlugins(&deps, dep.ImplementationAndResourcesJars, *plugin.pluginProperties.Processor_class)
+ if plugin, ok := android.OtherModuleProvider(ctx, module, JavaPluginInfoProvider); ok {
+ if plugin.ProcessorClass != nil {
+ addPlugins(&deps, dep.ImplementationAndResourcesJars, *plugin.ProcessorClass)
} else {
addPlugins(&deps, dep.ImplementationAndResourcesJars)
}
// Turbine doesn't run annotation processors, so any module that uses an
// annotation processor that generates API is incompatible with the turbine
// optimization.
- deps.disableTurbine = deps.disableTurbine || Bool(plugin.pluginProperties.Generates_api)
+ deps.disableTurbine = deps.disableTurbine || plugin.GeneratesApi
} else {
ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName)
}
case errorpronePluginTag:
- if _, ok := module.(*Plugin); ok {
+ if _, ok := android.OtherModuleProvider(ctx, module, JavaPluginInfoProvider); ok {
deps.errorProneProcessorPath = append(deps.errorProneProcessorPath, dep.ImplementationAndResourcesJars...)
} else {
ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName)
}
case exportedPluginTag:
- if plugin, ok := module.(*Plugin); ok {
+ if plugin, ok := android.OtherModuleProvider(ctx, module, JavaPluginInfoProvider); ok {
j.exportedPluginJars = append(j.exportedPluginJars, dep.ImplementationAndResourcesJars...)
- if plugin.pluginProperties.Processor_class != nil {
- j.exportedPluginClasses = append(j.exportedPluginClasses, *plugin.pluginProperties.Processor_class)
+ if plugin.ProcessorClass != nil {
+ j.exportedPluginClasses = append(j.exportedPluginClasses, *plugin.ProcessorClass)
}
// Turbine doesn't run annotation processors, so any module that uses an
// annotation processor that generates API is incompatible with the turbine
// optimization.
- j.exportedDisableTurbine = Bool(plugin.pluginProperties.Generates_api)
+ j.exportedDisableTurbine = plugin.GeneratesApi
} else {
ctx.PropertyErrorf("exported_plugins", "%q is not a java_plugin module", otherName)
}
case kotlinPluginTag:
- deps.kotlinPlugins = append(deps.kotlinPlugins, dep.ImplementationAndResourcesJars...)
+ if _, ok := android.OtherModuleProvider(ctx, module, KotlinPluginInfoProvider); ok {
+ deps.kotlinPlugins = append(deps.kotlinPlugins, dep.ImplementationAndResourcesJars...)
+ } else {
+ ctx.PropertyErrorf("kotlin_plugins", "%q is not a kotlin_plugin module", otherName)
+ }
case syspropPublicStubDepTag:
// This is a sysprop implementation library, forward the JavaInfoProvider from
// the corresponding sysprop public stub library as SyspropPublicStubInfoProvider.
@@ -2371,17 +2563,24 @@
JavaInfo: dep,
})
}
- } else if dep, ok := module.(android.SourceFileProducer); ok {
+ } else if dep, ok := android.OtherModuleProvider(ctx, module, android.SourceFilesInfoProvider); ok {
switch tag {
case sdkLibTag, libTag:
- checkProducesJars(ctx, dep)
- deps.classpath = append(deps.classpath, dep.Srcs()...)
- deps.dexClasspath = append(deps.classpath, dep.Srcs()...)
+ checkProducesJars(ctx, dep, module)
+ deps.classpath = append(deps.classpath, dep.Srcs...)
+ deps.dexClasspath = append(deps.classpath, dep.Srcs...)
+ transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars,
+ depset.New(depset.PREORDER, dep.Srcs, nil))
case staticLibTag:
- checkProducesJars(ctx, dep)
- deps.classpath = append(deps.classpath, dep.Srcs()...)
- deps.staticJars = append(deps.staticJars, dep.Srcs()...)
- deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs()...)
+ checkProducesJars(ctx, dep, module)
+ deps.classpath = append(deps.classpath, dep.Srcs...)
+ deps.staticJars = append(deps.staticJars, dep.Srcs...)
+ deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs...)
+
+ depHeaderJars := depset.New(depset.PREORDER, dep.Srcs, nil)
+ transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, depHeaderJars)
+ transitiveStaticJarsHeaderLibs = append(transitiveStaticJarsHeaderLibs, depHeaderJars)
+ transitiveStaticJarsImplementationLibs = append(transitiveStaticJarsImplementationLibs, depHeaderJars)
}
} else if dep, ok := android.OtherModuleProvider(ctx, module, android.CodegenInfoProvider); ok {
switch tag {
@@ -2394,8 +2593,9 @@
// If a system modules dependency has been added to the bootclasspath
// then add its libs to the bootclasspath.
if sm, ok := android.OtherModuleProvider(ctx, module, SystemModulesProvider); ok {
- depHeaderJars := sm.HeaderJars
- deps.bootClasspath = append(deps.bootClasspath, depHeaderJars...)
+ deps.bootClasspath = append(deps.bootClasspath, sm.HeaderJars...)
+ transitiveBootClasspathHeaderJars = append(transitiveBootClasspathHeaderJars,
+ sm.TransitiveStaticLibsHeaderJars)
} else {
ctx.PropertyErrorf("boot classpath dependency %q does not provide SystemModulesProvider",
ctx.OtherModuleName(module))
@@ -2426,6 +2626,39 @@
addMissingOptionalUsesLibsFromDep(ctx, module, &j.usesLibrary)
})
+ deps.transitiveStaticLibsHeaderJars = transitiveStaticJarsHeaderLibs
+ deps.transitiveStaticLibsImplementationJars = transitiveStaticJarsImplementationLibs
+ deps.transitiveStaticLibsResourceJars = transitiveStaticJarsResourceLibs
+
+ if ctx.Config().UseTransitiveJarsInClasspath() {
+ depSet := depset.New(depset.PREORDER, nil, transitiveClasspathHeaderJars)
+ deps.classpath = depSet.ToList()
+ depSet = depset.New(depset.PREORDER, nil, transitiveBootClasspathHeaderJars)
+ deps.bootClasspath = depSet.ToList()
+ depSet = depset.New(depset.PREORDER, nil, transitiveJava9ClasspathHeaderJars)
+ deps.java9Classpath = depSet.ToList()
+ }
+
+ if ctx.Device() {
+ sdkDep := decodeSdkDep(ctx, android.SdkContext(j))
+ if sdkDep.invalidVersion {
+ ctx.AddMissingDependencies(sdkDep.bootclasspath)
+ ctx.AddMissingDependencies(sdkDep.java9Classpath)
+ } else if sdkDep.useFiles {
+ // sdkDep.jar is actually equivalent to turbine header.jar.
+ deps.classpath = append(slices.Clone(classpath(sdkDep.jars)), deps.classpath...)
+ deps.dexClasspath = append(slices.Clone(classpath(sdkDep.jars)), deps.dexClasspath...)
+ deps.aidlPreprocess = sdkDep.aidl
+ // Add the sdk module dependency to `compileDepNames`.
+ // This ensures that the dependency is reported in `module_bp_java_deps.json`
+ // TODO (b/358608607): Move this to decodeSdkDep
+ sdkSpec := android.SdkContext(j).SdkVersion(ctx)
+ j.compileDepNames = append(j.compileDepNames, fmt.Sprintf("sdk_%s_%s_android", sdkSpec.Kind.String(), sdkSpec.ApiLevel.String()))
+ } else {
+ deps.aidlPreprocess = sdkDep.aidl
+ }
+ }
+
return deps
}
@@ -2445,18 +2678,11 @@
RenameUseExclude
)
-type RenameUseElement struct {
- DepName string
- RenameUse DependencyUse
- Why string // token for determining where in the logic the decision was made.
-}
-
type JarJarProviderData struct {
// Mapping of class names: original --> renamed. If the value is "", the class will be
// renamed by the next rdep that has the jarjar_prefix attribute (or this module if it has
// attribute). Rdeps of that module will inherit the renaming.
- Rename map[string]string
- RenameUse []RenameUseElement
+ Rename map[string]string
}
func (this JarJarProviderData) GetDebugString() string {
@@ -2476,6 +2702,8 @@
func init() {
android.SetJarJarPrefixHandler(mergeJarJarPrefixes)
+
+ gob.Register(BaseJarJarProviderData{})
}
// BaseJarJarProviderData contains information that will propagate across dependencies regardless of
@@ -2525,7 +2753,7 @@
module := ctx.Module()
moduleName := module.Name()
- ctx.VisitDirectDepsIgnoreBlueprint(func(m android.Module) {
+ ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) {
tag := ctx.OtherModuleDependencyTag(m)
// This logic mirrors that in (*Module).collectDeps above. There are several places
// where we explicitly return RenameUseExclude, even though it is the default, to
@@ -2533,93 +2761,89 @@
//
// Note well: there are probably cases that are getting to the unconditional return
// and are therefore wrong.
- shouldIncludeRenames := func() (DependencyUse, string) {
+ shouldIncludeRenames := func() DependencyUse {
if moduleName == m.Name() {
- return RenameUseInclude, "name" // If we have the same module name, include the renames.
+ return RenameUseInclude // If we have the same module name, include the renames.
}
if sc, ok := module.(android.SdkContext); ok {
if ctx.Device() {
sdkDep := decodeSdkDep(ctx, sc)
if !sdkDep.invalidVersion && sdkDep.useFiles {
- return RenameUseExclude, "useFiles"
+ return RenameUseExclude
}
}
}
if IsJniDepTag(tag) || tag == certificateTag || tag == proguardRaiseTag {
- return RenameUseExclude, "tags"
+ return RenameUseExclude
}
- if _, ok := m.(SdkLibraryDependency); ok {
+ if _, ok := android.OtherModuleProvider(ctx, m, SdkLibraryInfoProvider); ok {
switch tag {
case sdkLibTag, libTag:
- return RenameUseExclude, "sdklibdep" // matches collectDeps()
+ return RenameUseExclude // matches collectDeps()
}
- return RenameUseInvalid, "sdklibdep" // dep is not used in collectDeps()
+ return RenameUseInvalid // dep is not used in collectDeps()
} else if ji, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok {
switch ji.StubsLinkType {
case Stubs:
- return RenameUseExclude, "info"
+ return RenameUseExclude
case Implementation:
- return RenameUseInclude, "info"
+ return RenameUseInclude
default:
//fmt.Printf("collectDirectDepsProviders: %v -> %v StubsLinkType unknown\n", module, m)
// Fall through to the heuristic logic.
}
- switch reflect.TypeOf(m).String() {
- case "*java.GeneratedJavaLibraryModule":
+ if _, ok := android.OtherModuleProvider(ctx, m, android.CodegenInfoProvider); ok {
// Probably a java_aconfig_library module.
- // TODO: make this check better.
- return RenameUseInclude, "reflect"
+ return RenameUseInclude
}
switch tag {
case bootClasspathTag:
- return RenameUseExclude, "tagswitch"
+ return RenameUseExclude
case sdkLibTag, libTag, instrumentationForTag:
- return RenameUseInclude, "tagswitch"
+ return RenameUseInclude
case java9LibTag:
- return RenameUseExclude, "tagswitch"
+ return RenameUseExclude
case staticLibTag:
- return RenameUseInclude, "tagswitch"
+ return RenameUseInclude
case pluginTag:
- return RenameUseInclude, "tagswitch"
+ return RenameUseInclude
case errorpronePluginTag:
- return RenameUseInclude, "tagswitch"
+ return RenameUseInclude
case exportedPluginTag:
- return RenameUseInclude, "tagswitch"
+ return RenameUseInclude
case kotlinPluginTag:
- return RenameUseInclude, "tagswitch"
+ return RenameUseInclude
default:
- return RenameUseExclude, "tagswitch"
+ return RenameUseExclude
}
- } else if _, ok := m.(android.SourceFileProducer); ok {
+ } else if _, ok := android.OtherModuleProvider(ctx, m, android.SourceFilesInfoProvider); ok {
switch tag {
case sdkLibTag, libTag, staticLibTag:
- return RenameUseInclude, "srcfile"
+ return RenameUseInclude
default:
- return RenameUseExclude, "srcfile"
+ return RenameUseExclude
}
} else if _, ok := android.OtherModuleProvider(ctx, m, android.CodegenInfoProvider); ok {
- return RenameUseInclude, "aconfig_declarations_group"
+ return RenameUseInclude
} else {
switch tag {
case bootClasspathTag:
- return RenameUseExclude, "else"
+ return RenameUseExclude
case systemModulesTag:
- return RenameUseInclude, "else"
+ return RenameUseInclude
}
}
// If we got here, choose the safer option, which may lead to a build failure, rather
// than runtime failures on the device.
- return RenameUseExclude, "end"
+ return RenameUseExclude
}
if result == nil {
result = &JarJarProviderData{
- Rename: make(map[string]string),
- RenameUse: make([]RenameUseElement, 0),
+ Rename: make(map[string]string),
}
}
- how, why := shouldIncludeRenames()
- result.RenameUse = append(result.RenameUse, RenameUseElement{DepName: m.Name(), RenameUse: how, Why: why})
+ how := shouldIncludeRenames()
if how != RenameUseInclude {
// Nothing to merge.
return
@@ -2735,22 +2959,33 @@
}
// Repackage the flags if the jarjar rule txt for the flags is generated
-func (j *Module) repackageFlagsIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string) android.Path {
+func (j *Module) repackageFlagsIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string) (android.Path, bool) {
if j.repackageJarjarRules == nil {
- return infile
+ return infile, false
}
repackagedJarjarFile := android.PathForModuleOut(ctx, "repackaged-jarjar", info, jarName)
TransformJarJar(ctx, repackagedJarjarFile, infile, j.repackageJarjarRules)
- return repackagedJarjarFile
+ return repackagedJarjarFile, true
}
-func (j *Module) jarjarIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string) android.Path {
+func (j *Module) jarjarIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string, useShards bool) (android.Path, bool) {
if j.expandJarjarRules == nil {
- return infile
+ return infile, false
}
jarjarFile := android.PathForModuleOut(ctx, "jarjar", info, jarName)
- TransformJarJar(ctx, jarjarFile, infile, j.expandJarjarRules)
- return jarjarFile
+
+ totalShards := 1
+ if useShards {
+ totalShardsStr := j.properties.Jarjar_shards.GetOrDefault(ctx, "1")
+ ts, err := strconv.Atoi(totalShardsStr)
+ if err != nil {
+ ctx.PropertyErrorf("jarjar_shards", "jarjar_shards must be an integer represented as a string")
+ return infile, false
+ }
+ totalShards = ts
+ }
+ TransformJarJarWithShards(ctx, jarjarFile, infile, j.expandJarjarRules, totalShards)
+ return jarjarFile, true
}
diff --git a/java/boot_jars.go b/java/boot_jars.go
index 6223ded..3c3bd55 100644
--- a/java/boot_jars.go
+++ b/java/boot_jars.go
@@ -21,7 +21,7 @@
// isActiveModule returns true if the given module should be considered for boot
// jars, i.e. if it's enabled and the preferred one in case of source and
// prebuilt alternatives.
-func isActiveModule(ctx android.ConfigAndErrorContext, module android.Module) bool {
+func isActiveModule(ctx android.ConfigurableEvaluatorContext, module android.Module) bool {
if !module.Enabled(ctx) {
return false
}
diff --git a/java/bootclasspath.go b/java/bootclasspath.go
index 029f6f6..3413cf3 100644
--- a/java/bootclasspath.go
+++ b/java/bootclasspath.go
@@ -29,7 +29,7 @@
func registerBootclasspathBuildComponents(ctx android.RegistrationContext) {
ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("bootclasspath_deps", bootclasspathDepsMutator).Parallel()
+ ctx.BottomUp("bootclasspath_deps", bootclasspathDepsMutator)
})
}
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index bce507a..d6777e5 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -23,7 +23,6 @@
"android/soong/android"
"android/soong/dexpreopt"
- "android/soong/testing"
"github.com/google/blueprint/proptools"
@@ -84,10 +83,6 @@
return true
}
-// Contents of bootclasspath fragments in an apex are considered to be directly in the apex, as if
-// they were listed in java_libs.
-func (b bootclasspathFragmentContentDependencyTag) CopyDirectlyInAnyApex() {}
-
// Contents of bootclasspath fragments require files from prebuilt apex files.
func (b bootclasspathFragmentContentDependencyTag) RequiresFilesFromPrebuiltApex() {}
@@ -97,7 +92,6 @@
var _ android.ExcludeFromVisibilityEnforcementTag = bootclasspathFragmentContentDepTag
var _ android.ReplaceSourceWithPrebuilt = bootclasspathFragmentContentDepTag
var _ android.SdkMemberDependencyTag = bootclasspathFragmentContentDepTag
-var _ android.CopyDirectlyInAnyApexTag = bootclasspathFragmentContentDepTag
var _ android.RequiresFilesFromPrebuiltApexTag = bootclasspathFragmentContentDepTag
func IsBootclasspathFragmentContentDepTag(tag blueprint.DependencyTag) bool {
@@ -112,7 +106,7 @@
// property.
//
// The order of this list matters as it is the order that is used in the bootclasspath.
- Contents []string
+ Contents proptools.Configurable[[]string] `android:"arch_variant"`
// The properties for specifying the API stubs provided by this fragment.
BootclasspathAPIProperties
@@ -296,8 +290,8 @@
return m
}
-func (m *BootclasspathFragmentModule) bootclasspathFragmentPropertyCheck(ctx android.EarlyModuleContext) {
- contents := m.properties.Contents
+func (m *BootclasspathFragmentModule) bootclasspathFragmentPropertyCheck(ctx android.ModuleContext) {
+ contents := m.properties.Contents.GetOrDefault(ctx, nil)
if len(contents) == 0 {
ctx.PropertyErrorf("contents", "required property is missing")
return
@@ -399,11 +393,9 @@
return i.profileInstallPathInApex
}
-func (b *BootclasspathFragmentModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
- tag := ctx.OtherModuleDependencyTag(dep)
-
+func (b *BootclasspathFragmentModule) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
// If the module is a default module, do not check the tag
- if _, ok := dep.(*Defaults); ok {
+ if tag == android.DefaultsDepTag {
return true
}
if IsBootclasspathFragmentContentDepTag(tag) {
@@ -414,7 +406,13 @@
// Cross-cutting metadata dependencies are metadata.
return false
}
- panic(fmt.Errorf("boot_image module %q should not have a dependency on %q via tag %s", b, dep, android.PrettyPrintTag(tag)))
+ // Dependency to the bootclasspath fragment of another apex
+ // e.g. concsrypt-bootclasspath-fragment --> art-bootclasspath-fragment
+ if tag == bootclasspathFragmentDepTag {
+ return false
+
+ }
+ panic(fmt.Errorf("boot_image module %q should not have a dependency tag %s", b, android.PrettyPrintTag(tag)))
}
func (b *BootclasspathFragmentModule) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
@@ -429,7 +427,7 @@
module := ctx.Module()
_, isSourceModule := module.(*BootclasspathFragmentModule)
- for _, name := range b.properties.Contents {
+ for _, name := range b.properties.Contents.GetOrDefault(ctx, nil) {
// A bootclasspath_fragment must depend only on other source modules, while the
// prebuilt_bootclasspath_fragment must only depend on other prebuilt modules.
//
@@ -463,6 +461,12 @@
// Add a dependency onto the dex2oat tool which is needed for creating the boot image. The
// path is retrieved from the dependency by GetGlobalSoongConfig(ctx).
dexpreopt.RegisterToolDeps(ctx)
+
+ // Add a dependency to `all_apex_contributions` to determine if prebuilts are active.
+ // If prebuilts are active, `contents` validation on the source bootclasspath fragment should be disabled.
+ if _, isPrebuiltModule := ctx.Module().(*PrebuiltBootclasspathFragmentModule); !isPrebuiltModule {
+ ctx.AddDependency(b, android.AcDepTag, "all_apex_contributions")
+ }
}
func (b *BootclasspathFragmentModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
@@ -509,10 +513,9 @@
// be output to Make but it does not really matter which variant is output. The default/platform
// variant is the first (ctx.PrimaryModule()) and is usually hidden from make so this just picks
// the last variant (ctx.FinalModule()).
- if ctx.Module() != ctx.FinalModule() {
+ if !ctx.IsFinalModule(ctx.Module()) {
b.HideFromMake()
}
- android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
}
// getProfileProviderApex returns the name of the apex that provides a boot image profile, or an
@@ -578,7 +581,7 @@
return global.ArtApexJars
}
- possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, b.properties.Contents, bootclasspathFragmentContentDepTag)
+ possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, b.properties.Contents.GetOrDefault(ctx, nil), bootclasspathFragmentContentDepTag)
jars, unknown := global.ApexBootJars.Filter(possibleUpdatableModules)
// TODO(satayev): for apex_test we want to include all contents unconditionally to classpaths
@@ -590,7 +593,7 @@
} else if android.InList("test_framework-apexd", possibleUpdatableModules) {
jars = jars.Append("com.android.apex.test_package", "test_framework-apexd")
} else if global.ApexBootJars.Len() != 0 {
- unknown = android.RemoveListFromList(unknown, b.properties.Coverage.Contents)
+ unknown = android.RemoveListFromList(unknown, b.properties.Coverage.Contents.GetOrDefault(ctx, nil))
_, unknown = android.RemoveFromList("core-icu4j", unknown)
// This module only exists in car products.
// So ignore it even if it is not in PRODUCT_APEX_BOOT_JARS.
@@ -836,8 +839,8 @@
}
// Collect information for opening IDE project files in java/jdeps.go.
-func (b *BootclasspathFragmentModule) IDEInfo(dpInfo *android.IdeInfo) {
- dpInfo.Deps = append(dpInfo.Deps, b.properties.Contents...)
+func (b *BootclasspathFragmentModule) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
+ dpInfo.Deps = append(dpInfo.Deps, b.properties.Contents.GetOrDefault(ctx, nil)...)
}
type bootclasspathFragmentMemberType struct {
@@ -913,7 +916,7 @@
module := variant.(*BootclasspathFragmentModule)
b.Image_name = module.properties.Image_name
- b.Contents = module.properties.Contents
+ b.Contents = module.properties.Contents.GetOrDefault(ctx.SdkModuleContext(), nil)
// Get the hidden API information from the module.
mctx := ctx.SdkModuleContext()
@@ -1093,22 +1096,10 @@
return &output
}
+// DEPRECATED: this information is now generated in the context of the top level prebuilt apex.
// produceBootImageProfile extracts the boot image profile from the APEX if available.
func (module *PrebuiltBootclasspathFragmentModule) produceBootImageProfile(ctx android.ModuleContext) android.WritablePath {
- // This module does not provide a boot image profile.
- if module.getProfileProviderApex(ctx) == "" {
- return nil
- }
-
- di, err := android.FindDeapexerProviderForModule(ctx)
- if err != nil {
- // An error was found, possibly due to multiple apexes in the tree that export this library
- // Defer the error till a client tries to call getProfilePath
- module.profilePathErr = err
- return nil // An error has been reported by FindDeapexerProviderForModule.
- }
-
- return di.PrebuiltExportPath(ProfileInstallPathInApex)
+ return android.PathForModuleInstall(ctx, "intentionally_no_longer_supported")
}
func (b *PrebuiltBootclasspathFragmentModule) getProfilePath() android.Path {
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index 60f1a50..d181ce0 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -31,6 +31,7 @@
)
func TestBootclasspathFragment_UnknownImageName(t *testing.T) {
+ t.Parallel()
prepareForTestWithBootclasspathFragment.
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
`\Qimage_name: unknown image name "unknown", expected "art"\E`)).
@@ -50,6 +51,7 @@
}
func TestPrebuiltBootclasspathFragment_UnknownImageName(t *testing.T) {
+ t.Parallel()
prepareForTestWithBootclasspathFragment.
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
`\Qimage_name: unknown image name "unknown", expected "art"\E`)).
@@ -68,6 +70,7 @@
}
func TestBootclasspathFragmentInconsistentArtConfiguration_Platform(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForTestWithBootclasspathFragment,
dexpreopt.FixtureSetArtBootJars("platform:foo", "apex:bar"),
@@ -99,6 +102,7 @@
}
func TestBootclasspathFragmentInconsistentArtConfiguration_ApexMixture(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForTestWithBootclasspathFragment,
dexpreopt.FixtureSetArtBootJars("apex1:foo", "apex2:bar"),
@@ -131,6 +135,7 @@
}
func TestBootclasspathFragment_Coverage(t *testing.T) {
+ t.Parallel()
prepareWithBp := android.FixtureWithRootAndroidBp(`
bootclasspath_fragment {
name: "myfragment",
@@ -191,7 +196,8 @@
checkContents := func(t *testing.T, result *android.TestResult, expected ...string) {
module := result.Module("myfragment", "android_common").(*BootclasspathFragmentModule)
- android.AssertArrayString(t, "contents property", expected, module.properties.Contents)
+ eval := module.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+ android.AssertArrayString(t, "contents property", expected, module.properties.Contents.GetOrDefault(eval, nil))
}
preparer := android.GroupFixturePreparers(
@@ -203,11 +209,13 @@
)
t.Run("without coverage", func(t *testing.T) {
+ t.Parallel()
result := preparer.RunTest(t)
checkContents(t, result, "mybootlib")
})
t.Run("with coverage", func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithFrameworkJacocoInstrumentation,
preparer,
diff --git a/java/builder.go b/java/builder.go
index 49207e5..22dad10 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -46,6 +46,7 @@
`mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
`(if [ -s $srcJarDir/list ] || [ -s $out.rsp ] ; then ` +
+ `${config.FindInputDeltaCmd} --template '' --target "$out" --inputs_file "$out.rsp" && ` +
`${config.SoongJavacWrapper} $javaTemplate${config.JavacCmd} ` +
`${config.JavacHeapFlags} ${config.JavacVmFlags} ${config.CommonJdkFlags} ` +
`$processorpath $processor $javacFlags $bootClasspath $classpath ` +
@@ -55,8 +56,10 @@
`$zipTemplate${config.SoongZipCmd} -jar -o $out.tmp -C $outDir -D $outDir && ` +
`if ! cmp -s "$out.tmp" "$out"; then mv "$out.tmp" "$out"; fi && ` +
`if ! cmp -s "$annoSrcJar.tmp" "$annoSrcJar"; then mv "$annoSrcJar.tmp" "$annoSrcJar"; fi && ` +
+ `if [ -f "$out.pc_state.new" ]; then mv "$out.pc_state.new" "$out.pc_state"; fi && ` +
`rm -rf "$srcJarDir" "$outDir"`,
CommandDeps: []string{
+ "${config.FindInputDeltaCmd}",
"${config.JavacCmd}",
"${config.SoongZipCmd}",
"${config.ZipSyncCmd}",
@@ -165,7 +168,7 @@
"${config.JavaCmd}",
},
Rspfile: "$out.rsp",
- RspfileContent: "$in",
+ RspfileContent: "$in_newline",
Restat: true,
},
&remoteexec.REParams{Labels: map[string]string{"type": "tool", "name": "turbine"},
@@ -223,6 +226,12 @@
},
"jarArgs")
+ extractR8Rules = pctx.AndroidStaticRule("extractR8Rules",
+ blueprint.RuleParams{
+ Command: `${config.ExtractR8RulesCmd} --rules-output $out --include-origin-comments $in`,
+ CommandDeps: []string{"${config.ExtractR8RulesCmd}"},
+ })
+
jarjar = pctx.AndroidStaticRule("jarjar",
blueprint.RuleParams{
Command: "" +
@@ -235,12 +244,12 @@
// for newly repackaged classes. Dropping @UnsupportedAppUsage on repackaged classes
// avoids adding new hiddenapis after jarjar'ing.
" -DremoveAndroidCompatAnnotations=true" +
- " -jar ${config.JarjarCmd} process $rulesFile $in $out && " +
+ " -jar ${config.JarjarCmd} process $rulesFile $in $out $total_shards $shard_index && " +
// Turn a missing output file into a ninja error
`[ -e ${out} ] || (echo "Missing output file"; exit 1)`,
CommandDeps: []string{"${config.JavaCmd}", "${config.JarjarCmd}", "$rulesFile"},
},
- "rulesFile")
+ "rulesFile", "total_shards", "shard_index")
packageCheck = pctx.AndroidStaticRule("packageCheck",
blueprint.RuleParams{
@@ -260,9 +269,16 @@
ravenizer = pctx.AndroidStaticRule("ravenizer",
blueprint.RuleParams{
- Command: "rm -f $out && ${ravenizer} --in-jar $in --out-jar $out",
+ Command: "rm -f $out && ${ravenizer} --in-jar $in --out-jar $out $ravenizerArgs",
CommandDeps: []string{"${ravenizer}"},
},
+ "ravenizerArgs")
+
+ apimapper = pctx.AndroidStaticRule("apimapper",
+ blueprint.RuleParams{
+ Command: "${apimapper} --in-jar $in --out-jar $out",
+ CommandDeps: []string{"${apimapper}"},
+ },
)
zipalign = pctx.AndroidStaticRule("zipalign",
@@ -294,7 +310,7 @@
gatherReleasedFlaggedApisRule = pctx.AndroidStaticRule("gatherReleasedFlaggedApisRule",
blueprint.RuleParams{
- Command: `${aconfig} dump-cache --dedup --format='{fully_qualified_name}={state:bool}' ` +
+ Command: `${aconfig} dump-cache --dedup --format='{fully_qualified_name}' ` +
`--out ${out} ` +
`${flags_path} ` +
`${filter_args} `,
@@ -315,6 +331,7 @@
pctx.HostBinToolVariable("aconfig", "aconfig")
pctx.HostBinToolVariable("ravenizer", "ravenizer")
+ pctx.HostBinToolVariable("apimapper", "apimapper")
pctx.HostBinToolVariable("keep-flagged-apis", "keep-flagged-apis")
}
@@ -448,9 +465,10 @@
const srcJarArgsLimit = 32 * 1024
if len(srcJarArgs) > srcJarArgsLimit {
srcJarRspFile := android.PathForModuleOut(ctx, "turbine", "srcjars.rsp")
- android.WriteFileRule(ctx, srcJarRspFile, srcJarArgs)
+ android.WriteFileRule(ctx, srcJarRspFile, strings.Join(srcJars.Strings(), "\n"))
srcJarArgs = "@" + srcJarRspFile.String()
implicits = append(implicits, srcJarRspFile)
+ rspFiles = append(rspFiles, srcJarRspFile)
rbeInputs = append(rbeInputs, srcJarRspFile)
} else {
rbeInputs = append(rbeInputs, srcJars...)
@@ -480,7 +498,7 @@
const classpathLimit = 32 * 1024
if len(classpathFlags) > classpathLimit {
classpathRspFile := android.PathForModuleOut(ctx, dir, "classpath.rsp")
- android.WriteFileRule(ctx, classpathRspFile, classpathFlags)
+ android.WriteFileRule(ctx, classpathRspFile, strings.Join(classpath.Strings(), "\n"))
classpathFlags = "@" + classpathRspFile.String()
implicits = append(implicits, classpathRspFile)
rspFiles = append(rspFiles, classpathRspFile)
@@ -695,6 +713,7 @@
// Remove any module-info.class files that may have come from prebuilt jars, they cause problems
// for downstream tools like desugar.
jarArgs = append(jarArgs, "-stripFile module-info.class")
+ jarArgs = append(jarArgs, "-stripFile META-INF/versions/*/module-info.class")
if stripDirEntries {
jarArgs = append(jarArgs, "-D")
@@ -727,6 +746,16 @@
})
}
+func TransformJarToR8Rules(ctx android.ModuleContext, outputFile android.WritablePath,
+ jar android.Path) {
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: extractR8Rules,
+ Output: outputFile,
+ Input: jar,
+ })
+}
+
func convertImplementationJarToHeaderJar(ctx android.ModuleContext, implementationJarFile android.Path,
headerJarFile android.WritablePath) {
ctx.Build(pctx, android.BuildParams{
@@ -738,16 +767,58 @@
func TransformJarJar(ctx android.ModuleContext, outputFile android.WritablePath,
classesJar android.Path, rulesFile android.Path) {
+ TransformJarJarWithShards(ctx, outputFile, classesJar, rulesFile, 1)
+}
+
+func TransformJarJarWithShards(ctx android.ModuleContext, outputFile android.WritablePath,
+ classesJar android.Path, rulesFile android.Path, totalShards int) {
+
+ // If the total number of shards is 1, just run jarjar as-is, with `total_shards` = 1
+ // and `shard_index` == 0, which effectively disables sharding
+ if totalShards == 1 {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: jarjar,
+ Description: "jarjar",
+ Output: outputFile,
+ Input: classesJar,
+ Implicit: rulesFile,
+ Args: map[string]string{
+ "rulesFile": rulesFile.String(),
+ "total_shards": "1",
+ "shard_index": "0",
+ },
+ })
+ return
+ }
+
+ // Otherwise, run multiple jarjar instances and use merge_zips to combine the output.
+ tempJars := make([]android.Path, 0)
+ totalStr := strconv.Itoa(totalShards)
+ for i := 0; i < totalShards; i++ {
+ iStr := strconv.Itoa(i)
+ tempOut := outputFile.ReplaceExtension(ctx, "-"+iStr+".jar")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: jarjar,
+ Description: "jarjar (" + iStr + "/" + totalStr + ")",
+ Output: tempOut,
+ Input: classesJar,
+ Implicit: rulesFile,
+ Args: map[string]string{
+ "rulesFile": rulesFile.String(),
+ "total_shards": totalStr,
+ "shard_index": iStr,
+ },
+ })
+ tempJars = append(tempJars, tempOut)
+ }
+
ctx.Build(pctx, android.BuildParams{
- Rule: jarjar,
- Description: "jarjar",
+ Rule: combineJar,
+ Description: "merge jarjar shards",
Output: outputFile,
- Input: classesJar,
- Implicit: rulesFile,
- Args: map[string]string{
- "rulesFile": rulesFile.String(),
- },
+ Inputs: tempJars,
})
+
}
func CheckJarPackages(ctx android.ModuleContext, outputFile android.WritablePath,
@@ -774,12 +845,15 @@
}
func TransformRavenizer(ctx android.ModuleContext, outputFile android.WritablePath,
- inputFile android.Path) {
+ inputFile android.Path, ravenizerArgs string) {
ctx.Build(pctx, android.BuildParams{
Rule: ravenizer,
Description: "ravenizer",
Output: outputFile,
Input: inputFile,
+ Args: map[string]string{
+ "ravenizerArgs": ravenizerArgs,
+ },
})
}
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index 18a5dae..88a8fb8 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -18,9 +18,10 @@
import (
"fmt"
+ "strings"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
- "strings"
"android/soong/android"
)
@@ -103,7 +104,11 @@
func gatherPossibleApexModuleNamesAndStems(ctx android.ModuleContext, contents []string, tag blueprint.DependencyTag) []string {
set := map[string]struct{}{}
for _, name := range contents {
- dep, _ := ctx.GetDirectDepWithTag(name, tag).(android.Module)
+ dep := ctx.GetDirectDepWithTag(name, tag)
+ if dep == nil && ctx.Config().AllowMissingDependencies() {
+ // Ignore apex boot jars from dexpreopt if it does not exist, and missing deps are allowed.
+ continue
+ }
set[ModuleStemForDeapexing(dep)] = struct{}{}
if m, ok := dep.(ModuleWithStem); ok {
set[m.Stem()] = struct{}{}
diff --git a/java/code_metadata_test.go b/java/code_metadata_test.go
deleted file mode 100644
index 9dc9a22..0000000
--- a/java/code_metadata_test.go
+++ /dev/null
@@ -1,115 +0,0 @@
-package java
-
-import (
- "strings"
- "testing"
-
- "android/soong/android"
- soongTesting "android/soong/testing"
- "android/soong/testing/code_metadata_internal_proto"
-
- "google.golang.org/protobuf/proto"
-)
-
-func TestCodeMetadata(t *testing.T) {
- bp := `code_metadata {
- name: "module-name",
- teamId: "12345",
- code: [
- "foo",
- ]
- }
-
- java_sdk_library {
- name: "foo",
- srcs: ["a.java"],
- }`
- result := runCodeMetadataTest(t, android.FixtureExpectsNoErrors, bp)
-
- module := result.ModuleForTests("module-name", "")
-
- // Check that the provider has the right contents
- data, _ := android.OtherModuleProvider(result, module.Module(), soongTesting.CodeMetadataProviderKey)
- if !strings.HasSuffix(
- data.IntermediatePath.String(), "/intermediateCodeMetadata.pb",
- ) {
- t.Errorf(
- "Missing intermediates path in provider: %s",
- data.IntermediatePath.String(),
- )
- }
-
- metadata := android.ContentFromFileRuleForTests(t, result.TestContext,
- module.Output(data.IntermediatePath.String()))
-
- metadataList := make([]*code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership, 0, 2)
- teamId := "12345"
- bpFilePath := "Android.bp"
- targetName := "foo"
- srcFile := []string{"a.java"}
- expectedMetadataProto := code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership{
- TrendyTeamId: &teamId,
- TargetName: &targetName,
- Path: &bpFilePath,
- SourceFiles: srcFile,
- }
- metadataList = append(metadataList, &expectedMetadataProto)
-
- CodeMetadataMetadata := code_metadata_internal_proto.CodeMetadataInternal{TargetOwnershipList: metadataList}
- protoData, _ := proto.Marshal(&CodeMetadataMetadata)
- expectedMetadata := string(protoData)
-
- if metadata != expectedMetadata {
- t.Errorf(
- "Retrieved metadata: %s is not equal to expectedMetadata: %s", metadata,
- expectedMetadata,
- )
- }
-
- // Tests for all_test_spec singleton.
- singleton := result.SingletonForTests("all_code_metadata")
- rule := singleton.Rule("all_code_metadata_rule")
- prebuiltOs := result.Config.PrebuiltOS()
- expectedCmd := "out/soong/host/" + prebuiltOs + "/bin/metadata -rule code_metadata -inputFile out/soong/all_code_metadata_paths.rsp -outputFile out/soong/ownership/all_code_metadata.pb"
- expectedOutputFile := "out/soong/ownership/all_code_metadata.pb"
- expectedInputFile := "out/soong/.intermediates/module-name/intermediateCodeMetadata.pb"
- if !strings.Contains(
- strings.TrimSpace(rule.Output.String()),
- expectedOutputFile,
- ) {
- t.Errorf(
- "Retrieved singletonOutputFile: %s is not equal to expectedSingletonOutputFile: %s",
- rule.Output.String(), expectedOutputFile,
- )
- }
-
- if !strings.Contains(
- strings.TrimSpace(rule.Inputs[0].String()),
- expectedInputFile,
- ) {
- t.Errorf(
- "Retrieved singletonInputFile: %s is not equal to expectedSingletonInputFile: %s",
- rule.Inputs[0].String(), expectedInputFile,
- )
- }
-
- if !strings.Contains(
- strings.TrimSpace(rule.RuleParams.Command),
- expectedCmd,
- ) {
- t.Errorf(
- "Retrieved cmd: %s doesn't contain expectedCmd: %s",
- rule.RuleParams.Command, expectedCmd,
- )
- }
-}
-func runCodeMetadataTest(
- t *testing.T, errorHandler android.FixtureErrorHandler, bp string,
-) *android.TestResult {
- return android.GroupFixturePreparers(
- soongTesting.PrepareForTestWithTestingBuildComponents, prepareForJavaTest,
- PrepareForTestWithJavaSdkLibraryFiles, FixtureWithLastReleaseApis("foo"),
- ).
- ExtendWithErrorHandler(errorHandler).
- RunTestWithBp(t, bp)
-}
diff --git a/java/config/Android.bp b/java/config/Android.bp
index bfe83ab..6217390 100644
--- a/java/config/Android.bp
+++ b/java/config/Android.bp
@@ -17,4 +17,8 @@
"kotlin.go",
"makevars.go",
],
+ visibility: [
+ "//build/soong:__subpackages__",
+ "//external/error_prone/soong",
+ ],
}
diff --git a/java/config/config.go b/java/config/config.go
index a50c1b4..71025de 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -52,6 +52,7 @@
"core-icu4j",
"core-oj",
"core-libart",
+ "wear-sdk.impl",
}
)
@@ -96,11 +97,19 @@
"-JDcom.android.tools.r8.emitRecordAnnotationsInDex",
"-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex",
}, dexerJavaVmFlagsList...), " "))
- pctx.StaticVariable("R8Flags", strings.Join(append([]string{
- "-JXmx4096M",
- "-JDcom.android.tools.r8.emitRecordAnnotationsInDex",
- "-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex",
- }, dexerJavaVmFlagsList...), " "))
+
+ pctx.VariableFunc("R8Flags", func(ctx android.PackageVarContext) string {
+ r8flags := append([]string{
+ "-JXmx4096M",
+ "-JDcom.android.tools.r8.emitRecordAnnotationsInDex",
+ "-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex",
+ }, dexerJavaVmFlagsList...)
+ if r8DumpDir := ctx.Config().Getenv("R8_DUMP_DIRECTORY"); r8DumpDir != "" {
+ r8flags = append(r8flags, "-JDcom.android.tools.r8.dumpinputtodirectory="+r8DumpDir)
+ }
+ return strings.Join(r8flags, " ")
+
+ })
pctx.StaticVariable("CommonJdkFlags", strings.Join([]string{
`-Xmaxerrs 9999999`,
@@ -144,11 +153,13 @@
pctx.SourcePathVariable("JmodCmd", "${JavaToolchain}/jmod")
pctx.SourcePathVariable("JrtFsJar", "${JavaHome}/lib/jrt-fs.jar")
pctx.SourcePathVariable("JavaKytheExtractorJar", "prebuilts/build-tools/common/framework/javac_extractor.jar")
+ pctx.SourcePathVariable("KotlinKytheExtractor", "prebuilts/build-tools/${hostPrebuiltTag}/bin/kotlinc_extractor")
pctx.SourcePathVariable("Ziptime", "prebuilts/build-tools/${hostPrebuiltTag}/bin/ziptime")
pctx.SourcePathVariable("ResourceProcessorBusyBox", "prebuilts/bazel/common/android_tools/android_tools/all_android_tools_deploy.jar")
pctx.HostBinToolVariable("GenKotlinBuildFileCmd", "gen-kotlin-build-file")
+ pctx.HostBinToolVariable("FindInputDeltaCmd", "find_input_delta")
pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh")
pctx.SourcePathVariable("PackageCheckCmd", "build/soong/scripts/package-check.sh")
@@ -160,6 +171,7 @@
pctx.HostBinToolVariable("ApiCheckCmd", "apicheck")
pctx.HostBinToolVariable("D8Cmd", "d8")
pctx.HostBinToolVariable("R8Cmd", "r8")
+ pctx.HostBinToolVariable("ExtractR8RulesCmd", "extract-r8-rules")
pctx.HostBinToolVariable("ResourceShrinkerCmd", "resourceshrinker")
pctx.HostBinToolVariable("HiddenAPICmd", "hiddenapi")
pctx.HostBinToolVariable("ExtractApksCmd", "extract_apks")
diff --git a/java/config/kotlin.go b/java/config/kotlin.go
index e5e187c..ffb025d 100644
--- a/java/config/kotlin.go
+++ b/java/config/kotlin.go
@@ -21,6 +21,7 @@
KotlincIllegalFlags = []string{
"-no-jdk",
"-no-stdlib",
+ "-language-version",
}
)
@@ -50,4 +51,11 @@
}, " "))
pctx.StaticVariable("KotlincGlobalFlags", strings.Join([]string{}, " "))
+ // Use KotlincKytheGlobalFlags to prevent kotlinc version skew issues between android and
+ // g3 kythe indexers.
+ // This is necessary because there might be instances of kotlin code in android
+ // platform that are not fully compatible with the kotlinc used in g3 kythe indexers.
+ // e.g. uninitialized variables are a warning in 1.*, but an error in 2.*
+ // https://github.com/JetBrains/kotlin/blob/master/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt#L748
+ pctx.StaticVariable("KotlincKytheGlobalFlags", strings.Join([]string{}, " "))
}
diff --git a/java/container_test.go b/java/container_test.go
index 25cfa4c..515236d 100644
--- a/java/container_test.go
+++ b/java/container_test.go
@@ -26,6 +26,7 @@
}
func TestJavaContainersModuleProperties(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
).RunTestWithBp(t, `
diff --git a/java/core-libraries/Android.bp b/java/core-libraries/Android.bp
index cee7a19..8c808e4 100644
--- a/java/core-libraries/Android.bp
+++ b/java/core-libraries/Android.bp
@@ -38,12 +38,53 @@
visibility: ["//visibility:public"],
sdk_version: "none",
system_modules: "none",
+ is_stubs_module: true,
+}
+
+soong_config_module_type {
+ name: "core_current_stubs_soong_config_defaults",
+ module_type: "java_defaults",
+ config_namespace: "ANDROID",
+ bool_variables: [
+ "release_hidden_api_exportable_stubs",
+ ],
+ properties: [
+ "dist.targets",
+ "dist.dest",
+ ],
+}
+
+core_current_stubs_soong_config_defaults {
+ name: "core_current_stubs_everything_soong_config_defaults",
+ soong_config_variables: {
+ release_hidden_api_exportable_stubs: {
+ conditions_default: {
+ dist: {
+ targets: dist_targets,
+ dest: "core.current.stubs.jar",
+ },
+ },
+ },
+ },
+}
+
+core_current_stubs_soong_config_defaults {
+ name: "core_current_stubs_exportable_soong_config_defaults",
+ soong_config_variables: {
+ release_hidden_api_exportable_stubs: {
+ dist: {
+ targets: dist_targets,
+ dest: "core.current.stubs.jar",
+ },
+ },
+ },
}
java_library {
name: "core.current.stubs",
defaults: [
"core.current.stubs.defaults",
+ "core_current_stubs_everything_soong_config_defaults",
],
static_libs: [
"art.module.public.api.stubs",
@@ -75,16 +116,13 @@
name: "core.current.stubs.exportable",
defaults: [
"core.current.stubs.defaults",
+ "core_current_stubs_exportable_soong_config_defaults",
],
static_libs: [
"art.module.public.api.stubs.exportable",
"conscrypt.module.public.api.stubs.exportable",
"i18n.module.public.api.stubs.exportable",
],
- dist: {
- targets: dist_targets,
- dest: "core.current.stubs.jar",
- },
}
// Distributed with the SDK for turning into system modules to compile apps
@@ -94,10 +132,10 @@
// prebuilts/sdk/update_prebuilts.py script to update the prebuilts/sdk
// directory.
java_library {
- name: "core-current-stubs-for-system-modules",
+ name: "core-current-stubs-for-system-modules-exportable",
visibility: ["//development/sdk"],
static_libs: [
- "core.current.stubs",
+ "core.current.stubs.exportable",
// This one is not on device but it's needed when javac compiles code
// containing lambdas.
"core-lambda-stubs-for-system-modules",
@@ -117,6 +155,19 @@
],
}
+java_library {
+ name: "core-current-stubs-for-system-modules",
+ visibility: ["//development/sdk"],
+ static_libs: [
+ "core.current.stubs",
+ // This one is not on device but it's needed when javac compiles code
+ // containing lambdas.
+ "core-lambda-stubs-for-system-modules",
+ ],
+ sdk_version: "none",
+ system_modules: "none",
+}
+
// Defaults module to strip out android annotations
java_defaults {
name: "system-modules-no-annotations",
@@ -289,6 +340,7 @@
sdk_version: "none",
system_modules: "none",
patch_module: "java.base",
+ is_stubs_module: true,
}
// Same as legacy.core.platform.api.stubs, but android annotations are
@@ -307,6 +359,7 @@
"legacy.core.platform.api.stubs",
],
patch_module: "java.base",
+ is_stubs_module: true,
}
java_library {
@@ -339,6 +392,7 @@
"stable.core.platform.api.stubs",
],
patch_module: "java.base",
+ is_stubs_module: true,
}
// Used when compiling higher-level code against *.core.platform.api.stubs.
diff --git a/java/core-libraries/jarjar-strip-annotations-rules.txt b/java/core-libraries/jarjar-strip-annotations-rules.txt
index a1c261b..c74eaca 100644
--- a/java/core-libraries/jarjar-strip-annotations-rules.txt
+++ b/java/core-libraries/jarjar-strip-annotations-rules.txt
@@ -2,3 +2,4 @@
strip-annotation android.annotation.Nullable
strip-annotation androidx.annotation.RecentlyNonNull
strip-annotation androidx.annotation.RecentlyNullable
+strip-annotation android.annotation.FlaggedApi
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 63b69d0..04def3e 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -20,6 +20,8 @@
"android/soong/android"
"android/soong/dexpreopt"
+
+ "github.com/google/blueprint/depset"
)
type DeviceHostConverter struct {
@@ -96,6 +98,10 @@
ctx.PropertyErrorf("libs", "at least one dependency is required")
}
+ var transitiveHeaderJars []depset.DepSet[android.Path]
+ var transitiveImplementationJars []depset.DepSet[android.Path]
+ var transitiveResourceJars []depset.DepSet[android.Path]
+
ctx.VisitDirectDepsWithTag(deviceHostConverterDepTag, func(m android.Module) {
if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok {
d.headerJars = append(d.headerJars, dep.HeaderJars...)
@@ -105,6 +111,10 @@
d.srcJarArgs = append(d.srcJarArgs, dep.SrcJarArgs...)
d.srcJarDeps = append(d.srcJarDeps, dep.SrcJarDeps...)
+
+ transitiveHeaderJars = append(transitiveHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+ transitiveImplementationJars = append(transitiveImplementationJars, dep.TransitiveStaticLibsImplementationJars)
+ transitiveResourceJars = append(transitiveResourceJars, dep.TransitiveStaticLibsResourceJars)
} else {
ctx.PropertyErrorf("libs", "module %q cannot be used as a dependency", ctx.OtherModuleName(m))
}
@@ -130,17 +140,23 @@
d.combinedHeaderJar = d.headerJars[0]
}
- android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
- HeaderJars: d.headerJars,
- ImplementationAndResourcesJars: d.implementationAndResourceJars,
- ImplementationJars: d.implementationJars,
- ResourceJars: d.resourceJars,
- SrcJarArgs: d.srcJarArgs,
- SrcJarDeps: d.srcJarDeps,
- StubsLinkType: Implementation,
+ javaInfo := &JavaInfo{
+ HeaderJars: d.headerJars,
+ LocalHeaderJars: d.headerJars,
+ TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, nil, transitiveHeaderJars),
+ TransitiveStaticLibsImplementationJars: depset.New(depset.PREORDER, nil, transitiveImplementationJars),
+ TransitiveStaticLibsResourceJars: depset.New(depset.PREORDER, nil, transitiveResourceJars),
+ ImplementationAndResourcesJars: d.implementationAndResourceJars,
+ ImplementationJars: d.implementationJars,
+ ResourceJars: d.resourceJars,
+ SrcJarArgs: d.srcJarArgs,
+ SrcJarDeps: d.srcJarDeps,
+ StubsLinkType: Implementation,
// TODO: Not sure if aconfig flags that have been moved between device and host variants
// make sense.
- })
+ }
+ setExtraJavaInfo(ctx, d, javaInfo)
+ android.SetProvider(ctx, JavaInfoProvider, javaInfo)
}
@@ -192,7 +208,7 @@
// implement the following interface for IDE completion.
var _ android.IDEInfo = (*DeviceHostConverter)(nil)
-func (d *DeviceHostConverter) IDEInfo(ideInfo *android.IdeInfo) {
+func (d *DeviceHostConverter) IDEInfo(ctx android.BaseModuleContext, ideInfo *android.IdeInfo) {
ideInfo.Deps = append(ideInfo.Deps, d.properties.Libs...)
ideInfo.Libs = append(ideInfo.Libs, d.properties.Libs...)
}
diff --git a/java/device_host_converter_test.go b/java/device_host_converter_test.go
index 6ccc5c1..45369e2 100644
--- a/java/device_host_converter_test.go
+++ b/java/device_host_converter_test.go
@@ -22,6 +22,7 @@
)
func TestDeviceForHost(t *testing.T) {
+ t.Parallel()
bp := `
java_library {
name: "device_module",
@@ -102,6 +103,7 @@
}
func TestHostForDevice(t *testing.T) {
+ t.Parallel()
bp := `
java_library_host {
name: "host_module",
diff --git a/java/dex.go b/java/dex.go
index 6c739a2..00a0537 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -42,11 +42,25 @@
// True if the module containing this has it set by default.
EnabledByDefault bool `blueprint:"mutated"`
+ // Whether to allow that library classes inherit from program classes.
+ // Defaults to false.
+ Ignore_library_extends_program *bool
+
// Whether to continue building even if warnings are emitted. Defaults to true.
Ignore_warnings *bool
+ // Whether runtime invisible annotations should be kept by R8. Defaults to false.
+ // This is equivalent to:
+ // -keepattributes RuntimeInvisibleAnnotations,
+ // RuntimeInvisibleParameterAnnotations,
+ // RuntimeInvisibleTypeAnnotations
+ // This is only applicable when RELEASE_R8_ONLY_RUNTIME_VISIBLE_ANNOTATIONS is
+ // enabled and will be used to migrate away from keeping runtime invisible
+ // annotations (b/387958004).
+ Keep_runtime_invisible_annotations *bool
+
// If true, runs R8 in Proguard compatibility mode, otherwise runs R8 in full mode.
- // Defaults to false for apps, true for libraries and tests.
+ // Defaults to false for apps and tests, true for libraries.
Proguard_compatibility *bool
// If true, optimize for size by removing unused code. Defaults to true for apps,
@@ -108,7 +122,7 @@
resourcesInput android.OptionalPath
resourcesOutput android.OptionalPath
- providesTransitiveHeaderJars
+ providesTransitiveHeaderJarsForR8
}
func (d *dexer) effectiveOptimizeEnabled() bool {
@@ -120,7 +134,7 @@
}
func (d *DexProperties) optimizedResourceShrinkingEnabled(ctx android.ModuleContext) bool {
- return d.resourceShrinkingEnabled(ctx) && Bool(d.Optimize.Optimized_shrink_resources)
+ return d.resourceShrinkingEnabled(ctx) && BoolDefault(d.Optimize.Optimized_shrink_resources, ctx.Config().UseOptimizedResourceShrinkingByDefault())
}
func (d *dexer) optimizeOrObfuscateEnabled() bool {
@@ -133,7 +147,7 @@
`$d8Template${config.D8Cmd} ${config.D8Flags} $d8Flags --output $outDir --no-dex-input-jar $in && ` +
`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
`${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in && ` +
- `rm -f "$outDir/classes*.dex" "$outDir/classes.dex.jar"`,
+ `rm -f "$outDir"/classes*.dex "$outDir/classes.dex.jar"`,
CommandDeps: []string{
"${config.D8Cmd}",
"${config.SoongZipCmd}",
@@ -172,7 +186,7 @@
`rm -rf ${outUsageDir} && ` +
`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
`${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in && ` +
- `rm -f "$outDir/classes*.dex" "$outDir/classes.dex.jar"`,
+ `rm -f "$outDir"/classes*.dex "$outDir/classes.dex.jar"`,
Depfile: "${out}.d",
Deps: blueprint.DepsGCC,
CommandDeps: []string{
@@ -220,14 +234,21 @@
deps = append(deps, f)
}
- if ctx.Config().Getenv("NO_OPTIMIZE_DX") != "" {
+ var requestReleaseMode bool
+ requestReleaseMode, flags = android.RemoveFromList("--release", flags)
+
+ if ctx.Config().Getenv("NO_OPTIMIZE_DX") != "" || ctx.Config().Getenv("GENERATE_DEX_DEBUG") != "" {
flags = append(flags, "--debug")
+ requestReleaseMode = false
}
- if ctx.Config().Getenv("GENERATE_DEX_DEBUG") != "" {
- flags = append(flags,
- "--debug",
- "--verbose")
+ // Don't strip out debug information for eng builds, unless the target
+ // explicitly provided the `--release` build flag. This allows certain
+ // test targets to remain optimized as part of eng test_suites builds.
+ if requestReleaseMode {
+ flags = append(flags, "--release")
+ } else if ctx.Config().Eng() {
+ flags = append(flags, "--debug")
}
// Supplying the platform build flag disables various features like API modeling and desugaring.
@@ -245,6 +266,13 @@
if err != nil {
ctx.PropertyErrorf("min_sdk_version", "%s", err)
}
+ if !Bool(d.dexProperties.No_dex_container) && effectiveVersion.FinalOrFutureInt() >= 36 && ctx.Config().UseDexV41() {
+ // W is 36, but we have not bumped the SDK version yet, so check for both.
+ if ctx.Config().PlatformSdkVersion().FinalInt() >= 36 ||
+ ctx.Config().PlatformSdkCodename() == "Baklava" {
+ flags = append([]string{"-JDcom.android.tools.r8.dexContainerExperiment"}, flags...)
+ }
+ }
// If the specified SDK level is 10000, then configure the compiler to use the
// current platform SDK level and to compile the build as a platform build.
@@ -278,7 +306,7 @@
return d8Flags, d8Deps, artProfileOutput
}
-func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams) (r8Flags []string, r8Deps android.Paths, artProfileOutput *android.OutputPath) {
+func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, debugMode bool) (r8Flags []string, r8Deps android.Paths, artProfileOutput *android.OutputPath) {
flags := dexParams.flags
opt := d.dexProperties.Optimize
@@ -292,7 +320,7 @@
// TODO(b/360905238): Remove SdkSystemServer exception after resolving missing class references.
if !dexParams.sdkVersion.Stable() || dexParams.sdkVersion.Kind == android.SdkSystemServer {
var proguardRaiseDeps classpath
- ctx.VisitDirectDepsWithTag(proguardRaiseTag, func(m android.Module) {
+ ctx.VisitDirectDepsProxyWithTag(proguardRaiseTag, func(m android.ModuleProxy) {
if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok {
proguardRaiseDeps = append(proguardRaiseDeps, dep.RepackagedHeaderJars...)
}
@@ -307,20 +335,16 @@
r8Deps = append(r8Deps, flags.dexClasspath...)
transitiveStaticLibsLookupMap := map[android.Path]bool{}
- if d.transitiveStaticLibsHeaderJars != nil {
- for _, jar := range d.transitiveStaticLibsHeaderJars.ToList() {
- transitiveStaticLibsLookupMap[jar] = true
- }
+ for _, jar := range d.transitiveStaticLibsHeaderJarsForR8.ToList() {
+ transitiveStaticLibsLookupMap[jar] = true
}
transitiveHeaderJars := android.Paths{}
- if d.transitiveLibsHeaderJars != nil {
- for _, jar := range d.transitiveLibsHeaderJars.ToList() {
- if _, ok := transitiveStaticLibsLookupMap[jar]; ok {
- // don't include a lib if it is already packaged in the current JAR as a static lib
- continue
- }
- transitiveHeaderJars = append(transitiveHeaderJars, jar)
+ for _, jar := range d.transitiveLibsHeaderJarsForR8.ToList() {
+ if _, ok := transitiveStaticLibsLookupMap[jar]; ok {
+ // don't include a lib if it is already packaged in the current JAR as a static lib
+ continue
}
+ transitiveHeaderJars = append(transitiveHeaderJars, jar)
}
transitiveClasspath := classpath(transitiveHeaderJars)
r8Flags = append(r8Flags, transitiveClasspath.FormJavaClassPath("-libraryjars"))
@@ -346,11 +370,21 @@
r8Flags = append(r8Flags, opt.Proguard_flags...)
- if BoolDefault(opt.Proguard_compatibility, true) {
+ if BoolDefault(opt.Ignore_library_extends_program, false) {
+ r8Flags = append(r8Flags, "--ignore-library-extends-program")
+ }
+
+ if BoolDefault(opt.Keep_runtime_invisible_annotations, false) {
+ r8Flags = append(r8Flags, "--keep-runtime-invisible-annotations")
+ }
+
+ if BoolDefault(opt.Proguard_compatibility, !ctx.Config().UseR8FullModeByDefault()) {
r8Flags = append(r8Flags, "--force-proguard-compatibility")
}
- if Bool(opt.Optimize) || Bool(opt.Obfuscate) {
+ // Avoid unnecessary stack frame noise by only injecting source map ids for non-debug
+ // optimized or obfuscated targets.
+ if (Bool(opt.Optimize) || Bool(opt.Obfuscate)) && !debugMode {
// TODO(b/213833843): Allow configuration of the prefix via a build variable.
var sourceFilePrefix = "go/retraceme "
var sourceFileTemplate = "\"" + sourceFilePrefix + "%MAP_ID\""
@@ -374,11 +408,6 @@
// TODO(ccross): if this is an instrumentation test of an obfuscated app, use the
// dictionary of the app and move the app from libraryjars to injars.
- // Don't strip out debug information for eng builds.
- if ctx.Config().Eng() {
- r8Flags = append(r8Flags, "--debug")
- }
-
// TODO(b/180878971): missing classes should be added to the relevant builds.
// TODO(b/229727645): do not use true as default for Android platform builds.
if proptools.BoolDefault(opt.Ignore_warnings, true) {
@@ -390,8 +419,12 @@
r8Flags = append(r8Flags, "--resource-input", d.resourcesInput.Path().String())
r8Deps = append(r8Deps, d.resourcesInput.Path())
r8Flags = append(r8Flags, "--resource-output", d.resourcesOutput.Path().String())
- if Bool(opt.Optimized_shrink_resources) {
+ if d.dexProperties.optimizedResourceShrinkingEnabled(ctx) {
r8Flags = append(r8Flags, "--optimized-resource-shrinking")
+ if Bool(d.dexProperties.Optimize.Optimized_shrink_resources) {
+ // Explicitly opted into optimized shrinking, no need for keeping R$id entries
+ r8Flags = append(r8Flags, "--force-optimized-resource-shrinking")
+ }
}
}
@@ -401,6 +434,10 @@
artProfileOutput = profileOutput
}
+ if ctx.Config().UseR8StoreStoreFenceConstructorInlining() {
+ r8Flags = append(r8Flags, "--store-store-fence-constructor-inlining")
+ }
+
return r8Flags, r8Deps, artProfileOutput
}
@@ -416,17 +453,18 @@
// Adds --art-profile to r8/d8 command.
// r8/d8 will output a generated profile file to match the optimized dex code.
func (d *dexer) addArtProfile(ctx android.ModuleContext, dexParams *compileDexParams) (flags []string, deps android.Paths, artProfileOutputPath *android.OutputPath) {
- if dexParams.artProfileInput != nil {
- artProfileInputPath := android.PathForModuleSrc(ctx, *dexParams.artProfileInput)
- artProfileOutputPathValue := android.PathForModuleOut(ctx, "profile.prof.txt").OutputPath
- artProfileOutputPath = &artProfileOutputPathValue
- flags = []string{
- "--art-profile",
- artProfileInputPath.String(),
- artProfileOutputPath.String(),
- }
- deps = append(deps, artProfileInputPath)
+ if dexParams.artProfileInput == nil {
+ return nil, nil, nil
}
+ artProfileInputPath := android.PathForModuleSrc(ctx, *dexParams.artProfileInput)
+ artProfileOutputPathValue := android.PathForModuleOut(ctx, "profile.prof.txt").OutputPath
+ artProfileOutputPath = &artProfileOutputPathValue
+ flags = []string{
+ "--art-profile",
+ artProfileInputPath.String(),
+ artProfileOutputPath.String(),
+ }
+ deps = append(deps, artProfileInputPath)
return flags, deps, artProfileOutputPath
}
@@ -470,7 +508,8 @@
proguardUsageZip,
proguardConfiguration,
}
- r8Flags, r8Deps, r8ArtProfileOutputPath := d.r8Flags(ctx, dexParams)
+ debugMode := android.InList("--debug", commonFlags)
+ r8Flags, r8Deps, r8ArtProfileOutputPath := d.r8Flags(ctx, dexParams, debugMode)
rule := r8
args := map[string]string{
"r8Flags": strings.Join(append(commonFlags, r8Flags...), " "),
diff --git a/java/dex_test.go b/java/dex_test.go
index 4862d06..f261066 100644
--- a/java/dex_test.go
+++ b/java/dex_test.go
@@ -24,6 +24,7 @@
)
func TestR8(t *testing.T) {
+ t.Parallel()
result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, `
android_app {
name: "app",
@@ -91,6 +92,7 @@
}
func TestR8TransitiveDeps(t *testing.T) {
+ t.Parallel()
bp := `
override_android_app {
name: "override_app",
@@ -192,6 +194,7 @@
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
fixturePreparer := PrepareForTestWithJavaDefaultModules
if tc.unbundled {
fixturePreparer = android.GroupFixturePreparers(
@@ -259,6 +262,7 @@
}
func TestR8Flags(t *testing.T) {
+ t.Parallel()
result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, `
android_app {
name: "app",
@@ -288,6 +292,7 @@
}
func TestD8(t *testing.T) {
+ t.Parallel()
result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, `
java_library {
name: "foo",
@@ -329,6 +334,7 @@
}
func TestProguardFlagsInheritanceStatic(t *testing.T) {
+ t.Parallel()
result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, `
android_app {
name: "app",
@@ -383,6 +389,7 @@
}
func TestProguardFlagsInheritance(t *testing.T) {
+ t.Parallel()
directDepFlagsFileName := "direct_dep.flags"
transitiveDepFlagsFileName := "transitive_dep.flags"
@@ -601,6 +608,7 @@
for _, topLevelModuleDef := range topLevelModules {
for _, tc := range testcases {
t.Run(topLevelModuleDef.name+"-"+tc.name, func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
android.FixtureMergeMockFs(android.MockFS{
@@ -642,6 +650,7 @@
}
func TestProguardFlagsInheritanceAppImport(t *testing.T) {
+ t.Parallel()
bp := `
android_app {
name: "app",
@@ -664,6 +673,7 @@
}
func TestR8FlagsArtProfile(t *testing.T) {
+ t.Parallel()
result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, `
android_app {
name: "app",
@@ -696,6 +706,7 @@
//
// The rewritten profile should be used since the dex signatures in the checked-in profile will not match the optimized binary.
func TestEnableProfileRewritingIsRequiredForOptimizedApps(t *testing.T) {
+ t.Parallel()
testJavaError(t,
"Enable_profile_rewriting must be true when profile_guided dexpreopt and R8 optimization/obfuscation is turned on",
`
@@ -713,3 +724,99 @@
}
}`)
}
+
+func TestDebugReleaseFlags(t *testing.T) {
+ t.Parallel()
+ bp := `
+ android_app {
+ name: "app",
+ srcs: ["foo.java"],
+ platform_apis: true,
+ dxflags: ["%s"]
+ }
+ `
+
+ testcases := []struct {
+ name string
+ envVar string
+ isEng bool
+ dxFlags string
+ expectedFlags string
+ }{
+ {
+ name: "app_no_optimize_dx",
+ envVar: "NO_OPTIMIZE_DX",
+ expectedFlags: "--debug",
+ },
+ {
+ name: "app_release_no_optimize_dx",
+ envVar: "NO_OPTIMIZE_DX",
+ dxFlags: "--release",
+ // Global env vars override explicit dxflags.
+ expectedFlags: "--debug",
+ },
+ {
+ name: "app_generate_dex_debug",
+ envVar: "GENERATE_DEX_DEBUG",
+ expectedFlags: "--debug",
+ },
+ {
+ name: "app_release_generate_dex_debug",
+ envVar: "GENERATE_DEX_DEBUG",
+ dxFlags: "--release",
+ // Global env vars override explicit dxflags.
+ expectedFlags: "--debug",
+ },
+ {
+ name: "app_eng",
+ isEng: true,
+ expectedFlags: "--debug",
+ },
+ {
+ name: "app_release_eng",
+ isEng: true,
+ dxFlags: "--release",
+ // Eng mode does *not* override explicit dxflags.
+ expectedFlags: "--release",
+ },
+ }
+
+ for _, tc := range testcases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+ fixturePreparer := PrepareForTestWithJavaDefaultModules
+ fixturePreparer = android.GroupFixturePreparers(
+ fixturePreparer,
+ android.FixtureModifyProductVariables(
+ func(variables android.FixtureProductVariables) {
+ variables.Eng = proptools.BoolPtr(tc.isEng)
+ },
+ ),
+ )
+ if tc.envVar != "" {
+ fixturePreparer = android.GroupFixturePreparers(
+ fixturePreparer,
+ android.FixtureMergeEnv(map[string]string{
+ tc.envVar: "true",
+ }),
+ )
+ }
+ result := fixturePreparer.RunTestWithBp(t, fmt.Sprintf(bp, tc.dxFlags))
+
+ appR8 := result.ModuleForTests("app", "android_common").Rule("r8")
+ android.AssertStringDoesContain(t, "expected flag in R8 flags",
+ appR8.Args["r8Flags"], tc.expectedFlags)
+
+ var unexpectedFlags string
+ if tc.expectedFlags == "--debug" {
+ unexpectedFlags = "--release"
+ } else if tc.expectedFlags == "--release" {
+ unexpectedFlags = "--debug"
+ }
+ if unexpectedFlags != "" {
+ android.AssertStringDoesNotContain(t, "unexpected flag in R8 flags",
+ appR8.Args["r8Flags"], unexpectedFlags)
+ }
+ })
+ }
+}
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index a38642a..f52ce5d 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -80,24 +80,25 @@
// safe to use in `android.AndroidMkExtraEntriesFunc`.
func (install dexpreopterInstall) ToMakeEntries() android.AndroidMkEntries {
return android.AndroidMkEntries{
- Class: "ETC",
- OutputFile: android.OptionalPathForPath(install.outputPathOnHost),
+ OverrideName: install.FullModuleName(),
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(install.outputPathOnHost),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE", install.FullModuleName())
entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice)
entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false")
- // Unset LOCAL_SOONG_INSTALLED_MODULE so that this does not default to the primary .apex file
- // Without this, installation of the dexpreopt artifacts get skipped
- entries.SetString("LOCAL_SOONG_INSTALLED_MODULE", "")
},
},
}
}
-func (install dexpreopterInstall) PackageFile(ctx android.ModuleContext) android.PackagingSpec {
- return ctx.PackageFile(install.installDirOnDevice, install.installFileOnDevice, install.outputPathOnHost)
+func (install dexpreopterInstall) AddModuleInfoJSONForApex(ctx android.ModuleContext) {
+ moduleInfoJSON := ctx.ExtraModuleInfoJSON()
+ moduleInfoJSON.RegisterNameOverride = install.FullModuleName()
+ moduleInfoJSON.ModuleNameOverride = install.FullModuleName()
+ moduleInfoJSON.Class = []string{"ETC"}
+ moduleInfoJSON.SystemSharedLibs = []string{"none"}
}
type Dexpreopter struct {
@@ -154,25 +155,25 @@
type DexpreoptProperties struct {
Dex_preopt struct {
// If false, prevent dexpreopting. Defaults to true.
- Enabled *bool
+ Enabled proptools.Configurable[bool] `android:"replace_instead_of_append"`
// If true, generate an app image (.art file) for this module.
- App_image *bool
+ App_image proptools.Configurable[bool] `android:"replace_instead_of_append"`
// If true, use a checked-in profile to guide optimization. Defaults to false unless
// a matching profile is set or a profile is found in PRODUCT_DEX_PREOPT_PROFILE_DIR
// that matches the name of this module, in which case it is defaulted to true.
- Profile_guided *bool
+ Profile_guided proptools.Configurable[bool] `android:"replace_instead_of_append"`
// If set, provides the path to profile relative to the Android.bp file. If not set,
// defaults to searching for a file that matches the name of this module in the default
// profile location set by PRODUCT_DEX_PREOPT_PROFILE_DIR, or empty if not found.
- Profile *string `android:"path"`
+ Profile proptools.Configurable[string] `android:"path,replace_instead_of_append"`
// If set to true, r8/d8 will use `profile` as input to generate a new profile that matches
// the optimized dex.
// The new profile will be subsequently used as the profile to dexpreopt the dex file.
- Enable_profile_rewriting *bool
+ Enable_profile_rewriting proptools.Configurable[bool] `android:"replace_instead_of_append"`
}
Dex_preopt_result struct {
@@ -211,21 +212,29 @@
}
apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
psi := android.PrebuiltSelectionInfoMap{}
- ctx.VisitDirectDeps(func(am android.Module) {
+ ctx.VisitDirectDepsProxy(func(am android.ModuleProxy) {
if prebuiltSelectionInfo, ok := android.OtherModuleProvider(ctx, am, android.PrebuiltSelectionInfoProvider); ok {
psi = prebuiltSelectionInfo
}
})
+
// Find the apex variant for this module
- _, apexVariantsWithoutTestApexes, _ := android.ListSetDifference(apexInfo.InApexVariants, apexInfo.TestApexes)
+ apexVariants := []string{}
+ if apexInfo.BaseApexName != "" {
+ // This is a transitive dependency of an override_apex
+ apexVariants = append(apexVariants, apexInfo.BaseApexName)
+ } else {
+ apexVariants = append(apexVariants, apexInfo.InApexVariants...)
+ }
+ if apexInfo.ApexAvailableName != "" {
+ apexVariants = append(apexVariants, apexInfo.ApexAvailableName)
+ }
disableSource := false
// find the selected apexes
- for _, apexVariant := range apexVariantsWithoutTestApexes {
- for _, selected := range psi.GetSelectedModulesForApiDomain(apexVariant) {
- // If the apex_contribution for this api domain contains a prebuilt apex, disable the source variant
- if strings.HasPrefix(selected, "prebuilt_com.google.android") {
- disableSource = true
- }
+ for _, apexVariant := range apexVariants {
+ if len(psi.GetSelectedModulesForApiDomain(apexVariant)) > 0 {
+ // If the apex_contribution for this api domain is non-empty, disable the source variant
+ disableSource = true
}
}
return disableSource
@@ -242,7 +251,7 @@
return true
}
- if !BoolDefault(d.dexpreoptProperties.Dex_preopt.Enabled, true) {
+ if !d.dexpreoptProperties.Dex_preopt.Enabled.GetOrDefault(ctx, true) {
return true
}
@@ -345,7 +354,11 @@
d.installPath = android.PathForModuleInPartitionInstall(ctx, "", strings.TrimPrefix(dexpreopt.GetSystemServerDexLocation(ctx, dc, libraryName), "/"))
// generate the rules for creating the .odex and .vdex files for this system server jar
dexJarFile := di.PrebuiltExportPath(ApexRootRelativePathToJavaLib(libraryName))
-
+ if dexJarFile == nil {
+ ctx.ModuleErrorf(
+ `Could not find library %s in prebuilt apex %s.
+Please make sure that the value of PRODUCT_APEX_(SYSTEM_SERVER|STANDALONE_SYSTEM_SERVER)_JARS is correct`, libraryName, ctx.ModuleName())
+ }
d.inputProfilePathOnHost = nil // reset: TODO(spandandas): Make dexpreopter stateless
if android.InList(libraryName, di.GetDexpreoptProfileGuidedExportedModuleNames()) {
// Set the profile path to guide optimization
@@ -431,12 +444,12 @@
if d.inputProfilePathOnHost != nil {
profileClassListing = android.OptionalPathForPath(d.inputProfilePathOnHost)
- } else if BoolDefault(d.dexpreoptProperties.Dex_preopt.Profile_guided, true) && !forPrebuiltApex(ctx) {
+ } else if d.dexpreoptProperties.Dex_preopt.Profile_guided.GetOrDefault(ctx, true) && !forPrebuiltApex(ctx) {
// If enable_profile_rewriting is set, use the rewritten profile instead of the checked-in profile
- if d.EnableProfileRewriting() {
+ if d.EnableProfileRewriting(ctx) {
profileClassListing = android.OptionalPathForPath(d.GetRewrittenProfile())
profileIsTextListing = true
- } else if profile := d.GetProfile(); profile != "" {
+ } else if profile := d.GetProfile(ctx); profile != "" {
// If dex_preopt.profile_guided is not set, default it based on the existence of the
// dexprepot.profile option or the profile class listing.
profileClassListing = android.OptionalPathForPath(
@@ -456,6 +469,8 @@
// Use the dexJar to create a unique scope for each
dexJarStem := strings.TrimSuffix(dexJarFile.Base(), dexJarFile.Ext())
+ appImage := d.dexpreoptProperties.Dex_preopt.App_image.Get(ctx)
+
// Full dexpreopt config, used to create dexpreopt build rules.
dexpreoptConfig := &dexpreopt.ModuleConfig{
Name: libName,
@@ -484,14 +499,21 @@
PreoptBootClassPathDexFiles: dexFiles.Paths(),
PreoptBootClassPathDexLocations: dexLocations,
- NoCreateAppImage: !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true),
- ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false),
+ NoCreateAppImage: !appImage.GetOrDefault(true),
+ ForceCreateAppImage: appImage.GetOrDefault(false),
PresignedPrebuilt: d.isPresignedPrebuilt,
}
+ if ctx.Config().InstallApexSystemServerDexpreoptSamePartition() {
+ dexpreoptConfig.ApexPartition = android.PathForModuleInstall(ctx).Partition()
+ } else {
+ dexpreoptConfig.ApexPartition = "system"
+ }
+
d.configPath = android.PathForModuleOut(ctx, "dexpreopt", dexJarStem, "dexpreopt.config")
dexpreopt.WriteModuleConfig(ctx, dexpreoptConfig, d.configPath)
+ ctx.CheckbuildFile(d.configPath)
if d.dexpreoptDisabled(ctx, libName) {
return
@@ -551,7 +573,7 @@
// TODO(b/346662300): Let dexpreopter generate the installPath for dexpreopt files instead of
// using the dex location to generate the installPath.
if isApexSystemServerJar {
- dexpreoptPartition = "system"
+ dexpreoptPartition = dexpreoptConfig.ApexPartition
}
for _, install := range dexpreoptRule.Installs() {
// Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
@@ -583,16 +605,20 @@
// Preopting of boot classpath jars in the ART APEX are handled in
// java/dexpreopt_bootjars.go, and other APEX jars are not preopted.
// The installs will be handled by Make as sub-modules of the java library.
- d.builtInstalledForApex = append(d.builtInstalledForApex, dexpreopterInstall{
+ di := dexpreopterInstall{
name: arch + "-" + installBase,
moduleName: libName,
outputPathOnHost: install.From,
installDirOnDevice: installPath,
installFileOnDevice: installBase,
- })
+ }
+ ctx.InstallFile(di.installDirOnDevice, di.installFileOnDevice, di.outputPathOnHost)
+ d.builtInstalledForApex = append(d.builtInstalledForApex, di)
+
}
} else if !d.preventInstall {
- ctx.InstallFile(installPath, installBase, install.From)
+ // Install without adding to checkbuild to match behavior of previous Make-based checkbuild rules
+ ctx.InstallFileWithoutCheckbuild(installPath, installBase, install.From)
}
}
@@ -642,6 +668,12 @@
return entries
}
+func (d *dexpreopter) ModuleInfoJSONForApex(ctx android.ModuleContext) {
+ for _, install := range d.builtInstalledForApex {
+ install.AddModuleInfoJSONForApex(ctx)
+ }
+}
+
func (d *dexpreopter) OutputProfilePathOnHost() android.Path {
return d.outputProfilePathOnHost
}
@@ -650,16 +682,16 @@
d.shouldDisableDexpreopt = true
}
-func (d *dexpreopter) EnableProfileRewriting() bool {
- return proptools.Bool(d.dexpreoptProperties.Dex_preopt.Enable_profile_rewriting)
+func (d *dexpreopter) EnableProfileRewriting(ctx android.BaseModuleContext) bool {
+ return d.dexpreoptProperties.Dex_preopt.Enable_profile_rewriting.GetOrDefault(ctx, false)
}
-func (d *dexpreopter) GetProfile() string {
- return proptools.String(d.dexpreoptProperties.Dex_preopt.Profile)
+func (d *dexpreopter) GetProfile(ctx android.BaseModuleContext) string {
+ return d.dexpreoptProperties.Dex_preopt.Profile.GetOrDefault(ctx, "")
}
-func (d *dexpreopter) GetProfileGuided() bool {
- return proptools.Bool(d.dexpreoptProperties.Dex_preopt.Profile_guided)
+func (d *dexpreopter) GetProfileGuided(ctx android.BaseModuleContext) bool {
+ return d.dexpreoptProperties.Dex_preopt.Profile_guided.GetOrDefault(ctx, false)
}
func (d *dexpreopter) GetRewrittenProfile() android.Path {
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index a81ab83..8c60d23 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -463,8 +463,9 @@
func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) {
ctx.RegisterParallelSingletonModuleType("dex_bootjars", dexpreoptBootJarsFactory)
+ ctx.RegisterModuleType("art_boot_images", artBootImagesFactory)
ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("dex_bootjars_deps", DexpreoptBootJarsMutator).Parallel()
+ ctx.BottomUp("dex_bootjars_deps", DexpreoptBootJarsMutator)
})
}
@@ -558,6 +559,10 @@
apexVariationOfSelected := append(ctx.Target().Variations(), blueprint.Variation{Mutator: "apex", Variation: apex})
if ctx.OtherModuleDependencyVariantExists(apexVariationOfSelected, selected) {
ctx.AddFarVariationDependencies(apexVariationOfSelected, dexpreoptBootJarDepTag, selected)
+ } else if ctx.OtherModuleDependencyVariantExists(apexVariationOfSelected, android.RemoveOptionalPrebuiltPrefix(selected)) {
+ // The prebuilt might have been renamed by prebuilt_rename mutator if the source module does not exist.
+ // Remove the prebuilt_ prefix.
+ ctx.AddFarVariationDependencies(apexVariationOfSelected, dexpreoptBootJarDepTag, android.RemoveOptionalPrebuiltPrefix(selected))
}
}
}
@@ -597,6 +602,7 @@
d.defaultBootImage = defaultBootImageConfig(ctx)
d.otherImages = make([]*bootImageConfig, 0, len(imageConfigs)-1)
var profileInstalls android.RuleBuilderInstalls
+ var artBootImageHostInstalls android.RuleBuilderInstalls
for _, name := range getImageNames() {
config := imageConfigs[name]
if config != d.defaultBootImage {
@@ -612,6 +618,18 @@
d.bootFrameworkProfile = bootProfile
profileInstalls = append(profileInstalls, installs...)
}
+ // Gather the install files of the host variant of the ART boot image.
+ // These installed files will be used in ART tests.
+ if config.name == "art" {
+ for _, variant := range config.variants {
+ if variant.target.Os != ctx.Config().BuildOS {
+ // not a host variant
+ continue
+ }
+ artBootImageHostInstalls = append(artBootImageHostInstalls, variant.installs...)
+ artBootImageHostInstalls = append(artBootImageHostInstalls, variant.vdexInstalls...)
+ }
+ }
}
if len(profileInstalls) > 0 {
android.SetProvider(ctx, profileInstallInfoProvider, profileInstallInfo{
@@ -622,6 +640,15 @@
installFile(ctx, install)
}
}
+ // Set a provider containing the install files of the host variant of the ART boot image.
+ // The actual install rules will be created by `art_boot_images`
+ android.SetProvider(
+ ctx,
+ artBootImageHostInfoProvider,
+ artBootImageHostInfo{
+ installs: artBootImageHostInstalls,
+ },
+ )
}
// GenerateSingletonBuildActions generates build rules for the dexpreopt config for Make.
@@ -964,6 +991,14 @@
}
}
+var artBootImageHostInfoProvider = blueprint.NewProvider[artBootImageHostInfo]()
+
+// artBootImageHostInfo contains the install locations of the host variant of ART boot image
+// this contains both the primary and secondary arch locations
+type artBootImageHostInfo struct {
+ installs android.RuleBuilderInstalls
+}
+
// Generate boot image build rules for a specific target.
func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, profile android.Path) bootImageVariantOutputs {
@@ -1182,8 +1217,13 @@
return nil
}
- defaultProfile := "frameworks/base/config/boot-image-profile.txt"
- extraProfile := "frameworks/base/config/boot-image-profile-extra.txt"
+ defaultProfile := "frameworks/base/boot/boot-image-profile.txt"
+ // If ART is prebuilt, primarily in next release configs, this will still use
+ // the profile from source which represent the latest code, so it may not
+ // correspond to the BCP jars in the prebuilt APEX, but this is the profile we
+ // have access to.
+ artProfile := "art/build/boot/boot-image-profile.txt"
+ extraProfile := "frameworks/base/boot/boot-image-profile-extra.txt"
rule := android.NewRuleBuilder(pctx, ctx)
@@ -1198,6 +1238,9 @@
// Return nil and continue without profile.
return nil
}
+ if path := android.ExistentPathForSource(ctx, artProfile); path.Valid() {
+ profiles = append(profiles, path.Path())
+ }
if path := android.ExistentPathForSource(ctx, extraProfile); path.Valid() {
profiles = append(profiles, path.Path())
}
@@ -1255,7 +1298,7 @@
return nil, nil
}
- defaultProfile := "frameworks/base/config/boot-profile.txt"
+ defaultProfile := "frameworks/base/boot/boot-profile.txt"
bootFrameworkProfile := android.PathForSource(ctx, defaultProfile)
profile := image.dir.Join(ctx, "boot.bprof")
@@ -1340,18 +1383,7 @@
}
image := d.defaultBootImage
- if image != nil {
- if profileInstallInfo, ok := android.OtherModuleProvider(ctx, d, profileInstallInfoProvider); ok {
- ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", profileInstallInfo.profileInstalls.String())
- if profileInstallInfo.profileLicenseMetadataFile.Valid() {
- ctx.Strict("DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA", profileInstallInfo.profileLicenseMetadataFile.String())
- }
- }
-
- if SkipDexpreoptBootJars(ctx) {
- return
- }
-
+ if image != nil && !SkipDexpreoptBootJars(ctx) {
global := dexpreopt.GetGlobalConfig(ctx)
dexPaths, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp)
ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(dexPaths.Strings(), " "))
@@ -1392,3 +1424,70 @@
OutputFile: android.OptionalPathForPath(d.bootFrameworkProfile),
}}
}
+
+// artBootImages is a thin wrapper around `dex_bootjars`.
+// it creates the installation rules for the host variant of the ART boot image.
+type artBootImages struct {
+ android.ModuleBase
+
+ // A non-empty file that will be written as `LOCAL_SOONG_INSTALLED_MODULE` in out/soong/Android-*.mk
+ outputFile android.OptionalPath
+}
+
+func artBootImagesFactory() android.Module {
+ m := &artBootImages{}
+ android.InitAndroidMultiTargetsArchModule(m, android.HostSupported, android.MultilibCommon)
+ return m
+}
+
+func (dbj *artBootImages) DepsMutator(ctx android.BottomUpMutatorContext) {
+ // Create a dependency on `dex_bootjars` to access the intermediate locations of host art boot image.
+ ctx.AddVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), dexpreoptBootJarDepTag, "dex_bootjars")
+}
+
+func (d *artBootImages) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ ctx.VisitDirectDepsWithTag(dexpreoptBootJarDepTag, func(m android.Module) {
+ hostInstallsInfo, ok := android.OtherModuleProvider(ctx, m, artBootImageHostInfoProvider)
+ if !ok {
+ ctx.ModuleErrorf("Could not find information about the host variant of ART boot image")
+ }
+ installs := d.installFile(ctx, hostInstallsInfo.installs)
+ if len(installs) > 0 {
+ d.outputFile = android.OptionalPathForPath(installs[0])
+ // Create a phony target that can ART run-tests can depend on.
+ ctx.Phony(d.Name(), installs...)
+ } else {
+ // this might be true e.g. when building with `WITH_DEXPREOPT=false`
+ // create an empty file so that the `art_boot_images` is known to the packaging system.
+ d.outputFile = android.OptionalPathForPath(android.PathForModuleOut(ctx, "undefined_art_boot_images"))
+ }
+ })
+}
+
+// Creates an installation rule for host variant of ART boot image files.
+// Returns the list of install locations (out/host/linux-x86/...)
+func (d *artBootImages) installFile(ctx android.ModuleContext, ruleBuilderInstalls android.RuleBuilderInstalls) android.Paths {
+ var ret android.Paths
+ for _, ruleBuilderInstall := range ruleBuilderInstalls {
+ installDir := android.PathForModuleInstall(
+ ctx,
+ strings.TrimPrefix(filepath.Dir(ruleBuilderInstall.To), "/"),
+ )
+ filename := filepath.Base(ruleBuilderInstall.To)
+ ctx.InstallFile(
+ installDir,
+ filename,
+ ruleBuilderInstall.From,
+ )
+ ret = append(ret, installDir.Join(ctx, filename))
+ }
+ return ret
+}
+
+// Set `OutputFile` expclitly so that this module does not get elided when generating out/soong/Android-*.mk
+func (d *artBootImages) AndroidMkEntries() []android.AndroidMkEntries {
+ return []android.AndroidMkEntries{{
+ Class: "ETC",
+ OutputFile: d.outputFile,
+ }}
+}
diff --git a/java/dexpreopt_check.go b/java/dexpreopt_check.go
index 33be603..c971565 100644
--- a/java/dexpreopt_check.go
+++ b/java/dexpreopt_check.go
@@ -17,6 +17,8 @@
import (
"strings"
+ "github.com/google/blueprint"
+
"android/soong/android"
"android/soong/dexpreopt"
@@ -43,16 +45,12 @@
type dexpreoptSystemserverCheck struct {
android.SingletonModuleBase
- // Mapping from the module name to the install paths to the compilation artifacts.
- artifactsByModuleName map[string][]string
-
// The install paths to the compilation artifacts.
artifacts []string
}
func dexpreoptSystemserverCheckFactory() android.SingletonModule {
m := &dexpreoptSystemserverCheck{}
- m.artifactsByModuleName = make(map[string][]string)
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
return m
}
@@ -62,7 +60,25 @@
ctx, "", strings.TrimPrefix(location, "/"))
}
-func (m *dexpreoptSystemserverCheck) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+type systemServerDependencyTag struct {
+ blueprint.BaseDependencyTag
+}
+
+// systemServerJarDepTag willl be used for validation. Skip visiblility.
+func (b systemServerDependencyTag) ExcludeFromVisibilityEnforcement() {
+}
+
+var (
+ // dep tag for platform and apex system server jars
+ systemServerJarDepTag = systemServerDependencyTag{}
+)
+
+var _ android.ExcludeFromVisibilityEnforcementTag = systemServerJarDepTag
+
+// Add a depenendency on the system server jars. The dexpreopt files of those will be emitted to make.
+// The kati packaging system will verify that those files appear in installed files.
+// Adding the dependency allows the singleton module to determine whether an apex system server jar is system_ext specific.
+func (m *dexpreoptSystemserverCheck) DepsMutator(ctx android.BottomUpMutatorContext) {
global := dexpreopt.GetGlobalConfig(ctx)
targets := ctx.Config().Targets[android.Android]
@@ -72,23 +88,27 @@
return
}
- systemServerJars := global.AllSystemServerJars(ctx)
- for _, jar := range systemServerJars.CopyOfJars() {
- dexLocation := dexpreopt.GetSystemServerDexLocation(ctx, global, jar)
- odexLocation := dexpreopt.ToOdexPath(dexLocation, targets[0].Arch.ArchType)
+ ctx.AddDependency(ctx.Module(), systemServerJarDepTag, global.AllSystemServerJars(ctx).CopyOfJars()...)
+}
+
+func (m *dexpreoptSystemserverCheck) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ global := dexpreopt.GetGlobalConfig(ctx)
+ targets := ctx.Config().Targets[android.Android]
+
+ ctx.VisitDirectDepsWithTag(systemServerJarDepTag, func(systemServerJar android.Module) {
+ partition := "system"
+ if systemServerJar.InstallInSystemExt() && ctx.Config().InstallApexSystemServerDexpreoptSamePartition() {
+ partition = ctx.DeviceConfig().SystemExtPath() // system_ext
+ }
+ dexLocation := dexpreopt.GetSystemServerDexLocation(ctx, global, systemServerJar.Name())
+ odexLocation := dexpreopt.ToOdexPath(dexLocation, targets[0].Arch.ArchType, partition)
odexPath := getInstallPath(ctx, odexLocation)
vdexPath := getInstallPath(ctx, pathtools.ReplaceExtension(odexLocation, "vdex"))
- m.artifactsByModuleName[jar] = []string{odexPath.String(), vdexPath.String()}
- }
+ m.artifacts = append(m.artifacts, odexPath.String(), vdexPath.String())
+ })
}
func (m *dexpreoptSystemserverCheck) GenerateSingletonBuildActions(ctx android.SingletonContext) {
- // Only keep modules defined in Soong.
- ctx.VisitAllModules(func(module android.Module) {
- if artifacts, ok := m.artifactsByModuleName[module.Name()]; ok {
- m.artifacts = append(m.artifacts, artifacts...)
- }
- })
}
func (m *dexpreoptSystemserverCheck) MakeVars(ctx android.MakeVarsContext) {
diff --git a/java/dexpreopt_config_test.go b/java/dexpreopt_config_test.go
index 44d2127..99b1f23 100644
--- a/java/dexpreopt_config_test.go
+++ b/java/dexpreopt_config_test.go
@@ -23,6 +23,7 @@
)
func TestBootImageConfig(t *testing.T) {
+ t.Parallel()
if runtime.GOOS != "linux" {
t.Skipf("Skipping as boot image config test is only supported on linux not %s", runtime.GOOS)
}
diff --git a/java/dexpreopt_config_testing.go b/java/dexpreopt_config_testing.go
index 37c54b9..fbdb7b0 100644
--- a/java/dexpreopt_config_testing.go
+++ b/java/dexpreopt_config_testing.go
@@ -1217,6 +1217,7 @@
}
t.Run(imageConfig.name, func(t *testing.T) {
+ t.Parallel()
nestedCheckBootImageConfig(t, result, imageConfig, mutated, expected)
})
}
@@ -1246,6 +1247,7 @@
for i, variant := range imageConfig.variants {
expectedVariant := expected.variants[i]
t.Run(variant.target.Arch.ArchType.String(), func(t *testing.T) {
+ t.Parallel()
android.AssertDeepEquals(t, "archType", expectedVariant.archType, variant.target.Arch.ArchType)
android.AssertDeepEquals(t, "dexLocations", expectedVariant.dexLocations, variant.dexLocations)
android.AssertDeepEquals(t, "dexLocationsDeps", expectedVariant.dexLocationsDeps, variant.dexLocationsDeps)
@@ -1335,8 +1337,6 @@
DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTboot=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot.art
DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTmainline=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot.art:out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/boot-framework-foo.art
DEXPREOPT_IMAGE_NAMES=art boot mainline
-DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED=out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof:/system/etc/boot-image.prof out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof:/system/etc/boot-image.bprof
-DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-extra1.oat:/apex/art_boot_images/javalib/arm/boot-extra1.oat
DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-extra1.oat:/apex/art_boot_images/javalib/arm64/boot-extra1.oat
DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.oat:/apex/art_boot_images/javalib/x86/boot-extra1.oat
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index 73e33f4..53a0d71 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -30,6 +30,7 @@
}
func TestDexpreoptEnabled(t *testing.T) {
+ t.Parallel()
tests := []struct {
name string
bp string
@@ -54,6 +55,7 @@
name: "foo",
installable: true,
srcs: ["a.java"],
+ sdk_version: "current",
}`,
enabled: true,
},
@@ -98,6 +100,7 @@
java_library {
name: "foo",
installable: true,
+ sdk_version: "current",
}`,
enabled: false,
},
@@ -107,6 +110,7 @@
java_library {
name: "foo",
srcs: ["a.java"],
+ sdk_version: "current",
}`,
enabled: false,
},
@@ -144,6 +148,7 @@
name: "foo",
srcs: ["a.java"],
compile_dex: true,
+ sdk_version: "current",
}`,
enabled: false,
},
@@ -164,6 +169,7 @@
installable: true,
srcs: ["a.java"],
apex_available: ["com.android.apex1"],
+ sdk_version: "current",
}`,
apexVariant: true,
enabled: false,
@@ -176,6 +182,7 @@
installable: true,
srcs: ["a.java"],
apex_available: ["com.android.apex1"],
+ sdk_version: "current",
}`,
moduleName: "service-foo",
apexVariant: true,
@@ -189,6 +196,7 @@
installable: true,
srcs: ["a.java"],
apex_available: ["com.android.apex1"],
+ sdk_version: "current",
}`,
moduleName: "prebuilt_service-foo",
apexVariant: true,
@@ -202,6 +210,7 @@
installable: true,
srcs: ["a.java"],
apex_available: ["com.android.apex1"],
+ sdk_version: "current",
}`,
moduleName: "service-foo",
apexVariant: false,
@@ -211,6 +220,7 @@
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
preparers := android.GroupFixturePreparers(
PrepareForTestWithDexpreopt,
PrepareForTestWithFakeApexMutator,
@@ -250,6 +260,7 @@
}
func TestDex2oatToolDeps(t *testing.T) {
+ t.Parallel()
if runtime.GOOS != "linux" {
// The host binary paths checked below are build OS dependent.
t.Skipf("Unsupported build OS %s", runtime.GOOS)
@@ -265,6 +276,7 @@
name := fmt.Sprintf("sourceEnabled:%t,prebuiltEnabled:%t,prebuiltPreferred:%t",
sourceEnabled, prebuiltEnabled, prebuiltPreferred)
t.Run(name, func(t *testing.T) {
+ t.Parallel()
result := preparers.RunTestWithBp(t, fmt.Sprintf(`
cc_binary {
name: "dex2oatd",
@@ -288,7 +300,7 @@
})
}
- sourceDex2oatPath := "host/linux-x86/bin/dex2oatd"
+ sourceDex2oatPath := "../host/linux-x86/bin/dex2oatd"
prebuiltDex2oatPath := ".intermediates/prebuilt_dex2oatd/linux_glibc_x86_64/dex2oatd"
testDex2oatToolDep(true, false, false, sourceDex2oatPath)
@@ -311,6 +323,7 @@
installable: true,
srcs: ["a.java"],
apex_available: ["com.android.apex1"],
+ sdk_version: "current",
}`)
ctx := result.TestContext
module := ctx.ModuleForTests("service-foo", "android_common_apex1000")
@@ -342,6 +355,7 @@
name: "foo",
installable: true,
srcs: ["a.java"],
+ sdk_version: "current",
}`)
ctx = result.TestContext
module = ctx.ModuleForTests("foo", "android_common")
@@ -398,6 +412,7 @@
installable: true,
srcs: ["a.java"],
apex_available: ["com.android.apex1"],
+ sdk_version: "current",
}`)
ctx := result.TestContext
module := ctx.ModuleForTests("service-foo", "android_common_apex1000")
@@ -429,6 +444,7 @@
name: "foo",
installable: true,
srcs: ["a.java"],
+ sdk_version: "current",
}`)
ctx = result.TestContext
module = ctx.ModuleForTests("foo", "android_common")
@@ -454,6 +470,7 @@
profile: "art-profile",
},
srcs: ["a.java"],
+ sdk_version: "current",
}`)
ctx := result.TestContext
diff --git a/java/droiddoc.go b/java/droiddoc.go
index f81c5ba..225f201 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -19,6 +19,7 @@
"path/filepath"
"strings"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -54,7 +55,7 @@
Filter_packages []string
// list of java libraries that will be in the classpath.
- Libs []string `android:"arch_variant"`
+ Libs proptools.Configurable[[]string] `android:"arch_variant"`
// If set to false, don't allow this module(-docs.zip) to be exported. Defaults to true.
Installable *bool
@@ -274,7 +275,7 @@
}
}
- ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
+ ctx.AddVariationDependencies(nil, libTag, j.properties.Libs.GetOrDefault(ctx, nil)...)
}
func (j *Javadoc) collectAidlFlags(ctx android.ModuleContext, deps deps) droiddocBuilderFlags {
@@ -357,7 +358,7 @@
deps.aidlPreprocess = sdkDep.aidl
}
- ctx.VisitDirectDeps(func(module android.Module) {
+ ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) {
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
@@ -373,15 +374,17 @@
panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
}
case libTag, sdkLibTag:
- if dep, ok := module.(SdkLibraryDependency); ok {
- deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...)
+ if sdkInfo, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok {
+ generatingLibsString := android.PrettyConcat(
+ getGeneratingLibs(ctx, j.SdkVersion(ctx), module.Name(), sdkInfo), true, "or")
+ ctx.ModuleErrorf("cannot depend directly on java_sdk_library %q; try depending on %s instead", module.Name(), generatingLibsString)
} else if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
deps.classpath = append(deps.classpath, dep.HeaderJars...)
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...)
- } else if dep, ok := module.(android.SourceFileProducer); ok {
- checkProducesJars(ctx, dep)
- deps.classpath = append(deps.classpath, dep.Srcs()...)
+ } else if dep, ok := android.OtherModuleProvider(ctx, module, android.SourceFilesInfoProvider); ok {
+ checkProducesJars(ctx, dep, module)
+ deps.classpath = append(deps.classpath, dep.Srcs...)
} else {
ctx.ModuleErrorf("depends on non-java module %q", otherName)
}
@@ -425,9 +428,9 @@
// Find the corresponding aconfig_declarations module name for such case.
for _, src := range j.properties.Srcs {
if moduleName, tag := android.SrcIsModuleWithTag(src); moduleName != "" {
- otherModule := android.GetModuleFromPathDep(ctx, moduleName, tag)
+ otherModule := android.GetModuleProxyFromPathDep(ctx, moduleName, tag)
if otherModule != nil {
- if dep, ok := android.OtherModuleProvider(ctx, otherModule, android.CodegenInfoProvider); ok {
+ if dep, ok := android.OtherModuleProvider(ctx, *otherModule, android.CodegenInfoProvider); ok {
deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...)
}
}
@@ -576,7 +579,6 @@
rule.Build("javadoc", "javadoc")
- ctx.SetOutputFiles(android.Paths{j.stubsSrcJar}, "")
ctx.SetOutputFiles(android.Paths{j.docZip}, ".docs.zip")
}
@@ -873,6 +875,13 @@
Path *string
}
+type ExportedDroiddocDirInfo struct {
+ Deps android.Paths
+ Dir android.Path
+}
+
+var ExportedDroiddocDirInfoProvider = blueprint.NewProvider[ExportedDroiddocDirInfo]()
+
type ExportedDroiddocDir struct {
android.ModuleBase
@@ -896,6 +905,11 @@
path := String(d.properties.Path)
d.dir = android.PathForModuleSrc(ctx, path)
d.deps = android.PathsForModuleSrc(ctx, []string{filepath.Join(path, "**/*")})
+
+ android.SetProvider(ctx, ExportedDroiddocDirInfoProvider, ExportedDroiddocDirInfo{
+ Dir: d.dir,
+ Deps: d.deps,
+ })
}
// Defaults
diff --git a/java/droiddoc_test.go b/java/droiddoc_test.go
index 9e1ebbe..2256f1e 100644
--- a/java/droiddoc_test.go
+++ b/java/droiddoc_test.go
@@ -23,6 +23,7 @@
)
func TestDroiddoc(t *testing.T) {
+ t.Parallel()
ctx, _ := testJavaWithFS(t, `
droiddoc_exported_dir {
name: "droiddoc-templates-sdk",
@@ -97,6 +98,7 @@
}
func TestDroiddocArgsAndFlagsCausesError(t *testing.T) {
+ t.Parallel()
testJavaError(t, "flags is set. Cannot set args", `
droiddoc_exported_dir {
name: "droiddoc-templates-sdk",
diff --git a/java/droidstubs.go b/java/droidstubs.go
index d622903..22f4d98 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -20,6 +20,7 @@
"regexp"
"strings"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -27,6 +28,28 @@
"android/soong/remoteexec"
)
+type StubsInfo struct {
+ ApiVersionsXml android.Path
+ AnnotationsZip android.Path
+ ApiFile android.Path
+ RemovedApiFile android.Path
+}
+
+type DroidStubsInfo struct {
+ CurrentApiTimestamp android.Path
+ EverythingStubsInfo StubsInfo
+ ExportableStubsInfo StubsInfo
+}
+
+var DroidStubsInfoProvider = blueprint.NewProvider[DroidStubsInfo]()
+
+type StubsSrcInfo struct {
+ EverythingStubsSrcJar android.Path
+ ExportableStubsSrcJar android.Path
+}
+
+var StubsSrcInfoProvider = blueprint.NewProvider[StubsSrcInfo]()
+
// The values allowed for Droidstubs' Api_levels_sdk_type
var allowedApiLevelSdkTypes = []string{"public", "system", "module-lib", "system-server"}
@@ -498,9 +521,9 @@
}
func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
- ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
- if t, ok := m.(*ExportedDroiddocDir); ok {
- cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps)
+ ctx.VisitDirectDepsProxyWithTag(metalavaMergeAnnotationsDirTag, func(m android.ModuleProxy) {
+ if t, ok := android.OtherModuleProvider(ctx, m, ExportedDroiddocDirInfoProvider); ok {
+ cmd.FlagWithArg("--merge-qualifier-annotations ", t.Dir.String()).Implicits(t.Deps)
} else {
ctx.PropertyErrorf("merge_annotations_dirs",
"module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
@@ -509,9 +532,9 @@
}
func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
- ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) {
- if t, ok := m.(*ExportedDroiddocDir); ok {
- cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps)
+ ctx.VisitDirectDepsProxyWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.ModuleProxy) {
+ if t, ok := android.OtherModuleProvider(ctx, m, ExportedDroiddocDirInfoProvider); ok {
+ cmd.FlagWithArg("--merge-inclusion-annotations ", t.Dir.String()).Implicits(t.Deps)
} else {
ctx.PropertyErrorf("merge_inclusion_annotations_dirs",
"module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
@@ -525,12 +548,12 @@
d.apiLevelsGenerationFlags(ctx, cmd, stubsType, apiVersionsXml)
apiVersions = apiVersionsXml
} else {
- ctx.VisitDirectDepsWithTag(metalavaAPILevelsModuleTag, func(m android.Module) {
- if s, ok := m.(*Droidstubs); ok {
+ ctx.VisitDirectDepsProxyWithTag(metalavaAPILevelsModuleTag, func(m android.ModuleProxy) {
+ if s, ok := android.OtherModuleProvider(ctx, m, DroidStubsInfoProvider); ok {
if stubsType == Everything {
- apiVersions = s.everythingArtifacts.apiVersionsXml
+ apiVersions = s.EverythingStubsInfo.ApiVersionsXml
} else if stubsType == Exportable {
- apiVersions = s.exportableArtifacts.apiVersionsXml
+ apiVersions = s.ExportableStubsInfo.ApiVersionsXml
} else {
ctx.ModuleErrorf("%s stubs type does not generate api-versions.xml file", stubsType.String())
}
@@ -603,18 +626,18 @@
var dirs []string
var extensions_dir string
- ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
- if t, ok := m.(*ExportedDroiddocDir); ok {
- extRegex := regexp.MustCompile(t.dir.String() + extensionsPattern)
+ ctx.VisitDirectDepsProxyWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.ModuleProxy) {
+ if t, ok := android.OtherModuleProvider(ctx, m, ExportedDroiddocDirInfoProvider); ok {
+ extRegex := regexp.MustCompile(t.Dir.String() + extensionsPattern)
// Grab the first extensions_dir and we find while scanning ExportedDroiddocDir.deps;
// ideally this should be read from prebuiltApis.properties.Extensions_*
- for _, dep := range t.deps {
+ for _, dep := range t.Deps {
// Check to see if it matches an extension first.
depBase := dep.Base()
if extRegex.MatchString(dep.String()) && d.properties.Extensions_info_file != nil {
if extensions_dir == "" {
- extensions_dir = t.dir.String() + "/extensions"
+ extensions_dir = t.Dir.String() + "/extensions"
}
cmd.Implicit(dep)
} else if depBase == filename {
@@ -622,23 +645,17 @@
cmd.Implicit(dep)
} else if depBase == AndroidPlusUpdatableJar && d.properties.Extensions_info_file != nil {
// The output api-versions.xml has been requested to include information on SDK
- // extensions. That means it also needs to include
- // so
- // The module-lib and system-server directories should use `android-plus-updatable.jar`
- // instead of `android.jar`. See AndroidPlusUpdatableJar for more information.
- cmd.Implicit(dep)
- } else if filename != "android.jar" && depBase == "android.jar" {
- // Metalava implicitly searches these patterns:
- // prebuilts/tools/common/api-versions/android-%/android.jar
- // prebuilts/sdk/%/public/android.jar
- // Add android.jar files from the api_levels_annotations_dirs directories to try
- // to satisfy these patterns. If Metalava can't find a match for an API level
- // between 1 and 28 in at least one pattern it will fail.
+ // extensions, i.e. updatable Apis. That means it also needs to include the history of
+ // those updatable APIs. Usually, they would be included in the `android.jar` file but
+ // unfortunately, the `module-lib` and `system-server` cannot as it would lead to build
+ // cycles. So, the module-lib and system-server directories contain an
+ // `android-plus-updatable.jar` that should be used instead of `android.jar`. See
+ // AndroidPlusUpdatableJar for more information.
cmd.Implicit(dep)
}
}
- dirs = append(dirs, t.dir.String())
+ dirs = append(dirs, t.Dir.String())
} else {
ctx.PropertyErrorf("api_levels_annotations_dirs",
"module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
@@ -646,11 +663,11 @@
})
// Generate the list of --android-jar-pattern options. The order matters so the first one which
- // matches will be the one that is used for a specific api level..
+ // matches will be the one that is used for a specific api level.
for _, sdkDir := range sdkDirs {
for _, dir := range dirs {
addPattern := func(jarFilename string) {
- cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, jarFilename))
+ cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/{version:major.minor?}/%s/%s", dir, sdkDir, jarFilename))
}
if sdkDir == "module-lib" || sdkDir == "system-server" {
@@ -665,6 +682,10 @@
addPattern(filename)
}
+
+ if extensions_dir != "" {
+ cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/{version:extension}/%s/{module}.jar", extensions_dir, sdkDir))
+ }
}
if d.properties.Extensions_info_file != nil {
@@ -673,7 +694,6 @@
}
info_file := android.PathForModuleSrc(ctx, *d.properties.Extensions_info_file)
cmd.Implicit(info_file)
- cmd.FlagWithArg("--sdk-extensions-root ", extensions_dir)
cmd.FlagWithArg("--sdk-extensions-info ", info_file.String())
}
}
@@ -700,7 +720,8 @@
}
func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths,
- srcJarList android.Path, homeDir android.WritablePath, params stubsCommandConfigParams, configFiles android.Paths) *android.RuleBuilderCommand {
+ srcJarList android.Path, homeDir android.WritablePath, params stubsCommandConfigParams,
+ configFiles android.Paths, apiSurface *string) *android.RuleBuilderCommand {
rule.Command().Text("rm -rf").Flag(homeDir.String())
rule.Command().Text("mkdir -p").Flag(homeDir.String())
@@ -746,6 +767,8 @@
addMetalavaConfigFilesToCmd(cmd, configFiles)
+ addOptionalApiSurfaceToCmd(cmd, apiSurface)
+
return cmd
}
@@ -764,20 +787,19 @@
cmd.FlagForEachInput("--config-file ", configFiles)
}
+// addOptionalApiSurfaceToCmd adds --api-surface option is apiSurface is not `nil`.
+func addOptionalApiSurfaceToCmd(cmd *android.RuleBuilderCommand, apiSurface *string) {
+ if apiSurface != nil {
+ cmd.Flag("--api-surface")
+ cmd.Flag(*apiSurface)
+ }
+}
+
// Pass flagged apis related flags to metalava. When aconfig_declarations property is not
// defined for a module, simply revert all flagged apis annotations. If aconfig_declarations
// property is defined, apply transformations and only revert the flagged apis that are not
// enabled via release configurations and are not specified in aconfig_declarations
func generateRevertAnnotationArgs(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, aconfigFlagsPaths android.Paths) {
-
- if len(aconfigFlagsPaths) == 0 {
- cmd.Flag("--revert-annotation android.annotation.FlaggedApi")
- return
- }
-
- releasedFlaggedApisFile := android.PathForModuleOut(ctx, fmt.Sprintf("released-flagged-apis-%s.txt", stubsType.String()))
- revertAnnotationsFile := android.PathForModuleOut(ctx, fmt.Sprintf("revert-annotations-%s.txt", stubsType.String()))
-
var filterArgs string
switch stubsType {
// No flagged apis specific flags need to be passed to metalava when generating
@@ -799,6 +821,15 @@
}
}
+ if len(aconfigFlagsPaths) == 0 {
+ // This argument should not be added for "everything" stubs
+ cmd.Flag("--revert-annotation android.annotation.FlaggedApi")
+ return
+ }
+
+ releasedFlaggedApisFile := android.PathForModuleOut(ctx, fmt.Sprintf("released-flagged-apis-%s.txt", stubsType.String()))
+ revertAnnotationsFile := android.PathForModuleOut(ctx, fmt.Sprintf("revert-annotations-%s.txt", stubsType.String()))
+
ctx.Build(pctx, android.BuildParams{
Rule: gatherReleasedFlaggedApisRule,
Inputs: aconfigFlagsPaths,
@@ -838,7 +869,8 @@
configFiles := android.PathsForModuleSrc(ctx, d.properties.ConfigFiles)
- cmd := metalavaCmd(ctx, rule, d.Javadoc.srcFiles, srcJarList, homeDir, params.stubConfig, configFiles)
+ cmd := metalavaCmd(ctx, rule, d.Javadoc.srcFiles, srcJarList, homeDir, params.stubConfig,
+ configFiles, d.properties.Api_surface)
cmd.Implicits(d.Javadoc.implicits)
d.stubsFlags(ctx, cmd, params.stubsDir, params.stubConfig.stubsType, params.stubConfig.checkApi)
@@ -970,6 +1002,15 @@
d.apiLintReport = android.PathForModuleOut(ctx, Everything.String(), "api_lint_report.txt")
cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO: Change to ":api-lint"
+ // If UnflaggedApi issues have not already been configured then make sure that existing
+ // UnflaggedApi issues are reported as warnings but issues in new/changed code are treated as
+ // errors by the Build Warnings Aye Aye Analyzer in Gerrit.
+ // Once existing issues have been fixed this will be changed to error.
+ // TODO(b/362771529): Switch to --error
+ if !strings.Contains(cmd.String(), " UnflaggedApi ") {
+ cmd.Flag("--error-when-new UnflaggedApi")
+ }
+
// TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released.
if d.Name() != "android.car-system-stubs-docs" &&
d.Name() != "android.car-stubs-docs" {
@@ -988,12 +1029,13 @@
msg := `$'` + // Enclose with $' ... '
`************************************************************\n` +
`Your API changes are triggering API Lint warnings or errors.\n` +
- `To make these errors go away, fix the code according to the\n` +
- `error and/or warning messages above.\n` +
`\n` +
- `If it is not possible to do so, there are workarounds:\n` +
+ `To make the failures go away:\n` +
`\n` +
- `1. You can suppress the errors with @SuppressLint("<id>")\n` +
+ `1. REQUIRED: Read the messages carefully and address them by` +
+ ` fixing the API if appropriate.\n` +
+ `2. If the failure is a false positive, you can suppress it with:\n` +
+ ` @SuppressLint("<id>")\n` +
` where the <id> is given in brackets in the error message above.\n`
if baselineFile.Valid() {
@@ -1001,8 +1043,8 @@
cmd.FlagWithOutput("--update-baseline:api-lint ", updatedBaselineOutput)
msg += fmt.Sprintf(``+
- `2. You can update the baseline by executing the following\n`+
- ` command:\n`+
+ `3. FOR LSC ONLY: You can update the baseline by executing\n`+
+ ` the following command:\n`+
` (cd $ANDROID_BUILD_TOP && cp \\\n`+
` "%s" \\\n`+
` "%s")\n`+
@@ -1010,7 +1052,7 @@
` repository, you will need approval.\n`, updatedBaselineOutput, baselineFile.Path())
} else {
msg += fmt.Sprintf(``+
- `2. You can add a baseline file of existing lint failures\n`+
+ `3. FOR LSC ONLY: You can add a baseline file of existing lint failures\n`+
` to the build rule of %s.\n`, d.Name())
}
// Note the message ends with a ' (single quote), to close the $' ... ' .
@@ -1167,6 +1209,34 @@
rule.Build(fmt.Sprintf("metalava_%s", params.stubConfig.stubsType.String()), "metalava merged")
}
+func (d *Droidstubs) setPhonyRules(ctx android.ModuleContext) {
+ if d.apiFile != nil {
+ ctx.Phony(d.Name(), d.apiFile)
+ ctx.Phony(fmt.Sprintf("%s.txt", d.Name()), d.apiFile)
+ }
+ if d.removedApiFile != nil {
+ ctx.Phony(d.Name(), d.removedApiFile)
+ ctx.Phony(fmt.Sprintf("%s.txt", d.Name()), d.removedApiFile)
+ }
+ if d.checkCurrentApiTimestamp != nil {
+ ctx.Phony(fmt.Sprintf("%s-check-current-api", d.Name()), d.checkCurrentApiTimestamp)
+ ctx.Phony("checkapi", d.checkCurrentApiTimestamp)
+ }
+ if d.updateCurrentApiTimestamp != nil {
+ ctx.Phony(fmt.Sprintf("%s-update-current-api", d.Name()), d.updateCurrentApiTimestamp)
+ ctx.Phony("update-api", d.updateCurrentApiTimestamp)
+ }
+ if d.checkLastReleasedApiTimestamp != nil {
+ ctx.Phony(fmt.Sprintf("%s-check-last-released-api", d.Name()), d.checkLastReleasedApiTimestamp)
+ }
+ if d.apiLintTimestamp != nil {
+ ctx.Phony(fmt.Sprintf("%s-api-lint", d.Name()), d.apiLintTimestamp)
+ }
+ if d.checkNullabilityWarningsTimestamp != nil {
+ ctx.Phony(fmt.Sprintf("%s-check-nullability-warnings", d.Name()), d.checkNullabilityWarningsTimestamp)
+ }
+}
+
func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
deps := d.Javadoc.collectDeps(ctx)
@@ -1210,6 +1280,41 @@
stubCmdParams.stubsType = Exportable
d.exportableStubCmd(ctx, stubCmdParams)
+ if String(d.properties.Check_nullability_warnings) != "" {
+ if d.everythingArtifacts.nullabilityWarningsFile == nil {
+ ctx.PropertyErrorf("check_nullability_warnings",
+ "Cannot specify check_nullability_warnings unless validating nullability")
+ }
+
+ checkNullabilityWarningsPath := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings))
+
+ d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, Everything.String(), "check_nullability_warnings.timestamp")
+
+ msg := fmt.Sprintf(`\n******************************\n`+
+ `The warnings encountered during nullability annotation validation did\n`+
+ `not match the checked in file of expected warnings. The diffs are shown\n`+
+ `above. You have two options:\n`+
+ ` 1. Resolve the differences by editing the nullability annotations.\n`+
+ ` 2. Update the file of expected warnings by running:\n`+
+ ` cp %s %s\n`+
+ ` and submitting the updated file as part of your change.`,
+ d.everythingArtifacts.nullabilityWarningsFile, checkNullabilityWarningsPath)
+
+ rule := android.NewRuleBuilder(pctx, ctx)
+
+ rule.Command().
+ Text("(").
+ Text("diff").Input(checkNullabilityWarningsPath).Input(d.everythingArtifacts.nullabilityWarningsFile).
+ Text("&&").
+ Text("touch").Output(d.checkNullabilityWarningsTimestamp).
+ Text(") || (").
+ Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+ Text("; exit 38").
+ Text(")")
+
+ rule.Build("nullabilityWarningsCheck", "nullability warnings check")
+ }
+
if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
if len(d.Javadoc.properties.Out) > 0 {
@@ -1259,13 +1364,25 @@
`Note that DISABLE_STUB_VALIDATION=true does not bypass checkapi.\n`+
`******************************\n`, ctx.ModuleName())
- rule.Command().
+ cmd := rule.Command().
Text("touch").Output(d.checkCurrentApiTimestamp).
Text(") || (").
Text("echo").Flag("-e").Flag(`"` + msg + `"`).
Text("; exit 38").
Text(")")
+ if d.apiLintTimestamp != nil {
+ cmd.Validation(d.apiLintTimestamp)
+ }
+
+ if d.checkLastReleasedApiTimestamp != nil {
+ cmd.Validation(d.checkLastReleasedApiTimestamp)
+ }
+
+ if d.checkNullabilityWarningsTimestamp != nil {
+ cmd.Validation(d.checkNullabilityWarningsTimestamp)
+ }
+
rule.Build("metalavaCurrentApiCheck", "check current API")
d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, Everything.String(), "update_current_api.timestamp")
@@ -1295,42 +1412,39 @@
rule.Build("metalavaCurrentApiUpdate", "update current API")
}
- if String(d.properties.Check_nullability_warnings) != "" {
- if d.everythingArtifacts.nullabilityWarningsFile == nil {
- ctx.PropertyErrorf("check_nullability_warnings",
- "Cannot specify check_nullability_warnings unless validating nullability")
- }
-
- checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings))
-
- d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, Everything.String(), "check_nullability_warnings.timestamp")
-
- msg := fmt.Sprintf(`\n******************************\n`+
- `The warnings encountered during nullability annotation validation did\n`+
- `not match the checked in file of expected warnings. The diffs are shown\n`+
- `above. You have two options:\n`+
- ` 1. Resolve the differences by editing the nullability annotations.\n`+
- ` 2. Update the file of expected warnings by running:\n`+
- ` cp %s %s\n`+
- ` and submitting the updated file as part of your change.`,
- d.everythingArtifacts.nullabilityWarningsFile, checkNullabilityWarnings)
-
- rule := android.NewRuleBuilder(pctx, ctx)
-
- rule.Command().
- Text("(").
- Text("diff").Input(checkNullabilityWarnings).Input(d.everythingArtifacts.nullabilityWarningsFile).
- Text("&&").
- Text("touch").Output(d.checkNullabilityWarningsTimestamp).
- Text(") || (").
- Text("echo").Flag("-e").Flag(`"` + msg + `"`).
- Text("; exit 38").
- Text(")")
-
- rule.Build("nullabilityWarningsCheck", "nullability warnings check")
+ droidInfo := DroidStubsInfo{
+ CurrentApiTimestamp: d.CurrentApiTimestamp(),
+ EverythingStubsInfo: StubsInfo{},
+ ExportableStubsInfo: StubsInfo{},
}
+ setDroidInfo(ctx, d, &droidInfo.EverythingStubsInfo, Everything)
+ setDroidInfo(ctx, d, &droidInfo.ExportableStubsInfo, Exportable)
+ android.SetProvider(ctx, DroidStubsInfoProvider, droidInfo)
+
+ android.SetProvider(ctx, StubsSrcInfoProvider, StubsSrcInfo{
+ EverythingStubsSrcJar: d.stubsSrcJar,
+ ExportableStubsSrcJar: d.exportableStubsSrcJar,
+ })
d.setOutputFiles(ctx)
+
+ d.setPhonyRules(ctx)
+}
+
+func setDroidInfo(ctx android.ModuleContext, d *Droidstubs, info *StubsInfo, typ StubsType) {
+ if typ == Everything {
+ info.ApiFile = d.apiFile
+ info.RemovedApiFile = d.removedApiFile
+ info.AnnotationsZip = d.everythingArtifacts.annotationsZip
+ info.ApiVersionsXml = d.everythingArtifacts.apiVersionsXml
+ } else if typ == Exportable {
+ info.ApiFile = d.exportableApiFile
+ info.RemovedApiFile = d.exportableRemovedApiFile
+ info.AnnotationsZip = d.exportableArtifacts.annotationsZip
+ info.ApiVersionsXml = d.exportableArtifacts.apiVersionsXml
+ } else {
+ ctx.ModuleErrorf("failed to set ApiVersionsXml, stubs type not supported: %d", typ)
+ }
}
// This method sets the outputFiles property, which is used to set the
@@ -1364,7 +1478,7 @@
for _, stubType := range android.SortedKeys(stubsTypeToPrefix) {
tagWithPrefix := stubsTypeToPrefix[stubType] + tag
outputFile, err := tagToOutputFileFunc[tag](stubType)
- if err == nil {
+ if err == nil && outputFile != nil {
ctx.SetOutputFiles(android.Paths{outputFile}, tagWithPrefix)
}
}
@@ -1498,6 +1612,11 @@
p.stubsSrcJar = outPath
}
+ android.SetProvider(ctx, StubsSrcInfoProvider, StubsSrcInfo{
+ EverythingStubsSrcJar: p.stubsSrcJar,
+ ExportableStubsSrcJar: p.stubsSrcJar,
+ })
+
ctx.SetOutputFiles(android.Paths{p.stubsSrcJar}, "")
// prebuilt droidstubs does not output "exportable" stubs.
// Output the "everything" stubs srcjar file if the tag is ".exportable".
diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go
index 1e8362c..faa9a15 100644
--- a/java/droidstubs_test.go
+++ b/java/droidstubs_test.go
@@ -27,6 +27,7 @@
)
func TestDroidstubs(t *testing.T) {
+ t.Parallel()
ctx, _ := testJavaWithFS(t, `
droiddoc_exported_dir {
name: "droiddoc-templates-sdk",
@@ -88,7 +89,7 @@
cmdline := String(sboxProto.Commands[0].Command)
android.AssertStringContainsEquals(t, "api-versions generation flag", cmdline, "--generate-api-levels", c.generate_xml)
if c.expectedJarFilename != "" {
- expected := "--android-jar-pattern ./%/public/" + c.expectedJarFilename
+ expected := "--android-jar-pattern ./{version:major.minor?}/public/" + c.expectedJarFilename
if !strings.Contains(cmdline, expected) {
t.Errorf("For %q, expected metalava argument %q, but was not found %q", c.moduleName, expected, cmdline)
}
@@ -139,35 +140,38 @@
}
func TestPublicDroidstubs(t *testing.T) {
+ t.Parallel()
patterns := getAndroidJarPatternsForDroidstubs(t, "public")
android.AssertArrayString(t, "order of patterns", []string{
- "--android-jar-pattern somedir/%/public/android.jar",
- "--android-jar-pattern someotherdir/%/public/android.jar",
+ "--android-jar-pattern somedir/{version:major.minor?}/public/android.jar",
+ "--android-jar-pattern someotherdir/{version:major.minor?}/public/android.jar",
}, patterns)
}
func TestSystemDroidstubs(t *testing.T) {
+ t.Parallel()
patterns := getAndroidJarPatternsForDroidstubs(t, "system")
android.AssertArrayString(t, "order of patterns", []string{
- "--android-jar-pattern somedir/%/system/android.jar",
- "--android-jar-pattern someotherdir/%/system/android.jar",
- "--android-jar-pattern somedir/%/public/android.jar",
- "--android-jar-pattern someotherdir/%/public/android.jar",
+ "--android-jar-pattern somedir/{version:major.minor?}/system/android.jar",
+ "--android-jar-pattern someotherdir/{version:major.minor?}/system/android.jar",
+ "--android-jar-pattern somedir/{version:major.minor?}/public/android.jar",
+ "--android-jar-pattern someotherdir/{version:major.minor?}/public/android.jar",
}, patterns)
}
func TestModuleLibDroidstubs(t *testing.T) {
+ t.Parallel()
patterns := getAndroidJarPatternsForDroidstubs(t, "module-lib")
android.AssertArrayString(t, "order of patterns", []string{
- "--android-jar-pattern somedir/%/module-lib/android.jar",
- "--android-jar-pattern someotherdir/%/module-lib/android.jar",
- "--android-jar-pattern somedir/%/system/android.jar",
- "--android-jar-pattern someotherdir/%/system/android.jar",
- "--android-jar-pattern somedir/%/public/android.jar",
- "--android-jar-pattern someotherdir/%/public/android.jar",
+ "--android-jar-pattern somedir/{version:major.minor?}/module-lib/android.jar",
+ "--android-jar-pattern someotherdir/{version:major.minor?}/module-lib/android.jar",
+ "--android-jar-pattern somedir/{version:major.minor?}/system/android.jar",
+ "--android-jar-pattern someotherdir/{version:major.minor?}/system/android.jar",
+ "--android-jar-pattern somedir/{version:major.minor?}/public/android.jar",
+ "--android-jar-pattern someotherdir/{version:major.minor?}/public/android.jar",
}, patterns)
}
@@ -175,14 +179,14 @@
patterns := getAndroidJarPatternsForDroidstubs(t, "system-server")
android.AssertArrayString(t, "order of patterns", []string{
- "--android-jar-pattern somedir/%/system-server/android.jar",
- "--android-jar-pattern someotherdir/%/system-server/android.jar",
- "--android-jar-pattern somedir/%/module-lib/android.jar",
- "--android-jar-pattern someotherdir/%/module-lib/android.jar",
- "--android-jar-pattern somedir/%/system/android.jar",
- "--android-jar-pattern someotherdir/%/system/android.jar",
- "--android-jar-pattern somedir/%/public/android.jar",
- "--android-jar-pattern someotherdir/%/public/android.jar",
+ "--android-jar-pattern somedir/{version:major.minor?}/system-server/android.jar",
+ "--android-jar-pattern someotherdir/{version:major.minor?}/system-server/android.jar",
+ "--android-jar-pattern somedir/{version:major.minor?}/module-lib/android.jar",
+ "--android-jar-pattern someotherdir/{version:major.minor?}/module-lib/android.jar",
+ "--android-jar-pattern somedir/{version:major.minor?}/system/android.jar",
+ "--android-jar-pattern someotherdir/{version:major.minor?}/system/android.jar",
+ "--android-jar-pattern somedir/{version:major.minor?}/public/android.jar",
+ "--android-jar-pattern someotherdir/{version:major.minor?}/public/android.jar",
}, patterns)
}
@@ -303,7 +307,7 @@
m := ctx.ModuleForTests("baz-stubs", "android_common")
manifest := m.Output("metalava.sbox.textproto")
cmdline := String(android.RuleBuilderSboxProtoForTests(t, ctx, manifest).Commands[0].Command)
- android.AssertStringDoesContain(t, "sdk-extensions-root present", cmdline, "--sdk-extensions-root sdk/extensions")
+ android.AssertStringDoesContain(t, "android-jar-pattern present", cmdline, "--android-jar-pattern sdk/extensions/{version:extension}/public/{module}.jar")
android.AssertStringDoesContain(t, "sdk-extensions-info present", cmdline, "--sdk-extensions-info sdk/extensions/info.txt")
}
diff --git a/java/fuzz.go b/java/fuzz.go
index d37c558..5973957 100644
--- a/java/fuzz.go
+++ b/java/fuzz.go
@@ -63,7 +63,7 @@
module.Module.properties.Installable = proptools.BoolPtr(true)
module.Module.dexpreopter.isTest = true
- module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
+ module.Module.linter.properties.Lint.Test_module_type = proptools.BoolPtr(true)
module.Module.sourceProperties.Test_only = proptools.BoolPtr(true)
module.Module.sourceProperties.Top_level_test_target = true
@@ -85,10 +85,11 @@
func (j *JavaFuzzTest) DepsMutator(ctx android.BottomUpMutatorContext) {
if j.Os().Class.String() == deviceString {
- j.testProperties.Jni_libs = append(j.testProperties.Jni_libs, artDeps...)
+ j.testProperties.Jni_libs.AppendSimpleValue(artDeps)
}
- if len(j.testProperties.Jni_libs) > 0 {
+ jniLibs := j.testProperties.Jni_libs.GetOrDefault(ctx, nil)
+ if len(jniLibs) > 0 {
if j.fuzzPackagedModule.FuzzProperties.Fuzz_config == nil {
config := &fuzz.FuzzConfig{}
j.fuzzPackagedModule.FuzzProperties.Fuzz_config = config
@@ -98,7 +99,7 @@
j.fuzzPackagedModule.FuzzProperties.Fuzz_config.IsJni = proptools.BoolPtr(true)
for _, target := range ctx.MultiTargets() {
sharedLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"})
- ctx.AddFarVariationDependencies(sharedLibVariations, jniLibTag, j.testProperties.Jni_libs...)
+ ctx.AddFarVariationDependencies(sharedLibVariations, jniLibTag, jniLibs...)
}
}
@@ -106,20 +107,7 @@
}
func (j *JavaFuzzTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- if j.fuzzPackagedModule.FuzzProperties.Corpus != nil {
- j.fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, j.fuzzPackagedModule.FuzzProperties.Corpus)
- }
- if j.fuzzPackagedModule.FuzzProperties.Data != nil {
- j.fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, j.fuzzPackagedModule.FuzzProperties.Data)
- }
- if j.fuzzPackagedModule.FuzzProperties.Dictionary != nil {
- j.fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *j.fuzzPackagedModule.FuzzProperties.Dictionary)
- }
- if j.fuzzPackagedModule.FuzzProperties.Fuzz_config != nil {
- configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json")
- android.WriteFileRule(ctx, configPath, j.fuzzPackagedModule.FuzzProperties.Fuzz_config.String())
- j.fuzzPackagedModule.Config = configPath
- }
+ j.fuzzPackagedModule = cc.PackageFuzzModule(ctx, j.fuzzPackagedModule)
_, sharedDeps := cc.CollectAllSharedDependencies(ctx)
for _, dep := range sharedDeps {
diff --git a/java/fuzz_test.go b/java/fuzz_test.go
index f29c913..40adae0 100644
--- a/java/fuzz_test.go
+++ b/java/fuzz_test.go
@@ -30,6 +30,7 @@
)
func TestJavaFuzz(t *testing.T) {
+ t.Parallel()
result := prepForJavaFuzzTest.RunTestWithBp(t, `
java_fuzz {
name: "foo",
diff --git a/java/gen.go b/java/gen.go
index 1b4f4c7..aab8418 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -26,15 +26,14 @@
)
func init() {
- pctx.SourcePathVariable("logtagsCmd", "build/make/tools/java-event-log-tags.py")
- pctx.SourcePathVariable("logtagsLib", "build/make/tools/event_log_tags.py")
+ pctx.HostBinToolVariable("logtagsCmd", "java-event-log-tags")
}
var (
logtags = pctx.AndroidStaticRule("logtags",
blueprint.RuleParams{
Command: "$logtagsCmd -o $out $in",
- CommandDeps: []string{"$logtagsCmd", "$logtagsLib"},
+ CommandDeps: []string{"$logtagsCmd"},
})
)
diff --git a/java/generated_java_library.go b/java/generated_java_library.go
index d5e6d8f..79f1b6f 100644
--- a/java/generated_java_library.go
+++ b/java/generated_java_library.go
@@ -70,14 +70,6 @@
module.Library.properties.Libs = append(module.Library.properties.Libs, name)
}
-// Add a java shared library as a dependency, as if they had said `libs: [ "name" ]`
-func (module *GeneratedJavaLibraryModule) AddStaticLibrary(name string) {
- if module.depsMutatorDone {
- panic("GeneratedJavaLibraryModule.AddStaticLibrary called after DepsMutator")
- }
- module.Library.properties.Static_libs = append(module.Library.properties.Static_libs, name)
-}
-
func (module *GeneratedJavaLibraryModule) DepsMutator(ctx android.BottomUpMutatorContext) {
module.callbacks.DepsMutator(module, ctx)
module.depsMutatorDone = true
diff --git a/java/generated_java_library_test.go b/java/generated_java_library_test.go
index a5c4be1..7efd54b 100644
--- a/java/generated_java_library_test.go
+++ b/java/generated_java_library_test.go
@@ -52,6 +52,7 @@
}
func TestGenLib(t *testing.T) {
+ t.Parallel()
bp := `
test_java_gen_lib {
name: "javagenlibtest",
diff --git a/java/genrule_test.go b/java/genrule_test.go
index 1c294b2..b4e9d21 100644
--- a/java/genrule_test.go
+++ b/java/genrule_test.go
@@ -31,6 +31,7 @@
}
func TestGenruleCmd(t *testing.T) {
+ t.Parallel()
fs := map[string][]byte{
"tool": nil,
"foo": nil,
@@ -64,6 +65,7 @@
}
func TestJarGenrules(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index b1a9deb..c9a1f2b 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -97,7 +97,7 @@
// Save the classes jars even if this is not active as they may be used by modular hidden API
// processing.
classesJars := android.Paths{classesJar}
- ctx.VisitDirectDepsWithTag(hiddenApiAnnotationsTag, func(dep android.Module) {
+ ctx.VisitDirectDepsProxyWithTag(hiddenApiAnnotationsTag, func(dep android.ModuleProxy) {
if javaInfo, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok {
classesJars = append(classesJars, javaInfo.ImplementationJars...)
}
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 4144de8..3650058 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -298,13 +298,12 @@
// available, or reports an error.
func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path {
var dexJar OptionalDexJarPath
- if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
+ if sdkLibrary, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok {
if ctx.Config().ReleaseHiddenApiExportableStubs() {
- dexJar = sdkLibrary.SdkApiExportableStubDexJar(ctx, kind)
+ dexJar = sdkLibrary.ExportableStubDexJarPaths[kind]
} else {
- dexJar = sdkLibrary.SdkApiStubDexJar(ctx, kind)
+ dexJar = sdkLibrary.EverythingStubDexJarPaths[kind]
}
-
} else if j, ok := module.(UsesLibraryDependency); ok {
dexJar = j.DexJarBuildPath(ctx)
} else {
@@ -853,15 +852,15 @@
i.StubDexJarsByScope.addStubDexJar(ctx, module, apiScope, dexJar)
}
- if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
- removedTxtFile := sdkLibrary.SdkRemovedTxtFile(ctx, sdkKind)
+ if sdkLibrary, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok {
+ removedTxtFile := sdkLibrary.RemovedTxtFiles[sdkKind]
i.RemovedTxtFiles = append(i.RemovedTxtFiles, removedTxtFile.AsPaths()...)
}
}
// If the contents includes any java_sdk_library modules then add them to the stubs.
for _, module := range contents {
- if _, ok := module.(SdkLibraryDependency); ok {
+ if _, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok {
// Add information for every possible API scope needed by hidden API.
for _, apiScope := range hiddenAPISdkLibrarySupportedScopes {
addFromModule(ctx, module, apiScope)
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
index afe8b4c..c14fdb7 100644
--- a/java/hiddenapi_singleton_test.go
+++ b/java/hiddenapi_singleton_test.go
@@ -44,6 +44,7 @@
)
func TestHiddenAPISingleton(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
FixtureConfigureBootJars("platform:foo"),
@@ -63,6 +64,7 @@
}
func TestHiddenAPISingletonWithSourceAndPrebuiltPreferredButNoDex(t *testing.T) {
+ t.Parallel()
expectedErrorMessage := "module prebuilt_foo{os:android,arch:common} does not provide a dex jar"
android.GroupFixturePreparers(
@@ -86,6 +88,7 @@
}
func TestHiddenAPISingletonWithPrebuilt(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
FixtureConfigureBootJars("platform:foo"),
@@ -105,6 +108,7 @@
}
func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
FixtureConfigureBootJars("platform:foo"),
@@ -134,6 +138,7 @@
}
func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
FixtureConfigureBootJars("platform:foo"),
@@ -163,6 +168,7 @@
}
func TestHiddenAPISingletonSdks(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
unbundledBuild bool
@@ -246,6 +252,7 @@
}
func TestHiddenAPISingletonWithPrebuiltCsvFile(t *testing.T) {
+ t.Parallel()
// The idea behind this test is to ensure that when the build is
// confugured with a PrebuiltHiddenApiDir that the rules for the
@@ -289,6 +296,7 @@
}
func TestHiddenAPIEncoding_JavaSdkLibrary(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
@@ -324,10 +332,7 @@
android.AssertPathRelativeToTopEquals(t, "encode embedded java_library", encodedDexJar, exportedDexJar)
}
- // The java_library embedded with the java_sdk_library must be dex encoded.
- t.Run("foo", func(t *testing.T) {
- expectedUnencodedDexJar := "out/soong/.intermediates/foo.impl/android_common/aligned/foo.jar"
- expectedEncodedDexJar := "out/soong/.intermediates/foo.impl/android_common/hiddenapi/foo.jar"
- checkDexEncoded(t, "foo", expectedUnencodedDexJar, expectedEncodedDexJar)
- })
+ expectedUnencodedDexJar := "out/soong/.intermediates/foo.impl/android_common/aligned/foo.jar"
+ expectedEncodedDexJar := "out/soong/.intermediates/foo.impl/android_common/hiddenapi/foo.jar"
+ checkDexEncoded(t, "foo", expectedUnencodedDexJar, expectedEncodedDexJar)
}
diff --git a/java/jacoco_test.go b/java/jacoco_test.go
index 1882908..58a091e 100644
--- a/java/jacoco_test.go
+++ b/java/jacoco_test.go
@@ -17,6 +17,7 @@
import "testing"
func TestJacocoFilterToSpecs(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name, in, out string
}{
@@ -54,6 +55,7 @@
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
+ t.Parallel()
got, err := jacocoFilterToSpec(testCase.in)
if err != nil {
t.Error(err)
@@ -66,6 +68,7 @@
}
func TestJacocoFiltersToZipCommand(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
includes, excludes []string
@@ -96,6 +99,7 @@
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
+ t.Parallel()
got := jacocoFiltersToZipCommand(testCase.includes, testCase.excludes)
if got != testCase.out {
t.Errorf("expected %q got %q", testCase.out, got)
diff --git a/java/java.go b/java/java.go
index 46344c8..67b9ba9 100644
--- a/java/java.go
+++ b/java/java.go
@@ -26,9 +26,9 @@
"strings"
"android/soong/remoteexec"
- "android/soong/testing"
"github.com/google/blueprint"
+ "github.com/google/blueprint/depset"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -70,9 +70,9 @@
// established, to not get the dependencies split into the wrong variants and
// to support the checks in dexpreoptDisabled().
ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("dexpreopt_tool_deps", dexpreoptToolDepsMutator).Parallel()
+ ctx.BottomUp("dexpreopt_tool_deps", dexpreoptToolDepsMutator)
// needs access to ApexInfoProvider which is available after variant creation
- ctx.BottomUp("jacoco_deps", jacocoDepsMutator).Parallel()
+ ctx.BottomUp("jacoco_deps", jacocoDepsMutator)
})
ctx.RegisterParallelSingletonType("kythe_java_extract", kytheExtractJavaFactory)
@@ -226,9 +226,9 @@
// Rule for generating device binary default wrapper
deviceBinaryWrapper = pctx.StaticRule("deviceBinaryWrapper", blueprint.RuleParams{
- Command: `echo -e '#!/system/bin/sh\n` +
+ Command: `printf '#!/system/bin/sh\n` +
`export CLASSPATH=/system/framework/$jar_name\n` +
- `exec app_process /$partition/bin $main_class "$$@"'> ${out}`,
+ `exec app_process /$partition/bin $main_class "$$@"\n'> ${out}`,
Description: "Generating device binary wrapper ${jar_name}",
}, "jar_name", "partition", "main_class")
)
@@ -242,27 +242,68 @@
// TransitiveDepsProguardSpecFiles is a depset of paths to proguard flags files that are exported from
// all transitive deps. This list includes all proguard flags files from transitive static dependencies,
// and all proguard flags files from transitive libs dependencies which set `export_proguard_spec: true`.
- ProguardFlagsFiles *android.DepSet[android.Path]
+ ProguardFlagsFiles depset.DepSet[android.Path]
// implementation detail to store transitive proguard flags files from exporting shared deps
- UnconditionallyExportedProguardFlags *android.DepSet[android.Path]
+ UnconditionallyExportedProguardFlags depset.DepSet[android.Path]
}
var ProguardSpecInfoProvider = blueprint.NewProvider[ProguardSpecInfo]()
+type AndroidLibraryDependencyInfo struct {
+ ExportPackage android.Path
+ ResourcesNodeDepSet depset.DepSet[*resourcesNode]
+ RRODirsDepSet depset.DepSet[rroDir]
+ ManifestsDepSet depset.DepSet[android.Path]
+}
+
+type UsesLibraryDependencyInfo struct {
+ DexJarBuildPath OptionalDexJarPath
+ DexJarInstallPath android.Path
+ ClassLoaderContexts dexpreopt.ClassLoaderContextMap
+}
+
+type SdkLibraryComponentDependencyInfo struct {
+ // The name of the implementation library for the optional SDK library or nil, if there isn't one.
+ OptionalSdkLibraryImplementation *string
+}
+
+type ProvidesUsesLibInfo struct {
+ ProvidesUsesLib *string
+}
+
+type ModuleWithUsesLibraryInfo struct {
+ UsesLibrary *usesLibrary
+}
+
+type ModuleWithSdkDepInfo struct {
+ SdkLinkType sdkLinkType
+ Stubs bool
+}
+
// JavaInfo contains information about a java module for use by modules that depend on it.
type JavaInfo struct {
// HeaderJars is a list of jars that can be passed as the javac classpath in order to link
// against this module. If empty, ImplementationJars should be used instead.
+ // Unlike LocalHeaderJars, HeaderJars includes classes from static dependencies.
HeaderJars android.Paths
RepackagedHeaderJars android.Paths
// set of header jars for all transitive libs deps
- TransitiveLibsHeaderJars *android.DepSet[android.Path]
+ TransitiveLibsHeaderJarsForR8 depset.DepSet[android.Path]
// set of header jars for all transitive static libs deps
- TransitiveStaticLibsHeaderJars *android.DepSet[android.Path]
+ TransitiveStaticLibsHeaderJarsForR8 depset.DepSet[android.Path]
+
+ // depset of header jars for this module and all transitive static dependencies
+ TransitiveStaticLibsHeaderJars depset.DepSet[android.Path]
+
+ // depset of implementation jars for this module and all transitive static dependencies
+ TransitiveStaticLibsImplementationJars depset.DepSet[android.Path]
+
+ // depset of resource jars for this module and all transitive static dependencies
+ TransitiveStaticLibsResourceJars depset.DepSet[android.Path]
// ImplementationAndResourceJars is a list of jars that contain the implementations of classes
// in the module as well as any resources included in the module.
@@ -275,6 +316,9 @@
// ResourceJars is a list of jars that contain the resources included in the module.
ResourceJars android.Paths
+ // LocalHeaderJars is a list of jars that contain classes from this module, but not from any static dependencies.
+ LocalHeaderJars android.Paths
+
// AidlIncludeDirs is a list of directories that should be passed to the aidl tool when
// depending on this module.
AidlIncludeDirs android.Paths
@@ -287,7 +331,7 @@
SrcJarDeps android.Paths
// The source files of this module and all its transitive static dependencies.
- TransitiveSrcFiles *android.DepSet[android.Path]
+ TransitiveSrcFiles depset.DepSet[android.Path]
// ExportedPlugins is a list of paths that should be used as annotation processors for any
// module that depends on this module.
@@ -313,10 +357,89 @@
// AconfigIntermediateCacheOutputPaths is a path to the cache files collected from the
// java_aconfig_library modules that are statically linked to this module.
AconfigIntermediateCacheOutputPaths android.Paths
+
+ SdkVersion android.SdkSpec
+
+ // output file of the module, which may be a classes jar or a dex jar
+ OutputFile android.Path
+
+ ExtraOutputFiles android.Paths
+
+ AndroidLibraryDependencyInfo *AndroidLibraryDependencyInfo
+
+ UsesLibraryDependencyInfo *UsesLibraryDependencyInfo
+
+ SdkLibraryComponentDependencyInfo *SdkLibraryComponentDependencyInfo
+
+ ProvidesUsesLibInfo *ProvidesUsesLibInfo
+
+ ModuleWithUsesLibraryInfo *ModuleWithUsesLibraryInfo
+
+ ModuleWithSdkDepInfo *ModuleWithSdkDepInfo
+
+ // output file containing classes.dex and resources
+ DexJarFile OptionalDexJarPath
+
+ // installed file for binary dependency
+ InstallFile android.Path
+
+ // The path to the dex jar that is in the boot class path. If this is unset then the associated
+ // module is not a boot jar, but could be one of the <x>-hiddenapi modules that provide additional
+ // annotations for the <x> boot dex jar but which do not actually provide a boot dex jar
+ // themselves.
+ //
+ // This must be the path to the unencoded dex jar as the encoded dex jar indirectly depends on
+ // this file so using the encoded dex jar here would result in a cycle in the ninja rules.
+ BootDexJarPath OptionalDexJarPath
+
+ // The compressed state of the dex file being encoded. This is used to ensure that the encoded
+ // dex file has the same state.
+ UncompressDexState *bool
+
+ // True if the module containing this structure contributes to the hiddenapi information or has
+ // that information encoded within it.
+ Active bool
+
+ BuiltInstalled string
+
+ BuiltInstalledForApex []dexpreopterInstall
+
+ // The config is used for two purposes:
+ // - Passing dexpreopt information about libraries from Soong to Make. This is needed when
+ // a <uses-library> is defined in Android.bp, but used in Android.mk (see dex_preopt_config_merger.py).
+ // Note that dexpreopt.config might be needed even if dexpreopt is disabled for the library itself.
+ // - Dexpreopt post-processing (using dexpreopt artifacts from a prebuilt system image to incrementally
+ // dexpreopt another partition).
+ ConfigPath android.WritablePath
+
+ // The path to the profile on host that dexpreopter generates. This is used as the input for
+ // dex2oat.
+ OutputProfilePathOnHost android.Path
+
+ LogtagsSrcs android.Paths
+
+ ProguardDictionary android.OptionalPath
+
+ ProguardUsageZip android.OptionalPath
+
+ LinterReports android.Paths
+
+ // installed file for hostdex copy
+ HostdexInstallFile android.InstallPath
+
+ // Additional srcJars tacked in by GeneratedJavaLibraryModule
+ GeneratedSrcjars []android.Path
+
+ // True if profile-guided optimization is actually enabled.
+ ProfileGuided bool
}
var JavaInfoProvider = blueprint.NewProvider[*JavaInfo]()
+type JavaLibraryInfo struct{}
+
+var JavaLibraryInfoProvider = blueprint.NewProvider[JavaLibraryInfo]()
+
// SyspropPublicStubInfo contains info about the sysprop public stub library that corresponds to
// the sysprop implementation library.
type SyspropPublicStubInfo struct {
@@ -343,12 +466,17 @@
// TODO(jungjw): Move this to kythe.go once it's created.
type xref interface {
XrefJavaFiles() android.Paths
+ XrefKotlinFiles() android.Paths
}
func (j *Module) XrefJavaFiles() android.Paths {
return j.kytheFiles
}
+func (j *Module) XrefKotlinFiles() android.Paths {
+ return j.kytheKotlinFiles
+}
+
func (d dependencyTag) PropagateAconfigValidation() bool {
return d.static
}
@@ -432,7 +560,6 @@
javaApiContributionTag = dependencyTag{name: "java-api-contribution"}
aconfigDeclarationTag = dependencyTag{name: "aconfig-declaration"}
jniInstallTag = dependencyTag{name: "jni install", runtimeLinked: true, installable: true}
- binaryInstallTag = dependencyTag{name: "binary install", runtimeLinked: true, installable: true}
usesLibReqTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, false)
usesLibOptTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, true)
usesLibCompat28OptTag = makeUsesLibraryDependencyTag(28, true)
@@ -553,7 +680,7 @@
// are provided by systemModules.
java9Classpath classpath
- processorPath classpath
+ processorPath classpath ``
errorProneProcessorPath classpath
processorClasses []string
staticJars android.Paths
@@ -568,13 +695,17 @@
aconfigProtoFiles android.Paths
disableTurbine bool
+
+ transitiveStaticLibsHeaderJars []depset.DepSet[android.Path]
+ transitiveStaticLibsImplementationJars []depset.DepSet[android.Path]
+ transitiveStaticLibsResourceJars []depset.DepSet[android.Path]
}
-func checkProducesJars(ctx android.ModuleContext, dep android.SourceFileProducer) {
- for _, f := range dep.Srcs() {
+func checkProducesJars(ctx android.ModuleContext, dep android.SourceFilesInfo, module android.ModuleProxy) {
+ for _, f := range dep.Srcs {
if f.Ext() != ".jar" {
ctx.ModuleErrorf("genrule %q must generate files ending with .jar to be used as a libs or static_libs dependency",
- ctx.OtherModuleName(dep.(blueprint.Module)))
+ ctx.OtherModuleName(module))
}
}
}
@@ -585,10 +716,8 @@
} else if ctx.Device() {
return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion(ctx))
} else if ctx.Config().TargetsJava21() {
- // Temporary experimental flag to be able to try and build with
- // java version 21 options. The flag, if used, just sets Java
- // 21 as the default version, leaving any components that
- // target an older version intact.
+ // Build flag that controls whether Java 21 is used as the default
+ // target version, or Java 17.
return JAVA_VERSION_21
} else {
return JAVA_VERSION_17
@@ -923,6 +1052,7 @@
// Even though the source javalib is not used, we need to hide it to prevent duplicate installation rules.
// TODO (b/331665856): Implement a principled solution for this.
j.HideFromMake()
+ j.SkipInstall()
}
j.provideHiddenAPIPropertyInfo(ctx)
@@ -980,25 +1110,118 @@
j.dexpreopter.disableDexpreopt()
}
}
- j.compile(ctx, nil, nil, nil)
+ javaInfo := j.compile(ctx, nil, nil, nil, nil)
- // If this module is an impl library created from java_sdk_library,
- // install the files under the java_sdk_library module outdir instead of this module outdir.
- if j.SdkLibraryName() != nil && strings.HasSuffix(j.Name(), ".impl") {
- j.setInstallRules(ctx, proptools.String(j.SdkLibraryName()))
- } else {
- j.setInstallRules(ctx, ctx.ModuleName())
- }
+ j.setInstallRules(ctx)
android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{
TestOnly: Bool(j.sourceProperties.Test_only),
TopLevelTarget: j.sourceProperties.Top_level_test_target,
})
+ android.SetProvider(ctx, JavaLibraryInfoProvider, JavaLibraryInfo{})
+
+ if javaInfo != nil {
+ setExtraJavaInfo(ctx, j, javaInfo)
+ javaInfo.ExtraOutputFiles = j.extraOutputFiles
+ javaInfo.DexJarFile = j.dexJarFile
+ javaInfo.InstallFile = j.installFile
+ javaInfo.BootDexJarPath = j.bootDexJarPath
+ javaInfo.UncompressDexState = j.uncompressDexState
+ javaInfo.Active = j.active
+ javaInfo.BuiltInstalledForApex = j.builtInstalledForApex
+ javaInfo.BuiltInstalled = j.builtInstalled
+ javaInfo.ConfigPath = j.configPath
+ javaInfo.OutputProfilePathOnHost = j.outputProfilePathOnHost
+ javaInfo.LogtagsSrcs = j.logtagsSrcs
+ javaInfo.ProguardDictionary = j.proguardDictionary
+ javaInfo.ProguardUsageZip = j.proguardUsageZip
+ javaInfo.LinterReports = j.reports
+ javaInfo.HostdexInstallFile = j.hostdexInstallFile
+ javaInfo.GeneratedSrcjars = j.properties.Generated_srcjars
+ javaInfo.ProfileGuided = j.dexpreopter.dexpreoptProperties.Dex_preopt_result.Profile_guided
+
+ android.SetProvider(ctx, JavaInfoProvider, javaInfo)
+ }
+
setOutputFiles(ctx, j.Module)
+
+ j.javaLibraryModuleInfoJSON(ctx)
+
+ buildComplianceMetadata(ctx)
}
-func (j *Library) setInstallRules(ctx android.ModuleContext, installModuleName string) {
+func (j *Library) javaLibraryModuleInfoJSON(ctx android.ModuleContext) *android.ModuleInfoJSON {
+ moduleInfoJSON := ctx.ModuleInfoJSON()
+ moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"}
+ if j.implementationAndResourcesJar != nil {
+ moduleInfoJSON.ClassesJar = []string{j.implementationAndResourcesJar.String()}
+ }
+ moduleInfoJSON.SystemSharedLibs = []string{"none"}
+
+ if j.hostDexNeeded() {
+ hostDexModuleInfoJSON := ctx.ExtraModuleInfoJSON()
+ hostDexModuleInfoJSON.SubName = "-hostdex"
+ hostDexModuleInfoJSON.Class = []string{"JAVA_LIBRARIES"}
+ if j.implementationAndResourcesJar != nil {
+ hostDexModuleInfoJSON.ClassesJar = []string{j.implementationAndResourcesJar.String()}
+ }
+ hostDexModuleInfoJSON.SystemSharedLibs = []string{"none"}
+ hostDexModuleInfoJSON.SupportedVariantsOverride = []string{"HOST"}
+ }
+
+ if j.hideApexVariantFromMake {
+ moduleInfoJSON.Disabled = true
+ j.dexpreopter.ModuleInfoJSONForApex(ctx)
+ }
+ return moduleInfoJSON
+}
+
+func buildComplianceMetadata(ctx android.ModuleContext) {
+ // Dump metadata that can not be done in android/compliance-metadata.go
+ complianceMetadataInfo := ctx.ComplianceMetadataInfo()
+ builtFiles := ctx.GetOutputFiles().DefaultOutputFiles.Strings()
+ for _, paths := range ctx.GetOutputFiles().TaggedOutputFiles {
+ builtFiles = append(builtFiles, paths.Strings()...)
+ }
+ complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.BUILT_FILES, android.FirstUniqueStrings(builtFiles))
+
+ // Static deps
+ staticDepNames := make([]string, 0)
+ staticDepFiles := android.Paths{}
+ ctx.VisitDirectDepsWithTag(staticLibTag, func(module android.Module) {
+ if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
+ staticDepNames = append(staticDepNames, module.Name())
+ staticDepFiles = append(staticDepFiles, dep.ImplementationJars...)
+ staticDepFiles = append(staticDepFiles, dep.HeaderJars...)
+ staticDepFiles = append(staticDepFiles, dep.ResourceJars...)
+ }
+ })
+ complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.STATIC_DEPS, android.FirstUniqueStrings(staticDepNames))
+ complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.STATIC_DEP_FILES, android.FirstUniqueStrings(staticDepFiles.Strings()))
+}
+
+func (j *Library) getJarInstallDir(ctx android.ModuleContext) android.InstallPath {
+ var installDir android.InstallPath
+ if ctx.InstallInTestcases() {
+ var archDir string
+ if !ctx.Host() {
+ archDir = ctx.DeviceConfig().DeviceArch()
+ }
+ installModuleName := ctx.ModuleName()
+ // If this module is an impl library created from java_sdk_library,
+ // install the files under the java_sdk_library module outdir instead of this module outdir.
+ if j.SdkLibraryName() != nil && strings.HasSuffix(j.Name(), ".impl") {
+ installModuleName = proptools.String(j.SdkLibraryName())
+ }
+ installDir = android.PathForModuleInstall(ctx, installModuleName, archDir)
+ } else {
+ installDir = android.PathForModuleInstall(ctx, "framework")
+ }
+ return installDir
+}
+
+func (j *Library) setInstallRules(ctx android.ModuleContext) {
apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
if (Bool(j.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() {
@@ -1008,21 +1231,11 @@
}
hostDexNeeded := Bool(j.deviceProperties.Hostdex) && !ctx.Host()
if hostDexNeeded {
- j.hostdexInstallFile = ctx.InstallFile(
+ j.hostdexInstallFile = ctx.InstallFileWithoutCheckbuild(
android.PathForHostDexInstall(ctx, "framework"),
j.Stem()+"-hostdex.jar", j.outputFile)
}
- var installDir android.InstallPath
- if ctx.InstallInTestcases() {
- var archDir string
- if !ctx.Host() {
- archDir = ctx.DeviceConfig().DeviceArch()
- }
- installDir = android.PathForModuleInstall(ctx, installModuleName, archDir)
- } else {
- installDir = android.PathForModuleInstall(ctx, "framework")
- }
- j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...)
+ j.installFile = ctx.InstallFileWithoutCheckbuild(j.getJarInstallDir(ctx), j.Stem()+".jar", j.outputFile, extraInstallDeps...)
}
}
@@ -1266,6 +1479,22 @@
// the test
Data []string `android:"path"`
+ // Same as data, but will add dependencies on modules using the device's os variation and
+ // the common arch variation. Useful for a host test that wants to embed a module built for
+ // device.
+ Device_common_data []string `android:"path_device_common"`
+
+ // same as data, but adds dependencies using the device's os variation and the device's first
+ // architecture's variation. Can be used to add a module built for device to the data of a
+ // host test.
+ Device_first_data []string `android:"path_device_first"`
+
+ // same as data, but adds dependencies using the device's os variation and the device's first
+ // 32-bit architecture's variation. If a 32-bit arch doesn't exist for this device, it will use
+ // a 64 bit arch instead. Can be used to add a module built for device to the data of a
+ // host test.
+ Device_first_prefer32_data []string `android:"path_device_first_prefer32"`
+
// Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
// explicitly.
@@ -1279,7 +1508,7 @@
Test_options TestOptions
// Names of modules containing JNI libraries that should be installed alongside the test.
- Jni_libs []string
+ Jni_libs proptools.Configurable[[]string]
// Install the test into a folder named for the module in all test suites.
Per_testcase_directory *bool
@@ -1463,10 +1692,11 @@
}
}
- if len(j.testProperties.Jni_libs) > 0 {
+ jniLibs := j.testProperties.Jni_libs.GetOrDefault(ctx, nil)
+ if len(jniLibs) > 0 {
for _, target := range ctx.MultiTargets() {
sharedLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"})
- ctx.AddFarVariationDependencies(sharedLibVariations, jniLibTag, j.testProperties.Jni_libs...)
+ ctx.AddFarVariationDependencies(sharedLibVariations, jniLibTag, jniLibs...)
}
}
@@ -1515,23 +1745,28 @@
}
j.Test.generateAndroidBuildActionsWithConfig(ctx, configs)
- android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
android.SetProvider(ctx, tradefed.BaseTestProviderKey, tradefed.BaseTestProviderData{
- InstalledFiles: j.data,
- OutputFile: j.outputFile,
- TestConfig: j.testConfig,
- RequiredModuleNames: j.RequiredModuleNames(ctx),
- TestSuites: j.testProperties.Test_suites,
- IsHost: true,
- LocalSdkVersion: j.sdkVersion.String(),
- IsUnitTest: Bool(j.testProperties.Test_options.Unit_test),
+ TestcaseRelDataFiles: testcaseRel(j.data),
+ OutputFile: j.outputFile,
+ TestConfig: j.testConfig,
+ RequiredModuleNames: j.RequiredModuleNames(ctx),
+ TestSuites: j.testProperties.Test_suites,
+ IsHost: true,
+ LocalSdkVersion: j.sdkVersion.String(),
+ IsUnitTest: Bool(j.testProperties.Test_options.Unit_test),
+ MkInclude: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
+ MkAppClass: "JAVA_LIBRARIES",
})
+
+ moduleInfoJSON := ctx.ModuleInfoJSON()
+ if proptools.Bool(j.testProperties.Test_options.Unit_test) {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "host-unit-tests")
+ }
}
func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
checkMinSdkVersionMts(ctx, j.MinSdkVersion(ctx))
j.generateAndroidBuildActionsWithConfig(ctx, nil)
- android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
}
func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, configs []tradefed.Config) {
@@ -1555,18 +1790,23 @@
})
j.data = android.PathsForModuleSrc(ctx, j.testProperties.Data)
+ j.data = append(j.data, android.PathsForModuleSrc(ctx, j.testProperties.Device_common_data)...)
+ j.data = append(j.data, android.PathsForModuleSrc(ctx, j.testProperties.Device_first_data)...)
+ j.data = append(j.data, android.PathsForModuleSrc(ctx, j.testProperties.Device_first_prefer32_data)...)
j.extraTestConfigs = android.PathsForModuleSrc(ctx, j.testProperties.Test_options.Extra_test_configs)
- ctx.VisitDirectDepsWithTag(dataNativeBinsTag, func(dep android.Module) {
+ ctx.VisitDirectDepsProxyWithTag(dataNativeBinsTag, func(dep android.ModuleProxy) {
j.data = append(j.data, android.OutputFileForModule(ctx, dep, ""))
})
- ctx.VisitDirectDepsWithTag(dataDeviceBinsTag, func(dep android.Module) {
+ ctx.VisitDirectDepsProxyWithTag(dataDeviceBinsTag, func(dep android.ModuleProxy) {
j.data = append(j.data, android.OutputFileForModule(ctx, dep, ""))
})
- ctx.VisitDirectDepsWithTag(jniLibTag, func(dep android.Module) {
+ var directImplementationDeps android.Paths
+ var transitiveImplementationDeps []depset.DepSet[android.Path]
+ ctx.VisitDirectDepsProxyWithTag(jniLibTag, func(dep android.ModuleProxy) {
sharedLibInfo, _ := android.OtherModuleProvider(ctx, dep, cc.SharedLibraryInfoProvider)
if sharedLibInfo.SharedLibrary != nil {
// Copy to an intermediate output directory to append "lib[64]" to the path,
@@ -1584,16 +1824,85 @@
Output: relocatedLib,
})
j.data = append(j.data, relocatedLib)
+
+ directImplementationDeps = append(directImplementationDeps, android.OutputFileForModule(ctx, dep, ""))
+ if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok {
+ transitiveImplementationDeps = append(transitiveImplementationDeps, info.ImplementationDeps)
+ }
} else {
ctx.PropertyErrorf("jni_libs", "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep))
}
})
+ android.SetProvider(ctx, cc.ImplementationDepInfoProvider, &cc.ImplementationDepInfo{
+ ImplementationDeps: depset.New(depset.PREORDER, directImplementationDeps, transitiveImplementationDeps),
+ })
+
j.Library.GenerateAndroidBuildActions(ctx)
+
+ moduleInfoJSON := ctx.ModuleInfoJSON()
+ // LOCAL_MODULE_TAGS
+ moduleInfoJSON.Tags = append(moduleInfoJSON.Tags, "tests")
+ var allTestConfigs android.Paths
+ if j.testConfig != nil {
+ allTestConfigs = append(allTestConfigs, j.testConfig)
+ }
+ allTestConfigs = append(allTestConfigs, j.extraTestConfigs...)
+ if len(allTestConfigs) > 0 {
+ moduleInfoJSON.TestConfig = allTestConfigs.Strings()
+ } else {
+ optionalConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "AndroidTest.xml")
+ if optionalConfig.Valid() {
+ moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, optionalConfig.String())
+ }
+ }
+ if len(j.testProperties.Test_suites) > 0 {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, j.testProperties.Test_suites...)
+ } else {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite")
+ }
+ if _, ok := j.testConfig.(android.WritablePath); ok {
+ moduleInfoJSON.AutoTestConfig = []string{"true"}
+ }
+ if proptools.Bool(j.testProperties.Test_options.Unit_test) {
+ moduleInfoJSON.IsUnitTest = "true"
+ if ctx.Host() {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "host-unit-tests")
+ }
+ }
+ moduleInfoJSON.TestMainlineModules = append(moduleInfoJSON.TestMainlineModules, j.testProperties.Test_mainline_modules...)
+
+ // Install test deps
+ if !ctx.Config().KatiEnabled() {
+ pathInTestCases := android.PathForModuleInstall(ctx, "testcases", ctx.ModuleName())
+ if j.testConfig != nil {
+ ctx.InstallFile(pathInTestCases, ctx.ModuleName()+".config", j.testConfig)
+ }
+ testDeps := append(j.data, j.extraTestConfigs...)
+ for _, data := range android.SortedUniquePaths(testDeps) {
+ dataPath := android.DataPath{SrcPath: data}
+ ctx.InstallTestData(pathInTestCases, []android.DataPath{dataPath})
+ }
+ if j.installFile != nil {
+ ctx.InstallFile(pathInTestCases, ctx.ModuleName()+".jar", j.installFile)
+ }
+ }
}
func (j *TestHelperLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.Library.GenerateAndroidBuildActions(ctx)
+
+ moduleInfoJSON := ctx.ModuleInfoJSON()
+ moduleInfoJSON.Tags = append(moduleInfoJSON.Tags, "tests")
+ if len(j.testHelperLibraryProperties.Test_suites) > 0 {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, j.testHelperLibraryProperties.Test_suites...)
+ } else {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite")
+ }
+ optionalConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "AndroidTest.xml")
+ if optionalConfig.Valid() {
+ moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, optionalConfig.String())
+ }
}
func (j *JavaTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -1683,7 +1992,7 @@
module.Module.properties.Installable = proptools.BoolPtr(true)
module.Module.dexpreopter.isTest = true
- module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
+ module.Module.linter.properties.Lint.Test_module_type = proptools.BoolPtr(true)
module.Module.sourceProperties.Test_only = proptools.BoolPtr(true)
module.Module.sourceProperties.Top_level_test_target = true
@@ -1700,7 +2009,7 @@
module.Module.properties.Installable = proptools.BoolPtr(true)
module.Module.dexpreopter.isTest = true
- module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
+ module.Module.linter.properties.Lint.Test_module_type = proptools.BoolPtr(true)
module.Module.sourceProperties.Test_only = proptools.BoolPtr(true)
InitJavaModule(module, android.HostAndDeviceSupported)
@@ -1772,8 +2081,7 @@
// Name of the class containing main to be inserted into the manifest as Main-Class.
Main_class *string
- // Names of modules containing JNI libraries that should be installed alongside the host
- // variant of the binary.
+ // Names of modules containing JNI libraries that should be installed alongside the binary.
Jni_libs []string `android:"arch_variant"`
}
@@ -1782,10 +2090,10 @@
binaryProperties binaryProperties
- isWrapperVariant bool
-
wrapperFile android.Path
binaryFile android.InstallPath
+
+ androidMkNamesOfJniLibs []string
}
func (j *Binary) HostToolPath() android.OptionalPath {
@@ -1795,84 +2103,94 @@
func (j *Binary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.stem = proptools.StringDefault(j.overridableProperties.Stem, ctx.ModuleName())
- if ctx.Arch().ArchType == android.Common {
- // Compile the jar
- if j.binaryProperties.Main_class != nil {
- if j.properties.Manifest != nil {
- ctx.PropertyErrorf("main_class", "main_class cannot be used when manifest is set")
- }
- manifestFile := android.PathForModuleOut(ctx, "manifest.txt")
- GenerateMainClassManifest(ctx, manifestFile, String(j.binaryProperties.Main_class))
- j.overrideManifest = android.OptionalPathForPath(manifestFile)
- }
-
- j.Library.GenerateAndroidBuildActions(ctx)
+ // Handle the binary wrapper. This comes before compiling the jar so that the wrapper
+ // is the first PackagingSpec
+ if j.binaryProperties.Wrapper != nil {
+ j.wrapperFile = android.PathForModuleSrc(ctx, *j.binaryProperties.Wrapper)
} else {
- // Handle the binary wrapper
- j.isWrapperVariant = true
-
- if j.binaryProperties.Wrapper != nil {
- j.wrapperFile = android.PathForModuleSrc(ctx, *j.binaryProperties.Wrapper)
- } else {
- if ctx.Windows() {
- ctx.PropertyErrorf("wrapper", "wrapper is required for Windows")
- }
-
- if ctx.Device() {
- // device binary should have a main_class property if it does not
- // have a specific wrapper, so that a default wrapper can
- // be generated for it.
- if j.binaryProperties.Main_class == nil {
- ctx.PropertyErrorf("main_class", "main_class property "+
- "is required for device binary if no default wrapper is assigned")
- } else {
- wrapper := android.PathForModuleOut(ctx, ctx.ModuleName()+".sh")
- jarName := j.Stem() + ".jar"
- partition := j.PartitionTag(ctx.DeviceConfig())
- ctx.Build(pctx, android.BuildParams{
- Rule: deviceBinaryWrapper,
- Output: wrapper,
- Args: map[string]string{
- "jar_name": jarName,
- "partition": partition,
- "main_class": String(j.binaryProperties.Main_class),
- },
- })
- j.wrapperFile = wrapper
- }
- } else {
- j.wrapperFile = android.PathForSource(ctx, "build/soong/scripts/jar-wrapper.sh")
- }
- }
-
- ext := ""
if ctx.Windows() {
- ext = ".bat"
+ ctx.PropertyErrorf("wrapper", "wrapper is required for Windows")
}
- // The host installation rules make the installed wrapper depend on all the dependencies
- // of the wrapper variant, which will include the common variant's jar file and any JNI
- // libraries. This is verified by TestBinary.
- j.binaryFile = ctx.InstallExecutable(android.PathForModuleInstall(ctx, "bin"),
- ctx.ModuleName()+ext, j.wrapperFile)
-
- setOutputFiles(ctx, j.Library.Module)
+ if ctx.Device() {
+ // device binary should have a main_class property if it does not
+ // have a specific wrapper, so that a default wrapper can
+ // be generated for it.
+ if j.binaryProperties.Main_class == nil {
+ ctx.PropertyErrorf("main_class", "main_class property "+
+ "is required for device binary if no default wrapper is assigned")
+ } else {
+ wrapper := android.PathForModuleOut(ctx, ctx.ModuleName()+".sh")
+ jarName := j.Stem() + ".jar"
+ partition := j.PartitionTag(ctx.DeviceConfig())
+ ctx.Build(pctx, android.BuildParams{
+ Rule: deviceBinaryWrapper,
+ Output: wrapper,
+ Args: map[string]string{
+ "jar_name": jarName,
+ "partition": partition,
+ "main_class": String(j.binaryProperties.Main_class),
+ },
+ })
+ j.wrapperFile = wrapper
+ }
+ } else {
+ j.wrapperFile = android.PathForSource(ctx, "build/soong/scripts/jar-wrapper.sh")
+ }
}
+
+ ext := ""
+ if ctx.Windows() {
+ ext = ".bat"
+ }
+
+ // The host installation rules make the installed wrapper depend on all the dependencies
+ // of the wrapper variant, which will include the common variant's jar file and any JNI
+ // libraries. This is verified by TestBinary. Also make it depend on the jar file so that
+ // the binary file timestamp will update when the jar file timestamp does. The jar file is
+ // built later on, in j.Library.GenerateAndroidBuildActions, so we have to create an identical
+ // installpath representing it here.
+ j.binaryFile = ctx.InstallExecutable(android.PathForModuleInstall(ctx, "bin"),
+ ctx.ModuleName()+ext, j.wrapperFile, j.getJarInstallDir(ctx).Join(ctx, j.Stem()+".jar"))
+
+ // Set the jniLibs of this binary.
+ // These will be added to `LOCAL_REQUIRED_MODULES`, and the kati packaging system will
+ // install these alongside the java binary.
+ ctx.VisitDirectDepsProxyWithTag(jniInstallTag, func(jni android.ModuleProxy) {
+ // Use the BaseModuleName of the dependency (without any prebuilt_ prefix)
+ commonInfo, _ := android.OtherModuleProvider(ctx, jni, android.CommonModuleInfoKey)
+ j.androidMkNamesOfJniLibs = append(j.androidMkNamesOfJniLibs, commonInfo.BaseModuleName+":"+commonInfo.Target.Arch.ArchType.Bitness())
+ })
+ // Check that native libraries are not listed in `required`. Prompt users to use `jni_libs` instead.
+ ctx.VisitDirectDepsProxyWithTag(android.RequiredDepTag, func(dep android.ModuleProxy) {
+ if _, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, dep, cc.SharedLibraryInfoProvider); hasSharedLibraryInfo {
+ ctx.ModuleErrorf("cc_library %s is no longer supported in `required` of java_binary modules. Please use jni_libs instead.", dep.Name())
+ }
+ })
+
+ // Compile the jar
+ if j.binaryProperties.Main_class != nil {
+ if j.properties.Manifest != nil {
+ ctx.PropertyErrorf("main_class", "main_class cannot be used when manifest is set")
+ }
+ manifestFile := android.PathForModuleOut(ctx, "manifest.txt")
+ GenerateMainClassManifest(ctx, manifestFile, String(j.binaryProperties.Main_class))
+ j.overrideManifest = android.OptionalPathForPath(manifestFile)
+ }
+
+ j.Library.GenerateAndroidBuildActions(ctx)
}
func (j *Binary) DepsMutator(ctx android.BottomUpMutatorContext) {
- if ctx.Arch().ArchType == android.Common {
- j.deps(ctx)
- }
+ j.deps(ctx)
// These dependencies ensure the installation rules will install the jar file when the
- // wrapper is installed, and the jni libraries on host when the wrapper is installed.
- if ctx.Arch().ArchType != android.Common && ctx.Os().Class == android.Host {
- ctx.AddVariationDependencies(nil, jniInstallTag, j.binaryProperties.Jni_libs...)
- }
- if ctx.Arch().ArchType != android.Common {
- ctx.AddVariationDependencies(
- []blueprint.Variation{{Mutator: "arch", Variation: android.CommonArch.String()}},
- binaryInstallTag, ctx.ModuleName())
+ // wrapper is installed, and the jni libraries when the wrapper is installed.
+ if ctx.Os().Class == android.Host {
+ ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniInstallTag, j.binaryProperties.Jni_libs...)
+ } else if ctx.Os().Class == android.Device {
+ ctx.AddVariationDependencies(ctx.Config().AndroidFirstDeviceTarget.Variations(), jniInstallTag, j.binaryProperties.Jni_libs...)
+ } else {
+ ctx.ModuleErrorf("Unknown os class")
}
}
@@ -1892,7 +2210,7 @@
module.Module.properties.Installable = proptools.BoolPtr(true)
- android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommonFirst)
+ android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
return module
@@ -1910,7 +2228,7 @@
module.Module.properties.Installable = proptools.BoolPtr(true)
- android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommonFirst)
+ android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
return module
}
@@ -1994,11 +2312,11 @@
// List of shared java libs that this module has dependencies to and
// should be passed as classpath in javac invocation
- Libs []string
+ Libs proptools.Configurable[[]string]
// List of java libs that this module has static dependencies to and will be
// merge zipped after metalava invocation
- Static_libs []string
+ Static_libs proptools.Configurable[[]string]
// Version of previously released API file for compatibility check.
Previous_api *string `android:"path"`
@@ -2063,7 +2381,7 @@
func metalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder,
srcs android.Paths, homeDir android.WritablePath,
- classpath android.Paths, configFiles android.Paths) *android.RuleBuilderCommand {
+ classpath android.Paths, configFiles android.Paths, apiSurface *string) *android.RuleBuilderCommand {
rule.Command().Text("rm -rf").Flag(homeDir.String())
rule.Command().Text("mkdir -p").Flag(homeDir.String())
@@ -2104,6 +2422,8 @@
addMetalavaConfigFilesToCmd(cmd, configFiles)
+ addOptionalApiSurfaceToCmd(cmd, apiSurface)
+
if len(classpath) == 0 {
// The main purpose of the `--api-class-resolution api` option is to force metalava to ignore
// classes on the classpath when an API file contains missing classes. However, as this command
@@ -2174,8 +2494,8 @@
}
}
- ctx.AddVariationDependencies(nil, libTag, al.properties.Libs...)
- ctx.AddVariationDependencies(nil, staticLibTag, al.properties.Static_libs...)
+ ctx.AddVariationDependencies(nil, libTag, al.properties.Libs.GetOrDefault(ctx, nil)...)
+ ctx.AddVariationDependencies(nil, staticLibTag, al.properties.Static_libs.GetOrDefault(ctx, nil)...)
for _, aconfigDeclarationsName := range al.properties.Aconfig_declarations {
ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfigDeclarationsName)
@@ -2187,6 +2507,17 @@
var scopeOrderMap = AllApiScopes.MapToIndex(
func(s *apiScope) string { return s.name })
+// Add some extra entries into scopeOrderMap for some special api surface names needed by libcore,
+// external/conscrypt and external/icu and java/core-libraries.
+func init() {
+ count := len(scopeOrderMap)
+ scopeOrderMap["core"] = count + 1
+ scopeOrderMap["core-platform"] = count + 2
+ scopeOrderMap["intra-core"] = count + 3
+ scopeOrderMap["core-platform-plus-public"] = count + 4
+ scopeOrderMap["core-platform-legacy"] = count + 5
+}
+
func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFilesInfo []JavaApiImportInfo) []JavaApiImportInfo {
for _, srcFileInfo := range srcFilesInfo {
if srcFileInfo.ApiSurface == "" {
@@ -2235,7 +2566,7 @@
var bootclassPaths android.Paths
var staticLibs android.Paths
var systemModulesPaths android.Paths
- ctx.VisitDirectDeps(func(dep android.Module) {
+ ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) {
tag := ctx.OtherModuleDependencyTag(dep)
switch tag {
case javaApiContributionTag:
@@ -2247,22 +2578,25 @@
case libTag:
if provider, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok {
classPaths = append(classPaths, provider.HeaderJars...)
+ al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.AconfigIntermediateCacheOutputPaths...)
}
case bootClasspathTag:
if provider, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok {
bootclassPaths = append(bootclassPaths, provider.HeaderJars...)
+ al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.AconfigIntermediateCacheOutputPaths...)
}
case staticLibTag:
if provider, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok {
staticLibs = append(staticLibs, provider.HeaderJars...)
+ al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.AconfigIntermediateCacheOutputPaths...)
}
case systemModulesTag:
if sm, ok := android.OtherModuleProvider(ctx, dep, SystemModulesProvider); ok {
systemModulesPaths = append(systemModulesPaths, sm.HeaderJars...)
}
case metalavaCurrentApiTimestampTag:
- if currentApiTimestampProvider, ok := dep.(currentApiTimestampProvider); ok {
- al.validationPaths = append(al.validationPaths, currentApiTimestampProvider.CurrentApiTimestamp())
+ if currentApiTimestampProvider, ok := android.OtherModuleProvider(ctx, dep, DroidStubsInfoProvider); ok {
+ al.validationPaths = append(al.validationPaths, currentApiTimestampProvider.CurrentApiTimestamp)
}
case aconfigDeclarationTag:
if provider, ok := android.OtherModuleProvider(ctx, dep, android.AconfigDeclarationsProviderKey); ok {
@@ -2294,7 +2628,7 @@
combinedPaths := append(([]android.Path)(nil), systemModulesPaths...)
combinedPaths = append(combinedPaths, classPaths...)
combinedPaths = append(combinedPaths, bootclassPaths...)
- cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir, combinedPaths, configFiles)
+ cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir, combinedPaths, configFiles, al.properties.Api_surface)
al.stubsFlags(ctx, cmd, stubsDir)
@@ -2358,14 +2692,19 @@
ctx.Phony(ctx.ModuleName(), al.stubsJar)
- android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
- HeaderJars: android.PathsIfNonNil(al.stubsJar),
- ImplementationAndResourcesJars: android.PathsIfNonNil(al.stubsJar),
- ImplementationJars: android.PathsIfNonNil(al.stubsJar),
- AidlIncludeDirs: android.Paths{},
- StubsLinkType: Stubs,
+ javaInfo := &JavaInfo{
+ HeaderJars: android.PathsIfNonNil(al.stubsJar),
+ LocalHeaderJars: android.PathsIfNonNil(al.stubsJar),
+ TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, android.PathsIfNonNil(al.stubsJar), nil),
+ TransitiveStaticLibsImplementationJars: depset.New(depset.PREORDER, android.PathsIfNonNil(al.stubsJar), nil),
+ ImplementationAndResourcesJars: android.PathsIfNonNil(al.stubsJar),
+ ImplementationJars: android.PathsIfNonNil(al.stubsJar),
+ AidlIncludeDirs: android.Paths{},
+ StubsLinkType: Stubs,
// No aconfig libraries on api libraries
- })
+ }
+ setExtraJavaInfo(ctx, al, javaInfo)
+ android.SetProvider(ctx, JavaInfoProvider, javaInfo)
}
func (al *ApiLibrary) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
@@ -2404,19 +2743,19 @@
return al.SdkVersion(ctx).ApiLevel
}
-func (al *ApiLibrary) IDEInfo(i *android.IdeInfo) {
- i.Deps = append(i.Deps, al.ideDeps()...)
- i.Libs = append(i.Libs, al.properties.Libs...)
- i.Static_libs = append(i.Static_libs, al.properties.Static_libs...)
+func (al *ApiLibrary) IDEInfo(ctx android.BaseModuleContext, i *android.IdeInfo) {
+ i.Deps = append(i.Deps, al.ideDeps(ctx)...)
+ i.Libs = append(i.Libs, al.properties.Libs.GetOrDefault(ctx, nil)...)
+ i.Static_libs = append(i.Static_libs, al.properties.Static_libs.GetOrDefault(ctx, nil)...)
i.SrcJars = append(i.SrcJars, al.stubsSrcJar.String())
}
// deps of java_api_library for module_bp_java_deps.json
-func (al *ApiLibrary) ideDeps() []string {
+func (al *ApiLibrary) ideDeps(ctx android.BaseModuleContext) []string {
ret := []string{}
- ret = append(ret, al.properties.Libs...)
- ret = append(ret, al.properties.Static_libs...)
- if al.properties.System_modules != nil {
+ ret = append(ret, al.properties.Libs.GetOrDefault(ctx, nil)...)
+ ret = append(ret, al.properties.Static_libs.GetOrDefault(ctx, nil)...)
+ if proptools.StringDefault(al.properties.System_modules, "none") != "none" {
ret = append(ret, proptools.String(al.properties.System_modules))
}
// Other non java_library dependencies like java_api_contribution are ignored for now.
@@ -2459,7 +2798,7 @@
Libs []string
// List of static java libs that this module has dependencies to
- Static_libs []string
+ Static_libs proptools.Configurable[[]string]
// List of files to remove from the jar file(s)
Exclude_files []string
@@ -2587,20 +2926,9 @@
return nil
}
-func (j *Import) LintDepSets() LintDepSets {
- return LintDepSets{}
-}
-
-func (j *Import) getStrictUpdatabilityLinting() bool {
- return false
-}
-
-func (j *Import) setStrictUpdatabilityLinting(bool) {
-}
-
func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) {
ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
- ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs...)
+ ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs.GetOrDefault(ctx, nil)...)
if ctx.Device() && Bool(j.dexProperties.Compile_dex) {
sdkDeps(ctx, android.SdkContext(j), j.dexer)
@@ -2634,43 +2962,74 @@
var flags javaBuilderFlags
- j.collectTransitiveHeaderJars(ctx)
+ var transitiveClasspathHeaderJars []depset.DepSet[android.Path]
+ var transitiveBootClasspathHeaderJars []depset.DepSet[android.Path]
+ var transitiveStaticLibsHeaderJars []depset.DepSet[android.Path]
+ var transitiveStaticLibsImplementationJars []depset.DepSet[android.Path]
+ var transitiveStaticLibsResourceJars []depset.DepSet[android.Path]
+
+ j.collectTransitiveHeaderJarsForR8(ctx)
var staticJars android.Paths
var staticResourceJars android.Paths
var staticHeaderJars android.Paths
- ctx.VisitDirectDeps(func(module android.Module) {
+ ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) {
tag := ctx.OtherModuleDependencyTag(module)
if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
switch tag {
case libTag, sdkLibTag:
flags.classpath = append(flags.classpath, dep.HeaderJars...)
flags.dexClasspath = append(flags.dexClasspath, dep.HeaderJars...)
+ transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
case staticLibTag:
flags.classpath = append(flags.classpath, dep.HeaderJars...)
staticJars = append(staticJars, dep.ImplementationJars...)
staticResourceJars = append(staticResourceJars, dep.ResourceJars...)
staticHeaderJars = append(staticHeaderJars, dep.HeaderJars...)
+ transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+ transitiveStaticLibsHeaderJars = append(transitiveStaticLibsHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+ transitiveStaticLibsImplementationJars = append(transitiveStaticLibsImplementationJars, dep.TransitiveStaticLibsImplementationJars)
+ transitiveStaticLibsResourceJars = append(transitiveStaticLibsResourceJars, dep.TransitiveStaticLibsResourceJars)
case bootClasspathTag:
flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars...)
+ transitiveBootClasspathHeaderJars = append(transitiveBootClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
}
- } else if dep, ok := module.(SdkLibraryDependency); ok {
+ } else if _, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok {
switch tag {
case libTag, sdkLibTag:
- flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...)
+ sdkInfo, _ := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider)
+ generatingLibsString := android.PrettyConcat(
+ getGeneratingLibs(ctx, j.SdkVersion(ctx), module.Name(), sdkInfo), true, "or")
+ ctx.ModuleErrorf("cannot depend directly on java_sdk_library %q; try depending on %s instead", module.Name(), generatingLibsString)
}
}
addCLCFromDep(ctx, module, j.classLoaderContexts)
})
- jars := android.PathsForModuleSrc(ctx, j.properties.Jars)
+ localJars := android.PathsForModuleSrc(ctx, j.properties.Jars)
jarName := j.Stem() + ".jar"
+ // Combine only the local jars together for use in transitive classpaths.
+ // Always pass input jar through TransformJarsToJar to strip module-info.class from prebuilts.
+ localCombinedHeaderJar := android.PathForModuleOut(ctx, "local-combined", jarName)
+ TransformJarsToJar(ctx, localCombinedHeaderJar, "combine local prebuilt implementation jars", localJars, android.OptionalPath{},
+ false, j.properties.Exclude_files, j.properties.Exclude_dirs)
+ localStrippedJars := android.Paths{localCombinedHeaderJar}
+
+ completeStaticLibsHeaderJars := depset.New(depset.PREORDER, localStrippedJars, transitiveStaticLibsHeaderJars)
+ completeStaticLibsImplementationJars := depset.New(depset.PREORDER, localStrippedJars, transitiveStaticLibsImplementationJars)
+ completeStaticLibsResourceJars := depset.New(depset.PREORDER, nil, transitiveStaticLibsResourceJars)
+
// Always pass the input jars to TransformJarsToJar, even if there is only a single jar, we need the output
// file of the module to be named jarName.
var outputFile android.Path
combinedImplementationJar := android.PathForModuleOut(ctx, "combined", jarName)
- implementationJars := append(slices.Clone(jars), staticJars...)
+ var implementationJars android.Paths
+ if ctx.Config().UseTransitiveJarsInClasspath() {
+ implementationJars = completeStaticLibsImplementationJars.ToList()
+ } else {
+ implementationJars = append(slices.Clone(localJars), staticJars...)
+ }
TransformJarsToJar(ctx, combinedImplementationJar, "combine prebuilt implementation jars", implementationJars, android.OptionalPath{},
false, j.properties.Exclude_files, j.properties.Exclude_dirs)
outputFile = combinedImplementationJar
@@ -2693,7 +3052,12 @@
if reuseImplementationJarAsHeaderJar {
headerJar = outputFile
} else {
- headerJars := append(slices.Clone(jars), staticHeaderJars...)
+ var headerJars android.Paths
+ if ctx.Config().UseTransitiveJarsInClasspath() {
+ headerJars = completeStaticLibsHeaderJars.ToList()
+ } else {
+ headerJars = append(slices.Clone(localJars), staticHeaderJars...)
+ }
headerOutputFile := android.PathForModuleOut(ctx, "turbine-combined", jarName)
TransformJarsToJar(ctx, headerOutputFile, "combine prebuilt header jars", headerJars, android.OptionalPath{},
false, j.properties.Exclude_files, j.properties.Exclude_dirs)
@@ -2712,6 +3076,11 @@
} else {
headerJar = outputFile
}
+
+ // Enabling jetifier requires modifying classes from transitive dependencies, disable transitive
+ // classpath and use the combined header jar instead.
+ completeStaticLibsHeaderJars = depset.New(depset.PREORDER, android.Paths{headerJar}, nil)
+ completeStaticLibsImplementationJars = depset.New(depset.PREORDER, android.Paths{outputFile}, nil)
}
implementationJarFile := outputFile
@@ -2725,6 +3094,23 @@
outputFile = combinedJar
}
+ proguardFlags := android.PathForModuleOut(ctx, "proguard_flags")
+ TransformJarToR8Rules(ctx, proguardFlags, outputFile)
+
+ transitiveProguardFlags, transitiveUnconditionalExportedFlags := collectDepProguardSpecInfo(ctx)
+ android.SetProvider(ctx, ProguardSpecInfoProvider, ProguardSpecInfo{
+ ProguardFlagsFiles: depset.New[android.Path](
+ depset.POSTORDER,
+ android.Paths{proguardFlags},
+ transitiveProguardFlags,
+ ),
+ UnconditionallyExportedProguardFlags: depset.New[android.Path](
+ depset.POSTORDER,
+ nil,
+ transitiveUnconditionalExportedFlags,
+ ),
+ })
+
// Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource.
// Also strip the relative path from the header output file so that the reuseImplementationJarAsHeaderJar check
// in a module that depends on this module considers them equal.
@@ -2735,42 +3121,21 @@
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
+ if ctx.Config().UseTransitiveJarsInClasspath() {
+ ctx.CheckbuildFile(localJars...)
+ } else {
+ ctx.CheckbuildFile(outputFile)
+ }
+
if ctx.Device() {
- // If this is a variant created for a prebuilt_apex then use the dex implementation jar
- // obtained from the associated deapexer module.
+ // Shared libraries deapexed from prebuilt apexes are no longer supported.
+ // Set the dexJarBuildPath to a fake path.
+ // This allows soong analysis pass, but will be an error during ninja execution if there are
+ // any rdeps.
ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
if ai.ForPrebuiltApex {
- // Get the path of the dex implementation jar from the `deapexer` module.
- di, err := android.FindDeapexerProviderForModule(ctx)
- if err != nil {
- // An error was found, possibly due to multiple apexes in the tree that export this library
- // Defer the error till a client tries to call DexJarBuildPath
- j.dexJarFileErr = err
- j.initHiddenAPIError(err)
- return
- }
- dexJarFileApexRootRelative := ApexRootRelativePathToJavaLib(j.BaseModuleName())
- if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil {
- dexJarFile := makeDexJarPathFromPath(dexOutputPath)
- j.dexJarFile = dexJarFile
- installPath := android.PathForModuleInPartitionInstall(ctx, "apex", ai.ApexVariationName, ApexRootRelativePathToJavaLib(j.BaseModuleName()))
- j.dexJarInstallFile = installPath
-
- j.dexpreopter.installPath = j.dexpreopter.getInstallPath(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), installPath)
- setUncompressDex(ctx, &j.dexpreopter, &j.dexer)
- j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
-
- if profilePath := di.PrebuiltExportPath(dexJarFileApexRootRelative + ".prof"); profilePath != nil {
- j.dexpreopter.inputProfilePathOnHost = profilePath
- }
-
- // Initialize the hiddenapi structure.
- j.initHiddenAPI(ctx, dexJarFile, outputFile, j.dexProperties.Uncompress_dex)
- } else {
- // This should never happen as a variant for a prebuilt_apex is only created if the
- // prebuilt_apex has been configured to export the java library dex file.
- ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt APEX %s", di.ApexModuleName())
- }
+ j.dexJarFile = makeDexJarPathFromPath(android.PathForModuleInstall(ctx, "intentionally_no_longer_supported"))
+ j.initHiddenAPI(ctx, j.dexJarFile, outputFile, j.dexProperties.Uncompress_dex)
} else if Bool(j.dexProperties.Compile_dex) {
sdkDep := decodeSdkDep(ctx, android.SdkContext(j))
if sdkDep.invalidVersion {
@@ -2801,6 +3166,7 @@
if ctx.Failed() {
return
}
+ ctx.CheckbuildFile(dexOutputFile)
// Initialize the hiddenapi structure.
j.initHiddenAPI(ctx, makeDexJarPathFromPath(dexOutputFile), outputFile, j.dexProperties.Uncompress_dex)
@@ -2813,20 +3179,28 @@
}
}
- android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
- HeaderJars: android.PathsIfNonNil(j.combinedHeaderFile),
- TransitiveLibsHeaderJars: j.transitiveLibsHeaderJars,
- TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
- ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedImplementationFile),
- ImplementationJars: android.PathsIfNonNil(implementationJarFile.WithoutRel()),
- ResourceJars: android.PathsIfNonNil(resourceJarFile),
- AidlIncludeDirs: j.exportAidlIncludeDirs,
- StubsLinkType: j.stubsLinkType,
+ javaInfo := &JavaInfo{
+ HeaderJars: android.PathsIfNonNil(j.combinedHeaderFile),
+ LocalHeaderJars: android.PathsIfNonNil(j.combinedHeaderFile),
+ TransitiveLibsHeaderJarsForR8: j.transitiveLibsHeaderJarsForR8,
+ TransitiveStaticLibsHeaderJarsForR8: j.transitiveStaticLibsHeaderJarsForR8,
+ TransitiveStaticLibsHeaderJars: completeStaticLibsHeaderJars,
+ TransitiveStaticLibsImplementationJars: completeStaticLibsImplementationJars,
+ TransitiveStaticLibsResourceJars: completeStaticLibsResourceJars,
+ ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedImplementationFile),
+ ImplementationJars: android.PathsIfNonNil(implementationJarFile.WithoutRel()),
+ ResourceJars: android.PathsIfNonNil(resourceJarFile),
+ AidlIncludeDirs: j.exportAidlIncludeDirs,
+ StubsLinkType: j.stubsLinkType,
// TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
- })
+ }
+ setExtraJavaInfo(ctx, j, javaInfo)
+ android.SetProvider(ctx, JavaInfoProvider, javaInfo)
ctx.SetOutputFiles(android.Paths{j.combinedImplementationFile}, "")
ctx.SetOutputFiles(android.Paths{j.combinedImplementationFile}, ".jar")
+
+ buildComplianceMetadata(ctx)
}
func (j *Import) maybeInstall(ctx android.ModuleContext, jarName string, outputFile android.Path) {
@@ -2873,8 +3247,8 @@
var _ android.ApexModule = (*Import)(nil)
// Implements android.ApexModule
-func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
- return j.depIsInSameApex(ctx, dep)
+func (j *Import) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
+ return j.depIsInSameApex(tag)
}
// Implements android.ApexModule
@@ -2933,8 +3307,8 @@
// Collect information for opening IDE project files in java/jdeps.go.
-func (j *Import) IDEInfo(dpInfo *android.IdeInfo) {
- dpInfo.Jars = append(dpInfo.Jars, j.combinedHeaderFile.String())
+func (j *Import) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
+ dpInfo.Jars = append(dpInfo.Jars, j.combinedImplementationFile.String())
}
func (j *Import) IDECustomizedModuleName() string {
@@ -3038,21 +3412,10 @@
return nil
}
-func (a *DexImport) LintDepSets() LintDepSets {
- return LintDepSets{}
-}
-
func (j *DexImport) IsInstallable() bool {
return true
}
-func (j *DexImport) getStrictUpdatabilityLinting() bool {
- return false
-}
-
-func (j *DexImport) setStrictUpdatabilityLinting(bool) {
-}
-
func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if len(j.properties.Jars) != 1 {
ctx.PropertyErrorf("jars", "exactly one jar must be provided")
@@ -3207,6 +3570,9 @@
&JavaApiLibraryProperties{},
&bootclasspathFragmentProperties{},
&SourceOnlyBootclasspathProperties{},
+ &ravenwoodTestProperties{},
+ &AndroidAppImportProperties{},
+ &UsesLibraryProperties{},
)
android.InitDefaultsModule(module)
@@ -3222,15 +3588,20 @@
func (ks *kytheExtractJavaSingleton) GenerateBuildActions(ctx android.SingletonContext) {
var xrefTargets android.Paths
+ var xrefKotlinTargets android.Paths
ctx.VisitAllModules(func(module android.Module) {
if javaModule, ok := module.(xref); ok {
xrefTargets = append(xrefTargets, javaModule.XrefJavaFiles()...)
+ xrefKotlinTargets = append(xrefKotlinTargets, javaModule.XrefKotlinFiles()...)
}
})
// TODO(asmundak): perhaps emit a rule to output a warning if there were no xrefTargets
if len(xrefTargets) > 0 {
ctx.Phony("xref_java", xrefTargets...)
}
+ if len(xrefKotlinTargets) > 0 {
+ ctx.Phony("xref_kotlin", xrefKotlinTargets...)
+ }
}
var Bool = proptools.Bool
@@ -3239,24 +3610,28 @@
var inList = android.InList[string]
// Add class loader context (CLC) of a given dependency to the current CLC.
-func addCLCFromDep(ctx android.ModuleContext, depModule android.Module,
+func addCLCFromDep(ctx android.ModuleContext, depModule android.ModuleProxy,
clcMap dexpreopt.ClassLoaderContextMap) {
- dep, ok := depModule.(UsesLibraryDependency)
- if !ok {
+ dep, ok := android.OtherModuleProvider(ctx, depModule, JavaInfoProvider)
+ if !ok || dep.UsesLibraryDependencyInfo == nil {
return
}
depName := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(depModule))
var sdkLib *string
- if lib, ok := depModule.(SdkLibraryDependency); ok && lib.sharedLibrary() {
+ if lib, ok := android.OtherModuleProvider(ctx, depModule, SdkLibraryInfoProvider); ok && lib.SharedLibrary {
// A shared SDK library. This should be added as a top-level CLC element.
sdkLib = &depName
- } else if ulib, ok := depModule.(ProvidesUsesLib); ok {
+ } else if lib := dep.SdkLibraryComponentDependencyInfo; lib != nil && lib.OptionalSdkLibraryImplementation != nil {
+ if depModule.Name() == proptools.String(lib.OptionalSdkLibraryImplementation)+".impl" {
+ sdkLib = lib.OptionalSdkLibraryImplementation
+ }
+ } else if ulib := dep.ProvidesUsesLibInfo; ulib != nil {
// A non-SDK library disguised as an SDK library by the means of `provides_uses_lib`
// property. This should be handled in the same way as a shared SDK library.
- sdkLib = ulib.ProvidesUsesLib()
+ sdkLib = ulib.ProvidesUsesLib
}
depTag := ctx.OtherModuleDependencyTag(depModule)
@@ -3283,26 +3658,27 @@
if sdkLib != nil {
optional := false
if module, ok := ctx.Module().(ModuleWithUsesLibrary); ok {
- if android.InList(*sdkLib, module.UsesLibrary().usesLibraryProperties.Optional_uses_libs) {
+ if android.InList(*sdkLib, module.UsesLibrary().usesLibraryProperties.Optional_uses_libs.GetOrDefault(ctx, nil)) {
optional = true
}
}
clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *sdkLib, optional,
- dep.DexJarBuildPath(ctx).PathOrNil(), dep.DexJarInstallPath(), dep.ClassLoaderContexts())
+ dep.UsesLibraryDependencyInfo.DexJarBuildPath.PathOrNil(),
+ dep.UsesLibraryDependencyInfo.DexJarInstallPath, dep.UsesLibraryDependencyInfo.ClassLoaderContexts)
} else {
- clcMap.AddContextMap(dep.ClassLoaderContexts(), depName)
+ clcMap.AddContextMap(dep.UsesLibraryDependencyInfo.ClassLoaderContexts, depName)
}
}
-func addMissingOptionalUsesLibsFromDep(ctx android.ModuleContext, depModule android.Module,
+func addMissingOptionalUsesLibsFromDep(ctx android.ModuleContext, depModule android.ModuleProxy,
usesLibrary *usesLibrary) {
- dep, ok := depModule.(ModuleWithUsesLibrary)
- if !ok {
+ dep, ok := android.OtherModuleProvider(ctx, depModule, JavaInfoProvider)
+ if !ok || dep.ModuleWithUsesLibraryInfo == nil {
return
}
- for _, lib := range dep.UsesLibrary().usesLibraryProperties.Missing_optional_uses_libs {
+ for _, lib := range dep.ModuleWithUsesLibraryInfo.UsesLibrary.usesLibraryProperties.Missing_optional_uses_libs {
if !android.InList(lib, usesLibrary.usesLibraryProperties.Missing_optional_uses_libs) {
usesLibrary.usesLibraryProperties.Missing_optional_uses_libs =
append(usesLibrary.usesLibraryProperties.Missing_optional_uses_libs, lib)
@@ -3358,3 +3734,48 @@
func (ap *JavaApiContributionImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
ap.JavaApiContribution.GenerateAndroidBuildActions(ctx)
}
+
+func setExtraJavaInfo(ctx android.ModuleContext, module android.Module, javaInfo *JavaInfo) {
+ if alDep, ok := module.(AndroidLibraryDependency); ok {
+ javaInfo.AndroidLibraryDependencyInfo = &AndroidLibraryDependencyInfo{
+ ExportPackage: alDep.ExportPackage(),
+ ResourcesNodeDepSet: alDep.ResourcesNodeDepSet(),
+ RRODirsDepSet: alDep.RRODirsDepSet(),
+ ManifestsDepSet: alDep.ManifestsDepSet(),
+ }
+ }
+
+ if ulDep, ok := module.(UsesLibraryDependency); ok {
+ javaInfo.UsesLibraryDependencyInfo = &UsesLibraryDependencyInfo{
+ DexJarBuildPath: ulDep.DexJarBuildPath(ctx),
+ DexJarInstallPath: ulDep.DexJarInstallPath(),
+ ClassLoaderContexts: ulDep.ClassLoaderContexts(),
+ }
+ }
+
+ if slcDep, ok := module.(SdkLibraryComponentDependency); ok {
+ javaInfo.SdkLibraryComponentDependencyInfo = &SdkLibraryComponentDependencyInfo{
+ OptionalSdkLibraryImplementation: slcDep.OptionalSdkLibraryImplementation(),
+ }
+ }
+
+ if pul, ok := module.(ProvidesUsesLib); ok {
+ javaInfo.ProvidesUsesLibInfo = &ProvidesUsesLibInfo{
+ ProvidesUsesLib: pul.ProvidesUsesLib(),
+ }
+ }
+
+ if mwul, ok := module.(ModuleWithUsesLibrary); ok {
+ javaInfo.ModuleWithUsesLibraryInfo = &ModuleWithUsesLibraryInfo{
+ UsesLibrary: mwul.UsesLibrary(),
+ }
+ }
+
+ if mwsd, ok := module.(moduleWithSdkDep); ok {
+ linkType, stubs := mwsd.getSdkLinkType(ctx, ctx.ModuleName())
+ javaInfo.ModuleWithSdkDepInfo = &ModuleWithSdkDepInfo{
+ SdkLinkType: linkType,
+ Stubs: stubs,
+ }
+ }
+}
diff --git a/java/java_resources.go b/java/java_resources.go
index b0dc5a1..c525233 100644
--- a/java/java_resources.go
+++ b/java/java_resources.go
@@ -17,6 +17,7 @@
import (
"fmt"
"path/filepath"
+ "slices"
"strings"
"github.com/google/blueprint/pathtools"
@@ -99,10 +100,7 @@
// that should not be treated as resources (including *.java).
func ResourceFilesToJarArgs(ctx android.ModuleContext,
res, exclude []string) (args []string, deps android.Paths) {
-
- exclude = append([]string(nil), exclude...)
- exclude = append(exclude, resourceExcludes...)
- return resourceFilesToJarArgs(ctx, res, exclude)
+ return resourceFilesToJarArgs(ctx, res, slices.Concat(exclude, resourceExcludes))
}
func resourceFilesToJarArgs(ctx android.ModuleContext,
diff --git a/java/java_test.go b/java/java_test.go
index 9e39b51..de58237 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -20,6 +20,7 @@
"path/filepath"
"reflect"
"runtime"
+ "slices"
"strconv"
"strings"
"testing"
@@ -116,6 +117,7 @@
// Test that the PrepareForTestWithJavaDefaultModules provides all the files that it uses by
// running it in a fixture that requires all source files to exist.
func TestPrepareForTestWithJavaDefaultModules(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
android.PrepareForTestDisallowNonExistentPaths,
@@ -123,6 +125,7 @@
}
func TestJavaLinkType(t *testing.T) {
+ t.Parallel()
testJava(t, `
java_library {
name: "foo",
@@ -211,7 +214,8 @@
}
func TestSimple(t *testing.T) {
- ctx, _ := testJava(t, `
+ t.Parallel()
+ bp := `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -222,35 +226,163 @@
java_library {
name: "bar",
srcs: ["b.java"],
+ static_libs: ["quz"],
}
java_library {
name: "baz",
srcs: ["c.java"],
+ static_libs: ["quz"],
}
- `)
- javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
- combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
+ java_library {
+ name: "quz",
+ srcs: ["d.java"],
+ }`
- if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
- t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
+ frameworkTurbineCombinedJars := []string{
+ "out/soong/.intermediates/default/java/ext/android_common/turbine-combined/ext.jar",
+ "out/soong/.intermediates/default/java/framework/android_common/turbine-combined/framework.jar",
}
- baz := ctx.ModuleForTests("baz", "android_common").Rule("javac").Output.String()
- barTurbine := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar")
- bazTurbine := filepath.Join("out", "soong", ".intermediates", "baz", "android_common", "turbine-combined", "baz.jar")
+ frameworkTurbineJars := []string{
+ "out/soong/.intermediates/default/java/ext/android_common/turbine/ext.jar",
+ "out/soong/.intermediates/default/java/framework/android_common/turbine/framework.jar",
+ }
- android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], barTurbine)
+ testCases := []struct {
+ name string
- android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], bazTurbine)
+ preparer android.FixturePreparer
- if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
- t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
+ fooJavacInputs []string
+ fooJavacClasspath []string
+ fooCombinedInputs []string
+ fooHeaderCombinedInputs []string
+
+ barJavacInputs []string
+ barJavacClasspath []string
+ barCombinedInputs []string
+ barHeaderCombinedInputs []string
+ }{
+ {
+ name: "normal",
+ preparer: android.NullFixturePreparer,
+ fooJavacInputs: []string{"a.java"},
+ fooJavacClasspath: slices.Concat(
+ frameworkTurbineCombinedJars,
+ []string{
+ "out/soong/.intermediates/bar/android_common/turbine-combined/bar.jar",
+ "out/soong/.intermediates/baz/android_common/turbine-combined/baz.jar",
+ },
+ ),
+ fooCombinedInputs: []string{
+ "out/soong/.intermediates/foo/android_common/javac/foo.jar",
+ "out/soong/.intermediates/baz/android_common/combined/baz.jar",
+ },
+
+ fooHeaderCombinedInputs: []string{
+ "out/soong/.intermediates/foo/android_common/turbine/foo.jar",
+ "out/soong/.intermediates/baz/android_common/turbine-combined/baz.jar",
+ },
+
+ barJavacInputs: []string{"b.java"},
+ barJavacClasspath: slices.Concat(
+ frameworkTurbineCombinedJars,
+ []string{
+ "out/soong/.intermediates/quz/android_common/turbine-combined/quz.jar",
+ },
+ ),
+ barCombinedInputs: []string{
+ "out/soong/.intermediates/bar/android_common/javac/bar.jar",
+ "out/soong/.intermediates/quz/android_common/javac/quz.jar",
+ },
+ barHeaderCombinedInputs: []string{
+ "out/soong/.intermediates/bar/android_common/turbine/bar.jar",
+ "out/soong/.intermediates/quz/android_common/turbine-combined/quz.jar",
+ },
+ },
+ {
+ name: "transitive classpath",
+ preparer: PrepareForTestWithTransitiveClasspathEnabled,
+ fooJavacInputs: []string{"a.java"},
+ fooJavacClasspath: slices.Concat(
+ frameworkTurbineJars,
+ []string{
+ "out/soong/.intermediates/bar/android_common/turbine/bar.jar",
+ "out/soong/.intermediates/quz/android_common/turbine/quz.jar",
+ "out/soong/.intermediates/baz/android_common/turbine/baz.jar",
+ },
+ ),
+ fooCombinedInputs: []string{
+ "out/soong/.intermediates/foo/android_common/javac/foo.jar",
+ "out/soong/.intermediates/baz/android_common/javac/baz.jar",
+ "out/soong/.intermediates/quz/android_common/javac/quz.jar",
+ },
+
+ fooHeaderCombinedInputs: []string{
+ "out/soong/.intermediates/foo/android_common/turbine/foo.jar",
+ "out/soong/.intermediates/baz/android_common/turbine/baz.jar",
+ "out/soong/.intermediates/quz/android_common/turbine/quz.jar",
+ },
+
+ barJavacInputs: []string{"b.java"},
+ barJavacClasspath: slices.Concat(
+ frameworkTurbineJars,
+ []string{"out/soong/.intermediates/quz/android_common/turbine/quz.jar"},
+ ),
+ barCombinedInputs: []string{
+ "out/soong/.intermediates/bar/android_common/javac/bar.jar",
+ "out/soong/.intermediates/quz/android_common/javac/quz.jar",
+ },
+ barHeaderCombinedInputs: []string{
+ "out/soong/.intermediates/bar/android_common/turbine/bar.jar",
+ "out/soong/.intermediates/quz/android_common/turbine/quz.jar",
+ },
+ },
+ }
+
+ for _, tt := range testCases {
+ t.Run(tt.name, func(t *testing.T) {
+ t.Parallel()
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ tt.preparer,
+ ).RunTestWithBp(t, bp)
+ foo := result.ModuleForTests("foo", "android_common")
+
+ fooJavac := foo.Rule("javac")
+ android.AssertPathsRelativeToTopEquals(t, "foo javac inputs", tt.fooJavacInputs, fooJavac.Inputs)
+
+ fooJavacClasspath := fooJavac.Args["classpath"]
+ android.AssertStringPathsRelativeToTopEquals(t, "foo javac classpath", result.Config, tt.fooJavacClasspath,
+ strings.Split(strings.TrimPrefix(fooJavacClasspath, "-classpath "), ":"))
+
+ fooCombinedJar := foo.Output("combined/foo.jar")
+ android.AssertPathsRelativeToTopEquals(t, "foo combined inputs", tt.fooCombinedInputs, fooCombinedJar.Inputs)
+
+ fooCombinedHeaderJar := foo.Output("turbine-combined/foo.jar")
+ android.AssertPathsRelativeToTopEquals(t, "foo header combined inputs", tt.fooHeaderCombinedInputs, fooCombinedHeaderJar.Inputs)
+
+ bar := result.ModuleForTests("bar", "android_common")
+ barJavac := bar.Rule("javac")
+ android.AssertPathsRelativeToTopEquals(t, "bar javac inputs", tt.barJavacInputs, barJavac.Inputs)
+
+ barJavacClasspath := barJavac.Args["classpath"]
+ android.AssertStringPathsRelativeToTopEquals(t, "bar javac classpath", result.Config, tt.barJavacClasspath,
+ strings.Split(strings.TrimPrefix(barJavacClasspath, "-classpath "), ":"))
+
+ barCombinedJar := bar.Output("combined/bar.jar")
+ android.AssertPathsRelativeToTopEquals(t, "bar combined inputs", tt.barCombinedInputs, barCombinedJar.Inputs)
+
+ barCombinedHeaderJar := bar.Output("turbine-combined/bar.jar")
+ android.AssertPathsRelativeToTopEquals(t, "bar header combined inputs", tt.barHeaderCombinedInputs, barCombinedHeaderJar.Inputs)
+ })
}
}
func TestExportedPlugins(t *testing.T) {
+ t.Parallel()
type Result struct {
library string
processors string
@@ -329,6 +461,7 @@
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_plugin {
name: "plugin",
@@ -357,6 +490,7 @@
}
func TestSdkVersionByPartition(t *testing.T) {
+ t.Parallel()
testJavaError(t, "sdk_version must have a value when the module is located at vendor or product", `
java_library {
name: "foo",
@@ -398,6 +532,7 @@
}
func TestArchSpecific(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
@@ -417,6 +552,7 @@
}
func TestBinary(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library_host {
name: "foo",
@@ -442,8 +578,7 @@
bar := ctx.ModuleForTests("bar", buildOS+"_common")
barJar := bar.Output("bar.jar").Output.String()
- barWrapper := ctx.ModuleForTests("bar", buildOS+"_x86_64")
- barWrapperDeps := barWrapper.Output("bar").Implicits.Strings()
+ barWrapperDeps := bar.Output("bar").Implicits.Strings()
libjni := ctx.ModuleForTests("libjni", buildOS+"_x86_64_shared")
libjniSO := libjni.Rule("Cp").Output.String()
@@ -460,6 +595,7 @@
}
func TestTest(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_test_host {
name: "foo",
@@ -492,6 +628,7 @@
}
func TestHostBinaryNoJavaDebugInfoOverride(t *testing.T) {
+ t.Parallel()
bp := `
java_library {
name: "target_library",
@@ -539,11 +676,12 @@
var _ android.ModuleErrorfContext = (*moduleErrorfTestCtx)(nil)
func TestPrebuilts(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
srcs: ["a.java", ":stubs-source"],
- libs: ["bar", "sdklib"],
+ libs: ["bar", "sdklib.stubs"],
static_libs: ["baz"],
}
@@ -590,7 +728,7 @@
barModule := ctx.ModuleForTests("bar", "android_common")
barJar := barModule.Output("combined/bar.jar").Output
bazModule := ctx.ModuleForTests("baz", "android_common")
- bazJar := bazModule.Rule("combineJar").Output
+ bazJar := bazModule.Output("combined/baz.jar").Output
sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").
Output("combined/sdklib.stubs.jar").Output
@@ -639,6 +777,7 @@
}
func TestPrebuiltStubsSources(t *testing.T) {
+ t.Parallel()
test := func(t *testing.T, sourcesPath string, expectedInputs []string) {
ctx, _ := testJavaWithFS(t, fmt.Sprintf(`
prebuilt_stubs_sources {
@@ -656,10 +795,12 @@
}
t.Run("empty/missing directory", func(t *testing.T) {
+ t.Parallel()
test(t, "empty-directory", nil)
})
t.Run("non-empty set of sources", func(t *testing.T) {
+ t.Parallel()
test(t, "stubs/sources", []string{
"stubs/sources/pkg/A.java",
"stubs/sources/pkg/B.java",
@@ -668,6 +809,7 @@
}
func TestDefaults(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_defaults {
name: "defaults",
@@ -743,6 +885,7 @@
}
func TestResources(t *testing.T) {
+ t.Parallel()
var table = []struct {
name string
prop string
@@ -814,6 +957,7 @@
for _, test := range table {
t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
ctx, _ := testJavaWithFS(t, `
java_library {
name: "foo",
@@ -849,6 +993,7 @@
}
func TestIncludeSrcs(t *testing.T) {
+ t.Parallel()
ctx, _ := testJavaWithFS(t, `
java_library {
name: "foo",
@@ -916,6 +1061,7 @@
}
func TestGeneratedSources(t *testing.T) {
+ t.Parallel()
ctx, _ := testJavaWithFS(t, `
java_library {
name: "foo",
@@ -952,6 +1098,7 @@
}
func TestTurbine(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest, FixtureWithPrebuiltApis(map[string][]string{"14": {"foo"}})).
RunTestWithBp(t, `
@@ -993,6 +1140,7 @@
}
func TestSharding(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "bar",
@@ -1011,6 +1159,7 @@
}
func TestExcludeFileGroupInSrcs(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
@@ -1037,6 +1186,7 @@
}
func TestJavaLibraryOutputFiles(t *testing.T) {
+ t.Parallel()
testJavaWithFS(t, "", map[string][]byte{
"libcore/Android.bp": []byte(`
java_library {
@@ -1047,13 +1197,14 @@
filegroup {
name: "core-jar",
- srcs: [":core{.jar}"],
+ device_common_srcs: [":core{.jar}"],
}
`),
})
}
func TestJavaImportOutputFiles(t *testing.T) {
+ t.Parallel()
testJavaWithFS(t, "", map[string][]byte{
"libcore/Android.bp": []byte(`
java_import {
@@ -1063,13 +1214,14 @@
filegroup {
name: "core-jar",
- srcs: [":core{.jar}"],
+ device_common_srcs: [":core{.jar}"],
}
`),
})
}
func TestJavaImport(t *testing.T) {
+ t.Parallel()
bp := `
java_library {
name: "source_library",
@@ -1197,6 +1349,7 @@
}
func TestCompilerFlags(t *testing.T) {
+ t.Parallel()
for _, testCase := range compilerFlagsTestCases {
ctx := &mockContext{result: true}
CheckKotlincFlags(ctx, []string{testCase.in})
@@ -1227,7 +1380,9 @@
}
func TestPatchModule(t *testing.T) {
+ t.Parallel()
t.Run("Java language level 8", func(t *testing.T) {
+ t.Parallel()
// Test with legacy javac -source 1.8 -target 1.8
bp := `
java_library {
@@ -1260,6 +1415,7 @@
})
t.Run("Java language level 9", func(t *testing.T) {
+ t.Parallel()
// Test with default javac -source 9 -target 9
bp := `
java_library {
@@ -1300,6 +1456,7 @@
}
func TestJavaLibraryWithSystemModules(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "lib-with-source-system-modules",
@@ -1356,6 +1513,7 @@
}
func TestAidlExportIncludeDirsFromImports(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
@@ -1380,6 +1538,7 @@
}
func TestAidlFlagsArePassedToTheAidlCompiler(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
@@ -1396,6 +1555,7 @@
}
func TestAidlFlagsWithMinSdkVersion(t *testing.T) {
+ t.Parallel()
fixture := android.GroupFixturePreparers(
prepareForJavaTest, FixtureWithPrebuiltApis(map[string][]string{"14": {"foo"}}))
@@ -1409,6 +1569,7 @@
{"system_current", `sdk_version: "system_current"`, "current"},
} {
t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
ctx := fixture.RunTestWithBp(t, `
java_library {
name: "foo",
@@ -1426,6 +1587,7 @@
}
func TestAidlFlagsMinSdkVersionDroidstubs(t *testing.T) {
+ t.Parallel()
bpTemplate := `
droidstubs {
name: "foo-stubs",
@@ -1459,6 +1621,7 @@
}
func TestAidlEnforcePermissions(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
@@ -1475,6 +1638,7 @@
}
func TestAidlEnforcePermissionsException(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
@@ -1495,6 +1659,7 @@
}
func TestDataNativeBinaries(t *testing.T) {
+ t.Parallel()
ctx := android.GroupFixturePreparers(
prepareForJavaTest,
android.PrepareForTestWithAllowMissingDependencies).RunTestWithBp(t, `
@@ -1520,6 +1685,7 @@
}
func TestDefaultInstallable(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_test_host {
name: "foo"
@@ -1533,6 +1699,7 @@
}
func TestErrorproneEnabled(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
@@ -1561,6 +1728,7 @@
}
func TestErrorproneDisabled(t *testing.T) {
+ t.Parallel()
bp := `
java_library {
name: "foo",
@@ -1595,6 +1763,7 @@
}
func TestErrorproneEnabledOnlyByEnvironmentVariable(t *testing.T) {
+ t.Parallel()
bp := `
java_library {
name: "foo",
@@ -1625,6 +1794,7 @@
}
func TestDataDeviceBinsBuildsDeviceBinary(t *testing.T) {
+ t.Parallel()
testCases := []struct {
dataDeviceBinType string
depCompileMultilib string
@@ -1761,6 +1931,7 @@
testName := fmt.Sprintf(`data_device_bins_%s with compile_multilib:"%s"`, tc.dataDeviceBinType, tc.depCompileMultilib)
t.Run(testName, func(t *testing.T) {
+ t.Parallel()
ctx := android.GroupFixturePreparers(PrepareForIntegrationTestWithJava).
ExtendWithErrorHandler(errorHandler).
RunTestWithBp(t, bp)
@@ -1790,12 +1961,13 @@
}
actualData := entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"]
- android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", ctx.Config, expectedData, actualData)
+ android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", ctx.Config, android.SortedUniqueStrings(expectedData), android.SortedUniqueStrings(actualData))
})
}
}
func TestDeviceBinaryWrapperGeneration(t *testing.T) {
+ t.Parallel()
// Scenario 1: java_binary has main_class property in its bp
ctx, _ := testJava(t, `
java_binary {
@@ -1804,7 +1976,7 @@
main_class: "foo.bar.jb",
}
`)
- wrapperPath := fmt.Sprint(ctx.ModuleForTests("foo", "android_arm64_armv8-a").AllOutputs())
+ wrapperPath := fmt.Sprint(ctx.ModuleForTests("foo", "android_common").AllOutputs())
if !strings.Contains(wrapperPath, "foo.sh") {
t.Errorf("wrapper file foo.sh is not generated")
}
@@ -1819,6 +1991,7 @@
}
func TestJavaApiContributionEmptyApiFile(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForJavaTest,
android.FixtureMergeEnv(
@@ -1842,6 +2015,7 @@
}
func TestJavaApiLibraryAndProviderLink(t *testing.T) {
+ t.Parallel()
provider_bp_a := `
java_api_contribution {
name: "foo1",
@@ -1908,6 +2082,7 @@
}
func TestJavaApiLibraryAndDefaultsLink(t *testing.T) {
+ t.Parallel()
provider_bp_a := `
java_api_contribution {
name: "foo1",
@@ -2016,6 +2191,7 @@
}
func TestJavaApiLibraryJarGeneration(t *testing.T) {
+ t.Parallel()
provider_bp_a := `
java_api_contribution {
name: "foo1",
@@ -2082,6 +2258,7 @@
}
func TestJavaApiLibraryLibsLink(t *testing.T) {
+ t.Parallel()
provider_bp_a := `
java_api_contribution {
name: "foo1",
@@ -2170,6 +2347,7 @@
}
func TestJavaApiLibraryStaticLibsLink(t *testing.T) {
+ t.Parallel()
provider_bp_a := `
java_api_contribution {
name: "foo1",
@@ -2257,6 +2435,7 @@
}
func TestTransitiveSrcFiles(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "a",
@@ -2280,6 +2459,7 @@
}
func TestTradefedOptions(t *testing.T) {
+ t.Parallel()
result := PrepareForTestWithJavaBuildComponents.RunTestWithBp(t, `
java_test_host {
name: "foo",
@@ -2304,6 +2484,7 @@
}
func TestTestRunnerOptions(t *testing.T) {
+ t.Parallel()
result := PrepareForTestWithJavaBuildComponents.RunTestWithBp(t, `
java_test_host {
name: "foo",
@@ -2327,38 +2508,8 @@
}
}
-func TestJavaExcludeStaticLib(t *testing.T) {
- ctx, _ := testJava(t, `
- java_library {
- name: "bar",
- }
- java_library {
- name: "foo",
- }
- java_library {
- name: "baz",
- static_libs: [
- "foo",
- "bar",
- ],
- exclude_static_libs: [
- "bar",
- ],
- }
- `)
-
- // "bar" not included as dependency of "baz"
- CheckModuleDependencies(t, ctx, "baz", "android_common", []string{
- `core-lambda-stubs`,
- `ext`,
- `foo`,
- `framework`,
- `stable-core-platform-api-stubs-system-modules`,
- `stable.core.platform.api.stubs`,
- })
-}
-
func TestJavaLibraryWithResourcesStem(t *testing.T) {
+ t.Parallel()
ctx, _ := testJavaWithFS(t, `
java_library {
name: "foo",
@@ -2378,6 +2529,7 @@
}
func TestHeadersOnly(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
@@ -2396,6 +2548,7 @@
}
func TestJavaApiContributionImport(t *testing.T) {
+ t.Parallel()
ctx := android.GroupFixturePreparers(
prepareForJavaTest,
android.FixtureMergeEnv(
@@ -2424,6 +2577,7 @@
}
func TestJavaApiLibraryApiFilesSorting(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_api_library {
name: "foo",
@@ -2452,6 +2606,7 @@
}
func TestSdkLibraryProvidesSystemModulesToApiLibrary(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -2481,6 +2636,7 @@
}
func TestApiLibraryDroidstubsDependency(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -2527,6 +2683,7 @@
}
func TestDisableFromTextStubForCoverageBuild(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -2547,7 +2704,7 @@
android.AssertBoolEquals(t, "stub module expected to depend on from-source stub",
true, CheckModuleHasDependency(t, result.TestContext,
apiScopePublic.stubsLibraryModuleName("foo"), "android_common",
- apiScopePublic.sourceStubLibraryModuleName("foo")))
+ apiScopePublic.sourceStubsLibraryModuleName("foo")))
android.AssertBoolEquals(t, "stub module expected to not depend on from-text stub",
false, CheckModuleHasDependency(t, result.TestContext,
@@ -2556,6 +2713,7 @@
}
func TestMultiplePrebuilts(t *testing.T) {
+ t.Parallel()
bp := `
// an rdep
java_library {
@@ -2654,6 +2812,7 @@
}
func TestMultiplePlatformCompatConfigPrebuilts(t *testing.T) {
+ t.Parallel()
bp := `
// multiple variations of platform_compat_config
// source
@@ -2714,6 +2873,7 @@
}
func TestApiLibraryAconfigDeclarations(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
@@ -2824,6 +2984,7 @@
// Don't allow setting test-only on things that are always tests or never tests.
func TestInvalidTestOnlyTargets(t *testing.T) {
+ t.Parallel()
testCases := []string{
` java_test { name: "java-test", test_only: true, srcs: ["foo.java"], } `,
` java_test_host { name: "java-test-host", test_only: true, srcs: ["foo.java"], } `,
@@ -2859,6 +3020,7 @@
}
func TestJavaLibHostWithStem(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library_host {
name: "foo",
@@ -2877,6 +3039,7 @@
}
func TestJavaLibWithStem(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
@@ -2894,6 +3057,7 @@
}
func TestJavaLibraryOutputFilesRel(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
).RunTestWithBp(t, `
@@ -2938,6 +3102,45 @@
"baz.jar", bazOutputPaths[0].Rel())
}
+func TestCoverage(t *testing.T) {
+ t.Parallel()
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ prepareForTestWithFrameworkJacocoInstrumentation,
+ PrepareForTestWithTransitiveClasspathEnabled,
+ ).RunTestWithBp(t, `
+ android_app {
+ name: "foo",
+ srcs: ["foo.java"],
+ static_libs: ["android.car"],
+ platform_apis: true,
+ }
+
+ // A library in InstrumentFrameworkModules
+ java_library {
+ name: "android.car",
+ srcs: ["android.car.java"],
+ installable: true,
+ }
+ `)
+
+ foo := result.ModuleForTests("foo", "android_common")
+ androidCar := result.ModuleForTests("android.car", "android_common")
+
+ fooJacoco := foo.Rule("jacoco")
+ fooCombine := foo.Description("for javac")
+
+ androidCarJacoco := androidCar.Rule("jacoco")
+ androidCarJavac := androidCar.Rule("javac")
+
+ android.AssertStringEquals(t, "foo instrumentation rule inputs", fooJacoco.Input.String(), fooCombine.Output.String())
+ android.AssertStringEquals(t, "android.car instrumentation rule inputs", androidCarJacoco.Input.String(), androidCarJavac.Output.String())
+
+ // The input to instrumentation for the `foo` app contains the non-instrumented android.car classes.
+ android.AssertStringListContains(t, "foo combined inputs", fooCombine.Inputs.Strings(), androidCarJavac.Output.String())
+ android.AssertStringListDoesNotContain(t, "foo combined inputs", fooCombine.Inputs.Strings(), androidCarJacoco.Output.String())
+}
+
func assertTestOnlyAndTopLevel(t *testing.T, ctx *android.TestResult, expectedTestOnly []string, expectedTopLevel []string) {
t.Helper()
actualTrueModules := []string{}
@@ -2968,3 +3171,31 @@
t.Errorf("top-level: Expected but not found: %v, Found but not expected: %v", left, right)
}
}
+
+// Test that a dependency edge is created to the matching variant of a native library listed in `jni_libs` of java_binary
+func TestNativeRequiredDepOfJavaBinary(t *testing.T) {
+ t.Parallel()
+ findDepsOfModule := func(ctx *android.TestContext, module android.Module, depName string) []blueprint.Module {
+ var ret []blueprint.Module
+ ctx.VisitDirectDeps(module, func(dep blueprint.Module) {
+ if dep.Name() == depName {
+ ret = append(ret, dep)
+ }
+ })
+ return ret
+ }
+
+ bp := cc.GatherRequiredDepsForTest(android.Android) + `
+java_binary {
+ name: "myjavabin",
+ main_class: "com.android.MyJava",
+ jni_libs: ["mynativelib"],
+}
+cc_library_shared {
+ name: "mynativelib",
+}
+`
+ res, _ := testJava(t, bp)
+ deps := findDepsOfModule(res, res.ModuleForTests("myjavabin", "android_common").Module(), "mynativelib")
+ android.AssertIntEquals(t, "Create a dep on the first variant", 1, len(deps))
+}
diff --git a/java/jdeps.go b/java/jdeps.go
index e856b37..c2ce503 100644
--- a/java/jdeps.go
+++ b/java/jdeps.go
@@ -57,27 +57,19 @@
return
}
- ideInfoProvider, ok := module.(android.IDEInfo)
+ ideInfoProvider, ok := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey)
if !ok {
return
}
- name := ideInfoProvider.BaseModuleName()
+ name := ideInfoProvider.BaseModuleName
ideModuleNameProvider, ok := module.(android.IDECustomizedModuleName)
if ok {
name = ideModuleNameProvider.IDECustomizedModuleName()
}
dpInfo := moduleInfos[name]
- ideInfoProvider.IDEInfo(&dpInfo)
- dpInfo.Deps = android.FirstUniqueStrings(dpInfo.Deps)
- dpInfo.Srcs = android.FirstUniqueStrings(dpInfo.Srcs)
- dpInfo.Aidl_include_dirs = android.FirstUniqueStrings(dpInfo.Aidl_include_dirs)
- dpInfo.Jarjar_rules = android.FirstUniqueStrings(dpInfo.Jarjar_rules)
- dpInfo.Jars = android.FirstUniqueStrings(dpInfo.Jars)
- dpInfo.SrcJars = android.FirstUniqueStrings(dpInfo.SrcJars)
+ dpInfo = dpInfo.Merge(ideInfoProvider)
dpInfo.Paths = []string{ctx.ModuleDir(module)}
- dpInfo.Static_libs = android.FirstUniqueStrings(dpInfo.Static_libs)
- dpInfo.Libs = android.FirstUniqueStrings(dpInfo.Libs)
moduleInfos[name] = dpInfo
mkProvider, ok := module.(android.AndroidMkDataProvider)
diff --git a/java/jdeps_test.go b/java/jdeps_test.go
index ff54da9..2cbf75b 100644
--- a/java/jdeps_test.go
+++ b/java/jdeps_test.go
@@ -22,6 +22,7 @@
)
func TestCollectJavaLibraryPropertiesAddLibsDeps(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t,
`
java_library {name: "Foo"}
@@ -32,9 +33,7 @@
}
`)
module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library)
- dpInfo := &android.IdeInfo{}
-
- module.IDEInfo(dpInfo)
+ dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey)
for _, expected := range []string{"Foo", "Bar"} {
if !android.InList(expected, dpInfo.Deps) {
@@ -44,6 +43,7 @@
}
func TestCollectJavaLibraryPropertiesAddStaticLibsDeps(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t,
`
java_library {name: "Foo"}
@@ -54,9 +54,7 @@
}
`)
module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library)
- dpInfo := &android.IdeInfo{}
-
- module.IDEInfo(dpInfo)
+ dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey)
for _, expected := range []string{"Foo", "Bar"} {
if !android.InList(expected, dpInfo.Deps) {
@@ -66,32 +64,45 @@
}
func TestCollectJavaLibraryPropertiesAddScrs(t *testing.T) {
- expected := []string{"Foo", "Bar"}
- module := LibraryFactory().(*Library)
- module.expandIDEInfoCompiledSrcs = append(module.expandIDEInfoCompiledSrcs, expected...)
- dpInfo := &android.IdeInfo{}
+ t.Parallel()
+ ctx, _ := testJava(t,
+ `
+ java_library {
+ name: "javalib",
+ srcs: ["Foo.java", "Bar.java"],
+ }
+ `)
+ module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library)
+ dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey)
- module.IDEInfo(dpInfo)
-
+ expected := []string{"Foo.java", "Bar.java"}
if !reflect.DeepEqual(dpInfo.Srcs, expected) {
t.Errorf("Library.IDEInfo() Srcs = %v, want %v", dpInfo.Srcs, expected)
}
}
func TestCollectJavaLibraryPropertiesAddAidlIncludeDirs(t *testing.T) {
+ t.Parallel()
+ ctx, _ := testJava(t,
+ `
+ java_library {
+ name: "javalib",
+ aidl: {
+ include_dirs: ["Foo", "Bar"],
+ },
+ }
+ `)
+ module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library)
+ dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey)
+
expected := []string{"Foo", "Bar"}
- module := LibraryFactory().(*Library)
- module.deviceProperties.Aidl.Include_dirs = append(module.deviceProperties.Aidl.Include_dirs, expected...)
- dpInfo := &android.IdeInfo{}
-
- module.IDEInfo(dpInfo)
-
if !reflect.DeepEqual(dpInfo.Aidl_include_dirs, expected) {
t.Errorf("Library.IDEInfo() Aidl_include_dirs = %v, want %v", dpInfo.Aidl_include_dirs, expected)
}
}
func TestCollectJavaLibraryWithJarJarRules(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t,
`
java_library {
@@ -101,10 +112,9 @@
}
`)
module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library)
- dpInfo := &android.IdeInfo{}
+ dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey)
- module.IDEInfo(dpInfo)
- android.AssertBoolEquals(t, "IdeInfo.Srcs of repackaged library should be empty", true, len(dpInfo.Srcs) == 0)
+ android.AssertStringEquals(t, "IdeInfo.Srcs of repackaged library should not be empty", "foo.java", dpInfo.Srcs[0])
android.AssertStringEquals(t, "IdeInfo.Jar_rules of repackaged library should not be empty", "jarjar_rules.txt", dpInfo.Jarjar_rules[0])
if !android.SubstringInList(dpInfo.Jars, "soong/.intermediates/javalib/android_common/jarjar/turbine/javalib.jar") {
t.Errorf("IdeInfo.Jars of repackaged library should contain the output of jarjar-ing. All outputs: %v\n", dpInfo.Jars)
@@ -112,6 +122,7 @@
}
func TestCollectJavaLibraryLinkingAgainstVersionedSdk(t *testing.T) {
+ t.Parallel()
ctx := android.GroupFixturePreparers(
prepareForJavaTest,
FixtureWithPrebuiltApis(map[string][]string{
@@ -125,8 +136,46 @@
}
`)
module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library)
- dpInfo := &android.IdeInfo{}
+ dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey)
- module.IDEInfo(dpInfo)
android.AssertStringListContains(t, "IdeInfo.Deps should contain versioned sdk module", dpInfo.Deps, "sdk_public_29_android")
}
+
+func TestDoNotAddNoneSystemModulesToDeps(t *testing.T) {
+ ctx := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ android.FixtureMergeEnv(
+ map[string]string{
+ "DISABLE_STUB_VALIDATION": "true",
+ },
+ ),
+ ).RunTestWithBp(t,
+ `
+ java_library {
+ name: "javalib",
+ srcs: ["foo.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ }
+
+ java_api_library {
+ name: "javalib.stubs",
+ stubs_type: "everything",
+ api_contributions: ["javalib-current.txt"],
+ api_surface: "public",
+ system_modules: "none",
+ }
+ java_api_contribution {
+ name: "javalib-current.txt",
+ api_file: "javalib-current.txt",
+ api_surface: "public",
+ }
+ `)
+ javalib := ctx.ModuleForTests("javalib", "android_common").Module().(*Library)
+ dpInfo, _ := android.OtherModuleProvider(ctx, javalib, android.IdeInfoProviderKey)
+ android.AssertStringListDoesNotContain(t, "IdeInfo.Deps should contain not contain `none`", dpInfo.Deps, "none")
+
+ javalib_stubs := ctx.ModuleForTests("javalib.stubs", "android_common").Module().(*ApiLibrary)
+ dpInfo, _ = android.OtherModuleProvider(ctx, javalib_stubs, android.IdeInfoProviderKey)
+ android.AssertStringListDoesNotContain(t, "IdeInfo.Deps should contain not contain `none`", dpInfo.Deps, "none")
+}
diff --git a/java/kotlin.go b/java/kotlin.go
index c28bc3f..308bb03 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -64,6 +64,28 @@
"kotlincFlags", "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "classesDir",
"headerClassesDir", "headerJar", "kotlinJvmTarget", "kotlinBuildFile", "emptyDir", "name")
+var kotlinKytheExtract = pctx.AndroidStaticRule("kotlinKythe",
+ blueprint.RuleParams{
+ Command: `rm -rf "$srcJarDir" && mkdir -p "$srcJarDir" && ` +
+ `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" -f "*.kt" $srcJars && ` +
+ `${config.KotlinKytheExtractor} -corpus ${kytheCorpus} --srcs @$out.rsp --srcs @"$srcJarDir/list" $commonSrcFilesList --cp @$classpath -o $out --kotlin_out $outJar ` +
+ // wrap the additional kotlin args.
+ // Skip Xbuild file, pass the cp explicitly.
+ // Skip header jars, those should not have an effect on kythe results.
+ ` --args '${config.KotlincGlobalFlags} ` +
+ ` ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} ` +
+ ` $kotlincFlags -jvm-target $kotlinJvmTarget ` +
+ `${config.KotlincKytheGlobalFlags}'`,
+ CommandDeps: []string{
+ "${config.KotlinKytheExtractor}",
+ "${config.ZipSyncCmd}",
+ },
+ Rspfile: "$out.rsp",
+ RspfileContent: "$in",
+ },
+ "classpath", "kotlincFlags", "commonSrcFilesList", "kotlinJvmTarget", "outJar", "srcJars", "srcJarDir",
+)
+
func kotlinCommonSrcsList(ctx android.ModuleContext, commonSrcFiles android.Paths) android.OptionalPath {
if len(commonSrcFiles) > 0 {
// The list of common_srcs may be too long to put on the command line, but
@@ -81,7 +103,7 @@
}
// kotlinCompile takes .java and .kt sources and srcJars, and compiles the .kt sources into a classes jar in outputFile.
-func kotlinCompile(ctx android.ModuleContext, outputFile, headerOutputFile android.WritablePath,
+func (j *Module) kotlinCompile(ctx android.ModuleContext, outputFile, headerOutputFile android.WritablePath,
srcFiles, commonSrcFiles, srcJars android.Paths,
flags javaBuilderFlags) {
@@ -127,6 +149,31 @@
"name": kotlinName,
},
})
+
+ // Emit kythe xref rule
+ if (ctx.Config().EmitXrefRules()) && ctx.Module() == ctx.PrimaryModule() {
+ extractionFile := outputFile.ReplaceExtension(ctx, "kzip")
+ args := map[string]string{
+ "classpath": classpathRspFile.String(),
+ "kotlincFlags": flags.kotlincFlags,
+ "kotlinJvmTarget": flags.javaVersion.StringForKotlinc(),
+ "outJar": outputFile.String(),
+ "srcJars": strings.Join(srcJars.Strings(), " "),
+ "srcJarDir": android.PathForModuleOut(ctx, "kotlinc", "srcJars.xref").String(),
+ }
+ if commonSrcsList.Valid() {
+ args["commonSrcFilesList"] = "--common_srcs @" + commonSrcsList.String()
+ }
+ ctx.Build(pctx, android.BuildParams{
+ Rule: kotlinKytheExtract,
+ Description: "kotlinKythe",
+ Output: extractionFile,
+ Inputs: srcFiles,
+ Implicits: deps,
+ Args: args,
+ })
+ j.kytheKotlinFiles = append(j.kytheKotlinFiles, extractionFile)
+ }
}
var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupports{Goma: true},
@@ -134,6 +181,7 @@
Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && ` +
`mkdir -p "$srcJarDir" "$kaptDir/sources" "$kaptDir/classes" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
+ `${config.FindInputDeltaCmd} --template '' --target "$out" --inputs_file "$out.rsp" && ` +
`${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` +
` --srcs "$out.rsp" --srcs "$srcJarDir/list"` +
` $commonSrcFilesArg --out "$kotlinBuildFile" && ` +
@@ -150,8 +198,10 @@
`$kaptProcessor ` +
`-Xbuild-file=$kotlinBuildFile && ` +
`${config.SoongZipCmd} -jar -write_if_changed -o $out -C $kaptDir/stubs -D $kaptDir/stubs && ` +
+ `if [ -f "$out.pc_state.new" ]; then mv "$out.pc_state.new" "$out.pc_state"; fi && ` +
`rm -rf "$srcJarDir"`,
CommandDeps: []string{
+ "${config.FindInputDeltaCmd}",
"${config.KotlincCmd}",
"${config.KotlinCompilerJar}",
"${config.KotlinKaptJar}",
diff --git a/java/kotlin_test.go b/java/kotlin_test.go
index 844e974..3a20335 100644
--- a/java/kotlin_test.go
+++ b/java/kotlin_test.go
@@ -24,6 +24,7 @@
)
func TestKotlin(t *testing.T) {
+ t.Parallel()
bp := `
java_library {
name: "foo",
@@ -56,6 +57,13 @@
"out/soong/.intermediates/default/java/kotlin-annotations/android_common/turbine-combined/kotlin-annotations.jar",
}
+ kotlinStdlibTurbineJars := []string{
+ "out/soong/.intermediates/default/java/kotlin-stdlib/android_common/turbine/kotlin-stdlib.jar",
+ "out/soong/.intermediates/default/java/kotlin-stdlib-jdk7/android_common/turbine/kotlin-stdlib-jdk7.jar",
+ "out/soong/.intermediates/default/java/kotlin-stdlib-jdk8/android_common/turbine/kotlin-stdlib-jdk8.jar",
+ "out/soong/.intermediates/default/java/kotlin-annotations/android_common/turbine/kotlin-annotations.jar",
+ }
+
kotlinStdlibJavacJars := []string{
"out/soong/.intermediates/default/java/kotlin-stdlib/android_common/javac/kotlin-stdlib.jar",
"out/soong/.intermediates/default/java/kotlin-stdlib-jdk7/android_common/javac/kotlin-stdlib-jdk7.jar",
@@ -68,11 +76,21 @@
"out/soong/.intermediates/default/java/core-lambda-stubs/android_common/turbine-combined/core-lambda-stubs.jar",
}
+ bootclasspathTurbineJars := []string{
+ "out/soong/.intermediates/default/java/stable.core.platform.api.stubs/android_common/turbine/stable.core.platform.api.stubs.jar",
+ "out/soong/.intermediates/default/java/core-lambda-stubs/android_common/turbine/core-lambda-stubs.jar",
+ }
+
frameworkTurbineCombinedJars := []string{
"out/soong/.intermediates/default/java/ext/android_common/turbine-combined/ext.jar",
"out/soong/.intermediates/default/java/framework/android_common/turbine-combined/framework.jar",
}
+ frameworkTurbineJars := []string{
+ "out/soong/.intermediates/default/java/ext/android_common/turbine/ext.jar",
+ "out/soong/.intermediates/default/java/framework/android_common/turbine/framework.jar",
+ }
+
testCases := []struct {
name string
@@ -150,10 +168,74 @@
kotlinStdlibTurbineCombinedJars,
),
},
+ {
+ name: "transitive classpath",
+ preparer: PrepareForTestWithTransitiveClasspathEnabled,
+ fooKotlincInputs: []string{"a.java", "b.kt"},
+ fooJavacInputs: []string{"a.java"},
+ fooKotlincClasspath: slices.Concat(
+ bootclasspathTurbineJars,
+ frameworkTurbineJars,
+ []string{"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar"},
+ kotlinStdlibTurbineJars,
+ ),
+ fooJavacClasspath: slices.Concat(
+ []string{"out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar"},
+ frameworkTurbineJars,
+ []string{"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar"},
+ kotlinStdlibTurbineJars,
+ ),
+ fooCombinedInputs: slices.Concat(
+ []string{
+ "out/soong/.intermediates/foo/android_common/kotlin/foo.jar",
+ "out/soong/.intermediates/foo/android_common/javac/foo.jar",
+ "out/soong/.intermediates/quz/android_common/kotlin/quz.jar",
+ },
+ kotlinStdlibJavacJars,
+ ),
+ fooHeaderCombinedInputs: slices.Concat(
+ []string{
+ "out/soong/.intermediates/foo/android_common/turbine/foo.jar",
+ "out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar",
+ "out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar",
+ },
+ kotlinStdlibTurbineJars,
+ ),
+
+ barKotlincInputs: []string{"b.kt"},
+ barKotlincClasspath: slices.Concat(
+ bootclasspathTurbineJars,
+ frameworkTurbineJars,
+ []string{
+ "out/soong/.intermediates/foo/android_common/turbine/foo.jar",
+ "out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar",
+ "out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar",
+ },
+ kotlinStdlibTurbineJars,
+ []string{"out/soong/.intermediates/baz/android_common/turbine/baz.jar"},
+ ),
+ barCombinedInputs: slices.Concat(
+ []string{
+ "out/soong/.intermediates/bar/android_common/kotlin/bar.jar",
+ "out/soong/.intermediates/baz/android_common/javac/baz.jar",
+ "out/soong/.intermediates/quz/android_common/kotlin/quz.jar",
+ },
+ kotlinStdlibJavacJars,
+ ),
+ barHeaderCombinedInputs: slices.Concat(
+ []string{
+ "out/soong/.intermediates/bar/android_common/kotlin_headers/bar.jar",
+ "out/soong/.intermediates/baz/android_common/turbine/baz.jar",
+ "out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar",
+ },
+ kotlinStdlibTurbineJars,
+ ),
+ },
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
tt.preparer,
@@ -195,6 +277,7 @@
}
func TestKapt(t *testing.T) {
+ t.Parallel()
bp := `
java_library {
name: "foo",
@@ -223,6 +306,7 @@
}
`
t.Run("", func(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, bp)
buildOS := ctx.Config().BuildOS.String()
@@ -304,6 +388,7 @@
})
t.Run("errorprone", func(t *testing.T) {
+ t.Parallel()
env := map[string]string{
"RUN_ERROR_PRONE": "true",
}
@@ -354,6 +439,7 @@
}
func TestKaptEncodeFlags(t *testing.T) {
+ t.Parallel()
// Compares the kaptEncodeFlags against the results of the example implementation at
// https://kotlinlang.org/docs/reference/kapt.html#apjavac-options-encoding
tests := []struct {
@@ -404,6 +490,7 @@
for i, test := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
+ t.Parallel()
got := kaptEncodeFlags(test.in)
if got != test.out {
t.Errorf("\nwant %q\n got %q", test.out, got)
@@ -413,6 +500,7 @@
}
func TestKotlinCompose(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
).RunTestWithBp(t, `
@@ -420,8 +508,8 @@
name: "androidx.compose.runtime_runtime",
}
- java_library_host {
- name: "androidx.compose.compiler_compiler-hosted",
+ kotlin_plugin {
+ name: "kotlin-compose-compiler-plugin",
}
java_library {
@@ -443,7 +531,7 @@
buildOS := result.Config.BuildOS.String()
- composeCompiler := result.ModuleForTests("androidx.compose.compiler_compiler-hosted", buildOS+"_common").Rule("combineJar").Output
+ composeCompiler := result.ModuleForTests("kotlin-compose-compiler-plugin", buildOS+"_common").Rule("combineJar").Output
withCompose := result.ModuleForTests("withcompose", "android_common")
noCompose := result.ModuleForTests("nocompose", "android_common")
@@ -462,3 +550,51 @@
android.AssertStringDoesNotContain(t, "unexpected compose compiler plugin",
noCompose.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+composeCompiler.String())
}
+
+func TestKotlinPlugin(t *testing.T) {
+ t.Parallel()
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ ).RunTestWithBp(t, `
+ kotlin_plugin {
+ name: "kotlin_plugin",
+ }
+
+ java_library {
+ name: "with_kotlin_plugin",
+ srcs: ["a.kt"],
+ plugins: ["plugin"],
+ kotlin_plugins: ["kotlin_plugin"],
+ }
+
+ java_library {
+ name: "no_kotlin_plugin",
+ srcs: ["a.kt"],
+ }
+
+ java_plugin {
+ name: "plugin",
+ }
+ `)
+
+ buildOS := result.Config.BuildOS.String()
+
+ kotlinPlugin := result.ModuleForTests("kotlin_plugin", buildOS+"_common").Rule("combineJar").Output
+ withKotlinPlugin := result.ModuleForTests("with_kotlin_plugin", "android_common")
+ noKotlinPlugin := result.ModuleForTests("no_kotlin_plugin", "android_common")
+
+ android.AssertStringListContains(t, "missing plugin compiler dependency",
+ withKotlinPlugin.Rule("kotlinc").Implicits.Strings(), kotlinPlugin.String())
+
+ android.AssertStringDoesContain(t, "missing kotlin plugin",
+ withKotlinPlugin.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+kotlinPlugin.String())
+
+ android.AssertStringListContains(t, "missing kapt kotlin plugin dependency",
+ withKotlinPlugin.Rule("kapt").Implicits.Strings(), kotlinPlugin.String())
+
+ android.AssertStringListDoesNotContain(t, "unexpected kotlin plugin dependency",
+ noKotlinPlugin.Rule("kotlinc").Implicits.Strings(), kotlinPlugin.String())
+
+ android.AssertStringDoesNotContain(t, "unexpected kotlin plugin",
+ noKotlinPlugin.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+kotlinPlugin.String())
+}
diff --git a/java/lint.go b/java/lint.go
index 6782adc..3838745 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -19,6 +19,8 @@
"sort"
"strings"
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/depset"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -67,6 +69,11 @@
// If soong gets support for testonly, this flag should be replaced with that.
Test *bool
+ // Same as the regular Test property, but set by internal soong code based on if the module
+ // type is a test module type. This will act as the default value for the test property,
+ // but can be overridden by the user.
+ Test_module_type *bool `blueprint:"mutated"`
+
// Whether to ignore the exit code of Android lint. This is the --exit_code
// option. Defaults to false.
Suppress_exit_code *bool
@@ -90,7 +97,6 @@
compileSdkKind android.SdkKind
javaLanguageLevel string
kotlinLanguageLevel string
- outputs lintOutputs
properties LintProperties
extraMainlineLintErrors []string
compile_data android.Paths
@@ -100,68 +106,47 @@
buildModuleReportZip bool
}
-type lintOutputs struct {
- html android.Path
- text android.Path
- xml android.Path
- referenceBaseline android.Path
-
- depSets LintDepSets
-}
-
-type lintOutputsIntf interface {
- lintOutputs() *lintOutputs
-}
-
-type LintDepSetsIntf interface {
- LintDepSets() LintDepSets
-
- // Methods used to propagate strict_updatability_linting values.
- GetStrictUpdatabilityLinting() bool
- SetStrictUpdatabilityLinting(bool)
-}
-
type LintDepSets struct {
- HTML, Text, XML *android.DepSet[android.Path]
+ HTML, Text, XML, Baseline depset.DepSet[android.Path]
}
type LintDepSetsBuilder struct {
- HTML, Text, XML *android.DepSetBuilder[android.Path]
+ HTML, Text, XML, Baseline *depset.Builder[android.Path]
}
func NewLintDepSetBuilder() LintDepSetsBuilder {
return LintDepSetsBuilder{
- HTML: android.NewDepSetBuilder[android.Path](android.POSTORDER),
- Text: android.NewDepSetBuilder[android.Path](android.POSTORDER),
- XML: android.NewDepSetBuilder[android.Path](android.POSTORDER),
+ HTML: depset.NewBuilder[android.Path](depset.POSTORDER),
+ Text: depset.NewBuilder[android.Path](depset.POSTORDER),
+ XML: depset.NewBuilder[android.Path](depset.POSTORDER),
+ Baseline: depset.NewBuilder[android.Path](depset.POSTORDER),
}
}
-func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder {
+func (l LintDepSetsBuilder) Direct(html, text, xml android.Path, baseline android.OptionalPath) LintDepSetsBuilder {
l.HTML.Direct(html)
l.Text.Direct(text)
l.XML.Direct(xml)
+ if baseline.Valid() {
+ l.Baseline.Direct(baseline.Path())
+ }
return l
}
-func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder {
- if depSets.HTML != nil {
- l.HTML.Transitive(depSets.HTML)
- }
- if depSets.Text != nil {
- l.Text.Transitive(depSets.Text)
- }
- if depSets.XML != nil {
- l.XML.Transitive(depSets.XML)
- }
+func (l LintDepSetsBuilder) Transitive(info *LintInfo) LintDepSetsBuilder {
+ l.HTML.Transitive(info.TransitiveHTML)
+ l.Text.Transitive(info.TransitiveText)
+ l.XML.Transitive(info.TransitiveXML)
+ l.Baseline.Transitive(info.TransitiveBaseline)
return l
}
func (l LintDepSetsBuilder) Build() LintDepSets {
return LintDepSets{
- HTML: l.HTML.Build(),
- Text: l.Text.Build(),
- XML: l.XML.Build(),
+ HTML: l.HTML.Build(),
+ Text: l.Text.Build(),
+ XML: l.XML.Build(),
+ Baseline: l.Baseline.Build(),
}
}
@@ -209,24 +194,18 @@
},
}
-func (l *linter) LintDepSets() LintDepSets {
- return l.outputs.depSets
-}
+var LintProvider = blueprint.NewProvider[*LintInfo]()
-func (l *linter) GetStrictUpdatabilityLinting() bool {
- return BoolDefault(l.properties.Lint.Strict_updatability_linting, false)
-}
+type LintInfo struct {
+ HTML android.Path
+ Text android.Path
+ XML android.Path
+ ReferenceBaseline android.Path
-func (l *linter) SetStrictUpdatabilityLinting(strictLinting bool) {
- l.properties.Lint.Strict_updatability_linting = &strictLinting
-}
-
-var _ LintDepSetsIntf = (*linter)(nil)
-
-var _ lintOutputsIntf = (*linter)(nil)
-
-func (l *linter) lintOutputs() *lintOutputs {
- return &l.outputs
+ TransitiveHTML depset.DepSet[android.Path]
+ TransitiveText depset.DepSet[android.Path]
+ TransitiveXML depset.DepSet[android.Path]
+ TransitiveBaseline depset.DepSet[android.Path]
}
func (l *linter) enabled() bool {
@@ -262,7 +241,9 @@
return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
}
-func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder, srcsList android.Path) lintPaths {
+func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder, srcsList android.Path,
+ baselines android.Paths) lintPaths {
+
projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
// Lint looks for a lint.xml file next to the project.xml file, give it one.
configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
@@ -281,7 +262,12 @@
if l.library {
cmd.Flag("--library")
}
- if proptools.BoolDefault(l.properties.Lint.Test, false) {
+
+ test := proptools.BoolDefault(l.properties.Lint.Test_module_type, false)
+ if l.properties.Lint.Test != nil {
+ test = *l.properties.Lint.Test
+ }
+ if test {
cmd.Flag("--test")
}
if l.manifest != nil {
@@ -325,12 +311,10 @@
cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
- if l.GetStrictUpdatabilityLinting() {
+ if Bool(l.properties.Lint.Strict_updatability_linting) && len(baselines) > 0 {
// Verify the module does not baseline issues that endanger safe updatability.
- if l.properties.Lint.Baseline_filename != nil {
- cmd.FlagWithInput("--baseline ", android.PathForModuleSrc(ctx, *l.properties.Lint.Baseline_filename))
- cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
- }
+ strictUpdatabilityChecksOutputFile := VerifyStrictUpdatabilityChecks(ctx, baselines)
+ cmd.Validation(strictUpdatabilityChecksOutputFile)
}
return lintPaths{
@@ -342,6 +326,22 @@
}
+func VerifyStrictUpdatabilityChecks(ctx android.ModuleContext, baselines android.Paths) android.Path {
+ rule := android.NewRuleBuilder(pctx, ctx)
+ baselineRspFile := android.PathForModuleOut(ctx, "lint_strict_updatability_check_baselines.rsp")
+ outputFile := android.PathForModuleOut(ctx, "lint_strict_updatability_check.stamp")
+ rule.Command().Text("rm -f").Output(outputFile)
+ rule.Command().
+ BuiltTool("lint_strict_updatability_checks").
+ FlagWithArg("--name ", ctx.ModuleName()).
+ FlagWithRspFileInputList("--baselines ", baselineRspFile, baselines).
+ FlagForEachArg("--disallowed_issues ", updatabilityChecks)
+ rule.Command().Text("touch").Output(outputFile)
+ rule.Build("lint_strict_updatability_checks", "lint strict updatability checks")
+
+ return outputFile
+}
+
// generateManifest adds a command to the rule to write a simple manifest that contains the
// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
@@ -398,7 +398,7 @@
}
}
- extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
+ extraLintCheckModules := ctx.GetDirectDepsProxyWithTag(extraLintCheckTag)
for _, extraLintCheckModule := range extraLintCheckModules {
if dep, ok := android.OtherModuleProvider(ctx, extraLintCheckModule, JavaInfoProvider); ok {
l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
@@ -411,6 +411,26 @@
l.extraLintCheckJars = append(l.extraLintCheckJars, android.PathForSource(ctx,
"prebuilts/cmdline-tools/AndroidGlobalLintChecker.jar"))
+ var baseline android.OptionalPath
+ if l.properties.Lint.Baseline_filename != nil {
+ baseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, *l.properties.Lint.Baseline_filename))
+ }
+
+ html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
+ text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
+ xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
+ referenceBaseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
+
+ depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml, baseline)
+
+ ctx.VisitDirectDepsProxyWithTag(staticLibTag, func(dep android.ModuleProxy) {
+ if info, ok := android.OtherModuleProvider(ctx, dep, LintProvider); ok {
+ depSetsBuilder.Transitive(info)
+ }
+ })
+
+ depSets := depSetsBuilder.Build()
+
rule := android.NewRuleBuilder(pctx, ctx).
Sbox(android.PathForModuleOut(ctx, "lint"),
android.PathForModuleOut(ctx, "lint.sbox.textproto")).
@@ -437,20 +457,9 @@
srcsListRsp := android.PathForModuleOut(ctx, "lint-srcs.list.rsp")
rule.Command().Text("cp").FlagWithRspFileInputList("", srcsListRsp, l.srcs).Output(srcsList).Implicits(l.compile_data)
- lintPaths := l.writeLintProjectXML(ctx, rule, srcsList)
+ baselines := depSets.Baseline.ToList()
- html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
- text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
- xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
- referenceBaseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
-
- depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
-
- ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
- if depLint, ok := dep.(LintDepSetsIntf); ok {
- depSetsBuilder.Transitive(depLint.LintDepSets())
- }
- })
+ lintPaths := l.writeLintProjectXML(ctx, rule, srcsList, baselines)
rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
@@ -471,7 +480,7 @@
cmd := rule.Command()
- cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
+ cmd.Flag(`JAVA_OPTS="-Xmx4096m --add-opens java.base/java.util=ALL-UNNAMED"`).
FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
@@ -505,8 +514,8 @@
cmd.FlagWithArg("--check ", checkOnly)
}
- if l.properties.Lint.Baseline_filename != nil {
- cmd.FlagWithInput("--baseline ", android.PathForModuleSrc(ctx, *l.properties.Lint.Baseline_filename))
+ if baseline.Valid() {
+ cmd.FlagWithInput("--baseline ", baseline.Path())
}
cmd.FlagWithOutput("--write-reference-baseline ", referenceBaseline)
@@ -530,25 +539,30 @@
rule.Build("lint", "lint")
- l.outputs = lintOutputs{
- html: html,
- text: text,
- xml: xml,
- referenceBaseline: referenceBaseline,
+ android.SetProvider(ctx, LintProvider, &LintInfo{
+ HTML: html,
+ Text: text,
+ XML: xml,
+ ReferenceBaseline: referenceBaseline,
- depSets: depSetsBuilder.Build(),
- }
+ TransitiveHTML: depSets.HTML,
+ TransitiveText: depSets.Text,
+ TransitiveXML: depSets.XML,
+ TransitiveBaseline: depSets.Baseline,
+ })
if l.buildModuleReportZip {
- l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
+ l.reports = BuildModuleLintReportZips(ctx, depSets, nil)
}
// Create a per-module phony target to run the lint check.
phonyName := ctx.ModuleName() + "-lint"
ctx.Phony(phonyName, xml)
+
+ ctx.SetOutputFiles(android.Paths{xml}, ".lint")
}
-func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
+func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets, validations android.Paths) android.Paths {
htmlList := android.SortedUniquePaths(depSets.HTML.ToList())
textList := android.SortedUniquePaths(depSets.Text.ToList())
xmlList := android.SortedUniquePaths(depSets.XML.ToList())
@@ -558,13 +572,13 @@
}
htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
- lintZip(ctx, htmlList, htmlZip)
+ lintZip(ctx, htmlList, htmlZip, validations)
textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
- lintZip(ctx, textList, textZip)
+ lintZip(ctx, textList, textZip, validations)
xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
- lintZip(ctx, xmlList, xmlZip)
+ lintZip(ctx, xmlList, xmlZip, validations)
return android.Paths{htmlZip, textZip, xmlZip}
}
@@ -642,7 +656,7 @@
return
}
- var outputs []*lintOutputs
+ var outputs []*LintInfo
var dirs []string
ctx.VisitAllModules(func(m android.Module) {
if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
@@ -658,14 +672,14 @@
}
}
- if l, ok := m.(lintOutputsIntf); ok {
- outputs = append(outputs, l.lintOutputs())
+ if lintInfo, ok := android.OtherModuleProvider(ctx, m, LintProvider); ok {
+ outputs = append(outputs, lintInfo)
}
})
dirs = android.SortedUniqueStrings(dirs)
- zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
+ zip := func(outputPath android.WritablePath, get func(*LintInfo) android.Path) {
var paths android.Paths
for _, output := range outputs {
@@ -674,20 +688,20 @@
}
}
- lintZip(ctx, paths, outputPath)
+ lintZip(ctx, paths, outputPath, nil)
}
l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
- zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
+ zip(l.htmlZip, func(l *LintInfo) android.Path { return l.HTML })
l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
- zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
+ zip(l.textZip, func(l *LintInfo) android.Path { return l.Text })
l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
- zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
+ zip(l.xmlZip, func(l *LintInfo) android.Path { return l.XML })
l.referenceBaselineZip = android.PathForOutput(ctx, "lint-report-reference-baselines.zip")
- zip(l.referenceBaselineZip, func(l *lintOutputs) android.Path { return l.referenceBaseline })
+ zip(l.referenceBaselineZip, func(l *LintInfo) android.Path { return l.ReferenceBaseline })
ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip)
}
@@ -703,17 +717,9 @@
func init() {
android.RegisterParallelSingletonType("lint",
func() android.Singleton { return &lintSingleton{} })
-
- registerLintBuildComponents(android.InitRegistrationContext)
}
-func registerLintBuildComponents(ctx android.RegistrationContext) {
- ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel()
- })
-}
-
-func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
+func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath, validations android.Paths) {
paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
sort.Slice(paths, func(i, j int) bool {
@@ -725,19 +731,8 @@
rule.Command().BuiltTool("soong_zip").
FlagWithOutput("-o ", outputPath).
FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
- FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
+ FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths).
+ Validations(validations)
rule.Build(outputPath.Base(), outputPath.Base())
}
-
-// Enforce the strict updatability linting to all applicable transitive dependencies.
-func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) {
- m := ctx.Module()
- if d, ok := m.(LintDepSetsIntf); ok && d.GetStrictUpdatabilityLinting() {
- ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
- if a, ok := d.(LintDepSetsIntf); ok {
- a.SetStrictUpdatabilityLinting(true)
- }
- })
- }
-}
diff --git a/java/lint_test.go b/java/lint_test.go
index b51753f..f7d3229 100644
--- a/java/lint_test.go
+++ b/java/lint_test.go
@@ -22,6 +22,7 @@
)
func TestJavaLintDoesntUseBaselineImplicitly(t *testing.T) {
+ t.Parallel()
ctx, _ := testJavaWithFS(t, `
java_library {
name: "foo",
@@ -46,6 +47,7 @@
}
func TestJavaLintRequiresCustomLintFileToExist(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
android.PrepareForTestDisallowNonExistentPaths,
@@ -65,6 +67,7 @@
}
func TestJavaLintUsesCorrectBpConfig(t *testing.T) {
+ t.Parallel()
ctx, _ := testJavaWithFS(t, `
java_library {
name: "foo",
@@ -101,6 +104,7 @@
}
func TestJavaLintBypassUpdatableChecks(t *testing.T) {
+ t.Parallel()
testCases := []struct {
name string
bp string
@@ -144,6 +148,7 @@
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
+ t.Parallel()
errorHandler := android.FixtureExpectsAtLeastOneErrorMatchingPattern(testCase.error)
android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules).
ExtendWithErrorHandler(errorHandler).
@@ -153,6 +158,7 @@
}
func TestJavaLintStrictUpdatabilityLinting(t *testing.T) {
+ t.Parallel()
bp := `
java_library {
name: "foo",
@@ -164,7 +170,7 @@
sdk_version: "current",
lint: {
strict_updatability_linting: true,
- baseline_filename: "lint-baseline.xml",
+ baseline_filename: "foo_lint_baseline.xml",
},
}
@@ -176,7 +182,7 @@
min_sdk_version: "29",
sdk_version: "current",
lint: {
- baseline_filename: "lint-baseline.xml",
+ baseline_filename: "bar_lint_baseline.xml",
}
}
`
@@ -188,18 +194,13 @@
RunTestWithBp(t, bp)
foo := result.ModuleForTests("foo", "android_common")
- sboxProto := android.RuleBuilderSboxProtoForTests(t, result.TestContext, foo.Output("lint.sbox.textproto"))
- if !strings.Contains(*sboxProto.Commands[0].Command,
- "--baseline lint-baseline.xml --disallowed_issues NewApi") {
+ strictUpdatabilityCheck := foo.Output("lint_strict_updatability_check.stamp")
+ if !strings.Contains(strictUpdatabilityCheck.RuleParams.Command,
+ "--disallowed_issues NewApi") {
t.Error("did not restrict baselining NewApi")
}
-
- bar := result.ModuleForTests("bar", "android_common")
- sboxProto = android.RuleBuilderSboxProtoForTests(t, result.TestContext, bar.Output("lint.sbox.textproto"))
- if !strings.Contains(*sboxProto.Commands[0].Command,
- "--baseline lint-baseline.xml --disallowed_issues NewApi") {
- t.Error("did not restrict baselining NewApi")
- }
+ android.AssertStringListContains(t, "strict updatability check baseline inputs", strictUpdatabilityCheck.Inputs.Strings(), "foo_lint_baseline.xml")
+ android.AssertStringListContains(t, "strict updatability check baseline inputs", strictUpdatabilityCheck.Inputs.Strings(), "bar_lint_baseline.xml")
}
func TestJavaLintDatabaseSelectionFull(t *testing.T) {
@@ -281,3 +282,50 @@
ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("Don't use --disable, --enable, or --check in the flags field, instead use the dedicated disabled_checks, warning_checks, error_checks, or fatal_checks fields")).
RunTestWithBp(t, bp)
}
+
+// b/358643466
+func TestNotTestViaDefault(t *testing.T) {
+ bp := `
+ java_defaults {
+ name: "mydefaults",
+ lint: {
+ test: false,
+ },
+ }
+ android_test {
+ name: "foo",
+ srcs: [
+ "a.java",
+ ],
+ min_sdk_version: "29",
+ sdk_version: "current",
+ defaults: ["mydefaults"],
+ }
+ android_test {
+ name: "foo2",
+ srcs: [
+ "a.java",
+ ],
+ min_sdk_version: "29",
+ sdk_version: "current",
+ }
+ `
+ result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, bp)
+ ctx := result.TestContext
+
+ foo := ctx.ModuleForTests("foo", "android_common")
+ sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx, foo.Output("lint.sbox.textproto"))
+ command := *sboxProto.Commands[0].Command
+
+ if strings.Contains(command, "--test") {
+ t.Fatalf("Expected command to not contain --test")
+ }
+
+ foo2 := ctx.ModuleForTests("foo2", "android_common")
+ sboxProto2 := android.RuleBuilderSboxProtoForTests(t, ctx, foo2.Output("lint.sbox.textproto"))
+ command2 := *sboxProto2.Commands[0].Command
+
+ if !strings.Contains(command2, "--test") {
+ t.Fatalf("Expected command to contain --test")
+ }
+}
diff --git a/java/metalava/Android.bp b/java/metalava/Android.bp
index ccbd191..6bf1832 100644
--- a/java/metalava/Android.bp
+++ b/java/metalava/Android.bp
@@ -15,4 +15,5 @@
filegroup {
name: "metalava-config-files",
srcs: ["*-config.xml"],
+ visibility: ["//visibility:public"],
}
diff --git a/java/metalava/main-config.xml b/java/metalava/main-config.xml
index c61196f..c2881ac 100644
--- a/java/metalava/main-config.xml
+++ b/java/metalava/main-config.xml
@@ -16,4 +16,20 @@
<config xmlns="http://www.google.com/tools/metalava/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.google.com/tools/metalava/config ../../../../tools/metalava/metalava/src/main/resources/schemas/config.xsd"/>
+ xsi:schemaLocation="http://www.google.com/tools/metalava/config ../../../../tools/metalava/metalava/src/main/resources/schemas/config.xsd">
+ <api-surfaces>
+ <!-- These are hard coded into java_sdk_library. -->
+ <api-surface name="public"/>
+ <api-surface name="system" extends="public"/>
+ <api-surface name="module-lib" extends="system"/>
+ <api-surface name="test" extends="system"/>
+ <api-surface name="system-server" extends="public"/>
+ <!-- This is used in java/core-libraries/Android.bp. -->
+ <api-surface name="core"/>
+ <!-- These are used in libcore, external/conscrypt and external/icu. -->
+ <api-surface name="core-platform" extends="public"/>
+ <api-surface name="core-platform-legacy" extends="public"/>
+ <api-surface name="core-platform-plus-public"/>
+ <api-surface name="intra-core" extends="public"/>
+ </api-surfaces>
+</config>
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index d794e51..152eb1e 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -24,7 +24,7 @@
}
func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContext) {
- ctx.RegisterParallelSingletonModuleType("platform_bootclasspath", platformBootclasspathFactory)
+ ctx.RegisterModuleType("platform_bootclasspath", platformBootclasspathFactory)
}
// The tags used for the dependencies between the platform bootclasspath and any configured boot
@@ -33,10 +33,11 @@
platformBootclasspathArtBootJarDepTag = bootclasspathDependencyTag{name: "art-boot-jar"}
platformBootclasspathBootJarDepTag = bootclasspathDependencyTag{name: "platform-boot-jar"}
platformBootclasspathApexBootJarDepTag = bootclasspathDependencyTag{name: "apex-boot-jar"}
+ platformBootclasspathImplLibDepTag = dependencyTag{name: "impl-lib-tag"}
)
type platformBootclasspathModule struct {
- android.SingletonModuleBase
+ android.ModuleBase
ClasspathFragmentBase
properties platformBootclasspathProperties
@@ -63,7 +64,7 @@
HiddenAPIFlagFileProperties
}
-func platformBootclasspathFactory() android.SingletonModule {
+func platformBootclasspathFactory() android.Module {
m := &platformBootclasspathModule{}
m.AddProperties(&m.properties)
initClasspathFragment(m, BOOTCLASSPATH)
@@ -111,12 +112,18 @@
// Add dependencies on all the ART jars.
global := dexpreopt.GetGlobalConfig(ctx)
addDependenciesOntoSelectedBootImageApexes(ctx, "com.android.art")
+
+ var bootImageModuleNames []string
+
// TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly
addDependenciesOntoBootImageModules(ctx, global.ArtApexJars, platformBootclasspathArtBootJarDepTag)
+ bootImageModuleNames = append(bootImageModuleNames, global.ArtApexJars.CopyOfJars()...)
// Add dependencies on all the non-updatable jars, which are on the platform or in non-updatable
// APEXes.
- addDependenciesOntoBootImageModules(ctx, b.platformJars(ctx), platformBootclasspathBootJarDepTag)
+ platformJars := b.platformJars(ctx)
+ addDependenciesOntoBootImageModules(ctx, platformJars, platformBootclasspathBootJarDepTag)
+ bootImageModuleNames = append(bootImageModuleNames, platformJars.CopyOfJars()...)
// Add dependencies on all the updatable jars, except the ART jars.
apexJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
@@ -127,9 +134,17 @@
addDependenciesOntoSelectedBootImageApexes(ctx, android.FirstUniqueStrings(apexes)...)
// TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly
addDependenciesOntoBootImageModules(ctx, apexJars, platformBootclasspathApexBootJarDepTag)
+ bootImageModuleNames = append(bootImageModuleNames, apexJars.CopyOfJars()...)
// Add dependencies on all the fragments.
b.properties.BootclasspathFragmentsDepsProperties.addDependenciesOntoFragments(ctx)
+
+ for _, bootImageModuleName := range bootImageModuleNames {
+ implLibName := implLibraryModuleName(bootImageModuleName)
+ if ctx.OtherModuleExists(implLibName) {
+ ctx.AddFarVariationDependencies(nil, platformBootclasspathImplLibDepTag, implLibName)
+ }
+ }
}
func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList, tag bootclasspathDependencyTag) {
@@ -141,18 +156,6 @@
}
}
-// GenerateSingletonBuildActions does nothing and must never do anything.
-//
-// This module only implements android.SingletonModule so that it can implement
-// android.SingletonMakeVarsProvider.
-func (b *platformBootclasspathModule) GenerateSingletonBuildActions(android.SingletonContext) {
- // Keep empty
-}
-
-func (d *platformBootclasspathModule) MakeVars(ctx android.MakeVarsContext) {
- d.generateHiddenApiMakeVars(ctx)
-}
-
func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// Gather all the dependencies from the art, platform, and apex boot jars.
artModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathArtBootJarDepTag)
@@ -166,17 +169,22 @@
allModules = append(allModules, apexModules...)
b.configuredModules = allModules
+ // Do not add implLibModule to allModules as the impl lib is only used to collect the
+ // transitive source files
+ var implLibModule []android.Module
+ ctx.VisitDirectDepsWithTag(platformBootclasspathImplLibDepTag, func(m android.Module) {
+ implLibModule = append(implLibModule, m)
+ })
+
var transitiveSrcFiles android.Paths
- for _, module := range allModules {
+ for _, module := range append(allModules, implLibModule...) {
if depInfo, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
- if depInfo.TransitiveSrcFiles != nil {
- transitiveSrcFiles = append(transitiveSrcFiles, depInfo.TransitiveSrcFiles.ToList()...)
- }
+ transitiveSrcFiles = append(transitiveSrcFiles, depInfo.TransitiveSrcFiles.ToList()...)
}
}
jarArgs := resourcePathsToJarArgs(transitiveSrcFiles)
jarArgs = append(jarArgs, "-srcjar") // Move srcfiles to the right package
- srcjar := android.PathForModuleOut(ctx, ctx.ModuleName()+"-transitive.srcjar").OutputPath
+ srcjar := android.PathForModuleOut(ctx, ctx.ModuleName()+"-transitive.srcjar")
TransformResourcesToJar(ctx, srcjar, jarArgs, transitiveSrcFiles)
// Gather all the fragments dependencies.
@@ -408,13 +416,3 @@
rule.Build(desc, desc)
}
-
-// generateHiddenApiMakeVars generates make variables needed by hidden API related make rules, e.g.
-// veridex and run-appcompat.
-func (b *platformBootclasspathModule) generateHiddenApiMakeVars(ctx android.MakeVarsContext) {
- if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
- return
- }
- // INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/.
- ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", b.hiddenAPIFlagsCSV.String())
-}
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index 0d2acae..db85579 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -27,21 +27,27 @@
)
func TestPlatformBootclasspath(t *testing.T) {
+ t.Parallel()
preparer := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
FixtureConfigureBootJars("platform:foo", "system_ext:bar"),
+ android.FixtureMergeMockFs(android.MockFS{
+ "api/current.txt": nil,
+ "api/removed.txt": nil,
+ }),
android.FixtureWithRootAndroidBp(`
platform_bootclasspath {
name: "platform-bootclasspath",
}
- java_library {
+ java_sdk_library {
name: "bar",
srcs: ["a.java"],
system_modules: "none",
sdk_version: "none",
compile_dex: true,
system_ext_specific: true,
+ unsafe_ignore_missing_latest_api: true,
}
`),
)
@@ -76,6 +82,7 @@
`)
t.Run("missing", func(t *testing.T) {
+ t.Parallel()
preparer.
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`"platform-bootclasspath" depends on undefined module "foo"`)).
RunTest(t)
@@ -91,6 +98,7 @@
android.AssertArrayString(t, "srcjar inputs", expected, srcjar.Implicits.Strings())
}
t.Run("source", func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
preparer,
addSourceBootclassPathModule,
@@ -107,6 +115,7 @@
})
t.Run("prebuilt", func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
preparer,
addPrebuiltBootclassPathModule,
@@ -123,6 +132,7 @@
})
t.Run("source+prebuilt - source preferred", func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
preparer,
addSourceBootclassPathModule,
@@ -140,6 +150,7 @@
})
t.Run("source+prebuilt - prebuilt preferred", func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
preparer,
addSourceBootclassPathModule,
@@ -157,6 +168,7 @@
})
t.Run("dex import", func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
preparer,
android.FixtureAddTextFile("deximport/Android.bp", `
@@ -179,6 +191,7 @@
}
func TestPlatformBootclasspathVariant(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
android.FixtureWithRootAndroidBp(`
@@ -193,6 +206,7 @@
}
func TestPlatformBootclasspath_ClasspathFragmentPaths(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
android.FixtureWithRootAndroidBp(`
@@ -204,10 +218,11 @@
p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
android.AssertStringEquals(t, "output filepath", "bootclasspath.pb", p.ClasspathFragmentBase.outputFilepath.Base())
- android.AssertPathRelativeToTopEquals(t, "install filepath", "out/soong/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath)
+ android.AssertPathRelativeToTopEquals(t, "install filepath", "out/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath)
}
func TestPlatformBootclasspathModule_AndroidMkEntries(t *testing.T) {
+ t.Parallel()
preparer := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
android.FixtureWithRootAndroidBp(`
@@ -218,6 +233,7 @@
)
t.Run("AndroidMkEntries", func(t *testing.T) {
+ t.Parallel()
result := preparer.RunTest(t)
p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
@@ -227,6 +243,7 @@
})
t.Run("hiddenapi-flags-entry", func(t *testing.T) {
+ t.Parallel()
result := preparer.RunTest(t)
p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
@@ -238,6 +255,7 @@
})
t.Run("classpath-fragment-entry", func(t *testing.T) {
+ t.Parallel()
result := preparer.RunTest(t)
want := map[string][]string{
@@ -262,6 +280,7 @@
}
func TestPlatformBootclasspath_Dist(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
FixtureConfigureBootJars("platform:foo", "platform:bar"),
@@ -298,13 +317,14 @@
platformBootclasspath := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
entries := android.AndroidMkEntriesForTest(t, result.TestContext, platformBootclasspath)
goals := entries[0].GetDistForGoals(platformBootclasspath)
- android.AssertStringEquals(t, "platform dist goals phony", ".PHONY: droidcore\n", goals[0])
+ android.AssertStringEquals(t, "platform dist goals phony", ".PHONY: droidcore", goals[0])
android.AssertStringDoesContain(t, "platform dist goals meta check", goals[1], "$(if $(strip $(ALL_TARGETS.")
android.AssertStringDoesContain(t, "platform dist goals meta assign", goals[1], "),,$(eval ALL_TARGETS.")
- android.AssertStringEquals(t, "platform dist goals call", "$(call dist-for-goals,droidcore,out/soong/hiddenapi/hiddenapi-flags.csv:hiddenapi-flags.csv)\n", android.StringRelativeToTop(result.Config, goals[2]))
+ android.AssertStringEquals(t, "platform dist goals call", "$(call dist-for-goals,droidcore,out/soong/hiddenapi/hiddenapi-flags.csv:hiddenapi-flags.csv)", android.StringRelativeToTop(result.Config, goals[2]))
}
func TestPlatformBootclasspath_HiddenAPIMonolithicFiles(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
PrepareForTestWithJavaSdkLibraryFiles,
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index 67ed84e..bb98944 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -51,6 +51,10 @@
type platformCompatConfigProperties struct {
Src *string `android:"path"`
+
+ // If true, we include it in the "merged" XML (merged_compat_config.xml).
+ // Default is true.
+ Include_in_merged_xml *bool
}
type platformCompatConfig struct {
@@ -60,6 +64,7 @@
installDirPath android.InstallPath
configFile android.OutputPath
metadataFile android.OutputPath
+ doMerge bool
installConfigFile android.InstallPath
}
@@ -68,6 +73,10 @@
return p.metadataFile
}
+func (p *platformCompatConfig) includeInMergedXml() bool {
+ return p.doMerge
+}
+
func (p *platformCompatConfig) CompatConfig() android.OutputPath {
return p.configFile
}
@@ -78,6 +87,9 @@
type platformCompatConfigMetadataProvider interface {
compatConfigMetadata() android.Path
+
+ // Whether to include it in the "merged" XML (merged_compat_config.xml) or not.
+ includeInMergedXml() bool
}
type PlatformCompatConfigIntf interface {
@@ -98,6 +110,7 @@
metadataFileName := p.Name() + "_meta.xml"
p.configFile = android.PathForModuleOut(ctx, configFileName).OutputPath
p.metadataFile = android.PathForModuleOut(ctx, metadataFileName).OutputPath
+ p.doMerge = proptools.BoolDefault(p.properties.Include_in_merged_xml, true)
path := android.PathForModuleSrc(ctx, String(p.properties.Src))
rule.Command().
@@ -110,6 +123,7 @@
p.installConfigFile = android.PathForModuleInstall(ctx, "etc", "compatconfig", p.configFile.Base())
rule.Build(configFileName, "Extract compat/compat_config.xml and install it")
ctx.InstallFile(p.installDirPath, p.configFile.Base(), p.configFile)
+ ctx.SetOutputFiles(android.Paths{p.configFile}, "")
}
func (p *platformCompatConfig) AndroidMkEntries() []android.AndroidMkEntries {
@@ -200,6 +214,10 @@
return module.metadataFile
}
+func (module *prebuiltCompatConfigModule) includeInMergedXml() bool {
+ return true // Always include in merged.xml
+}
+
func (module *prebuiltCompatConfigModule) BaseModuleName() string {
return proptools.StringDefault(module.properties.Source_module_name, module.ModuleBase.Name())
}
@@ -236,6 +254,9 @@
if !android.IsModulePreferred(module) {
return
}
+ if !c.includeInMergedXml() {
+ return
+ }
metadata := c.compatConfigMetadata()
compatConfigMetadata = append(compatConfigMetadata, metadata)
}
diff --git a/java/platform_compat_config_test.go b/java/platform_compat_config_test.go
index 80d991c..72f81e0 100644
--- a/java/platform_compat_config_test.go
+++ b/java/platform_compat_config_test.go
@@ -21,11 +21,13 @@
)
func TestPlatformCompatConfig(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithPlatformCompatConfig,
android.FixtureWithRootAndroidBp(`
platform_compat_config {
name: "myconfig2",
+ include_in_merged_xml: false,
}
platform_compat_config {
name: "myconfig1",
@@ -38,7 +40,6 @@
CheckMergedCompatConfigInputs(t, result, "myconfig",
"out/soong/.intermediates/myconfig1/myconfig1_meta.xml",
- "out/soong/.intermediates/myconfig2/myconfig2_meta.xml",
"out/soong/.intermediates/myconfig3/myconfig3_meta.xml",
)
}
diff --git a/java/plugin.go b/java/plugin.go
index 9c4774a..3534c7b 100644
--- a/java/plugin.go
+++ b/java/plugin.go
@@ -16,14 +16,28 @@
import (
"android/soong/android"
+ "github.com/google/blueprint"
)
+type JavaPluginInfo struct {
+ ProcessorClass *string
+ GeneratesApi bool
+}
+
+var JavaPluginInfoProvider = blueprint.NewProvider[JavaPluginInfo]()
+
+type KotlinPluginInfo struct {
+}
+
+var KotlinPluginInfoProvider = blueprint.NewProvider[KotlinPluginInfo]()
+
func init() {
registerJavaPluginBuildComponents(android.InitRegistrationContext)
}
func registerJavaPluginBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("java_plugin", PluginFactory)
+ ctx.RegisterModuleType("kotlin_plugin", KotlinPluginFactory)
}
func PluginFactory() android.Module {
@@ -37,6 +51,16 @@
return module
}
+func KotlinPluginFactory() android.Module {
+ module := &KotlinPlugin{}
+
+ module.addHostProperties()
+
+ InitJavaModule(module, android.HostSupported)
+
+ return module
+}
+
// Plugin describes a java_plugin module, a host java library that will be used by javac as an annotation processor.
type Plugin struct {
Library
@@ -53,3 +77,23 @@
// parallelism and cause more recompilation for modules that depend on modules that use this plugin.
Generates_api *bool
}
+
+func (p *Plugin) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ p.Library.GenerateAndroidBuildActions(ctx)
+
+ android.SetProvider(ctx, JavaPluginInfoProvider, JavaPluginInfo{
+ ProcessorClass: p.pluginProperties.Processor_class,
+ GeneratesApi: Bool(p.pluginProperties.Generates_api),
+ })
+}
+
+// Plugin describes a kotlin_plugin module, a host java/kotlin library that will be used by kotlinc as a compiler plugin.
+type KotlinPlugin struct {
+ Library
+}
+
+func (p *KotlinPlugin) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ p.Library.GenerateAndroidBuildActions(ctx)
+
+ android.SetProvider(ctx, KotlinPluginInfoProvider, KotlinPluginInfo{})
+}
diff --git a/java/plugin_test.go b/java/plugin_test.go
index dc29b1c..95f4aca 100644
--- a/java/plugin_test.go
+++ b/java/plugin_test.go
@@ -19,6 +19,7 @@
)
func TestNoPlugin(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
@@ -43,6 +44,7 @@
}
func TestPlugin(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
@@ -82,6 +84,7 @@
}
func TestPluginGeneratesApi(t *testing.T) {
+ t.Parallel()
ctx, _ := testJava(t, `
java_library {
name: "foo",
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 00613ee..527e479 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -124,8 +124,8 @@
return
}
-func prebuiltApiModuleName(mctx android.LoadHookContext, module, scope, version string) string {
- return fmt.Sprintf("%s_%s_%s_%s", mctx.ModuleName(), scope, version, module)
+func prebuiltApiModuleName(moduleName, module, scope, version string) string {
+ return fmt.Sprintf("%s_%s_%s_%s", moduleName, scope, version, module)
}
func createImport(mctx android.LoadHookContext, module, scope, version, path, sdkVersion string, compileDex bool) {
props := struct {
@@ -135,7 +135,7 @@
Installable *bool
Compile_dex *bool
}{
- Name: proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, version)),
+ Name: proptools.StringPtr(prebuiltApiModuleName(mctx.ModuleName(), module, scope, version)),
Jars: []string{path},
Sdk_version: proptools.StringPtr(sdkVersion),
Installable: proptools.BoolPtr(false),
@@ -257,8 +257,8 @@
Name *string
Libs []string
}{}
- props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, "system_modules", scope, version))
- props.Libs = append(props.Libs, prebuiltApiModuleName(mctx, "core-for-system-modules", scope, version))
+ props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx.ModuleName(), "system_modules", scope, version))
+ props.Libs = append(props.Libs, prebuiltApiModuleName(mctx.ModuleName(), "core-for-system-modules", scope, version))
mctx.CreateModule(systemModulesImportFactory, &props)
}
diff --git a/java/prebuilt_apis_test.go b/java/prebuilt_apis_test.go
index b6fb2c6..c6a5913 100644
--- a/java/prebuilt_apis_test.go
+++ b/java/prebuilt_apis_test.go
@@ -29,6 +29,7 @@
}
func TestPrebuiltApis_SystemModulesCreation(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
FixtureWithPrebuiltApis(map[string][]string{
@@ -61,6 +62,7 @@
}
func TestPrebuiltApis_WithExtensions(t *testing.T) {
+ t.Parallel()
runTestWithBaseExtensionLevel := func(v int) (foo_input, bar_input, baz_input string) {
result := android.GroupFixturePreparers(
prepareForJavaTest,
@@ -101,6 +103,7 @@
}
func TestPrebuiltApis_WithIncrementalApi(t *testing.T) {
+ t.Parallel()
runTestWithIncrementalApi := func() (foo_input, bar_input, baz_input string) {
result := android.GroupFixturePreparers(
prepareForJavaTest,
diff --git a/java/proto_test.go b/java/proto_test.go
index d1cb714..5b184b6 100644
--- a/java/proto_test.go
+++ b/java/proto_test.go
@@ -28,6 +28,7 @@
`
func TestProtoStream(t *testing.T) {
+ t.Parallel()
bp := `
java_library {
name: "java-stream-protos",
diff --git a/java/ravenwood.go b/java/ravenwood.go
index bb136cf..3b6c80b 100644
--- a/java/ravenwood.go
+++ b/java/ravenwood.go
@@ -14,6 +14,8 @@
package java
import (
+ "strconv"
+
"android/soong/android"
"android/soong/tradefed"
@@ -33,8 +35,16 @@
var ravenwoodLibContentTag = dependencyTag{name: "ravenwoodlibcontent"}
var ravenwoodUtilsTag = dependencyTag{name: "ravenwoodutils"}
var ravenwoodRuntimeTag = dependencyTag{name: "ravenwoodruntime"}
-var ravenwoodDataTag = dependencyTag{name: "ravenwooddata"}
var ravenwoodTestResourceApkTag = dependencyTag{name: "ravenwoodtestresapk"}
+var ravenwoodTestInstResourceApkTag = dependencyTag{name: "ravenwoodtest-inst-res-apk"}
+
+var genManifestProperties = pctx.AndroidStaticRule("genManifestProperties",
+ blueprint.RuleParams{
+ Command: "echo targetSdkVersionInt=$targetSdkVersionInt > $out && " +
+ "echo targetSdkVersionRaw=$targetSdkVersionRaw >> $out && " +
+ "echo packageName=$packageName >> $out && " +
+ "echo instPackageName=$instPackageName >> $out",
+ }, "targetSdkVersionInt", "targetSdkVersionRaw", "packageName", "instPackageName")
const ravenwoodUtilsName = "ravenwood-utils"
const ravenwoodRuntimeName = "ravenwood-runtime"
@@ -54,14 +64,31 @@
}
type ravenwoodTestProperties struct {
- Jni_libs []string
+ Jni_libs proptools.Configurable[[]string]
// Specify another android_app module here to copy it to the test directory, so that
- // the ravenwood test can access it.
+ // the ravenwood test can access it. This APK will be loaded as resources of the test
+ // target app.
// TODO: For now, we simply refer to another android_app module and copy it to the
// test directory. Eventually, android_ravenwood_test should support all the resource
// related properties and build resources from the `res/` directory.
Resource_apk *string
+
+ // Specify another android_app module here to copy it to the test directory, so that
+ // the ravenwood test can access it. This APK will be loaded as resources of the test
+ // instrumentation app itself.
+ Inst_resource_apk *string
+
+ // Specify the package name of the test target apk.
+ // This will be set to the target Context's package name.
+ // (i.e. Instrumentation.getTargetContext().getPackageName())
+ // If this is omitted, Package_name will be used.
+ Package_name *string
+
+ // Specify the package name of this test module.
+ // This will be set to the test Context's package name.
+ //(i.e. Instrumentation.getContext().getPackageName())
+ Inst_package_name *string
}
type ravenwoodTest struct {
@@ -83,7 +110,7 @@
module.AddProperties(&module.testProperties, &module.ravenwoodTestProperties)
module.Module.dexpreopter.isTest = true
- module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
+ module.Module.linter.properties.Lint.Test_module_type = proptools.BoolPtr(true)
module.testProperties.Test_suites = []string{
"general-tests",
@@ -120,7 +147,7 @@
}
// Add jni libs
- for _, lib := range r.ravenwoodTestProperties.Jni_libs {
+ for _, lib := range r.ravenwoodTestProperties.Jni_libs.GetOrDefault(ctx, nil) {
ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib)
}
@@ -128,6 +155,10 @@
if resourceApk := proptools.String(r.ravenwoodTestProperties.Resource_apk); resourceApk != "" {
ctx.AddVariationDependencies(nil, ravenwoodTestResourceApkTag, resourceApk)
}
+
+ if resourceApk := proptools.String(r.ravenwoodTestProperties.Inst_resource_apk); resourceApk != "" {
+ ctx.AddVariationDependencies(nil, ravenwoodTestInstResourceApkTag, resourceApk)
+ }
}
func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -154,26 +185,24 @@
// All JNI libraries included in the runtime
var runtimeJniModuleNames map[string]bool
- if utils := ctx.GetDirectDepsWithTag(ravenwoodUtilsTag)[0]; utils != nil {
- for _, installFile := range android.OtherModuleProviderOrDefault(
- ctx, utils, android.InstallFilesProvider).InstallFiles {
- installDeps = append(installDeps, installFile)
- }
- jniDeps, ok := android.OtherModuleProvider(ctx, utils, ravenwoodLibgroupJniDepProvider)
- if ok {
- runtimeJniModuleNames = jniDeps.names
- }
+ utils := ctx.GetDirectDepsProxyWithTag(ravenwoodUtilsTag)[0]
+ for _, installFile := range android.OtherModuleProviderOrDefault(
+ ctx, utils, android.InstallFilesProvider).InstallFiles {
+ installDeps = append(installDeps, installFile)
+ }
+ jniDeps, ok := android.OtherModuleProvider(ctx, utils, ravenwoodLibgroupJniDepProvider)
+ if ok {
+ runtimeJniModuleNames = jniDeps.names
}
- if runtime := ctx.GetDirectDepsWithTag(ravenwoodRuntimeTag)[0]; runtime != nil {
- for _, installFile := range android.OtherModuleProviderOrDefault(
- ctx, runtime, android.InstallFilesProvider).InstallFiles {
- installDeps = append(installDeps, installFile)
- }
- jniDeps, ok := android.OtherModuleProvider(ctx, runtime, ravenwoodLibgroupJniDepProvider)
- if ok {
- runtimeJniModuleNames = jniDeps.names
- }
+ runtime := ctx.GetDirectDepsProxyWithTag(ravenwoodRuntimeTag)[0]
+ for _, installFile := range android.OtherModuleProviderOrDefault(
+ ctx, runtime, android.InstallFilesProvider).InstallFiles {
+ installDeps = append(installDeps, installFile)
+ }
+ jniDeps, ok = android.OtherModuleProvider(ctx, runtime, ravenwoodLibgroupJniDepProvider)
+ if ok {
+ runtimeJniModuleNames = jniDeps.names
}
// Also remember what JNI libs are in the runtime.
@@ -195,16 +224,49 @@
}
resApkInstallPath := installPath.Join(ctx, "ravenwood-res-apks")
- if resApk := ctx.GetDirectDepsWithTag(ravenwoodTestResourceApkTag); len(resApk) > 0 {
- for _, installFile := range android.OtherModuleProviderOrDefault(
- ctx, resApk[0], android.InstallFilesProvider).InstallFiles {
- installResApk := ctx.InstallFile(resApkInstallPath, "ravenwood-res.apk", installFile)
+
+ copyResApk := func(tag blueprint.DependencyTag, toFileName string) {
+ if resApk := ctx.GetDirectDepsProxyWithTag(tag); len(resApk) > 0 {
+ installFile := android.OutputFileForModule(ctx, resApk[0], "")
+ installResApk := ctx.InstallFile(resApkInstallPath, toFileName, installFile)
installDeps = append(installDeps, installResApk)
}
}
+ copyResApk(ravenwoodTestResourceApkTag, "ravenwood-res.apk")
+ copyResApk(ravenwoodTestInstResourceApkTag, "ravenwood-inst-res.apk")
+
+ // Generate manifest properties
+ propertiesOutputPath := android.PathForModuleGen(ctx, "ravenwood.properties")
+
+ targetSdkVersion := proptools.StringDefault(r.deviceProperties.Target_sdk_version, "")
+ targetSdkVersionInt := r.TargetSdkVersion(ctx).FinalOrFutureInt() // FinalOrFutureInt may be 10000.
+ packageName := proptools.StringDefault(r.ravenwoodTestProperties.Package_name, "")
+ instPackageName := proptools.StringDefault(r.ravenwoodTestProperties.Inst_package_name, "")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: genManifestProperties,
+ Description: "genManifestProperties",
+ Output: propertiesOutputPath,
+ Args: map[string]string{
+ "targetSdkVersionInt": strconv.Itoa(targetSdkVersionInt),
+ "targetSdkVersionRaw": targetSdkVersion,
+ "packageName": packageName,
+ "instPackageName": instPackageName,
+ },
+ })
+ installProps := ctx.InstallFile(installPath, "ravenwood.properties", propertiesOutputPath)
+ installDeps = append(installDeps, installProps)
// Install our JAR with all dependencies
ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.outputFile, installDeps...)
+
+ moduleInfoJSON := ctx.ModuleInfoJSON()
+ if _, ok := r.testConfig.(android.WritablePath); ok {
+ moduleInfoJSON.AutoTestConfig = []string{"true"}
+ }
+ if r.testConfig != nil {
+ moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, r.testConfig.String())
+ }
+ moduleInfoJSON.CompatibilitySuites = []string{"general-tests", "ravenwood-tests"}
}
func (r *ravenwoodTest) AndroidMkEntries() []android.AndroidMkEntries {
@@ -225,10 +287,13 @@
type ravenwoodLibgroupProperties struct {
Libs []string
- Jni_libs []string
+ Jni_libs proptools.Configurable[[]string]
// We use this to copy framework-res.apk to the ravenwood runtime directory.
- Data []string
+ Data []string `android:"path,arch_variant"`
+
+ // We use this to copy font files to the ravenwood runtime directory.
+ Fonts []string `android:"path,arch_variant"`
}
type ravenwoodLibgroup struct {
@@ -264,12 +329,9 @@
for _, lib := range r.ravenwoodLibgroupProperties.Libs {
ctx.AddVariationDependencies(nil, ravenwoodLibContentTag, lib)
}
- for _, lib := range r.ravenwoodLibgroupProperties.Jni_libs {
+ for _, lib := range r.ravenwoodLibgroupProperties.Jni_libs.GetOrDefault(ctx, nil) {
ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib)
}
- for _, data := range r.ravenwoodLibgroupProperties.Data {
- ctx.AddVariationDependencies(nil, ravenwoodDataTag, data)
- }
}
func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -290,7 +352,7 @@
// Install our runtime into expected location for packaging
installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
for _, lib := range r.ravenwoodLibgroupProperties.Libs {
- libModule := ctx.GetDirectDepWithTag(lib, ravenwoodLibContentTag)
+ libModule := ctx.GetDirectDepProxyWithTag(lib, ravenwoodLibContentTag)
if libModule == nil {
if ctx.Config().AllowMissingDependencies() {
ctx.AddMissingDependencies([]string{lib})
@@ -309,12 +371,17 @@
}
dataInstallPath := installPath.Join(ctx, "ravenwood-data")
- for _, data := range r.ravenwoodLibgroupProperties.Data {
- libModule := ctx.GetDirectDepWithTag(data, ravenwoodDataTag)
- file := android.OutputFileForModule(ctx, libModule, "")
+ data := android.PathsForModuleSrc(ctx, r.ravenwoodLibgroupProperties.Data)
+ for _, file := range data {
ctx.InstallFile(dataInstallPath, file.Base(), file)
}
+ fontsInstallPath := installPath.Join(ctx, "fonts")
+ fonts := android.PathsForModuleSrc(ctx, r.ravenwoodLibgroupProperties.Fonts)
+ for _, file := range fonts {
+ ctx.InstallFile(fontsInstallPath, file.Base(), file)
+ }
+
// Normal build should perform install steps
ctx.Phony(r.BaseModuleName(), android.PathForPhony(ctx, r.BaseModuleName()+"-install"))
}
diff --git a/java/ravenwood_test.go b/java/ravenwood_test.go
index d26db93..ac4f147 100644
--- a/java/ravenwood_test.go
+++ b/java/ravenwood_test.go
@@ -19,6 +19,7 @@
"testing"
"android/soong/android"
+ "android/soong/etc"
)
var prepareRavenwoodRuntime = android.GroupFixturePreparers(
@@ -59,11 +60,19 @@
}
android_app {
name: "app1",
- sdk_version: "current",
+ sdk_version: "current",
}
android_app {
name: "app2",
- sdk_version: "current",
+ sdk_version: "current",
+ }
+ android_app {
+ name: "app3",
+ sdk_version: "current",
+ }
+ prebuilt_font {
+ name: "Font.ttf",
+ src: "Font.ttf",
}
android_ravenwood_libgroup {
name: "ravenwood-runtime",
@@ -76,7 +85,10 @@
"ravenwood-runtime-jni2",
],
data: [
- "app1",
+ ":app1",
+ ],
+ fonts: [
+ ":Font.ttf"
],
}
android_ravenwood_libgroup {
@@ -88,15 +100,17 @@
`),
)
-var installPathPrefix = "out/soong/host/linux-x86/testcases"
+var installPathPrefix = "out/host/linux-x86/testcases"
func TestRavenwoodRuntime(t *testing.T) {
+ t.Parallel()
if runtime.GOOS != "linux" {
t.Skip("requires linux")
}
ctx := android.GroupFixturePreparers(
PrepareForIntegrationTestWithJava,
+ etc.PrepareForTestWithPrebuiltEtc,
prepareRavenwoodRuntime,
).RunTest(t)
@@ -114,49 +128,63 @@
runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/libred.so")
runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni3.so")
runtime.Output(installPathPrefix + "/ravenwood-runtime/ravenwood-data/app1.apk")
+ runtime.Output(installPathPrefix + "/ravenwood-runtime/fonts/Font.ttf")
utils := ctx.ModuleForTests("ravenwood-utils", "android_common")
utils.Output(installPathPrefix + "/ravenwood-utils/framework-rules.ravenwood.jar")
}
func TestRavenwoodTest(t *testing.T) {
+ t.Parallel()
if runtime.GOOS != "linux" {
t.Skip("requires linux")
}
ctx := android.GroupFixturePreparers(
PrepareForIntegrationTestWithJava,
+ etc.PrepareForTestWithPrebuiltEtc,
prepareRavenwoodRuntime,
).RunTestWithBp(t, `
- cc_library_shared {
- name: "jni-lib1",
- host_supported: true,
- srcs: ["jni.cpp"],
- }
- cc_library_shared {
- name: "jni-lib2",
- host_supported: true,
- srcs: ["jni.cpp"],
- stem: "libblue",
- shared_libs: [
- "jni-lib3",
- ],
- }
- cc_library_shared {
- name: "jni-lib3",
- host_supported: true,
- srcs: ["jni.cpp"],
- stem: "libpink",
- }
- android_ravenwood_test {
+ cc_library_shared {
+ name: "jni-lib1",
+ host_supported: true,
+ srcs: ["jni.cpp"],
+ }
+ cc_library_shared {
+ name: "jni-lib2",
+ host_supported: true,
+ srcs: ["jni.cpp"],
+ stem: "libblue",
+ shared_libs: [
+ "jni-lib3",
+ ],
+ }
+ cc_library_shared {
+ name: "jni-lib3",
+ host_supported: true,
+ srcs: ["jni.cpp"],
+ stem: "libpink",
+ }
+ java_defaults {
+ name: "ravenwood-test-defaults",
+ jni_libs: ["jni-lib2"],
+ }
+ android_ravenwood_test {
name: "ravenwood-test",
srcs: ["Test.java"],
+ defaults: ["ravenwood-test-defaults"],
jni_libs: [
"jni-lib1",
- "jni-lib2",
"ravenwood-runtime-jni2",
],
resource_apk: "app2",
+ inst_resource_apk: "app3",
sdk_version: "test_current",
+ target_sdk_version: "34",
+ package_name: "a.b.c",
+ inst_package_name: "x.y.z",
+ }
+ android_ravenwood_test {
+ name: "ravenwood-test-empty",
}
`)
@@ -179,10 +207,15 @@
// Verify that we've emitted test artifacts in expected location
outputJar := module.Output(installPathPrefix + "/ravenwood-test/ravenwood-test.jar")
module.Output(installPathPrefix + "/ravenwood-test/ravenwood-test.config")
+ module.Output(installPathPrefix + "/ravenwood-test/ravenwood.properties")
module.Output(installPathPrefix + "/ravenwood-test/lib64/jni-lib1.so")
module.Output(installPathPrefix + "/ravenwood-test/lib64/libblue.so")
module.Output(installPathPrefix + "/ravenwood-test/lib64/libpink.so")
module.Output(installPathPrefix + "/ravenwood-test/ravenwood-res-apks/ravenwood-res.apk")
+ module.Output(installPathPrefix + "/ravenwood-test/ravenwood-res-apks/ravenwood-inst-res.apk")
+
+ module = ctx.ModuleForTests("ravenwood-test-empty", "android_common")
+ module.Output(installPathPrefix + "/ravenwood-test-empty/ravenwood.properties")
// ravenwood-runtime*.so are included in the runtime, so it shouldn't be emitted.
for _, o := range module.AllOutputs() {
diff --git a/java/robolectric.go b/java/robolectric.go
index 26f4b71..43e17f9 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -16,15 +16,12 @@
import (
"fmt"
- "io"
- "strconv"
- "strings"
"android/soong/android"
"android/soong/java/config"
- "android/soong/testing"
"android/soong/tradefed"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -32,6 +29,23 @@
RegisterRobolectricBuildComponents(android.InitRegistrationContext)
}
+type RobolectricRuntimesInfo struct {
+ Runtimes []android.InstallPath
+}
+
+var RobolectricRuntimesInfoProvider = blueprint.NewProvider[RobolectricRuntimesInfo]()
+
+type roboRuntimeOnlyDependencyTag struct {
+ blueprint.BaseDependencyTag
+}
+
+var roboRuntimeOnlyDepTag roboRuntimeOnlyDependencyTag
+
+// Mark this tag so dependencies that use it are excluded from visibility enforcement.
+func (t roboRuntimeOnlyDependencyTag) ExcludeFromVisibilityEnforcement() {}
+
+var _ android.ExcludeFromVisibilityEnforcementTag = roboRuntimeOnlyDepTag
+
func RegisterRobolectricBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("android_robolectric_test", RobolectricTestFactory)
ctx.RegisterModuleType("android_robolectric_runtimes", robolectricRuntimesFactory)
@@ -45,12 +59,12 @@
}
const robolectricCurrentLib = "Robolectric_all-target"
+const clearcutJunitLib = "ClearcutJunitListenerAar"
const robolectricPrebuiltLibPattern = "platform-robolectric-%s-prebuilt"
var (
roboCoverageLibsTag = dependencyTag{name: "roboCoverageLibs"}
roboRuntimesTag = dependencyTag{name: "roboRuntimes"}
- roboRuntimeOnlyTag = dependencyTag{name: "roboRuntimeOnlyTag"}
)
type robolectricProperties struct {
@@ -68,10 +82,6 @@
Shards *int64
}
- // The version number of a robolectric prebuilt to use from prebuilts/misc/common/robolectric
- // instead of the one built from source in external/robolectric-shadows.
- Robolectric_prebuilt_version *string
-
// Use /external/robolectric rather than /external/robolectric-shadows as the version of robolectric
// to use. /external/robolectric closely tracks github's master, and will fully replace /external/robolectric-shadows
Upstream *bool
@@ -79,7 +89,7 @@
// Use strict mode to limit access of Robolectric API directly. See go/roboStrictMode
Strict_mode *bool
- Jni_libs []string
+ Jni_libs proptools.Configurable[[]string]
}
type robolectricTest struct {
@@ -88,16 +98,6 @@
robolectricProperties robolectricProperties
testProperties testProperties
- libs []string
- tests []string
-
- manifest android.Path
- resourceApk android.Path
-
- combinedJar android.WritablePath
-
- roboSrcJar android.Path
-
testConfig android.Path
data android.Paths
@@ -120,31 +120,22 @@
ctx.PropertyErrorf("instrumentation_for", "missing required instrumented module")
}
- if v := String(r.robolectricProperties.Robolectric_prebuilt_version); v != "" {
- ctx.AddVariationDependencies(nil, libTag, fmt.Sprintf(robolectricPrebuiltLibPattern, v))
- } else if !proptools.BoolDefault(r.robolectricProperties.Strict_mode, true) {
- if proptools.Bool(r.robolectricProperties.Upstream) {
- ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib+"_upstream")
- } else {
- ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib)
- }
- }
+ ctx.AddVariationDependencies(nil, roboRuntimeOnlyDepTag, clearcutJunitLib)
if proptools.BoolDefault(r.robolectricProperties.Strict_mode, true) {
- ctx.AddVariationDependencies(nil, roboRuntimeOnlyTag, robolectricCurrentLib+"_upstream")
+ ctx.AddVariationDependencies(nil, roboRuntimeOnlyDepTag, robolectricCurrentLib)
} else {
- // opting out from strict mode, robolectric_non_strict_mode_permission lib should be added
- ctx.AddVariationDependencies(nil, libTag, "robolectric_non_strict_mode_permission")
+ ctx.AddVariationDependencies(nil, staticLibTag, robolectricCurrentLib)
}
- ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...)
+ ctx.AddVariationDependencies(nil, staticLibTag, robolectricDefaultLibs...)
ctx.AddVariationDependencies(nil, roboCoverageLibsTag, r.robolectricProperties.Coverage_libs...)
ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
roboRuntimesTag, "robolectric-android-all-prebuilts")
- for _, lib := range r.robolectricProperties.Jni_libs {
+ for _, lib := range r.robolectricProperties.Jni_libs.GetOrDefault(ctx, nil) {
ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib)
}
}
@@ -153,161 +144,141 @@
r.forceOSType = ctx.Config().BuildOS
r.forceArchType = ctx.Config().BuildArch
+ var extraTestRunnerOptions []tradefed.Option
+ extraTestRunnerOptions = append(extraTestRunnerOptions, tradefed.Option{Name: "java-flags", Value: "-Drobolectric=true"})
+ if proptools.BoolDefault(r.robolectricProperties.Strict_mode, true) {
+ extraTestRunnerOptions = append(extraTestRunnerOptions, tradefed.Option{Name: "java-flags", Value: "-Drobolectric.strict.mode=true"})
+ }
+
+ var extraOptions []tradefed.Option
+ var javaHome = ctx.Config().Getenv("ANDROID_JAVA_HOME")
+ extraOptions = append(extraOptions, tradefed.Option{Name: "java-folder", Value: javaHome})
+
r.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
- TestConfigProp: r.testProperties.Test_config,
- TestConfigTemplateProp: r.testProperties.Test_config_template,
- TestSuites: r.testProperties.Test_suites,
- AutoGenConfig: r.testProperties.Auto_gen_config,
- DeviceTemplate: "${RobolectricTestConfigTemplate}",
- HostTemplate: "${RobolectricTestConfigTemplate}",
+ TestConfigProp: r.testProperties.Test_config,
+ TestConfigTemplateProp: r.testProperties.Test_config_template,
+ TestSuites: r.testProperties.Test_suites,
+ OptionsForAutogenerated: extraOptions,
+ TestRunnerOptions: extraTestRunnerOptions,
+ AutoGenConfig: r.testProperties.Auto_gen_config,
+ DeviceTemplate: "${RobolectricTestConfigTemplate}",
+ HostTemplate: "${RobolectricTestConfigTemplate}",
})
r.data = android.PathsForModuleSrc(ctx, r.testProperties.Data)
-
- roboTestConfig := android.PathForModuleGen(ctx, "robolectric").
- Join(ctx, "com/android/tools/test_config.properties")
+ r.data = append(r.data, android.PathsForModuleSrc(ctx, r.testProperties.Device_common_data)...)
+ r.data = append(r.data, android.PathsForModuleSrc(ctx, r.testProperties.Device_first_data)...)
+ r.data = append(r.data, android.PathsForModuleSrc(ctx, r.testProperties.Device_first_prefer32_data)...)
var ok bool
- var instrumentedApp *AndroidApp
+ var instrumentedApp *JavaInfo
+ var appInfo *AppInfo
// TODO: this inserts paths to built files into the test, it should really be inserting the contents.
- instrumented := ctx.GetDirectDepsWithTag(instrumentationForTag)
+ instrumented := ctx.GetDirectDepsProxyWithTag(instrumentationForTag)
if len(instrumented) == 1 {
- instrumentedApp, ok = instrumented[0].(*AndroidApp)
+ appInfo, ok = android.OtherModuleProvider(ctx, instrumented[0], AppInfoProvider)
if !ok {
ctx.PropertyErrorf("instrumentation_for", "dependency must be an android_app")
}
+ instrumentedApp = android.OtherModuleProviderOrDefault(ctx, instrumented[0], JavaInfoProvider)
} else if !ctx.Config().AllowMissingDependencies() {
panic(fmt.Errorf("expected exactly 1 instrumented dependency, got %d", len(instrumented)))
}
- if instrumentedApp != nil {
- r.manifest = instrumentedApp.mergedManifestFile
- r.resourceApk = instrumentedApp.outputFile
-
- generateRoboTestConfig(ctx, roboTestConfig, instrumentedApp)
- r.extraResources = android.Paths{roboTestConfig}
- }
-
- r.Library.GenerateAndroidBuildActions(ctx)
-
- roboSrcJar := android.PathForModuleGen(ctx, "robolectric", ctx.ModuleName()+".srcjar")
-
- if instrumentedApp != nil {
- r.generateRoboSrcJar(ctx, roboSrcJar, instrumentedApp)
- r.roboSrcJar = roboSrcJar
+ var resourceApk android.Path
+ var manifest android.Path
+ if appInfo != nil {
+ manifest = appInfo.MergedManifestFile
+ resourceApk = instrumentedApp.OutputFile
}
roboTestConfigJar := android.PathForModuleOut(ctx, "robolectric_samedir", "samedir_config.jar")
generateSameDirRoboTestConfigJar(ctx, roboTestConfigJar)
- combinedJarJars := android.Paths{
- // roboTestConfigJar comes first so that its com/android/tools/test_config.properties
- // overrides the one from r.extraResources. The r.extraResources one can be removed
- // once the Make test runner is removed.
- roboTestConfigJar,
- r.outputFile,
- }
+ extraCombinedJars := android.Paths{roboTestConfigJar}
- if instrumentedApp != nil {
- combinedJarJars = append(combinedJarJars, instrumentedApp.implementationAndResourcesJar)
- }
-
- handleLibDeps := func(dep android.Module, runtimeOnly bool) {
- if !runtimeOnly {
- r.libs = append(r.libs, ctx.OtherModuleName(dep))
- }
+ handleLibDeps := func(dep android.ModuleProxy) {
if !android.InList(ctx.OtherModuleName(dep), config.FrameworkLibraries) {
if m, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok {
- combinedJarJars = append(combinedJarJars, m.ImplementationAndResourcesJars...)
+ extraCombinedJars = append(extraCombinedJars, m.ImplementationAndResourcesJars...)
}
}
}
- for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
- handleLibDeps(dep, false)
+ for _, dep := range ctx.GetDirectDepsProxyWithTag(libTag) {
+ handleLibDeps(dep)
}
- for _, dep := range ctx.GetDirectDepsWithTag(sdkLibTag) {
- handleLibDeps(dep, false)
+ for _, dep := range ctx.GetDirectDepsProxyWithTag(sdkLibTag) {
+ handleLibDeps(dep)
}
// handle the runtimeOnly tag for strict_mode
- for _, dep := range ctx.GetDirectDepsWithTag(roboRuntimeOnlyTag) {
- handleLibDeps(dep, true)
+ for _, dep := range ctx.GetDirectDepsProxyWithTag(roboRuntimeOnlyDepTag) {
+ handleLibDeps(dep)
}
- r.combinedJar = android.PathForModuleOut(ctx, "robolectric_combined", r.outputFile.Base())
- TransformJarsToJar(ctx, r.combinedJar, "combine jars", combinedJarJars, android.OptionalPath{},
- false, nil, nil)
-
- // TODO: this could all be removed if tradefed was used as the test runner, it will find everything
- // annotated as a test and run it.
- for _, src := range r.uniqueSrcFiles {
- s := src.Rel()
- if !strings.HasSuffix(s, "Test.java") && !strings.HasSuffix(s, "Test.kt") {
- continue
- } else if strings.HasSuffix(s, "/BaseRobolectricTest.java") {
- continue
- } else {
- s = strings.TrimPrefix(s, "src/")
- }
- r.tests = append(r.tests, s)
+ if appInfo != nil {
+ extraCombinedJars = append(extraCombinedJars, instrumentedApp.ImplementationAndResourcesJars...)
}
+ r.stem = proptools.StringDefault(r.overridableProperties.Stem, ctx.ModuleName())
+ r.classLoaderContexts = r.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
+ r.dexpreopter.disableDexpreopt()
+ javaInfo := r.compile(ctx, nil, nil, nil, extraCombinedJars)
+
installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
var installDeps android.InstallPaths
- if r.manifest != nil {
- r.data = append(r.data, r.manifest)
- installedManifest := ctx.InstallFile(installPath, ctx.ModuleName()+"-AndroidManifest.xml", r.manifest)
+ for _, data := range r.data {
+ installedData := ctx.InstallFile(installPath, data.Rel(), data)
+ installDeps = append(installDeps, installedData)
+ }
+
+ if manifest != nil {
+ r.data = append(r.data, manifest)
+ installedManifest := ctx.InstallFile(installPath, ctx.ModuleName()+"-AndroidManifest.xml", manifest)
installDeps = append(installDeps, installedManifest)
}
- if r.resourceApk != nil {
- r.data = append(r.data, r.resourceApk)
- installedResourceApk := ctx.InstallFile(installPath, ctx.ModuleName()+".apk", r.resourceApk)
+ if resourceApk != nil {
+ r.data = append(r.data, resourceApk)
+ installedResourceApk := ctx.InstallFile(installPath, ctx.ModuleName()+".apk", resourceApk)
installDeps = append(installDeps, installedResourceApk)
}
- runtimes := ctx.GetDirectDepWithTag("robolectric-android-all-prebuilts", roboRuntimesTag)
- for _, runtime := range runtimes.(*robolectricRuntimes).runtimes {
+ runtimes := ctx.GetDirectDepProxyWithTag("robolectric-android-all-prebuilts", roboRuntimesTag)
+ for _, runtime := range android.OtherModuleProviderOrDefault(ctx, runtimes, RobolectricRuntimesInfoProvider).Runtimes {
installDeps = append(installDeps, runtime)
}
installedConfig := ctx.InstallFile(installPath, ctx.ModuleName()+".config", r.testConfig)
installDeps = append(installDeps, installedConfig)
- for _, data := range android.PathsForModuleSrc(ctx, r.testProperties.Data) {
- installedData := ctx.InstallFile(installPath, data.Rel(), data)
- installDeps = append(installDeps, installedData)
- }
-
soInstallPath := installPath.Join(ctx, getLibPath(r.forceArchType))
for _, jniLib := range collectTransitiveJniDeps(ctx) {
installJni := ctx.InstallFile(soInstallPath, jniLib.path.Base(), jniLib.path)
installDeps = append(installDeps, installJni)
}
- r.installFile = ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...)
- android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
-}
+ r.installFile = ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.outputFile, installDeps...)
-func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath,
- instrumentedApp *AndroidApp) {
- rule := android.NewRuleBuilder(pctx, ctx)
+ if javaInfo != nil {
+ setExtraJavaInfo(ctx, r, javaInfo)
+ android.SetProvider(ctx, JavaInfoProvider, javaInfo)
+ }
- manifest := instrumentedApp.mergedManifestFile
- resourceApk := instrumentedApp.outputFile
-
- rule.Command().Text("rm -f").Output(outputFile)
- rule.Command().
- Textf(`echo "android_merged_manifest=%s" >>`, manifest.String()).Output(outputFile).Text("&&").
- Textf(`echo "android_resource_apk=%s" >>`, resourceApk.String()).Output(outputFile).
- // Make it depend on the files to which it points so the test file's timestamp is updated whenever the
- // contents change
- Implicit(manifest).
- Implicit(resourceApk)
-
- rule.Build("generate_test_config", "generate test_config.properties")
+ moduleInfoJSON := r.javaLibraryModuleInfoJSON(ctx)
+ if _, ok := r.testConfig.(android.WritablePath); ok {
+ moduleInfoJSON.AutoTestConfig = []string{"true"}
+ }
+ if r.testConfig != nil {
+ moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, r.testConfig.String())
+ }
+ if len(r.testProperties.Test_suites) > 0 {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, r.testProperties.Test_suites...)
+ } else {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite")
+ }
}
func generateSameDirRoboTestConfigJar(ctx android.ModuleContext, outputFile android.ModuleOutPath) {
@@ -332,22 +303,6 @@
rule.Build("generate_test_config_samedir", "generate test_config.properties")
}
-func (r *robolectricTest) generateRoboSrcJar(ctx android.ModuleContext, outputFile android.WritablePath,
- instrumentedApp *AndroidApp) {
-
- srcJarArgs := android.CopyOf(instrumentedApp.srcJarArgs)
- srcJarDeps := append(android.Paths(nil), instrumentedApp.srcJarDeps...)
-
- for _, m := range ctx.GetDirectDepsWithTag(roboCoverageLibsTag) {
- if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok {
- srcJarArgs = append(srcJarArgs, dep.SrcJarArgs...)
- srcJarDeps = append(srcJarDeps, dep.SrcJarDeps...)
- }
- }
-
- TransformResourcesToJar(ctx, outputFile, srcJarArgs, srcJarDeps)
-}
-
func (r *robolectricTest) AndroidMkEntries() []android.AndroidMkEntries {
entriesList := r.Library.AndroidMkEntries()
entries := &entriesList[0]
@@ -359,61 +314,11 @@
entries.SetPath("LOCAL_FULL_TEST_CONFIG", r.testConfig)
}
})
-
- entries.ExtraFooters = []android.AndroidMkExtraFootersFunc{
- func(w io.Writer, name, prefix, moduleDir string) {
- if s := r.robolectricProperties.Test_options.Shards; s != nil && *s > 1 {
- numShards := int(*s)
- shardSize := (len(r.tests) + numShards - 1) / numShards
- shards := android.ShardStrings(r.tests, shardSize)
- for i, shard := range shards {
- r.writeTestRunner(w, name, "Run"+name+strconv.Itoa(i), shard)
- }
-
- // TODO: add rules to dist the outputs of the individual tests, or combine them together?
- fmt.Fprintln(w, "")
- fmt.Fprintln(w, ".PHONY:", "Run"+name)
- fmt.Fprintln(w, "Run"+name, ": \\")
- for i := range shards {
- fmt.Fprintln(w, " ", "Run"+name+strconv.Itoa(i), "\\")
- }
- fmt.Fprintln(w, "")
- } else {
- r.writeTestRunner(w, name, "Run"+name, r.tests)
- }
- },
- }
-
return entriesList
}
-func (r *robolectricTest) writeTestRunner(w io.Writer, module, name string, tests []string) {
- fmt.Fprintln(w, "")
- fmt.Fprintln(w, "include $(CLEAR_VARS)", " # java.robolectricTest")
- fmt.Fprintln(w, "LOCAL_MODULE :=", name)
- android.AndroidMkEmitAssignList(w, "LOCAL_JAVA_LIBRARIES", []string{module}, r.libs)
- fmt.Fprintln(w, "LOCAL_TEST_PACKAGE :=", String(r.robolectricProperties.Instrumentation_for))
- if r.roboSrcJar != nil {
- fmt.Fprintln(w, "LOCAL_INSTRUMENT_SRCJARS :=", r.roboSrcJar.String())
- }
- android.AndroidMkEmitAssignList(w, "LOCAL_ROBOTEST_FILES", tests)
- if t := r.robolectricProperties.Test_options.Timeout; t != nil {
- fmt.Fprintln(w, "LOCAL_ROBOTEST_TIMEOUT :=", *t)
- }
- if v := String(r.robolectricProperties.Robolectric_prebuilt_version); v != "" {
- fmt.Fprintf(w, "-include prebuilts/misc/common/robolectric/%s/run_robotests.mk\n", v)
- } else {
- fmt.Fprintln(w, "-include external/robolectric-shadows/run_robotests.mk")
- }
-}
-
// An android_robolectric_test module compiles tests against the Robolectric framework that can run on the local host
-// instead of on a device. It also generates a rule with the name of the module prefixed with "Run" that can be
-// used to run the tests. Running the tests with build rule will eventually be deprecated and replaced with atest.
-//
-// The test runner considers any file listed in srcs whose name ends with Test.java to be a test class, unless
-// it is named BaseRobolectricTest.java. The path to the each source file must exactly match the package
-// name, or match the package name when the prefix "src/" is removed.
+// instead of on a device.
func RobolectricTestFactory() android.Module {
module := &robolectricTest{}
@@ -424,7 +329,7 @@
&module.testProperties)
module.Module.dexpreopter.isTest = true
- module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
+ module.Module.linter.properties.Lint.Test_module_type = proptools.BoolPtr(true)
module.testProperties.Test_suites = []string{"robolectric-tests"}
@@ -489,7 +394,7 @@
}
if !ctx.Config().AlwaysUsePrebuiltSdks() && r.props.Lib != nil {
- runtimeFromSourceModule := ctx.GetDirectDepWithTag(String(r.props.Lib), libTag)
+ runtimeFromSourceModule := ctx.GetDirectDepProxyWithTag(String(r.props.Lib), libTag)
if runtimeFromSourceModule == nil {
if ctx.Config().AllowMissingDependencies() {
ctx.AddMissingDependencies([]string{String(r.props.Lib)})
@@ -507,6 +412,10 @@
installedRuntime := ctx.InstallFile(androidAllDir, runtimeName, runtimeFromSourceJar)
r.runtimes = append(r.runtimes, installedRuntime)
}
+
+ android.SetProvider(ctx, RobolectricRuntimesInfoProvider, RobolectricRuntimesInfo{
+ Runtimes: r.runtimes,
+ })
}
func (r *robolectricRuntimes) InstallInTestcases() bool { return true }
diff --git a/java/robolectric_test.go b/java/robolectric_test.go
index 4775bac..ad0613e 100644
--- a/java/robolectric_test.go
+++ b/java/robolectric_test.go
@@ -32,6 +32,11 @@
}
java_library {
+ name: "Robolectric_all-target",
+ srcs: ["Robo.java"]
+ }
+
+ java_library {
name: "mockito-robolectric-prebuilt",
srcs: ["Mockito.java"]
}
@@ -44,6 +49,12 @@
java_library {
name: "junitxml",
srcs: ["JUnitXml.java"]
+
+ }
+
+ java_library {
+ name: "ClearcutJunitListenerAar",
+ srcs: ["Runtime.java"]
}
java_library_host {
@@ -60,6 +71,7 @@
)
func TestRobolectricJniTest(t *testing.T) {
+ t.Parallel()
if runtime.GOOS != "linux" {
t.Skip("requires linux")
}
diff --git a/java/rro.go b/java/rro.go
index 0fc6e1c..d9f4ff7 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -17,7 +17,12 @@
// This file contains the module implementations for runtime_resource_overlay and
// override_runtime_resource_overlay.
-import "android/soong/android"
+import (
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
func init() {
RegisterRuntimeResourceOverlayBuildComponents(android.InitRegistrationContext)
@@ -25,6 +30,7 @@
func RegisterRuntimeResourceOverlayBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("runtime_resource_overlay", RuntimeResourceOverlayFactory)
+ ctx.RegisterModuleType("autogen_runtime_resource_overlay", AutogenRuntimeResourceOverlayFactory)
ctx.RegisterModuleType("override_runtime_resource_overlay", OverrideRuntimeResourceOverlayModuleFactory)
}
@@ -46,7 +52,7 @@
type RuntimeResourceOverlayProperties struct {
// the name of a certificate in the default certificate directory or an android_app_certificate
// module name in the form ":module".
- Certificate *string
+ Certificate proptools.Configurable[string] `android:"replace_instead_of_append"`
// Name of the signing certificate lineage file.
Lineage *string
@@ -71,7 +77,7 @@
Min_sdk_version *string
// list of android_library modules whose resources are extracted and linked against statically
- Static_libs []string
+ Static_libs proptools.Configurable[[]string]
// list of android_app modules whose resources are extracted and linked against
Resource_libs []string
@@ -115,12 +121,12 @@
r.aapt.deps(ctx, sdkDep)
}
- cert := android.SrcIsModule(String(r.properties.Certificate))
+ cert := android.SrcIsModule(r.properties.Certificate.GetOrDefault(ctx, ""))
if cert != "" {
ctx.AddDependency(ctx.Module(), certificateTag, cert)
}
- ctx.AddVariationDependencies(nil, staticLibTag, r.properties.Static_libs...)
+ ctx.AddVariationDependencies(nil, staticLibTag, r.properties.Static_libs.GetOrDefault(ctx, nil)...)
ctx.AddVariationDependencies(nil, libTag, r.properties.Resource_libs...)
for _, aconfig_declaration := range r.aaptProperties.Flags_packages {
@@ -133,6 +139,25 @@
r.aapt.hasNoCode = true
// Do not remove resources without default values nor dedupe resource configurations with the same value
aaptLinkFlags := []string{"--no-resource-deduping", "--no-resource-removal"}
+
+ // Add TARGET_AAPT_CHARACTERISTICS values to AAPT link flags if they exist and --product flags were not provided.
+ hasProduct := android.PrefixInList(r.aaptProperties.Aaptflags, "--product")
+ if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
+ aaptLinkFlags = append(aaptLinkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
+ }
+
+ if !Bool(r.aaptProperties.Aapt_include_all_resources) {
+ // Product AAPT config
+ for _, aaptConfig := range ctx.Config().ProductAAPTConfig() {
+ aaptLinkFlags = append(aaptLinkFlags, "-c", aaptConfig)
+ }
+
+ // Product AAPT preferred config
+ if len(ctx.Config().ProductAAPTPreferredConfig()) > 0 {
+ aaptLinkFlags = append(aaptLinkFlags, "--preferred-density", ctx.Config().ProductAAPTPreferredConfig())
+ }
+ }
+
// Allow the override of "package name" and "overlay target package name"
manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName())
if overridden || r.overridableProperties.Package_name != nil {
@@ -162,7 +187,7 @@
// Sign the built package
_, _, certificates := collectAppDeps(ctx, r, false, false)
- r.certificate, certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx)
+ r.certificate, certificates = processMainCert(r.ModuleBase, r.properties.Certificate.GetOrDefault(ctx, ""), certificates, ctx)
signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk")
var lineageFile android.Path
if lineage := String(r.properties.Lineage); lineage != "" {
@@ -181,6 +206,8 @@
android.SetProvider(ctx, FlagsPackagesProvider, FlagsPackages{
AconfigTextFiles: aconfigTextFilePaths,
})
+
+ buildComplianceMetadata(ctx)
}
func (r *RuntimeResourceOverlay) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
@@ -265,3 +292,147 @@
android.InitOverrideModule(m)
return m
}
+
+var (
+ generateOverlayManifestFile = pctx.AndroidStaticRule("generate_overlay_manifest",
+ blueprint.RuleParams{
+ Command: "build/make/tools/generate-enforce-rro-android-manifest.py " +
+ "--package-info $in " +
+ "--partition ${partition} " +
+ "--priority ${priority} -o $out",
+ CommandDeps: []string{"build/make/tools/generate-enforce-rro-android-manifest.py"},
+ }, "partition", "priority",
+ )
+)
+
+type AutogenRuntimeResourceOverlay struct {
+ android.ModuleBase
+ aapt
+
+ properties AutogenRuntimeResourceOverlayProperties
+
+ certificate Certificate
+ outputFile android.Path
+}
+
+type AutogenRuntimeResourceOverlayProperties struct {
+ Base *string
+ Sdk_version *string
+ Manifest *string `android:"path"`
+}
+
+func AutogenRuntimeResourceOverlayFactory() android.Module {
+ m := &AutogenRuntimeResourceOverlay{}
+ m.AddProperties(&m.properties)
+ android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
+
+ return m
+}
+
+type rroDependencyTag struct {
+ blueprint.DependencyTag
+}
+
+// Autogenerated RROs should always depend on the source android_app that created it.
+func (tag rroDependencyTag) ReplaceSourceWithPrebuilt() bool {
+ return false
+}
+
+var rroDepTag = rroDependencyTag{}
+
+func (a *AutogenRuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) {
+ sdkDep := decodeSdkDep(ctx, android.SdkContext(a))
+ if sdkDep.hasFrameworkLibs() {
+ a.aapt.deps(ctx, sdkDep)
+ }
+ ctx.AddDependency(ctx.Module(), rroDepTag, proptools.String(a.properties.Base))
+}
+
+func (a *AutogenRuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ if !a.Enabled(ctx) {
+ return
+ }
+ var rroDirs android.Paths
+ // Get rro dirs of the base app
+ ctx.VisitDirectDepsWithTag(rroDepTag, func(m android.Module) {
+ aarDep, _ := m.(AndroidLibraryDependency)
+ if ctx.InstallInProduct() {
+ rroDirs = filterRRO(aarDep.RRODirsDepSet(), product)
+ } else {
+ rroDirs = filterRRO(aarDep.RRODirsDepSet(), device)
+ }
+ })
+
+ if len(rroDirs) == 0 {
+ return
+ }
+
+ // Generate a manifest file
+ genManifest := android.PathForModuleGen(ctx, "AndroidManifest.xml")
+ partition := "vendor"
+ priority := "0"
+ if ctx.InstallInProduct() {
+ partition = "product"
+ priority = "1"
+ }
+ ctx.Build(pctx, android.BuildParams{
+ Rule: generateOverlayManifestFile,
+ Input: android.PathForModuleSrc(ctx, proptools.String(a.properties.Manifest)),
+ Output: genManifest,
+ Args: map[string]string{
+ "partition": partition,
+ "priority": priority,
+ },
+ })
+
+ // Compile and link resources into package-res.apk
+ a.aapt.hasNoCode = true
+ aaptLinkFlags := []string{"--auto-add-overlay", "--keep-raw-values", "--no-resource-deduping", "--no-resource-removal"}
+
+ a.aapt.buildActions(ctx,
+ aaptBuildActionOptions{
+ sdkContext: a,
+ extraLinkFlags: aaptLinkFlags,
+ rroDirs: &rroDirs,
+ manifestForAapt: genManifest,
+ },
+ )
+
+ if a.exportPackage == nil {
+ return
+ }
+ // Sign the built package
+ var certificates []Certificate
+ a.certificate, certificates = processMainCert(a.ModuleBase, "", nil, ctx)
+ signed := android.PathForModuleOut(ctx, "signed", a.Name()+".apk")
+ SignAppPackage(ctx, signed, a.exportPackage, certificates, nil, nil, "")
+ a.outputFile = signed
+
+ // Install the signed apk
+ installDir := android.PathForModuleInstall(ctx, "overlay")
+ ctx.InstallFile(installDir, signed.Base(), signed)
+}
+
+func (a *AutogenRuntimeResourceOverlay) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecFrom(ctx, String(a.properties.Sdk_version))
+}
+
+func (a *AutogenRuntimeResourceOverlay) SystemModules() string {
+ return ""
+}
+
+func (a *AutogenRuntimeResourceOverlay) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
+ return a.SdkVersion(ctx).ApiLevel
+}
+
+func (r *AutogenRuntimeResourceOverlay) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.ApiLevel {
+ return android.SdkSpecPrivate.ApiLevel
+}
+
+func (a *AutogenRuntimeResourceOverlay) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
+ return a.SdkVersion(ctx).ApiLevel
+}
+
+func (a *AutogenRuntimeResourceOverlay) InstallInProduct() bool {
+ return a.ProductSpecific()
+}
diff --git a/java/rro_test.go b/java/rro_test.go
index 742c839..1978ad6 100644
--- a/java/rro_test.go
+++ b/java/rro_test.go
@@ -24,6 +24,7 @@
)
func TestRuntimeResourceOverlay(t *testing.T) {
+ t.Parallel()
fs := android.MockFS{
"baz/res/res/values/strings.xml": nil,
"bar/res/res/values/strings.xml": nil,
@@ -129,6 +130,7 @@
}
func TestRuntimeResourceOverlay_JavaDefaults(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
android.FixtureModifyConfig(android.SetKatiEnabledForTests),
@@ -216,7 +218,7 @@
}{
{
variantName: "android_common",
- apkPath: "out/soong/target/product/test_device/product/overlay/foo_overlay.apk",
+ apkPath: "out/target/product/test_device/product/overlay/foo_overlay.apk",
overrides: nil,
targetVariant: "android_common",
packageFlag: "",
@@ -224,7 +226,7 @@
},
{
variantName: "android_common_bar_overlay",
- apkPath: "out/soong/target/product/test_device/product/overlay/bar_overlay.apk",
+ apkPath: "out/target/product/test_device/product/overlay/bar_overlay.apk",
overrides: []string{"foo_overlay"},
targetVariant: "android_common_bar",
packageFlag: "com.android.bar.overlay",
@@ -255,103 +257,6 @@
}
}
-func TestEnforceRRO_propagatesToDependencies(t *testing.T) {
- testCases := []struct {
- name string
- enforceRROTargets []string
- rroDirs map[string][]string
- }{
- {
- name: "no RRO",
- enforceRROTargets: nil,
- rroDirs: map[string][]string{
- "foo": nil,
- "bar": nil,
- },
- },
- {
- name: "enforce RRO on all",
- enforceRROTargets: []string{"*"},
- rroDirs: map[string][]string{
- "foo": {"product/vendor/blah/overlay/lib2/res"},
- "bar": {"product/vendor/blah/overlay/lib2/res"},
- },
- },
- {
- name: "enforce RRO on foo",
- enforceRROTargets: []string{"foo"},
- rroDirs: map[string][]string{
- "foo": {"product/vendor/blah/overlay/lib2/res"},
- "bar": {"product/vendor/blah/overlay/lib2/res"},
- },
- },
- }
-
- productResourceOverlays := []string{
- "product/vendor/blah/overlay",
- }
-
- fs := android.MockFS{
- "lib2/res/values/strings.xml": nil,
- "product/vendor/blah/overlay/lib2/res/values/strings.xml": nil,
- }
-
- bp := `
- android_app {
- name: "foo",
- sdk_version: "current",
- resource_dirs: [],
- static_libs: ["lib"],
- }
-
- android_app {
- name: "bar",
- sdk_version: "current",
- resource_dirs: [],
- static_libs: ["lib"],
- }
-
- android_library {
- name: "lib",
- sdk_version: "current",
- resource_dirs: [],
- static_libs: ["lib2"],
- }
-
- android_library {
- name: "lib2",
- sdk_version: "current",
- resource_dirs: ["lib2/res"],
- }
- `
-
- for _, testCase := range testCases {
- t.Run(testCase.name, func(t *testing.T) {
- result := android.GroupFixturePreparers(
- PrepareForTestWithJavaDefaultModules,
- fs.AddToFixture(),
- android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.ProductResourceOverlays = productResourceOverlays
- if testCase.enforceRROTargets != nil {
- variables.EnforceRROTargets = testCase.enforceRROTargets
- }
- }),
- ).RunTestWithBp(t, bp)
-
- modules := []string{"foo", "bar"}
- for _, moduleName := range modules {
- module := result.ModuleForTests(moduleName, "android_common")
- mkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, module.Module())[0]
- actualRRODirs := mkEntries.EntryMap["LOCAL_SOONG_PRODUCT_RRO_DIRS"]
- if !reflect.DeepEqual(actualRRODirs, testCase.rroDirs[moduleName]) {
- t.Errorf("exected %s LOCAL_SOONG_PRODUCT_RRO_DIRS entry: %v\ngot:%q",
- moduleName, testCase.rroDirs[moduleName], actualRRODirs)
- }
- }
- })
- }
-}
-
func TestRuntimeResourceOverlayPartition(t *testing.T) {
bp := `
runtime_resource_overlay {
@@ -380,23 +285,23 @@
}{
{
name: "device_specific",
- expectedPath: "out/soong/target/product/test_device/odm/overlay",
+ expectedPath: "out/target/product/test_device/odm/overlay",
},
{
name: "soc_specific",
- expectedPath: "out/soong/target/product/test_device/vendor/overlay",
+ expectedPath: "out/target/product/test_device/vendor/overlay",
},
{
name: "system_ext_specific",
- expectedPath: "out/soong/target/product/test_device/system_ext/overlay",
+ expectedPath: "out/target/product/test_device/system_ext/overlay",
},
{
name: "product_specific",
- expectedPath: "out/soong/target/product/test_device/product/overlay",
+ expectedPath: "out/target/product/test_device/product/overlay",
},
{
name: "default",
- expectedPath: "out/soong/target/product/test_device/product/overlay",
+ expectedPath: "out/target/product/test_device/product/overlay",
},
}
for _, testCase := range testCases {
diff --git a/java/sdk.go b/java/sdk.go
index dd198ac..bb2aa8d 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -66,10 +66,8 @@
} else if sdk.FinalOrFutureInt() <= 33 {
return JAVA_VERSION_11
} else if ctx.Config().TargetsJava21() {
- // Temporary experimental flag to be able to try and build with
- // java version 21 options. The flag, if used, just sets Java
- // 21 as the default version, leaving any components that
- // target an older version intact.
+ // Build flag that controls whether Java 21 is used as the
+ // default target version, or Java 17.
return JAVA_VERSION_21
} else {
return JAVA_VERSION_17
@@ -308,10 +306,12 @@
rule.Command().
Text("rm -f").Output(aidl)
+
rule.Command().
BuiltTool("sdkparcelables").
Input(jar).
- Output(aidl)
+ Output(aidl).
+ Flag("--guarantee_stable")
aidls = append(aidls, aidl)
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 4f95a99..05a5b49 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -29,11 +29,6 @@
"android/soong/android"
"android/soong/dexpreopt"
- "android/soong/etc"
-)
-
-const (
- sdkXmlFileSuffix = ".xml"
)
// A tag to associated a dependency with a specific api scope.
@@ -248,7 +243,7 @@
return scope.stubsLibraryModuleName(baseName) + ".from-text"
}
-func (scope *apiScope) sourceStubLibraryModuleName(baseName string) string {
+func (scope *apiScope) sourceStubsLibraryModuleName(baseName string) string {
return scope.stubsLibraryModuleName(baseName) + ".from-source"
}
@@ -268,10 +263,6 @@
return baseName + ".stubs.source" + scope.moduleSuffix
}
-func (scope *apiScope) apiModuleName(baseName string) string {
- return baseName + ".api" + scope.moduleSuffix
-}
-
func (scope *apiScope) String() string {
return scope.name
}
@@ -489,6 +480,9 @@
// Extra libs used when compiling stubs for this scope.
Libs []string
+
+ // Name to override the api_surface that is passed down to droidstubs.
+ Api_surface *string
}
type sdkLibraryProperties struct {
@@ -699,9 +693,9 @@
paths.stubsHeaderPath = lib.HeaderJars
paths.stubsImplPath = lib.ImplementationJars
- libDep := dep.(UsesLibraryDependency)
- paths.stubsDexJarPath = libDep.DexJarBuildPath(ctx)
- paths.exportableStubsDexJarPath = libDep.DexJarBuildPath(ctx)
+ libDep := android.OtherModuleProviderOrDefault(ctx, dep, JavaInfoProvider).UsesLibraryDependencyInfo
+ paths.stubsDexJarPath = libDep.DexJarBuildPath
+ paths.exportableStubsDexJarPath = libDep.DexJarBuildPath
return nil
} else {
return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library")
@@ -715,8 +709,8 @@
paths.stubsImplPath = lib.ImplementationJars
}
- libDep := dep.(UsesLibraryDependency)
- paths.stubsDexJarPath = libDep.DexJarBuildPath(ctx)
+ libDep := android.OtherModuleProviderOrDefault(ctx, dep, JavaInfoProvider).UsesLibraryDependencyInfo
+ paths.stubsDexJarPath = libDep.DexJarBuildPath
return nil
} else {
return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library")
@@ -729,58 +723,67 @@
paths.stubsImplPath = lib.ImplementationJars
}
- libDep := dep.(UsesLibraryDependency)
- paths.exportableStubsDexJarPath = libDep.DexJarBuildPath(ctx)
+ libDep := android.OtherModuleProviderOrDefault(ctx, dep, JavaInfoProvider).UsesLibraryDependencyInfo
+ paths.exportableStubsDexJarPath = libDep.DexJarBuildPath
return nil
} else {
return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library")
}
}
-func (paths *scopePaths) treatDepAsApiStubsProvider(dep android.Module, action func(provider ApiStubsProvider) error) error {
- if apiStubsProvider, ok := dep.(ApiStubsProvider); ok {
- err := action(apiStubsProvider)
+func (paths *scopePaths) treatDepAsApiStubsProvider(ctx android.ModuleContext, dep android.Module,
+ action func(*DroidStubsInfo, *StubsSrcInfo) error) error {
+ apiStubsProvider, ok := android.OtherModuleProvider(ctx, dep, DroidStubsInfoProvider)
+ if !ok {
+ return fmt.Errorf("expected module that provides DroidStubsInfo, e.g. droidstubs")
+ }
+
+ apiStubsSrcProvider, ok := android.OtherModuleProvider(ctx, dep, StubsSrcInfoProvider)
+ if !ok {
+ return fmt.Errorf("expected module that provides StubsSrcInfo, e.g. droidstubs")
+ }
+ return action(&apiStubsProvider, &apiStubsSrcProvider)
+}
+
+func (paths *scopePaths) treatDepAsApiStubsSrcProvider(
+ ctx android.ModuleContext, dep android.Module, action func(provider *StubsSrcInfo) error) error {
+ if apiStubsProvider, ok := android.OtherModuleProvider(ctx, dep, StubsSrcInfoProvider); ok {
+ err := action(&apiStubsProvider)
if err != nil {
return err
}
return nil
} else {
- return fmt.Errorf("expected module that implements ExportableApiStubsSrcProvider, e.g. droidstubs")
+ return fmt.Errorf("expected module that provides DroidStubsInfo, e.g. droidstubs")
}
}
-func (paths *scopePaths) treatDepAsApiStubsSrcProvider(dep android.Module, action func(provider ApiStubsSrcProvider) error) error {
- if apiStubsProvider, ok := dep.(ApiStubsSrcProvider); ok {
- err := action(apiStubsProvider)
- if err != nil {
- return err
- }
- return nil
- } else {
- return fmt.Errorf("expected module that implements ApiStubsSrcProvider, e.g. droidstubs")
+func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider *DroidStubsInfo, stubsType StubsType) error {
+ var currentApiFilePathErr, removedApiFilePathErr error
+ info, err := getStubsInfoForType(provider, stubsType)
+ if err != nil {
+ return err
}
-}
-
-func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsProvider, stubsType StubsType) error {
- var annotationsZip, currentApiFilePath, removedApiFilePath android.Path
- annotationsZip, annotationsZipErr := provider.AnnotationsZip(stubsType)
- currentApiFilePath, currentApiFilePathErr := provider.ApiFilePath(stubsType)
- removedApiFilePath, removedApiFilePathErr := provider.RemovedApiFilePath(stubsType)
-
- combinedError := errors.Join(annotationsZipErr, currentApiFilePathErr, removedApiFilePathErr)
+ if info.ApiFile == nil {
+ currentApiFilePathErr = fmt.Errorf("expected module that provides ApiFile")
+ }
+ if info.RemovedApiFile == nil {
+ removedApiFilePathErr = fmt.Errorf("expected module that provides RemovedApiFile")
+ }
+ combinedError := errors.Join(currentApiFilePathErr, removedApiFilePathErr)
if combinedError == nil {
- paths.annotationsZip = android.OptionalPathForPath(annotationsZip)
- paths.currentApiFilePath = android.OptionalPathForPath(currentApiFilePath)
- paths.removedApiFilePath = android.OptionalPathForPath(removedApiFilePath)
+ paths.annotationsZip = android.OptionalPathForPath(info.AnnotationsZip)
+ paths.currentApiFilePath = android.OptionalPathForPath(info.ApiFile)
+ paths.removedApiFilePath = android.OptionalPathForPath(info.RemovedApiFile)
}
return combinedError
}
-func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider ApiStubsSrcProvider, stubsType StubsType) error {
- stubsSrcJar, err := provider.StubsSrcJar(stubsType)
+func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider *StubsSrcInfo, stubsType StubsType) error {
+ path, err := getStubsSrcInfoForType(provider, stubsType)
if err == nil {
- paths.stubsSrcJar = android.OptionalPathForPath(stubsSrcJar)
+ paths.stubsSrcJar = android.OptionalPathForPath(path)
}
return err
}
@@ -790,7 +793,7 @@
if ctx.Config().ReleaseHiddenApiExportableStubs() {
stubsType = Exportable
}
- return paths.treatDepAsApiStubsSrcProvider(dep, func(provider ApiStubsSrcProvider) error {
+ return paths.treatDepAsApiStubsSrcProvider(ctx, dep, func(provider *StubsSrcInfo) error {
return paths.extractStubsSourceInfoFromApiStubsProviders(provider, stubsType)
})
}
@@ -800,17 +803,17 @@
if ctx.Config().ReleaseHiddenApiExportableStubs() {
stubsType = Exportable
}
- return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) error {
- extractApiInfoErr := paths.extractApiInfoFromApiStubsProvider(provider, stubsType)
- extractStubsSourceInfoErr := paths.extractStubsSourceInfoFromApiStubsProviders(provider, stubsType)
+ return paths.treatDepAsApiStubsProvider(ctx, dep, func(apiStubsProvider *DroidStubsInfo, apiStubsSrcProvider *StubsSrcInfo) error {
+ extractApiInfoErr := paths.extractApiInfoFromApiStubsProvider(apiStubsProvider, stubsType)
+ extractStubsSourceInfoErr := paths.extractStubsSourceInfoFromApiStubsProviders(apiStubsSrcProvider, stubsType)
return errors.Join(extractApiInfoErr, extractStubsSourceInfoErr)
})
}
-func extractOutputPaths(dep android.Module) (android.Paths, error) {
+func extractOutputPaths(ctx android.ModuleContext, dep android.Module) (android.Paths, error) {
var paths android.Paths
- if sourceFileProducer, ok := dep.(android.SourceFileProducer); ok {
- paths = sourceFileProducer.Srcs()
+ if sourceFileProducer, ok := android.OtherModuleProvider(ctx, dep, android.SourceFilesInfoProvider); ok {
+ paths = sourceFileProducer.Srcs
return paths, nil
} else {
return nil, fmt.Errorf("module %q does not produce source files", dep)
@@ -818,28 +821,48 @@
}
func (paths *scopePaths) extractLatestApiPath(ctx android.ModuleContext, dep android.Module) error {
- outputPaths, err := extractOutputPaths(dep)
+ outputPaths, err := extractOutputPaths(ctx, dep)
paths.latestApiPaths = outputPaths
return err
}
func (paths *scopePaths) extractLatestRemovedApiPath(ctx android.ModuleContext, dep android.Module) error {
- outputPaths, err := extractOutputPaths(dep)
+ outputPaths, err := extractOutputPaths(ctx, dep)
paths.latestRemovedApiPaths = outputPaths
return err
}
-type commonToSdkLibraryAndImportProperties struct {
- // The naming scheme to use for the components that this module creates.
- //
- // If not specified then it defaults to "default".
- //
- // This is a temporary mechanism to simplify conversion from separate modules for each
- // component that follow a different naming pattern to the default one.
- //
- // TODO(b/155480189) - Remove once naming inconsistencies have been resolved.
- Naming_scheme *string
+func getStubsInfoForType(info *DroidStubsInfo, stubsType StubsType) (ret *StubsInfo, err error) {
+ switch stubsType {
+ case Everything:
+ ret, err = &info.EverythingStubsInfo, nil
+ case Exportable:
+ ret, err = &info.ExportableStubsInfo, nil
+ default:
+ ret, err = nil, fmt.Errorf("stubs info not supported for the stub type %s", stubsType.String())
+ }
+ if ret == nil && err == nil {
+ err = fmt.Errorf("stubs info is null for the stub type %s", stubsType.String())
+ }
+ return ret, err
+}
+func getStubsSrcInfoForType(info *StubsSrcInfo, stubsType StubsType) (ret android.Path, err error) {
+ switch stubsType {
+ case Everything:
+ ret, err = info.EverythingStubsSrcJar, nil
+ case Exportable:
+ ret, err = info.ExportableStubsSrcJar, nil
+ default:
+ ret, err = nil, fmt.Errorf("stubs src info not supported for the stub type %s", stubsType.String())
+ }
+ if ret == nil && err == nil {
+ err = fmt.Errorf("stubs src info is null for the stub type %s", stubsType.String())
+ }
+ return ret, err
+}
+
+type commonToSdkLibraryAndImportProperties struct {
// Specifies whether this module can be used as an Android shared library; defaults
// to true.
//
@@ -915,8 +938,6 @@
scopePaths map[*apiScope]*scopePaths
- namingScheme sdkLibraryComponentNamingScheme
-
commonSdkLibraryProperties commonToSdkLibraryAndImportProperties
// Paths to commonSdkLibraryProperties.Doctag_files
@@ -929,9 +950,9 @@
// This is non-empty only when api_only is false.
implLibraryHeaderJars android.Paths
- // The reference to the implementation library created by the source module.
- // Is nil if the source module does not exist.
- implLibraryModule *Library
+ // The reference to the JavaInfo provided by implementation library created by
+ // the source module. Is nil if the source module does not exist.
+ implLibraryInfo *JavaInfo
}
func (c *commonToSdkLibraryAndImport) initCommon(module commonSdkLibraryAndImportModule) {
@@ -943,16 +964,7 @@
c.initSdkLibraryComponent(module)
}
-func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied(ctx android.DefaultableHookContext) bool {
- schemeProperty := proptools.StringDefault(c.commonSdkLibraryProperties.Naming_scheme, "default")
- switch schemeProperty {
- case "default":
- c.namingScheme = &defaultNamingScheme{}
- default:
- ctx.PropertyErrorf("naming_scheme", "expected 'default' but was %q", schemeProperty)
- return false
- }
-
+func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied() bool {
namePtr := proptools.StringPtr(c.module.RootLibraryName())
c.sdkLibraryComponentProperties.SdkLibraryName = namePtr
@@ -974,62 +986,36 @@
return c.sharedLibrary()
}
-func (c *commonToSdkLibraryAndImport) generateCommonBuildActions(ctx android.ModuleContext) {
+func (c *commonToSdkLibraryAndImport) generateCommonBuildActions(ctx android.ModuleContext) SdkLibraryInfo {
c.doctagPaths = android.PathsForModuleSrc(ctx, c.commonSdkLibraryProperties.Doctag_files)
-}
-func (c *commonToSdkLibraryAndImport) getImplLibraryModule() *Library {
- return c.implLibraryModule
-}
+ everythingStubPaths := make(map[android.SdkKind]OptionalDexJarPath)
+ exportableStubPaths := make(map[android.SdkKind]OptionalDexJarPath)
+ removedApiFilePaths := make(map[android.SdkKind]android.OptionalPath)
+ for kind := android.SdkNone; kind <= android.SdkPrivate; kind += 1 {
+ everythingStubPath := makeUnsetDexJarPath()
+ exportableStubPath := makeUnsetDexJarPath()
+ removedApiFilePath := android.OptionalPath{}
+ if scopePath := c.findClosestScopePath(sdkKindToApiScope(kind)); scopePath != nil {
+ everythingStubPath = scopePath.stubsDexJarPath
+ exportableStubPath = scopePath.exportableStubsDexJarPath
+ removedApiFilePath = scopePath.removedApiFilePath
+ }
+ everythingStubPaths[kind] = everythingStubPath
+ exportableStubPaths[kind] = exportableStubPath
+ removedApiFilePaths[kind] = removedApiFilePath
+ }
-// Module name of the runtime implementation library
-func (c *commonToSdkLibraryAndImport) implLibraryModuleName() string {
- return c.module.RootLibraryName() + ".impl"
-}
+ javaInfo := &JavaInfo{}
+ setExtraJavaInfo(ctx, ctx.Module(), javaInfo)
+ android.SetProvider(ctx, JavaInfoProvider, javaInfo)
-// Module name of the XML file for the lib
-func (c *commonToSdkLibraryAndImport) xmlPermissionsModuleName() string {
- return c.module.RootLibraryName() + sdkXmlFileSuffix
-}
-
-// Name of the java_library module that compiles the stubs source.
-func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope) string {
- baseName := c.module.RootLibraryName()
- return c.namingScheme.stubsLibraryModuleName(apiScope, baseName)
-}
-
-// Name of the java_library module that compiles the exportable stubs source.
-func (c *commonToSdkLibraryAndImport) exportableStubsLibraryModuleName(apiScope *apiScope) string {
- baseName := c.module.RootLibraryName()
- return c.namingScheme.exportableStubsLibraryModuleName(apiScope, baseName)
-}
-
-// Name of the droidstubs module that generates the stubs source and may also
-// generate/check the API.
-func (c *commonToSdkLibraryAndImport) stubsSourceModuleName(apiScope *apiScope) string {
- baseName := c.module.RootLibraryName()
- return c.namingScheme.stubsSourceModuleName(apiScope, baseName)
-}
-
-// Name of the java_api_library module that generates the from-text stubs source
-// and compiles to a jar file.
-func (c *commonToSdkLibraryAndImport) apiLibraryModuleName(apiScope *apiScope) string {
- baseName := c.module.RootLibraryName()
- return c.namingScheme.apiLibraryModuleName(apiScope, baseName)
-}
-
-// Name of the java_library module that compiles the stubs
-// generated from source Java files.
-func (c *commonToSdkLibraryAndImport) sourceStubsLibraryModuleName(apiScope *apiScope) string {
- baseName := c.module.RootLibraryName()
- return c.namingScheme.sourceStubsLibraryModuleName(apiScope, baseName)
-}
-
-// Name of the java_library module that compiles the exportable stubs
-// generated from source Java files.
-func (c *commonToSdkLibraryAndImport) exportableSourceStubsLibraryModuleName(apiScope *apiScope) string {
- baseName := c.module.RootLibraryName()
- return c.namingScheme.exportableSourceStubsLibraryModuleName(apiScope, baseName)
+ return SdkLibraryInfo{
+ EverythingStubDexJarPaths: everythingStubPaths,
+ ExportableStubDexJarPaths: exportableStubPaths,
+ RemovedTxtFiles: removedApiFilePaths,
+ SharedLibrary: c.sharedLibrary(),
+ }
}
// The component names for different outputs of the java_sdk_library.
@@ -1103,44 +1089,6 @@
return nil
}
-func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
-
- // If a specific numeric version has been requested then use prebuilt versions of the sdk.
- if !sdkVersion.ApiLevel.IsPreview() {
- return PrebuiltJars(ctx, c.module.RootLibraryName(), sdkVersion)
- }
-
- paths := c.selectScopePaths(ctx, sdkVersion.Kind)
- if paths == nil {
- return nil
- }
-
- return paths.stubsHeaderPath
-}
-
-// selectScopePaths returns the *scopePaths appropriate for the specific kind.
-//
-// If the module does not support the specific kind then it will return the *scopePaths for the
-// closest kind which is a subset of the requested kind. e.g. if requesting android.SdkModule then
-// it will return *scopePaths for android.SdkSystem if available or android.SdkPublic of not.
-func (c *commonToSdkLibraryAndImport) selectScopePaths(ctx android.BaseModuleContext, kind android.SdkKind) *scopePaths {
- apiScope := sdkKindToApiScope(kind)
-
- paths := c.findClosestScopePath(apiScope)
- if paths == nil {
- var scopes []string
- for _, s := range AllApiScopes {
- if c.findScopePaths(s) != nil {
- scopes = append(scopes, s.name)
- }
- }
- ctx.ModuleErrorf("requires api scope %s from %s but it only has %q available", apiScope.name, c.module.RootLibraryName(), scopes)
- return nil
- }
-
- return paths
-}
-
// sdkKindToApiScope maps from android.SdkKind to apiScope.
func sdkKindToApiScope(kind android.SdkKind) *apiScope {
var apiScope *apiScope
@@ -1159,37 +1107,6 @@
return apiScope
}
-// to satisfy SdkLibraryDependency interface
-func (c *commonToSdkLibraryAndImport) SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath {
- paths := c.selectScopePaths(ctx, kind)
- if paths == nil {
- return makeUnsetDexJarPath()
- }
-
- return paths.stubsDexJarPath
-}
-
-// to satisfy SdkLibraryDependency interface
-func (c *commonToSdkLibraryAndImport) SdkApiExportableStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath {
- paths := c.selectScopePaths(ctx, kind)
- if paths == nil {
- return makeUnsetDexJarPath()
- }
-
- return paths.exportableStubsDexJarPath
-}
-
-// to satisfy SdkLibraryDependency interface
-func (c *commonToSdkLibraryAndImport) SdkRemovedTxtFile(ctx android.BaseModuleContext, kind android.SdkKind) android.OptionalPath {
- apiScope := sdkKindToApiScope(kind)
- paths := c.findScopePaths(apiScope)
- if paths == nil {
- return android.OptionalPath{}
- }
-
- return paths.removedApiFilePath
-}
-
func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() interface{} {
componentProps := &struct {
SdkLibraryName *string
@@ -1280,33 +1197,43 @@
var _ SdkLibraryComponentDependency = (*SdkLibrary)(nil)
var _ SdkLibraryComponentDependency = (*SdkLibraryImport)(nil)
-// Provides access to sdk_version related files, e.g. header and implementation jars.
-type SdkLibraryDependency interface {
- SdkLibraryComponentDependency
+type SdkLibraryInfo struct {
+ // GeneratingLibs is the names of the library modules that this sdk library
+ // generates. Note that this only includes the name of the modules that other modules can
+ // depend on, and is not a holistic list of generated modules.
+ GeneratingLibs []string
- // Get the header jars appropriate for the supplied sdk_version.
- //
- // These are turbine generated jars so they only change if the externals of the
- // class changes but it does not contain and implementation or JavaDoc.
- SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths
+ // Map of sdk kind to the dex jar for the "everything" stubs.
+ // It is needed by the hiddenapi processing tool which processes dex files.
+ EverythingStubDexJarPaths map[android.SdkKind]OptionalDexJarPath
- // SdkApiStubDexJar returns the dex jar for the stubs for the prebuilt
- // java_sdk_library_import module. It is needed by the hiddenapi processing tool which
- // processes dex files.
- SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath
+ // Map of sdk kind to the dex jar for the "exportable" stubs.
+ // It is needed by the hiddenapi processing tool which processes dex files.
+ ExportableStubDexJarPaths map[android.SdkKind]OptionalDexJarPath
- // SdkApiExportableStubDexJar returns the exportable dex jar for the stubs for
- // java_sdk_library module. It is needed by the hiddenapi processing tool which processes
- // dex files.
- SdkApiExportableStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath
+ // Map of sdk kind to the optional path to the removed.txt file.
+ RemovedTxtFiles map[android.SdkKind]android.OptionalPath
- // SdkRemovedTxtFile returns the optional path to the removed.txt file for the specified sdk kind.
- SdkRemovedTxtFile(ctx android.BaseModuleContext, kind android.SdkKind) android.OptionalPath
+ // Whether if this can be used as a shared library.
+ SharedLibrary bool
+}
- // sharedLibrary returns true if this can be used as a shared library.
- sharedLibrary() bool
+var SdkLibraryInfoProvider = blueprint.NewProvider[SdkLibraryInfo]()
- getImplLibraryModule() *Library
+func getGeneratingLibs(ctx android.ModuleContext, sdkVersion android.SdkSpec, sdkLibraryModuleName string, sdkInfo SdkLibraryInfo) []string {
+ apiLevel := sdkVersion.ApiLevel
+ if apiLevel.IsPreview() {
+ return sdkInfo.GeneratingLibs
+ }
+
+ generatingPrebuilts := []string{}
+ for _, apiScope := range AllApiScopes {
+ scopePrebuiltModuleName := prebuiltApiModuleName("sdk", sdkLibraryModuleName, apiScope.name, apiLevel.String())
+ if ctx.OtherModuleExists(scopePrebuiltModuleName) {
+ generatingPrebuilts = append(generatingPrebuilts, scopePrebuiltModuleName)
+ }
+ }
+ return generatingPrebuilts
}
type SdkLibrary struct {
@@ -1322,22 +1249,24 @@
builtInstalledForApex []dexpreopterInstall
}
-var _ SdkLibraryDependency = (*SdkLibrary)(nil)
-
func (module *SdkLibrary) generateTestAndSystemScopesByDefault() bool {
return module.sdkLibraryProperties.Generate_system_and_test_apis
}
+var _ UsesLibraryDependency = (*SdkLibrary)(nil)
+
+// To satisfy the UsesLibraryDependency interface
func (module *SdkLibrary) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
- if module.implLibraryModule != nil {
- return module.implLibraryModule.DexJarBuildPath(ctx)
+ if module.implLibraryInfo != nil {
+ return module.implLibraryInfo.DexJarFile
}
return makeUnsetDexJarPath()
}
+// To satisfy the UsesLibraryDependency interface
func (module *SdkLibrary) DexJarInstallPath() android.Path {
- if module.implLibraryModule != nil {
- return module.implLibraryModule.DexJarInstallPath()
+ if module.implLibraryInfo != nil {
+ return module.implLibraryInfo.InstallFile
}
return nil
}
@@ -1397,9 +1326,9 @@
}
func CheckMinSdkVersion(ctx android.ModuleContext, module *Library) {
- android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx), func(c android.ModuleContext, do android.PayloadDepsCallback) {
+ android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx), func(c android.BaseModuleContext, do android.PayloadDepsCallback) {
ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
- isExternal := !module.depIsInSameApex(ctx, child)
+ isExternal := !android.IsDepInSameApex(ctx, module, child)
if am, ok := child.(android.ApexModule); ok {
if !do(ctx, parent, am, isExternal) {
return false
@@ -1431,12 +1360,6 @@
var _ android.InstallNeededDependencyTag = sdkLibraryComponentTag{}
-// To satisfy the CopyDirectlyInAnyApexTag interface. Implementation library of the sdk library
-// in an apex is considered to be directly in the apex, as if it was listed in java_libs.
-func (t sdkLibraryComponentTag) CopyDirectlyInAnyApex() {}
-
-var _ android.CopyDirectlyInAnyApexTag = implLibraryTag
-
func (t sdkLibraryComponentTag) InstallDepNeeded() bool {
return t.name == "xml-permissions-file" || t.name == "impl-library"
}
@@ -1452,7 +1375,7 @@
ctx.AddVariationDependencies(nil, apiScope.exportableStubsTag, exportableStubModuleName)
// Add a dependency on the stubs source in order to access both stubs source and api information.
- ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceModuleName(apiScope))
+ ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.droidstubsModuleName(apiScope))
if module.compareAgainstLatestApi(apiScope) {
// Add dependencies on the latest finalized version of the API .txt file.
@@ -1520,10 +1443,9 @@
// Even though the source javalib is not used, we need to hide it to prevent duplicate installation rules.
// TODO (b/331665856): Implement a principled solution for this.
module.HideFromMake()
+ module.SkipInstall()
}
- module.generateCommonBuildActions(ctx)
-
module.stem = proptools.StringDefault(module.overridableProperties.Stem, ctx.ModuleName())
module.provideHiddenAPIPropertyInfo(ctx)
@@ -1531,11 +1453,11 @@
// Collate the components exported by this module. All scope specific modules are exported but
// the impl and xml component modules are not.
exportedComponents := map[string]struct{}{}
-
+ var implLib android.ModuleProxy
// Record the paths to the header jars of the library (stubs and impl).
// When this java_sdk_library is depended upon from others via "libs" property,
// the recorded paths will be returned depending on the link type of the caller.
- ctx.VisitDirectDeps(func(to android.Module) {
+ ctx.VisitDirectDepsProxy(func(to android.ModuleProxy) {
tag := ctx.OtherModuleDependencyTag(to)
// Extract information from any of the scope specific dependencies.
@@ -1548,52 +1470,62 @@
scopeTag.extractDepInfo(ctx, to, scopePaths)
exportedComponents[ctx.OtherModuleName(to)] = struct{}{}
+
+ ctx.Phony(ctx.ModuleName(), scopePaths.stubsHeaderPath...)
}
if tag == implLibraryTag {
if dep, ok := android.OtherModuleProvider(ctx, to, JavaInfoProvider); ok {
module.implLibraryHeaderJars = append(module.implLibraryHeaderJars, dep.HeaderJars...)
- module.implLibraryModule = to.(*Library)
- android.SetProvider(ctx, JavaInfoProvider, dep)
+ module.implLibraryInfo = dep
+ implLib = to
}
}
})
+ sdkLibInfo := module.generateCommonBuildActions(ctx)
apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
if !apexInfo.IsForPlatform() {
module.hideApexVariantFromMake = true
}
- if module.implLibraryModule != nil {
+ if module.implLibraryInfo != nil {
if ctx.Device() {
- module.classesJarPaths = android.Paths{module.implLibraryModule.implementationJarFile}
- module.bootDexJarPath = module.implLibraryModule.bootDexJarPath
- module.uncompressDexState = module.implLibraryModule.uncompressDexState
- module.active = module.implLibraryModule.active
+ module.classesJarPaths = module.implLibraryInfo.ImplementationJars
+ module.bootDexJarPath = module.implLibraryInfo.BootDexJarPath
+ module.uncompressDexState = module.implLibraryInfo.UncompressDexState
+ module.active = module.implLibraryInfo.Active
}
- module.outputFile = module.implLibraryModule.outputFile
- module.dexJarFile = makeDexJarPathFromPath(module.implLibraryModule.dexJarFile.Path())
- module.headerJarFile = module.implLibraryModule.headerJarFile
- module.implementationAndResourcesJar = module.implLibraryModule.implementationAndResourcesJar
- module.builtInstalledForApex = module.implLibraryModule.builtInstalledForApex
- module.dexpreopter.configPath = module.implLibraryModule.dexpreopter.configPath
- module.dexpreopter.outputProfilePathOnHost = module.implLibraryModule.dexpreopter.outputProfilePathOnHost
+ module.outputFile = module.implLibraryInfo.OutputFile
+ module.dexJarFile = makeDexJarPathFromPath(module.implLibraryInfo.DexJarFile.Path())
+ module.headerJarFile = module.implLibraryInfo.HeaderJars[0]
+ module.implementationAndResourcesJar = module.implLibraryInfo.ImplementationAndResourcesJars[0]
+ module.builtInstalledForApex = module.implLibraryInfo.BuiltInstalledForApex
+ module.dexpreopter.configPath = module.implLibraryInfo.ConfigPath
+ module.dexpreopter.outputProfilePathOnHost = module.implLibraryInfo.OutputProfilePathOnHost
// Properties required for Library.AndroidMkEntries
- module.logtagsSrcs = module.implLibraryModule.logtagsSrcs
- module.dexpreopter.builtInstalled = module.implLibraryModule.dexpreopter.builtInstalled
- module.jacocoReportClassesFile = module.implLibraryModule.jacocoReportClassesFile
- module.dexer.proguardDictionary = module.implLibraryModule.dexer.proguardDictionary
- module.dexer.proguardUsageZip = module.implLibraryModule.dexer.proguardUsageZip
- module.linter.reports = module.implLibraryModule.linter.reports
- module.linter.outputs.depSets = module.implLibraryModule.LintDepSets()
+ module.logtagsSrcs = module.implLibraryInfo.LogtagsSrcs
+ module.dexpreopter.builtInstalled = module.implLibraryInfo.BuiltInstalled
+ module.jacocoReportClassesFile = module.implLibraryInfo.JacocoReportClassesFile
+ module.dexer.proguardDictionary = module.implLibraryInfo.ProguardDictionary
+ module.dexer.proguardUsageZip = module.implLibraryInfo.ProguardUsageZip
+ module.linter.reports = module.implLibraryInfo.LinterReports
- if !module.Host() {
- module.hostdexInstallFile = module.implLibraryModule.hostdexInstallFile
+ if lintInfo, ok := android.OtherModuleProvider(ctx, implLib, LintProvider); ok {
+ android.SetProvider(ctx, LintProvider, lintInfo)
}
- android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: module.implLibraryModule.uniqueSrcFiles.Strings()})
+ if !module.Host() {
+ module.hostdexInstallFile = module.implLibraryInfo.HostdexInstallFile
+ }
+
+ if installFilesInfo, ok := android.OtherModuleProvider(ctx, implLib, android.InstallFilesProvider); ok {
+ if installFilesInfo.CheckbuildTarget != nil {
+ ctx.CheckbuildFile(installFilesInfo.CheckbuildTarget)
+ }
+ }
}
// Make the set of components exported by this module available for use elsewhere.
@@ -1624,9 +1556,32 @@
}
android.SetProvider(ctx, android.AdditionalSdkInfoProvider, android.AdditionalSdkInfo{additionalSdkInfo})
module.setOutputFiles(ctx)
- if module.requiresRuntimeImplementationLibrary() && module.implLibraryModule != nil {
- setOutputFiles(ctx, module.implLibraryModule.Module)
+
+ var generatingLibs []string
+ for _, apiScope := range AllApiScopes {
+ if _, ok := module.scopePaths[apiScope]; ok {
+ generatingLibs = append(generatingLibs, module.stubsLibraryModuleName(apiScope))
+ }
}
+
+ if module.requiresRuntimeImplementationLibrary() && module.implLibraryInfo != nil {
+ generatingLibs = append(generatingLibs, module.implLibraryModuleName())
+ setOutputFilesFromJavaInfo(ctx, module.implLibraryInfo)
+ }
+
+ sdkLibInfo.GeneratingLibs = generatingLibs
+ android.SetProvider(ctx, SdkLibraryInfoProvider, sdkLibInfo)
+}
+
+func setOutputFilesFromJavaInfo(ctx android.ModuleContext, info *JavaInfo) {
+ ctx.SetOutputFiles(append(android.PathsIfNonNil(info.OutputFile), info.ExtraOutputFiles...), "")
+ ctx.SetOutputFiles(android.PathsIfNonNil(info.OutputFile), android.DefaultDistTag)
+ ctx.SetOutputFiles(info.ImplementationAndResourcesJars, ".jar")
+ ctx.SetOutputFiles(info.HeaderJars, ".hjar")
+ if info.ProguardDictionary.Valid() {
+ ctx.SetOutputFiles(android.Paths{info.ProguardDictionary.Path()}, ".proguard_map")
+ }
+ ctx.SetOutputFiles(info.GeneratedSrcjars, ".generated_srcjars")
}
func (module *SdkLibrary) BuiltInstalledForApex() []dexpreopterInstall {
@@ -1733,416 +1688,19 @@
return visibility
}
-// Creates the implementation java library
-func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) {
- visibility := childModuleVisibility(module.sdkLibraryProperties.Impl_library_visibility)
-
- props := struct {
- Name *string
- Visibility []string
- Libs []string
- Static_libs []string
- Apex_available []string
- Stem *string
- }{
- Name: proptools.StringPtr(module.implLibraryModuleName()),
- Visibility: visibility,
-
- Libs: append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...),
-
- Static_libs: append(module.properties.Static_libs, module.sdkLibraryProperties.Impl_only_static_libs...),
- // Pass the apex_available settings down so that the impl library can be statically
- // embedded within a library that is added to an APEX. Needed for updatable-media.
- Apex_available: module.ApexAvailable(),
-
- Stem: proptools.StringPtr(module.Name()),
- }
-
- properties := []interface{}{
- &module.properties,
- &module.protoProperties,
- &module.deviceProperties,
- &module.dexProperties,
- &module.dexpreoptProperties,
- &module.linter.properties,
- &module.overridableProperties,
- &props,
- module.sdkComponentPropertiesForChildLibrary(),
- }
- mctx.CreateModule(LibraryFactory, properties...)
-}
-
-type libraryProperties struct {
- Name *string
- Visibility []string
- Srcs []string
- Installable *bool
- Sdk_version *string
- System_modules *string
- Patch_module *string
- Libs []string
- Static_libs []string
- Compile_dex *bool
- Java_version *string
- Openjdk9 struct {
- Srcs []string
- Javacflags []string
- }
- Dist struct {
- Targets []string
- Dest *string
- Dir *string
- Tag *string
- }
- Is_stubs_module *bool
-}
-
-func (module *SdkLibrary) stubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope) libraryProperties {
- props := libraryProperties{}
- props.Visibility = []string{"//visibility:override", "//visibility:private"}
- // sources are generated from the droiddoc
- sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
- props.Sdk_version = proptools.StringPtr(sdkVersion)
- props.System_modules = module.deviceProperties.System_modules
- props.Patch_module = module.properties.Patch_module
- props.Installable = proptools.BoolPtr(false)
- props.Libs = module.sdkLibraryProperties.Stub_only_libs
- props.Libs = append(props.Libs, module.scopeToProperties[apiScope].Libs...)
- props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs
- // The stub-annotations library contains special versions of the annotations
- // with CLASS retention policy, so that they're kept.
- if proptools.Bool(module.sdkLibraryProperties.Annotations_enabled) {
- props.Libs = append(props.Libs, "stub-annotations")
- }
- props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs
- props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags
- // We compile the stubs for 1.8 in line with the main android.jar stubs, and potential
- // interop with older developer tools that don't support 1.9.
- props.Java_version = proptools.StringPtr("1.8")
- props.Is_stubs_module = proptools.BoolPtr(true)
-
- return props
-}
-
-// Creates a static java library that has API stubs
-func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
-
- props := module.stubsLibraryProps(mctx, apiScope)
- props.Name = proptools.StringPtr(module.sourceStubsLibraryModuleName(apiScope))
- props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)}
-
- mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
-}
-
-// Create a static java library that compiles the "exportable" stubs
-func (module *SdkLibrary) createExportableStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
- props := module.stubsLibraryProps(mctx, apiScope)
- props.Name = proptools.StringPtr(module.exportableSourceStubsLibraryModuleName(apiScope))
- props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope) + "{.exportable}"}
-
- mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
-}
-
-// Creates a droidstubs module that creates stubs source files from the given full source
-// files and also updates and checks the API specification files.
-func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope, name string, scopeSpecificDroidstubsArgs []string) {
- props := struct {
- Name *string
- Visibility []string
- Srcs []string
- Installable *bool
- Sdk_version *string
- Api_surface *string
- System_modules *string
- Libs []string
- Output_javadoc_comments *bool
- Arg_files []string
- Args *string
- Java_version *string
- Annotations_enabled *bool
- Merge_annotations_dirs []string
- Merge_inclusion_annotations_dirs []string
- Generate_stubs *bool
- Previous_api *string
- Aconfig_declarations []string
- Check_api struct {
- Current ApiToCheck
- Last_released ApiToCheck
-
- Api_lint struct {
- Enabled *bool
- New_since *string
- Baseline_file *string
- }
- }
- Aidl struct {
- Include_dirs []string
- Local_include_dirs []string
- }
- Dists []android.Dist
- }{}
-
- // The stubs source processing uses the same compile time classpath when extracting the
- // API from the implementation library as it does when compiling it. i.e. the same
- // * sdk version
- // * system_modules
- // * libs (static_libs/libs)
-
- props.Name = proptools.StringPtr(name)
- props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_source_visibility)
- props.Srcs = append(props.Srcs, module.properties.Srcs...)
- props.Srcs = append(props.Srcs, module.sdkLibraryProperties.Api_srcs...)
- props.Sdk_version = module.deviceProperties.Sdk_version
- props.Api_surface = &apiScope.name
- props.System_modules = module.deviceProperties.System_modules
- props.Installable = proptools.BoolPtr(false)
- // A droiddoc module has only one Libs property and doesn't distinguish between
- // shared libs and static libs. So we need to add both of these libs to Libs property.
- props.Libs = module.properties.Libs
- props.Libs = append(props.Libs, module.properties.Static_libs...)
- props.Libs = append(props.Libs, module.sdkLibraryProperties.Stub_only_libs...)
- props.Libs = append(props.Libs, module.scopeToProperties[apiScope].Libs...)
- props.Aidl.Include_dirs = module.deviceProperties.Aidl.Include_dirs
- props.Aidl.Local_include_dirs = module.deviceProperties.Aidl.Local_include_dirs
- props.Java_version = module.properties.Java_version
-
- props.Annotations_enabled = module.sdkLibraryProperties.Annotations_enabled
- props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs
- props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs
- props.Aconfig_declarations = module.sdkLibraryProperties.Aconfig_declarations
-
- droidstubsArgs := []string{}
- if len(module.sdkLibraryProperties.Api_packages) != 0 {
- droidstubsArgs = append(droidstubsArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":"))
- }
- droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...)
- disabledWarnings := []string{"HiddenSuperclass"}
- if proptools.BoolDefault(module.sdkLibraryProperties.Api_lint.Legacy_errors_allowed, true) {
- disabledWarnings = append(disabledWarnings,
- "BroadcastBehavior",
- "DeprecationMismatch",
- "MissingPermission",
- "SdkConstant",
- "Todo",
- )
- }
- droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
-
- // Output Javadoc comments for public scope.
- if apiScope == apiScopePublic {
- props.Output_javadoc_comments = proptools.BoolPtr(true)
- }
-
- // Add in scope specific arguments.
- droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...)
- props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
- props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " "))
-
- // List of APIs identified from the provided source files are created. They are later
- // compared against to the not-yet-released (a.k.a current) list of APIs and to the
- // last-released (a.k.a numbered) list of API.
- currentApiFileName := apiScope.apiFilePrefix + "current.txt"
- removedApiFileName := apiScope.apiFilePrefix + "removed.txt"
- apiDir := module.getApiDir()
- currentApiFileName = path.Join(apiDir, currentApiFileName)
- removedApiFileName = path.Join(apiDir, removedApiFileName)
-
- // check against the not-yet-release API
- props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
- props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
-
- if module.compareAgainstLatestApi(apiScope) {
- // check against the latest released API
- latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope))
- props.Previous_api = latestApiFilegroupName
- props.Check_api.Last_released.Api_file = latestApiFilegroupName
- props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
- module.latestRemovedApiFilegroupName(apiScope))
- props.Check_api.Last_released.Baseline_file = proptools.StringPtr(
- module.latestIncompatibilitiesFilegroupName(apiScope))
-
- if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) {
- // Enable api lint.
- props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true)
- props.Check_api.Api_lint.New_since = latestApiFilegroupName
-
- // If it exists then pass a lint-baseline.txt through to droidstubs.
- baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt")
- baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath)
- paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil)
- if err != nil {
- mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err)
- }
- if len(paths) == 1 {
- props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath)
- } else if len(paths) != 0 {
- mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths)
- }
- }
- }
-
- if !Bool(module.sdkLibraryProperties.No_dist) {
- // Dist the api txt and removed api txt artifacts for sdk builds.
- distDir := proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
- stubsTypeTagPrefix := ""
- if mctx.Config().ReleaseHiddenApiExportableStubs() {
- stubsTypeTagPrefix = ".exportable"
- }
- for _, p := range []struct {
- tag string
- pattern string
- }{
- // "exportable" api files are copied to the dist directory instead of the
- // "everything" api files when "RELEASE_HIDDEN_API_EXPORTABLE_STUBS" build flag
- // is set. Otherwise, the "everything" api files are copied to the dist directory.
- {tag: "%s.api.txt", pattern: "%s.txt"},
- {tag: "%s.removed-api.txt", pattern: "%s-removed.txt"},
- } {
- props.Dists = append(props.Dists, android.Dist{
- Targets: []string{"sdk", "win_sdk"},
- Dir: distDir,
- Dest: proptools.StringPtr(fmt.Sprintf(p.pattern, module.distStem())),
- Tag: proptools.StringPtr(fmt.Sprintf(p.tag, stubsTypeTagPrefix)),
- })
- }
- }
-
- mctx.CreateModule(DroidstubsFactory, &props, module.sdkComponentPropertiesForChildLibrary()).(*Droidstubs).CallHookIfAvailable(mctx)
-}
-
-func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
- props := struct {
- Name *string
- Visibility []string
- Api_contributions []string
- Libs []string
- Static_libs []string
- System_modules *string
- Enable_validation *bool
- Stubs_type *string
- Sdk_version *string
- Previous_api *string
- }{}
-
- props.Name = proptools.StringPtr(module.apiLibraryModuleName(apiScope))
- props.Visibility = []string{"//visibility:override", "//visibility:private"}
-
- apiContributions := []string{}
-
- // Api surfaces are not independent of each other, but have subset relationships,
- // and so does the api files. To generate from-text stubs for api surfaces other than public,
- // all subset api domains' api_contriubtions must be added as well.
- scope := apiScope
- for scope != nil {
- apiContributions = append(apiContributions, module.stubsSourceModuleName(scope)+".api.contribution")
- scope = scope.extends
- }
- if apiScope == apiScopePublic {
- additionalApiContribution := module.apiLibraryAdditionalApiContribution()
- if additionalApiContribution != "" {
- apiContributions = append(apiContributions, additionalApiContribution)
- }
- }
-
- props.Api_contributions = apiContributions
-
- // Ensure that stub-annotations is added to the classpath before any other libs
- props.Libs = []string{"stub-annotations"}
- props.Libs = append(props.Libs, module.properties.Libs...)
- props.Libs = append(props.Libs, module.properties.Static_libs...)
- props.Libs = append(props.Libs, module.sdkLibraryProperties.Stub_only_libs...)
- props.Libs = append(props.Libs, module.scopeToProperties[apiScope].Libs...)
- props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs
-
- props.System_modules = module.deviceProperties.System_modules
- props.Enable_validation = proptools.BoolPtr(true)
- props.Stubs_type = proptools.StringPtr("everything")
-
- if module.deviceProperties.Sdk_version != nil {
- props.Sdk_version = module.deviceProperties.Sdk_version
- }
-
- if module.compareAgainstLatestApi(apiScope) {
- // check against the latest released API
- latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope))
- props.Previous_api = latestApiFilegroupName
- }
-
- mctx.CreateModule(ApiLibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
-}
-
-func (module *SdkLibrary) topLevelStubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope, doDist bool) libraryProperties {
- props := libraryProperties{}
-
- props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
- sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
- props.Sdk_version = proptools.StringPtr(sdkVersion)
-
- props.System_modules = module.deviceProperties.System_modules
-
- // The imports need to be compiled to dex if the java_sdk_library requests it.
- compileDex := module.dexProperties.Compile_dex
- if module.stubLibrariesCompiledForDex() {
- compileDex = proptools.BoolPtr(true)
- }
- props.Compile_dex = compileDex
-
- if !Bool(module.sdkLibraryProperties.No_dist) && doDist {
- props.Dist.Targets = []string{"sdk", "win_sdk"}
- props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.distStem()))
- props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
- props.Dist.Tag = proptools.StringPtr(".jar")
- }
-
- return props
-}
-
-func (module *SdkLibrary) createTopLevelStubsLibrary(
- mctx android.DefaultableHookContext, apiScope *apiScope) {
-
- // Dist the "everything" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is false
- doDist := !mctx.Config().ReleaseHiddenApiExportableStubs()
- props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist)
- props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
-
- // Add the stub compiling java_library/java_api_library as static lib based on build config
- staticLib := module.sourceStubsLibraryModuleName(apiScope)
- if mctx.Config().BuildFromTextStub() && module.ModuleBuildFromTextStubs() {
- staticLib = module.apiLibraryModuleName(apiScope)
- }
- props.Static_libs = append(props.Static_libs, staticLib)
-
- mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
-}
-
-func (module *SdkLibrary) createTopLevelExportableStubsLibrary(
- mctx android.DefaultableHookContext, apiScope *apiScope) {
-
- // Dist the "exportable" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is true
- doDist := mctx.Config().ReleaseHiddenApiExportableStubs()
- props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist)
- props.Name = proptools.StringPtr(module.exportableStubsLibraryModuleName(apiScope))
-
- staticLib := module.exportableSourceStubsLibraryModuleName(apiScope)
- props.Static_libs = append(props.Static_libs, staticLib)
-
- mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
-}
-
func (module *SdkLibrary) compareAgainstLatestApi(apiScope *apiScope) bool {
return !(apiScope.unstable || module.sdkLibraryProperties.Unsafe_ignore_missing_latest_api)
}
// Implements android.ApexModule
-func (module *SdkLibrary) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool {
- depTag := mctx.OtherModuleDependencyTag(dep)
+func (module *SdkLibrary) OutgoingDepIsInSameApex(depTag blueprint.DependencyTag) bool {
if depTag == xmlPermissionsFileTag {
return true
}
- if dep.Name() == module.implLibraryModuleName() {
+ if depTag == implLibraryTag {
return true
}
- return module.Library.DepIsInSameApex(mctx, dep)
+ return module.Library.OutgoingDepIsInSameApex(depTag)
}
// Implements android.ApexModule
@@ -2154,104 +1712,6 @@
return proptools.BoolDefault(module.sdkLibraryProperties.Build_from_text_stub, true)
}
-// Creates the xml file that publicizes the runtime library
-func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) {
- moduleMinApiLevel := module.Library.MinSdkVersion(mctx)
- var moduleMinApiLevelStr = moduleMinApiLevel.String()
- if moduleMinApiLevel == android.NoneApiLevel {
- moduleMinApiLevelStr = "current"
- }
- props := struct {
- Name *string
- Lib_name *string
- Apex_available []string
- On_bootclasspath_since *string
- On_bootclasspath_before *string
- Min_device_sdk *string
- Max_device_sdk *string
- Sdk_library_min_api_level *string
- Uses_libs_dependencies []string
- }{
- Name: proptools.StringPtr(module.xmlPermissionsModuleName()),
- Lib_name: proptools.StringPtr(module.BaseModuleName()),
- Apex_available: module.ApexProperties.Apex_available,
- On_bootclasspath_since: module.commonSdkLibraryProperties.On_bootclasspath_since,
- On_bootclasspath_before: module.commonSdkLibraryProperties.On_bootclasspath_before,
- Min_device_sdk: module.commonSdkLibraryProperties.Min_device_sdk,
- Max_device_sdk: module.commonSdkLibraryProperties.Max_device_sdk,
- Sdk_library_min_api_level: &moduleMinApiLevelStr,
- Uses_libs_dependencies: module.usesLibraryProperties.Uses_libs,
- }
-
- mctx.CreateModule(sdkLibraryXmlFactory, &props)
-}
-
-func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s android.SdkSpec) android.Paths {
- var ver android.ApiLevel
- var kind android.SdkKind
- if s.UsePrebuilt(ctx) {
- ver = s.ApiLevel
- kind = s.Kind
- } else {
- // We don't have prebuilt SDK for the specific sdkVersion.
- // Instead of breaking the build, fallback to use "system_current"
- ver = android.FutureApiLevel
- kind = android.SdkSystem
- }
-
- dir := filepath.Join("prebuilts", "sdk", ver.String(), kind.String())
- jar := filepath.Join(dir, baseName+".jar")
- jarPath := android.ExistentPathForSource(ctx, jar)
- if !jarPath.Valid() {
- if ctx.Config().AllowMissingDependencies() {
- return android.Paths{android.PathForSource(ctx, jar)}
- } else {
- ctx.PropertyErrorf("sdk_library", "invalid sdk version %q, %q does not exist", s.Raw, jar)
- }
- return nil
- }
- return android.Paths{jarPath.Path()}
-}
-
-// Check to see if the other module is within the same set of named APEXes as this module.
-//
-// If either this or the other module are on the platform then this will return
-// false.
-func withinSameApexesAs(ctx android.BaseModuleContext, other android.Module) bool {
- apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
- otherApexInfo, _ := android.OtherModuleProvider(ctx, other, android.ApexInfoProvider)
- return len(otherApexInfo.InApexVariants) > 0 && reflect.DeepEqual(apexInfo.InApexVariants, otherApexInfo.InApexVariants)
-}
-
-func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
- // If the client doesn't set sdk_version, but if this library prefers stubs over
- // the impl library, let's provide the widest API surface possible. To do so,
- // force override sdk_version to module_current so that the closest possible API
- // surface could be found in selectHeaderJarsForSdkVersion
- if module.defaultsToStubs() && !sdkVersion.Specified() {
- sdkVersion = android.SdkSpecFrom(ctx, "module_current")
- }
-
- // Only provide access to the implementation library if it is actually built.
- if module.requiresRuntimeImplementationLibrary() {
- // Check any special cases for java_sdk_library.
- //
- // Only allow access to the implementation library in the following condition:
- // * No sdk_version specified on the referencing module.
- // * The referencing module is in the same apex as this.
- if sdkVersion.Kind == android.SdkPrivate || withinSameApexesAs(ctx, module) {
- return module.implLibraryHeaderJars
- }
- }
-
- return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion)
-}
-
-// to satisfy SdkLibraryDependency interface
-func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
- return module.sdkJars(ctx, sdkVersion)
-}
-
var javaSdkLibrariesKey = android.NewOnceKey("javaSdkLibraries")
func javaSdkLibraries(config android.Config) *[]string {
@@ -2268,11 +1728,6 @@
// runtime libs and xml file. If requested, the stubs and docs are created twice
// once for public API level and once for system API level
func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookContext) {
- // If the module has been disabled then don't create any child modules.
- if !module.Enabled(mctx) {
- return
- }
-
if len(module.properties.Srcs) == 0 {
mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs")
return
@@ -2322,10 +1777,10 @@
for _, scope := range generatedScopes {
// Use the stubs source name for legacy reasons.
- module.createStubsSourcesAndApi(mctx, scope, module.stubsSourceModuleName(scope), scope.droidstubsArgs)
+ module.createDroidstubs(mctx, scope, module.droidstubsModuleName(scope), scope.droidstubsArgs)
- module.createStubsLibrary(mctx, scope)
- module.createExportableStubsLibrary(mctx, scope)
+ module.createFromSourceStubsLibrary(mctx, scope)
+ module.createExportableFromSourceStubsLibrary(mctx, scope)
if mctx.Config().BuildFromTextStub() && module.ModuleBuildFromTextStubs() {
module.createApiLibrary(mctx, scope)
@@ -2358,7 +1813,7 @@
// Add the impl_only_libs and impl_only_static_libs *after* we're done using them in submodules.
module.properties.Libs = append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...)
- module.properties.Static_libs = append(module.properties.Static_libs, module.sdkLibraryProperties.Impl_only_static_libs...)
+ module.properties.Static_libs.AppendSimpleValue(module.sdkLibraryProperties.Impl_only_static_libs)
}
func (module *SdkLibrary) InitSdkLibraryProperties() {
@@ -2375,84 +1830,25 @@
return !proptools.Bool(module.sdkLibraryProperties.Api_only)
}
-func (module *SdkLibrary) defaultsToStubs() bool {
- return proptools.Bool(module.sdkLibraryProperties.Default_to_stubs)
-}
-
-// Defines how to name the individual component modules the sdk library creates.
-type sdkLibraryComponentNamingScheme interface {
- stubsLibraryModuleName(scope *apiScope, baseName string) string
-
- stubsSourceModuleName(scope *apiScope, baseName string) string
-
- apiLibraryModuleName(scope *apiScope, baseName string) string
-
- sourceStubsLibraryModuleName(scope *apiScope, baseName string) string
-
- exportableStubsLibraryModuleName(scope *apiScope, baseName string) string
-
- exportableSourceStubsLibraryModuleName(scope *apiScope, baseName string) string
-}
-
-type defaultNamingScheme struct {
-}
-
-func (s *defaultNamingScheme) stubsLibraryModuleName(scope *apiScope, baseName string) string {
- return scope.stubsLibraryModuleName(baseName)
-}
-
-func (s *defaultNamingScheme) stubsSourceModuleName(scope *apiScope, baseName string) string {
- return scope.stubsSourceModuleName(baseName)
-}
-
-func (s *defaultNamingScheme) apiLibraryModuleName(scope *apiScope, baseName string) string {
- return scope.apiLibraryModuleName(baseName)
-}
-
-func (s *defaultNamingScheme) sourceStubsLibraryModuleName(scope *apiScope, baseName string) string {
- return scope.sourceStubLibraryModuleName(baseName)
-}
-
-func (s *defaultNamingScheme) exportableStubsLibraryModuleName(scope *apiScope, baseName string) string {
- return scope.exportableStubsLibraryModuleName(baseName)
-}
-
-func (s *defaultNamingScheme) exportableSourceStubsLibraryModuleName(scope *apiScope, baseName string) string {
- return scope.exportableSourceStubsLibraryModuleName(baseName)
-}
-
-var _ sdkLibraryComponentNamingScheme = (*defaultNamingScheme)(nil)
-
-func hasStubsLibrarySuffix(name string, apiScope *apiScope) bool {
- return strings.HasSuffix(name, apiScope.stubsLibraryModuleNameSuffix()) ||
- strings.HasSuffix(name, apiScope.exportableStubsLibraryModuleNameSuffix())
-}
-
-func moduleStubLinkType(name string) (stub bool, ret sdkLinkType) {
- name = strings.TrimSuffix(name, ".from-source")
-
- // This suffix-based approach is fragile and could potentially mis-trigger.
- // TODO(b/155164730): Clean this up when modules no longer reference sdk_lib stubs directly.
- if hasStubsLibrarySuffix(name, apiScopePublic) {
- if name == "hwbinder.stubs" || name == "libcore_private.stubs" {
- // Due to a previous bug, these modules were not considered stubs, so we retain that.
- return false, javaPlatform
- }
+func moduleStubLinkType(j *Module) (stub bool, ret sdkLinkType) {
+ kind := android.ToSdkKind(proptools.String(j.properties.Stub_contributing_api))
+ switch kind {
+ case android.SdkPublic:
return true, javaSdk
- }
- if hasStubsLibrarySuffix(name, apiScopeSystem) {
+ case android.SdkSystem:
return true, javaSystem
- }
- if hasStubsLibrarySuffix(name, apiScopeModuleLib) {
+ case android.SdkModule:
return true, javaModule
- }
- if hasStubsLibrarySuffix(name, apiScopeTest) {
+ case android.SdkTest:
return true, javaSystem
- }
- if hasStubsLibrarySuffix(name, apiScopeSystemServer) {
+ case android.SdkSystemServer:
return true, javaSystemServer
+ // Default value for all modules other than java_sdk_library-generated stub submodules
+ case android.SdkInvalid:
+ return false, javaPlatform
+ default:
+ panic(fmt.Sprintf("stub_contributing_api set as an unsupported sdk kind %s", kind.String()))
}
- return false, javaPlatform
}
// java_sdk_library is a special Java library that provides optional platform APIs to apps.
@@ -2495,7 +1891,7 @@
module.commonSdkLibraryProperties.Shared_library = proptools.BoolPtr(false)
}
- if module.initCommonAfterDefaultsApplied(ctx) {
+ if module.initCommonAfterDefaultsApplied() {
module.CreateInternalModules(ctx)
}
})
@@ -2561,10 +1957,6 @@
commonToSdkLibraryAndImport
- // The reference to the xml permissions module created by the source module.
- // Is nil if the source module does not exist.
- xmlPermissionsFileModule *sdkLibraryXml
-
// Build path to the dex implementation jar obtained from the prebuilt_apex, if any.
dexJarFile OptionalDexJarPath
dexJarFileErr error
@@ -2574,8 +1966,6 @@
installFile android.Path
}
-var _ SdkLibraryDependency = (*SdkLibraryImport)(nil)
-
// The type of a structure that contains a field of type sdkLibraryScopeProperties
// for each apiscope in allApiScopes, e.g. something like:
//
@@ -2631,7 +2021,7 @@
InitJavaModule(module, android.HostAndDeviceSupported)
module.SetDefaultableHook(func(mctx android.DefaultableHookContext) {
- if module.initCommonAfterDefaultsApplied(mctx) {
+ if module.initCommonAfterDefaultsApplied() {
module.createInternalModules(mctx)
}
})
@@ -2685,86 +2075,6 @@
*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
}
-func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
- // Creates a java import for the jar with ".stubs" suffix
- props := struct {
- Name *string
- Source_module_name *string
- Created_by_java_sdk_library_name *string
- Sdk_version *string
- Libs []string
- Jars []string
- Compile_dex *bool
- Is_stubs_module *bool
-
- android.UserSuppliedPrebuiltProperties
- }{}
- props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
- props.Source_module_name = proptools.StringPtr(apiScope.stubsLibraryModuleName(module.BaseModuleName()))
- props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName())
- props.Sdk_version = scopeProperties.Sdk_version
- // Prepend any of the libs from the legacy public properties to the libs for each of the
- // scopes to avoid having to duplicate them in each scope.
- props.Libs = append(module.properties.Libs, scopeProperties.Libs...)
- props.Jars = scopeProperties.Jars
-
- // The imports are preferred if the java_sdk_library_import is preferred.
- props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt)
-
- // The imports need to be compiled to dex if the java_sdk_library_import requests it.
- compileDex := module.properties.Compile_dex
- if module.stubLibrariesCompiledForDex() {
- compileDex = proptools.BoolPtr(true)
- }
- props.Compile_dex = compileDex
- props.Is_stubs_module = proptools.BoolPtr(true)
-
- mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
-}
-
-func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
- props := struct {
- Name *string
- Source_module_name *string
- Created_by_java_sdk_library_name *string
- Srcs []string
-
- android.UserSuppliedPrebuiltProperties
- }{}
- props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope))
- props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName()))
- props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName())
- props.Srcs = scopeProperties.Stub_srcs
-
- // The stubs source is preferred if the java_sdk_library_import is preferred.
- props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt)
-
- mctx.CreateModule(PrebuiltStubsSourcesFactory, &props, module.sdkComponentPropertiesForChildLibrary())
-}
-
-func (module *SdkLibraryImport) createPrebuiltApiContribution(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
- api_file := scopeProperties.Current_api
- api_surface := &apiScope.name
-
- props := struct {
- Name *string
- Source_module_name *string
- Created_by_java_sdk_library_name *string
- Api_surface *string
- Api_file *string
- Visibility []string
- }{}
-
- props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope) + ".api.contribution")
- props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName()) + ".api.contribution")
- props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName())
- props.Api_surface = api_surface
- props.Api_file = api_file
- props.Visibility = []string{"//visibility:override", "//visibility:public"}
-
- mctx.CreateModule(ApiContributionImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
-}
-
// Add the dependencies on the child module in the component deps mutator so that it
// creates references to the prebuilt and not the source modules.
func (module *SdkLibraryImport) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
@@ -2778,7 +2088,7 @@
if len(scopeProperties.Stub_srcs) > 0 {
// Add dependencies to the prebuilt stubs source library
- ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, android.PrebuiltNameFromSource(module.stubsSourceModuleName(apiScope)))
+ ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, android.PrebuiltNameFromSource(module.droidstubsModuleName(apiScope)))
}
}
}
@@ -2801,8 +2111,7 @@
var _ android.ApexModule = (*SdkLibraryImport)(nil)
// Implements android.ApexModule
-func (module *SdkLibraryImport) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool {
- depTag := mctx.OtherModuleDependencyTag(dep)
+func (module *SdkLibraryImport) OutgoingDepIsInSameApex(depTag blueprint.DependencyTag) bool {
if depTag == xmlPermissionsFileTag {
return true
}
@@ -2832,13 +2141,11 @@
var _ hiddenAPIModule = (*SdkLibraryImport)(nil)
func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- module.generateCommonBuildActions(ctx)
-
// Assume that source module(sdk_library) is installed in /<sdk_library partition>/framework
module.installFile = android.PathForModuleInstall(ctx, "framework", module.Stem()+".jar")
// Record the paths to the prebuilt stubs library and stubs source.
- ctx.VisitDirectDeps(func(to android.Module) {
+ ctx.VisitDirectDepsProxy(func(to android.ModuleProxy) {
tag := ctx.OtherModuleDependencyTag(to)
// Extract information from any of the scope specific dependencies.
@@ -2850,19 +2157,14 @@
// is determined by the nature of the dependency which is determined by the tag.
scopeTag.extractDepInfo(ctx, to, scopePaths)
} else if tag == implLibraryTag {
- if implLibrary, ok := to.(*Library); ok {
- module.implLibraryModule = implLibrary
+ if implInfo, ok := android.OtherModuleProvider(ctx, to, JavaInfoProvider); ok {
+ module.implLibraryInfo = implInfo
} else {
ctx.ModuleErrorf("implementation library must be of type *java.Library but was %T", to)
}
- } else if tag == xmlPermissionsFileTag {
- if xmlPermissionsFileModule, ok := to.(*sdkLibraryXml); ok {
- module.xmlPermissionsFileModule = xmlPermissionsFileModule
- } else {
- ctx.ModuleErrorf("xml permissions file module must be of type *sdkLibraryXml but was %T", to)
- }
}
})
+ sdkLibInfo := module.generateCommonBuildActions(ctx)
// Populate the scope paths with information from the properties.
for apiScope, scopeProperties := range module.scopeProperties {
@@ -2877,70 +2179,38 @@
}
if ctx.Device() {
- // If this is a variant created for a prebuilt_apex then use the dex implementation jar
- // obtained from the associated deapexer module.
+ // Shared libraries deapexed from prebuilt apexes are no longer supported.
+ // Set the dexJarBuildPath to a fake path.
+ // This allows soong analysis pass, but will be an error during ninja execution if there are
+ // any rdeps.
ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
if ai.ForPrebuiltApex {
- // Get the path of the dex implementation jar from the `deapexer` module.
- di, err := android.FindDeapexerProviderForModule(ctx)
- if err != nil {
- // An error was found, possibly due to multiple apexes in the tree that export this library
- // Defer the error till a client tries to call DexJarBuildPath
- module.dexJarFileErr = err
- module.initHiddenAPIError(err)
- return
- }
- dexJarFileApexRootRelative := ApexRootRelativePathToJavaLib(module.BaseModuleName())
- if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil {
- dexJarFile := makeDexJarPathFromPath(dexOutputPath)
- module.dexJarFile = dexJarFile
- installPath := android.PathForModuleInPartitionInstall(
- ctx, "apex", ai.ApexVariationName, dexJarFileApexRootRelative)
- module.installFile = installPath
- module.initHiddenAPI(ctx, dexJarFile, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil)
+ module.dexJarFile = makeDexJarPathFromPath(android.PathForModuleInstall(ctx, "intentionally_no_longer_supported"))
+ module.initHiddenAPI(ctx, module.dexJarFile, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil)
+ }
+ }
- module.dexpreopter.installPath = module.dexpreopter.getInstallPath(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), installPath)
- module.dexpreopter.isSDKLibrary = true
- module.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), &module.dexpreopter)
-
- if profilePath := di.PrebuiltExportPath(dexJarFileApexRootRelative + ".prof"); profilePath != nil {
- module.dexpreopter.inputProfilePathOnHost = profilePath
- }
- } else {
- // This should never happen as a variant for a prebuilt_apex is only created if the
- // prebuilt_apex has been configured to export the java library dex file.
- ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt APEX %s", di.ApexModuleName())
+ var generatingLibs []string
+ for _, apiScope := range AllApiScopes {
+ if scopeProperties, ok := module.scopeProperties[apiScope]; ok {
+ if len(scopeProperties.Jars) == 0 {
+ continue
}
+ generatingLibs = append(generatingLibs, module.stubsLibraryModuleName(apiScope))
}
}
module.setOutputFiles(ctx)
- if module.implLibraryModule != nil {
- setOutputFiles(ctx, module.implLibraryModule.Module)
- }
-}
-
-func (module *SdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec, headerJars bool) android.Paths {
-
- // For consistency with SdkLibrary make the implementation jar available to libraries that
- // are within the same APEX.
- implLibraryModule := module.implLibraryModule
- if implLibraryModule != nil && withinSameApexesAs(ctx, module) {
- if headerJars {
- return implLibraryModule.HeaderJars()
- } else {
- return implLibraryModule.ImplementationJars()
- }
+ if module.implLibraryInfo != nil {
+ generatingLibs = append(generatingLibs, module.implLibraryModuleName())
+ setOutputFilesFromJavaInfo(ctx, module.implLibraryInfo)
}
- return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion)
+ sdkLibInfo.GeneratingLibs = generatingLibs
+ android.SetProvider(ctx, SdkLibraryInfoProvider, sdkLibInfo)
}
-// to satisfy SdkLibraryDependency interface
-func (module *SdkLibraryImport) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
- // This module is just a wrapper for the prebuilt stubs.
- return module.sdkJars(ctx, sdkVersion, true)
-}
+var _ UsesLibraryDependency = (*SdkLibraryImport)(nil)
// to satisfy UsesLibraryDependency interface
func (module *SdkLibraryImport) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
@@ -2952,10 +2222,10 @@
if module.dexJarFile.IsSet() {
return module.dexJarFile
}
- if module.implLibraryModule == nil {
+ if module.implLibraryInfo == nil {
return makeUnsetDexJarPath()
} else {
- return module.implLibraryModule.DexJarBuildPath(ctx)
+ return module.implLibraryInfo.DexJarFile
}
}
@@ -2971,33 +2241,10 @@
// to satisfy apex.javaDependency interface
func (module *SdkLibraryImport) JacocoReportClassesFile() android.Path {
- if module.implLibraryModule == nil {
+ if module.implLibraryInfo == nil {
return nil
} else {
- return module.implLibraryModule.JacocoReportClassesFile()
- }
-}
-
-// to satisfy apex.javaDependency interface
-func (module *SdkLibraryImport) LintDepSets() LintDepSets {
- if module.implLibraryModule == nil {
- return LintDepSets{}
- } else {
- return module.implLibraryModule.LintDepSets()
- }
-}
-
-func (module *SdkLibraryImport) GetStrictUpdatabilityLinting() bool {
- if module.implLibraryModule == nil {
- return false
- } else {
- return module.implLibraryModule.GetStrictUpdatabilityLinting()
- }
-}
-
-func (module *SdkLibraryImport) SetStrictUpdatabilityLinting(strictLinting bool) {
- if module.implLibraryModule != nil {
- module.implLibraryModule.SetStrictUpdatabilityLinting(strictLinting)
+ return module.implLibraryInfo.JacocoReportClassesFile
}
}
@@ -3010,19 +2257,19 @@
// to satisfy java.ApexDependency interface
func (module *SdkLibraryImport) HeaderJars() android.Paths {
- if module.implLibraryModule == nil {
+ if module.implLibraryInfo == nil {
return nil
} else {
- return module.implLibraryModule.HeaderJars()
+ return module.implLibraryInfo.HeaderJars
}
}
// to satisfy java.ApexDependency interface
func (module *SdkLibraryImport) ImplementationAndResourcesJars() android.Paths {
- if module.implLibraryModule == nil {
+ if module.implLibraryInfo == nil {
return nil
} else {
- return module.implLibraryModule.ImplementationAndResourcesJars()
+ return module.implLibraryInfo.ImplementationAndResourcesJars
}
}
@@ -3042,333 +2289,6 @@
return proptools.Bool(j.importDexpreoptProperties.Dex_preopt.Profile_guided)
}
-// java_sdk_library_xml
-type sdkLibraryXml struct {
- android.ModuleBase
- android.DefaultableModuleBase
- android.ApexModuleBase
-
- properties sdkLibraryXmlProperties
-
- outputFilePath android.OutputPath
- installDirPath android.InstallPath
-
- hideApexVariantFromMake bool
-}
-
-type sdkLibraryXmlProperties struct {
- // canonical name of the lib
- Lib_name *string
-
- // Signals that this shared library is part of the bootclasspath starting
- // on the version indicated in this attribute.
- //
- // This will make platforms at this level and above to ignore
- // <uses-library> tags with this library name because the library is already
- // available
- On_bootclasspath_since *string
-
- // Signals that this shared library was part of the bootclasspath before
- // (but not including) the version indicated in this attribute.
- //
- // The system will automatically add a <uses-library> tag with this library to
- // apps that target any SDK less than the version indicated in this attribute.
- On_bootclasspath_before *string
-
- // Indicates that PackageManager should ignore this shared library if the
- // platform is below the version indicated in this attribute.
- //
- // This means that the device won't recognise this library as installed.
- Min_device_sdk *string
-
- // Indicates that PackageManager should ignore this shared library if the
- // platform is above the version indicated in this attribute.
- //
- // This means that the device won't recognise this library as installed.
- Max_device_sdk *string
-
- // The SdkLibrary's min api level as a string
- //
- // This value comes from the ApiLevel of the MinSdkVersion property.
- Sdk_library_min_api_level *string
-
- // Uses-libs dependencies that the shared library requires to work correctly.
- //
- // This will add dependency="foo:bar" to the <library> section.
- Uses_libs_dependencies []string
-}
-
-// java_sdk_library_xml builds the permission xml file for a java_sdk_library.
-// Not to be used directly by users. java_sdk_library internally uses this.
-func sdkLibraryXmlFactory() android.Module {
- module := &sdkLibraryXml{}
-
- module.AddProperties(&module.properties)
-
- android.InitApexModule(module)
- android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
-
- return module
-}
-
-func (module *sdkLibraryXml) UniqueApexVariations() bool {
- // sdkLibraryXml needs a unique variation per APEX because the generated XML file contains the path to the
- // mounted APEX, which contains the name of the APEX.
- return true
-}
-
-// from android.PrebuiltEtcModule
-func (module *sdkLibraryXml) BaseDir() string {
- return "etc"
-}
-
-// from android.PrebuiltEtcModule
-func (module *sdkLibraryXml) SubDir() string {
- return "permissions"
-}
-
-var _ etc.PrebuiltEtcModule = (*sdkLibraryXml)(nil)
-
-// from android.ApexModule
-func (module *sdkLibraryXml) AvailableFor(what string) bool {
- return true
-}
-
-func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) {
- // do nothing
-}
-
-var _ android.ApexModule = (*sdkLibraryXml)(nil)
-
-// Implements android.ApexModule
-func (module *sdkLibraryXml) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
- sdkVersion android.ApiLevel) error {
- // sdkLibraryXml doesn't need to be checked separately because java_sdk_library is checked
- return nil
-}
-
-// File path to the runtime implementation library
-func (module *sdkLibraryXml) implPath(ctx android.ModuleContext) string {
- implName := proptools.String(module.properties.Lib_name)
- if apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider); !apexInfo.IsForPlatform() {
- // TODO(b/146468504): ApexVariationName() is only a soong module name, not apex name.
- // In most cases, this works fine. But when apex_name is set or override_apex is used
- // this can be wrong.
- return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexInfo.BaseApexName, implName)
- }
- partition := "system"
- if module.SocSpecific() {
- partition = "vendor"
- } else if module.DeviceSpecific() {
- partition = "odm"
- } else if module.ProductSpecific() {
- partition = "product"
- } else if module.SystemExtSpecific() {
- partition = "system_ext"
- }
- return "/" + partition + "/framework/" + implName + ".jar"
-}
-
-func formattedOptionalSdkLevelAttribute(ctx android.ModuleContext, attrName string, value *string) string {
- if value == nil {
- return ""
- }
- apiLevel, err := android.ApiLevelFromUser(ctx, *value)
- if err != nil {
- // attributes in bp files have underscores but in the xml have dashes.
- ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"), err.Error())
- return ""
- }
- if apiLevel.IsCurrent() {
- // passing "current" would always mean a future release, never the current (or the current in
- // progress) which means some conditions would never be triggered.
- ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"),
- `"current" is not an allowed value for this attribute`)
- return ""
- }
- // "safeValue" is safe because it translates finalized codenames to a string
- // with their SDK int.
- safeValue := apiLevel.String()
- return formattedOptionalAttribute(attrName, &safeValue)
-}
-
-// formats an attribute for the xml permissions file if the value is not null
-// returns empty string otherwise
-func formattedOptionalAttribute(attrName string, value *string) string {
- if value == nil {
- return ""
- }
- return fmt.Sprintf(" %s=\"%s\"\n", attrName, *value)
-}
-
-func formattedDependenciesAttribute(dependencies []string) string {
- if dependencies == nil {
- return ""
- }
- return fmt.Sprintf(" dependency=\"%s\"\n", strings.Join(dependencies, ":"))
-}
-
-func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) string {
- libName := proptools.String(module.properties.Lib_name)
- libNameAttr := formattedOptionalAttribute("name", &libName)
- filePath := module.implPath(ctx)
- filePathAttr := formattedOptionalAttribute("file", &filePath)
- implicitFromAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-since", module.properties.On_bootclasspath_since)
- implicitUntilAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-before", module.properties.On_bootclasspath_before)
- minSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "min-device-sdk", module.properties.Min_device_sdk)
- maxSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "max-device-sdk", module.properties.Max_device_sdk)
- dependenciesAttr := formattedDependenciesAttribute(module.properties.Uses_libs_dependencies)
- // <library> is understood in all android versions whereas <apex-library> is only understood from API T (and ignored before that).
- // similarly, min_device_sdk is only understood from T. So if a library is using that, we need to use the apex-library to make sure this library is not loaded before T
- var libraryTag string
- if module.properties.Min_device_sdk != nil {
- libraryTag = " <apex-library\n"
- } else {
- libraryTag = " <library\n"
- }
-
- return strings.Join([]string{
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n",
- "<!-- Copyright (C) 2018 The Android Open Source Project\n",
- "\n",
- " Licensed under the Apache License, Version 2.0 (the \"License\");\n",
- " you may not use this file except in compliance with the License.\n",
- " You may obtain a copy of the License at\n",
- "\n",
- " http://www.apache.org/licenses/LICENSE-2.0\n",
- "\n",
- " Unless required by applicable law or agreed to in writing, software\n",
- " distributed under the License is distributed on an \"AS IS\" BASIS,\n",
- " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
- " See the License for the specific language governing permissions and\n",
- " limitations under the License.\n",
- "-->\n",
- "<permissions>\n",
- libraryTag,
- libNameAttr,
- filePathAttr,
- implicitFromAttr,
- implicitUntilAttr,
- minSdkAttr,
- maxSdkAttr,
- dependenciesAttr,
- " />\n",
- "</permissions>\n",
- }, "")
-}
-
-func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
- module.hideApexVariantFromMake = !apexInfo.IsForPlatform()
-
- libName := proptools.String(module.properties.Lib_name)
- module.selfValidate(ctx)
- xmlContent := module.permissionsContents(ctx)
-
- module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath
- android.WriteFileRuleVerbatim(ctx, module.outputFilePath, xmlContent)
-
- module.installDirPath = android.PathForModuleInstall(ctx, "etc", module.SubDir())
- ctx.PackageFile(module.installDirPath, libName+".xml", module.outputFilePath)
-
- ctx.SetOutputFiles(android.OutputPaths{module.outputFilePath}.Paths(), "")
-}
-
-func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries {
- if module.hideApexVariantFromMake {
- return []android.AndroidMkEntries{{
- Disabled: true,
- }}
- }
-
- return []android.AndroidMkEntries{{
- Class: "ETC",
- OutputFile: android.OptionalPathForPath(module.outputFilePath),
- ExtraEntries: []android.AndroidMkExtraEntriesFunc{
- func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_TAGS", "optional")
- entries.SetString("LOCAL_MODULE_PATH", module.installDirPath.String())
- entries.SetString("LOCAL_INSTALLED_MODULE_STEM", module.outputFilePath.Base())
- },
- },
- }}
-}
-
-func (module *sdkLibraryXml) selfValidate(ctx android.ModuleContext) {
- module.validateAtLeastTAttributes(ctx)
- module.validateMinAndMaxDeviceSdk(ctx)
- module.validateMinMaxDeviceSdkAndModuleMinSdk(ctx)
- module.validateOnBootclasspathBeforeRequirements(ctx)
-}
-
-func (module *sdkLibraryXml) validateAtLeastTAttributes(ctx android.ModuleContext) {
- t := android.ApiLevelOrPanic(ctx, "Tiramisu")
- module.attrAtLeastT(ctx, t, module.properties.Min_device_sdk, "min_device_sdk")
- module.attrAtLeastT(ctx, t, module.properties.Max_device_sdk, "max_device_sdk")
- module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_before, "on_bootclasspath_before")
- module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_since, "on_bootclasspath_since")
-}
-
-func (module *sdkLibraryXml) attrAtLeastT(ctx android.ModuleContext, t android.ApiLevel, attr *string, attrName string) {
- if attr != nil {
- if level, err := android.ApiLevelFromUser(ctx, *attr); err == nil {
- // we will inform the user of invalid inputs when we try to write the
- // permissions xml file so we don't need to do it here
- if t.GreaterThan(level) {
- ctx.PropertyErrorf(attrName, "Attribute value needs to be at least T")
- }
- }
- }
-}
-
-func (module *sdkLibraryXml) validateMinAndMaxDeviceSdk(ctx android.ModuleContext) {
- if module.properties.Min_device_sdk != nil && module.properties.Max_device_sdk != nil {
- min, minErr := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk)
- max, maxErr := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk)
- if minErr == nil && maxErr == nil {
- // we will inform the user of invalid inputs when we try to write the
- // permissions xml file so we don't need to do it here
- if min.GreaterThan(max) {
- ctx.ModuleErrorf("min_device_sdk can't be greater than max_device_sdk")
- }
- }
- }
-}
-
-func (module *sdkLibraryXml) validateMinMaxDeviceSdkAndModuleMinSdk(ctx android.ModuleContext) {
- moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level)
- if module.properties.Min_device_sdk != nil {
- api, err := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk)
- if err == nil {
- if moduleMinApi.GreaterThan(api) {
- ctx.PropertyErrorf("min_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi)
- }
- }
- }
- if module.properties.Max_device_sdk != nil {
- api, err := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk)
- if err == nil {
- if moduleMinApi.GreaterThan(api) {
- ctx.PropertyErrorf("max_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi)
- }
- }
- }
-}
-
-func (module *sdkLibraryXml) validateOnBootclasspathBeforeRequirements(ctx android.ModuleContext) {
- moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level)
- if module.properties.On_bootclasspath_before != nil {
- t := android.ApiLevelOrPanic(ctx, "Tiramisu")
- // if we use the attribute, then we need to do this validation
- if moduleMinApi.LessThan(t) {
- // if minAPi is < T, then we need to have min_device_sdk (which only accepts T+)
- if module.properties.Min_device_sdk == nil {
- ctx.PropertyErrorf("on_bootclasspath_before", "Using this property requires that the module's min_sdk_version or the shared library's min_device_sdk is at least T")
- }
- }
- }
-}
-
type sdkLibrarySdkMemberType struct {
android.SdkMemberTypeBase
}
@@ -3505,7 +2425,6 @@
}
}
- s.Naming_scheme = sdk.commonSdkLibraryProperties.Naming_scheme
s.Shared_library = proptools.BoolPtr(sdk.sharedLibrary())
s.Compile_dex = sdk.dexProperties.Compile_dex
s.Doctag_paths = sdk.doctagPaths
@@ -3515,8 +2434,7 @@
s.Min_device_sdk = sdk.commonSdkLibraryProperties.Min_device_sdk
s.Max_device_sdk = sdk.commonSdkLibraryProperties.Max_device_sdk
- implLibrary := sdk.getImplLibraryModule()
- if implLibrary != nil && implLibrary.dexpreopter.dexpreoptProperties.Dex_preopt_result.Profile_guided {
+ if sdk.implLibraryInfo != nil && sdk.implLibraryInfo.ProfileGuided {
s.DexPreoptProfileGuided = proptools.BoolPtr(true)
}
}
@@ -3602,19 +2520,3 @@
propertySet.AddProperty("doctag_files", dests)
}
}
-
-// TODO(b/358613520): This can be removed when modules are no longer allowed to depend on the top-level library.
-func (s *SdkLibrary) IDEInfo(dpInfo *android.IdeInfo) {
- s.Library.IDEInfo(dpInfo)
- if s.implLibraryModule != nil {
- dpInfo.Deps = append(dpInfo.Deps, s.implLibraryModule.Name())
- } else {
- // This java_sdk_library does not have an implementation (it sets `api_only` to true).
- // Examples of this are `art.module.intra.core.api` (IntraCore api surface).
- // Return the "public" stubs for these.
- stubPaths := s.findClosestScopePath(apiScopePublic)
- if len(stubPaths.stubsHeaderPath) > 0 {
- dpInfo.Jars = append(dpInfo.Jars, stubPaths.stubsHeaderPath[0].String())
- }
- }
-}
diff --git a/java/sdk_library_external.go b/java/sdk_library_external.go
deleted file mode 100644
index 4f83981..0000000
--- a/java/sdk_library_external.go
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2020 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 java
-
-import (
- "android/soong/android"
-)
-
-type partitionGroup int
-
-// Representation of partition group for checking inter-partition library dependencies.
-// Between system and system_ext, there are no restrictions of dependencies,
-// so we can treat these partitions as the same in terms of inter-partition dependency.
-// Same policy is applied between vendor and odm partiton.
-const (
- partitionGroupNone partitionGroup = iota
- // group for system, and system_ext partition
- partitionGroupSystem
- // group for vendor and odm partition
- partitionGroupVendor
- // product partition
- partitionGroupProduct
-)
-
-func (g partitionGroup) String() string {
- switch g {
- case partitionGroupSystem:
- return "system"
- case partitionGroupVendor:
- return "vendor"
- case partitionGroupProduct:
- return "product"
- }
-
- return ""
-}
-
-// Get partition group of java module that can be used at inter-partition dependency check.
-// We currently have three groups
-//
-// (system, system_ext) => system partition group
-// (vendor, odm) => vendor partition group
-// (product) => product partition group
-func (j *Module) partitionGroup(ctx android.EarlyModuleContext) partitionGroup {
- // system and system_ext partition can be treated as the same in terms of inter-partition dependency.
- if j.Platform() || j.SystemExtSpecific() {
- return partitionGroupSystem
- }
-
- // vendor and odm partition can be treated as the same in terms of inter-partition dependency.
- if j.SocSpecific() || j.DeviceSpecific() {
- return partitionGroupVendor
- }
-
- // product partition is independent.
- if j.ProductSpecific() {
- return partitionGroupProduct
- }
-
- panic("Cannot determine partition type")
-}
-
-func (j *Module) allowListedInterPartitionJavaLibrary(ctx android.EarlyModuleContext) bool {
- return inList(j.Name(), ctx.Config().InterPartitionJavaLibraryAllowList())
-}
-
-func (j *Module) syspropWithPublicStubs() bool {
- return j.deviceProperties.SyspropPublicStub != ""
-}
-
-type javaSdkLibraryEnforceContext interface {
- Name() string
- allowListedInterPartitionJavaLibrary(ctx android.EarlyModuleContext) bool
- partitionGroup(ctx android.EarlyModuleContext) partitionGroup
- syspropWithPublicStubs() bool
-}
-
-var _ javaSdkLibraryEnforceContext = (*Module)(nil)
-
-func (j *Module) checkPartitionsForJavaDependency(ctx android.EarlyModuleContext, propName string, dep javaSdkLibraryEnforceContext) {
- if dep.allowListedInterPartitionJavaLibrary(ctx) {
- return
- }
-
- if dep.syspropWithPublicStubs() {
- return
- }
-
- // If product interface is not enforced, skip check between system and product partition.
- // But still need to check between product and vendor partition because product interface flag
- // just represents enforcement between product and system, and vendor interface enforcement
- // that is enforced here by precondition is representing enforcement between vendor and other partitions.
- if !ctx.Config().EnforceProductPartitionInterface() {
- productToSystem := j.partitionGroup(ctx) == partitionGroupProduct && dep.partitionGroup(ctx) == partitionGroupSystem
- systemToProduct := j.partitionGroup(ctx) == partitionGroupSystem && dep.partitionGroup(ctx) == partitionGroupProduct
-
- if productToSystem || systemToProduct {
- return
- }
- }
-
- // If module and dependency library is inter-partition
- if j.partitionGroup(ctx) != dep.partitionGroup(ctx) {
- errorFormat := "dependency on java_library (%q) is not allowed across the partitions (%s -> %s), use java_sdk_library instead"
- ctx.PropertyErrorf(propName, errorFormat, dep.Name(), j.partitionGroup(ctx), dep.partitionGroup(ctx))
- }
-}
diff --git a/java/sdk_library_internal.go b/java/sdk_library_internal.go
new file mode 100644
index 0000000..db9cd24
--- /dev/null
+++ b/java/sdk_library_internal.go
@@ -0,0 +1,1036 @@
+// 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 java
+
+import (
+ "fmt"
+ "path"
+ "strings"
+
+ "android/soong/android"
+ "android/soong/etc"
+
+ "github.com/google/blueprint/proptools"
+)
+
+// ---------------------------------------------------------------------------------------------
+// Naming scheme of the submodules generated by java_sdk_library and java_sdk_library_import
+// ---------------------------------------------------------------------------------------------
+
+const (
+ sdkXmlFileSuffix = ".xml"
+ implLibSuffix = ".impl"
+)
+
+func implLibraryModuleName(sdkLibName string) string {
+ return sdkLibName + implLibSuffix
+}
+
+// Module name of the runtime implementation library
+func (c *commonToSdkLibraryAndImport) implLibraryModuleName() string {
+ return implLibraryModuleName(c.module.RootLibraryName())
+}
+
+// Module name of the XML file for the lib
+func (c *commonToSdkLibraryAndImport) xmlPermissionsModuleName() string {
+ return c.module.RootLibraryName() + sdkXmlFileSuffix
+}
+
+// Name of the java_library module that compiles the stubs source.
+func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope) string {
+ baseName := c.module.RootLibraryName()
+ return apiScope.stubsLibraryModuleName(baseName)
+}
+
+// Name of the java_library module that compiles the exportable stubs source.
+func (c *commonToSdkLibraryAndImport) exportableStubsLibraryModuleName(apiScope *apiScope) string {
+ baseName := c.module.RootLibraryName()
+ return apiScope.exportableStubsLibraryModuleName(baseName)
+}
+
+// Name of the droidstubs module that generates the stubs source and may also
+// generate/check the API.
+func (c *commonToSdkLibraryAndImport) droidstubsModuleName(apiScope *apiScope) string {
+ baseName := c.module.RootLibraryName()
+ return apiScope.stubsSourceModuleName(baseName)
+}
+
+// Name of the java_api_library module that generates the from-text stubs source
+// and compiles to a jar file.
+func (c *commonToSdkLibraryAndImport) fromTextStubsLibraryModuleName(apiScope *apiScope) string {
+ baseName := c.module.RootLibraryName()
+ return apiScope.apiLibraryModuleName(baseName)
+}
+
+// Name of the java_library module that compiles the stubs
+// generated from source Java files.
+func (c *commonToSdkLibraryAndImport) fromSourceStubsLibraryModuleName(apiScope *apiScope) string {
+ baseName := c.module.RootLibraryName()
+ return apiScope.sourceStubsLibraryModuleName(baseName)
+}
+
+// Name of the java_library module that compiles the exportable stubs
+// generated from source Java files.
+func (c *commonToSdkLibraryAndImport) exportableFromSourceStubsLibraryModuleName(apiScope *apiScope) string {
+ baseName := c.module.RootLibraryName()
+ return apiScope.exportableSourceStubsLibraryModuleName(baseName)
+}
+
+// ---------------------------------------------------------------------------------------------
+// Build rules of the submodules generated by java_sdk_library.
+// java_sdk_library "framework-foo" generates the following submodules:
+//
+// - "framework-foo.impl" (type: [Library]): the implementation library, which generates the
+// compilation outputs that include the implementation details and the private apis
+// (i.e. class/methods that are annotated @hide).
+//
+// - "framework-foo.stubs.source.<[apiScope.name]>" (type: [Droidstubs]): droidstubs module that
+// generates the stubs and the api files for the given api scope.
+//
+// - "framework-foo.stubs.<[apiScope.name]>" (type: [Library]): stub library module that
+// provides the compilation output of the stubs to the reverse dependencies. The module
+// itself does not perform any compilation actions; the module statically depends on one of
+// the from-source stub module or the from-text stub configuration based on the build
+// configuration.
+//
+// - "framework-foo.stubs.<[apiScope.name]>.from-source" (type: [Library]): stub library module
+// that compiles the stubs generated by the droidstubs submodule. This module is a static
+// dependency of the stub library module when
+// [android/soong/android/config.BuildFromTextStub()] is false.
+//
+// - "framework-foo.stubs.<[apiScope.name]>.from-text" (type: [ApiLibrary]): api library module
+// that generates and compiles the stubs from the api files checked in the tree instead of
+// the source Java files (e.g. *-current.txt files). This module is a static dependency of
+// the stub library module when [android/soong/android/config.BuildFromTextStub()] is true.
+//
+// - "framework-foo.stubs.exportable.<[apiScope.name]>" (type: [Library]): stub library module
+// that provides the "exportable" stubs. "exportable" stubs are the stubs that do not
+// include in-development flagged apis. This module is only used for SDK builds to generate
+// the SDK artifacts, and not purposed for consumption for other modules.
+//
+// - "framework-foo.stubs.exportable.<[apiScope.name]>.from-source" (type: [Library]): stub
+// library module that compiles the "exportable" stubs generated by the droidstubs
+// submodule. This module is always a static dependency of the "exportable" stub library
+// module given that from-text stubs cannot be used for SDK builds as it does not contain
+// documentations.
+//
+// - "framework-foo.xml" (type: [sdkLibraryXml]): xml library that generates the permission xml
+// file, which allows [SdkLibrary] to be used with <uses-permission> tag in the
+// AndroidManifest.xml files.
+// ---------------------------------------------------------------------------------------------
+
+// Creates the implementation [Library] with ".impl" suffix.
+func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) {
+ visibility := childModuleVisibility(module.sdkLibraryProperties.Impl_library_visibility)
+
+ staticLibs := module.properties.Static_libs.Clone()
+ staticLibs.AppendSimpleValue(module.sdkLibraryProperties.Impl_only_static_libs)
+ props := struct {
+ Name *string
+ Enabled proptools.Configurable[bool]
+ Visibility []string
+ Libs []string
+ Static_libs proptools.Configurable[[]string]
+ Apex_available []string
+ Stem *string
+ }{
+ Name: proptools.StringPtr(module.implLibraryModuleName()),
+ Enabled: module.EnabledProperty(),
+ Visibility: visibility,
+
+ Libs: append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...),
+
+ Static_libs: staticLibs,
+ // Pass the apex_available settings down so that the impl library can be statically
+ // embedded within a library that is added to an APEX. Needed for updatable-media.
+ Apex_available: module.ApexAvailable(),
+
+ Stem: proptools.StringPtr(module.Name()),
+ }
+
+ properties := []interface{}{
+ &module.properties,
+ &module.protoProperties,
+ &module.deviceProperties,
+ &module.dexProperties,
+ &module.dexpreoptProperties,
+ &module.linter.properties,
+ &module.overridableProperties,
+ &props,
+ module.sdkComponentPropertiesForChildLibrary(),
+ }
+ mctx.CreateModule(LibraryFactory, properties...)
+}
+
+// getApiSurfaceForScope returns the api surface name to use for the apiScope. If one is specified
+// in the corresponding ApiScopeProperties.Api_surface property that is used, otherwise the name of
+// the apiScope is used.
+func (module *SdkLibrary) getApiSurfaceForScope(apiScope *apiScope) *string {
+ scopeProperties := module.scopeToProperties[apiScope]
+
+ apiSurface := scopeProperties.Api_surface
+ if apiSurface == nil {
+ apiSurface = &apiScope.name
+ }
+
+ return apiSurface
+}
+
+// Creates the [Droidstubs] module with ".stubs.source.<[apiScope.name]>" that creates stubs
+// source files from the given full source files and also updates and checks the API
+// specification files (i.e. "*-current.txt", "*-removed.txt" files).
+func (module *SdkLibrary) createDroidstubs(mctx android.DefaultableHookContext, apiScope *apiScope, name string, scopeSpecificDroidstubsArgs []string) {
+ props := struct {
+ Name *string
+ Enabled proptools.Configurable[bool]
+ Visibility []string
+ Srcs []string
+ Installable *bool
+ Sdk_version *string
+ Api_surface *string
+ System_modules *string
+ Libs proptools.Configurable[[]string]
+ Output_javadoc_comments *bool
+ Arg_files []string
+ Args *string
+ Java_version *string
+ Annotations_enabled *bool
+ Merge_annotations_dirs []string
+ Merge_inclusion_annotations_dirs []string
+ Generate_stubs *bool
+ Previous_api *string
+ Aconfig_declarations []string
+ Check_api struct {
+ Current ApiToCheck
+ Last_released ApiToCheck
+
+ Api_lint struct {
+ Enabled *bool
+ New_since *string
+ Baseline_file *string
+ }
+ }
+ Aidl struct {
+ Include_dirs []string
+ Local_include_dirs []string
+ }
+ Dists []android.Dist
+ }{}
+
+ // The stubs source processing uses the same compile time classpath when extracting the
+ // API from the implementation library as it does when compiling it. i.e. the same
+ // * sdk version
+ // * system_modules
+ // * libs (static_libs/libs)
+
+ props.Name = proptools.StringPtr(name)
+ props.Enabled = module.EnabledProperty()
+ props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_source_visibility)
+ props.Srcs = append(props.Srcs, module.properties.Srcs...)
+ props.Srcs = append(props.Srcs, module.sdkLibraryProperties.Api_srcs...)
+ props.Sdk_version = module.deviceProperties.Sdk_version
+ props.Api_surface = module.getApiSurfaceForScope(apiScope)
+ props.System_modules = module.deviceProperties.System_modules
+ props.Installable = proptools.BoolPtr(false)
+ // A droiddoc module has only one Libs property and doesn't distinguish between
+ // shared libs and static libs. So we need to add both of these libs to Libs property.
+ props.Libs = proptools.NewConfigurable[[]string](nil, nil)
+ props.Libs.AppendSimpleValue(module.properties.Libs)
+ props.Libs.Append(module.properties.Static_libs)
+ props.Libs.AppendSimpleValue(module.sdkLibraryProperties.Stub_only_libs)
+ props.Libs.AppendSimpleValue(module.scopeToProperties[apiScope].Libs)
+ props.Aidl.Include_dirs = module.deviceProperties.Aidl.Include_dirs
+ props.Aidl.Local_include_dirs = module.deviceProperties.Aidl.Local_include_dirs
+ props.Java_version = module.properties.Java_version
+
+ props.Annotations_enabled = module.sdkLibraryProperties.Annotations_enabled
+ props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs
+ props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs
+ props.Aconfig_declarations = module.sdkLibraryProperties.Aconfig_declarations
+
+ droidstubsArgs := []string{}
+ if len(module.sdkLibraryProperties.Api_packages) != 0 {
+ droidstubsArgs = append(droidstubsArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":"))
+ }
+ droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...)
+ disabledWarnings := []string{"HiddenSuperclass"}
+ if proptools.BoolDefault(module.sdkLibraryProperties.Api_lint.Legacy_errors_allowed, true) {
+ disabledWarnings = append(disabledWarnings,
+ "BroadcastBehavior",
+ "DeprecationMismatch",
+ "MissingPermission",
+ "SdkConstant",
+ "Todo",
+ )
+ }
+ droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
+
+ // Output Javadoc comments for public scope.
+ if apiScope == apiScopePublic {
+ props.Output_javadoc_comments = proptools.BoolPtr(true)
+ }
+
+ // Add in scope specific arguments.
+ droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...)
+ props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
+ props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " "))
+
+ // List of APIs identified from the provided source files are created. They are later
+ // compared against to the not-yet-released (a.k.a current) list of APIs and to the
+ // last-released (a.k.a numbered) list of API.
+ currentApiFileName := apiScope.apiFilePrefix + "current.txt"
+ removedApiFileName := apiScope.apiFilePrefix + "removed.txt"
+ apiDir := module.getApiDir()
+ currentApiFileName = path.Join(apiDir, currentApiFileName)
+ removedApiFileName = path.Join(apiDir, removedApiFileName)
+
+ // check against the not-yet-release API
+ props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
+ props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
+
+ if module.compareAgainstLatestApi(apiScope) {
+ // check against the latest released API
+ latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope))
+ props.Previous_api = latestApiFilegroupName
+ props.Check_api.Last_released.Api_file = latestApiFilegroupName
+ props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
+ module.latestRemovedApiFilegroupName(apiScope))
+ props.Check_api.Last_released.Baseline_file = proptools.StringPtr(
+ module.latestIncompatibilitiesFilegroupName(apiScope))
+
+ if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) {
+ // Enable api lint.
+ props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true)
+ props.Check_api.Api_lint.New_since = latestApiFilegroupName
+
+ // If it exists then pass a lint-baseline.txt through to droidstubs.
+ baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt")
+ baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath)
+ paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil)
+ if err != nil {
+ mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err)
+ }
+ if len(paths) == 1 {
+ props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath)
+ } else if len(paths) != 0 {
+ mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths)
+ }
+ }
+ }
+
+ if !Bool(module.sdkLibraryProperties.No_dist) {
+ // Dist the api txt and removed api txt artifacts for sdk builds.
+ distDir := proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
+ stubsTypeTagPrefix := ""
+ if mctx.Config().ReleaseHiddenApiExportableStubs() {
+ stubsTypeTagPrefix = ".exportable"
+ }
+ for _, p := range []struct {
+ tag string
+ pattern string
+ }{
+ // "exportable" api files are copied to the dist directory instead of the
+ // "everything" api files when "RELEASE_HIDDEN_API_EXPORTABLE_STUBS" build flag
+ // is set. Otherwise, the "everything" api files are copied to the dist directory.
+ {tag: "%s.api.txt", pattern: "%s.txt"},
+ {tag: "%s.removed-api.txt", pattern: "%s-removed.txt"},
+ } {
+ props.Dists = append(props.Dists, android.Dist{
+ Targets: []string{"sdk", "win_sdk"},
+ Dir: distDir,
+ Dest: proptools.StringPtr(fmt.Sprintf(p.pattern, module.distStem())),
+ Tag: proptools.StringPtr(fmt.Sprintf(p.tag, stubsTypeTagPrefix)),
+ })
+ }
+ }
+
+ mctx.CreateModule(DroidstubsFactory, &props, module.sdkComponentPropertiesForChildLibrary()).(*Droidstubs).CallHookIfAvailable(mctx)
+}
+
+type libraryProperties struct {
+ Name *string
+ Enabled proptools.Configurable[bool]
+ Visibility []string
+ Srcs []string
+ Installable *bool
+ Sdk_version *string
+ System_modules *string
+ Patch_module *string
+ Libs []string
+ Static_libs []string
+ Compile_dex *bool
+ Java_version *string
+ Openjdk9 struct {
+ Srcs []string
+ Javacflags []string
+ }
+ Dist struct {
+ Targets []string
+ Dest *string
+ Dir *string
+ Tag *string
+ }
+ Is_stubs_module *bool
+ Stub_contributing_api *string
+}
+
+func (module *SdkLibrary) stubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope) libraryProperties {
+ props := libraryProperties{}
+ props.Enabled = module.EnabledProperty()
+ props.Visibility = []string{"//visibility:override", "//visibility:private"}
+ // sources are generated from the droiddoc
+ sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
+ props.Sdk_version = proptools.StringPtr(sdkVersion)
+ props.System_modules = module.deviceProperties.System_modules
+ props.Patch_module = module.properties.Patch_module
+ props.Installable = proptools.BoolPtr(false)
+ props.Libs = module.sdkLibraryProperties.Stub_only_libs
+ props.Libs = append(props.Libs, module.scopeToProperties[apiScope].Libs...)
+ props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs
+ // The stub-annotations library contains special versions of the annotations
+ // with CLASS retention policy, so that they're kept.
+ if proptools.Bool(module.sdkLibraryProperties.Annotations_enabled) {
+ props.Libs = append(props.Libs, "stub-annotations")
+ }
+ props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs
+ props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags
+ // We compile the stubs for 1.8 in line with the main android.jar stubs, and potential
+ // interop with older developer tools that don't support 1.9.
+ props.Java_version = proptools.StringPtr("1.8")
+ props.Is_stubs_module = proptools.BoolPtr(true)
+ props.Stub_contributing_api = proptools.StringPtr(apiScope.kind.String())
+
+ return props
+}
+
+// Creates the from-source stub [Library] with ".stubs.<[apiScope.name]>.from-source" suffix.
+func (module *SdkLibrary) createFromSourceStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
+
+ props := module.stubsLibraryProps(mctx, apiScope)
+ props.Name = proptools.StringPtr(module.fromSourceStubsLibraryModuleName(apiScope))
+ props.Srcs = []string{":" + module.droidstubsModuleName(apiScope)}
+
+ mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
+}
+
+// Creates the "exportable" from-source stub [Library] with
+// ".stubs.exportable.<[apiScope.name]>" suffix.
+func (module *SdkLibrary) createExportableFromSourceStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
+ props := module.stubsLibraryProps(mctx, apiScope)
+ props.Name = proptools.StringPtr(module.exportableFromSourceStubsLibraryModuleName(apiScope))
+ props.Srcs = []string{":" + module.droidstubsModuleName(apiScope) + "{.exportable}"}
+
+ mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
+}
+
+// Creates the from-text stub [ApiLibrary] with ".stubs.<[apiScope.name]>.from-text" suffix.
+func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
+ props := struct {
+ Name *string
+ Enabled proptools.Configurable[bool]
+ Visibility []string
+ Api_contributions []string
+ Libs proptools.Configurable[[]string]
+ Static_libs []string
+ System_modules *string
+ Enable_validation *bool
+ Stubs_type *string
+ Sdk_version *string
+ Previous_api *string
+ }{}
+
+ props.Name = proptools.StringPtr(module.fromTextStubsLibraryModuleName(apiScope))
+ props.Enabled = module.EnabledProperty()
+ props.Visibility = []string{"//visibility:override", "//visibility:private"}
+
+ apiContributions := []string{}
+
+ // Api surfaces are not independent of each other, but have subset relationships,
+ // and so does the api files. To generate from-text stubs for api surfaces other than public,
+ // all subset api domains' api_contriubtions must be added as well.
+ scope := apiScope
+ for scope != nil {
+ apiContributions = append(apiContributions, module.droidstubsModuleName(scope)+".api.contribution")
+ scope = scope.extends
+ }
+ if apiScope == apiScopePublic {
+ additionalApiContribution := module.apiLibraryAdditionalApiContribution()
+ if additionalApiContribution != "" {
+ apiContributions = append(apiContributions, additionalApiContribution)
+ }
+ }
+
+ props.Api_contributions = apiContributions
+
+ // Ensure that stub-annotations is added to the classpath before any other libs
+ props.Libs = proptools.NewConfigurable[[]string](nil, nil)
+ props.Libs.AppendSimpleValue([]string{"stub-annotations"})
+ props.Libs.AppendSimpleValue(module.properties.Libs)
+ props.Libs.Append(module.properties.Static_libs)
+ props.Libs.AppendSimpleValue(module.sdkLibraryProperties.Stub_only_libs)
+ props.Libs.AppendSimpleValue(module.scopeToProperties[apiScope].Libs)
+ props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs
+
+ props.System_modules = module.deviceProperties.System_modules
+ props.Enable_validation = proptools.BoolPtr(true)
+ props.Stubs_type = proptools.StringPtr("everything")
+
+ if module.deviceProperties.Sdk_version != nil {
+ props.Sdk_version = module.deviceProperties.Sdk_version
+ }
+
+ if module.compareAgainstLatestApi(apiScope) {
+ // check against the latest released API
+ latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope))
+ props.Previous_api = latestApiFilegroupName
+ }
+
+ mctx.CreateModule(ApiLibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
+}
+
+func (module *SdkLibrary) topLevelStubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope, doDist bool) libraryProperties {
+ props := libraryProperties{}
+
+ props.Enabled = module.EnabledProperty()
+ props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
+ sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
+ props.Sdk_version = proptools.StringPtr(sdkVersion)
+
+ props.System_modules = module.deviceProperties.System_modules
+
+ // The imports need to be compiled to dex if the java_sdk_library requests it.
+ compileDex := module.dexProperties.Compile_dex
+ if module.stubLibrariesCompiledForDex() {
+ compileDex = proptools.BoolPtr(true)
+ }
+ props.Compile_dex = compileDex
+
+ props.Stub_contributing_api = proptools.StringPtr(apiScope.kind.String())
+
+ if !Bool(module.sdkLibraryProperties.No_dist) && doDist {
+ props.Dist.Targets = []string{"sdk", "win_sdk"}
+ props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.distStem()))
+ props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
+ props.Dist.Tag = proptools.StringPtr(".jar")
+ }
+ props.Is_stubs_module = proptools.BoolPtr(true)
+
+ return props
+}
+
+// Creates the stub [Library] with ".stubs.<[apiScope.name]>" suffix.
+func (module *SdkLibrary) createTopLevelStubsLibrary(
+ mctx android.DefaultableHookContext, apiScope *apiScope) {
+
+ // Dist the "everything" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is false
+ doDist := !mctx.Config().ReleaseHiddenApiExportableStubs()
+ props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist)
+ props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
+
+ // Add the stub compiling java_library/java_api_library as static lib based on build config
+ staticLib := module.fromSourceStubsLibraryModuleName(apiScope)
+ if mctx.Config().BuildFromTextStub() && module.ModuleBuildFromTextStubs() {
+ staticLib = module.fromTextStubsLibraryModuleName(apiScope)
+ }
+ props.Static_libs = append(props.Static_libs, staticLib)
+
+ mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
+}
+
+// Creates the "exportable" stub [Library] with ".stubs.exportable.<[apiScope.name]>" suffix.
+func (module *SdkLibrary) createTopLevelExportableStubsLibrary(
+ mctx android.DefaultableHookContext, apiScope *apiScope) {
+
+ // Dist the "exportable" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is true
+ doDist := mctx.Config().ReleaseHiddenApiExportableStubs()
+ props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist)
+ props.Name = proptools.StringPtr(module.exportableStubsLibraryModuleName(apiScope))
+
+ staticLib := module.exportableFromSourceStubsLibraryModuleName(apiScope)
+ props.Static_libs = append(props.Static_libs, staticLib)
+
+ mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
+}
+
+// Creates the [sdkLibraryXml] with ".xml" suffix.
+func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) {
+ moduleMinApiLevel := module.Library.MinSdkVersion(mctx)
+ var moduleMinApiLevelStr = moduleMinApiLevel.String()
+ if moduleMinApiLevel == android.NoneApiLevel {
+ moduleMinApiLevelStr = "current"
+ }
+ props := struct {
+ Name *string
+ Enabled proptools.Configurable[bool]
+ Lib_name *string
+ Apex_available []string
+ On_bootclasspath_since *string
+ On_bootclasspath_before *string
+ Min_device_sdk *string
+ Max_device_sdk *string
+ Sdk_library_min_api_level *string
+ Uses_libs_dependencies proptools.Configurable[[]string]
+ }{
+ Name: proptools.StringPtr(module.xmlPermissionsModuleName()),
+ Enabled: module.EnabledProperty(),
+ Lib_name: proptools.StringPtr(module.BaseModuleName()),
+ Apex_available: module.ApexProperties.Apex_available,
+ On_bootclasspath_since: module.commonSdkLibraryProperties.On_bootclasspath_since,
+ On_bootclasspath_before: module.commonSdkLibraryProperties.On_bootclasspath_before,
+ Min_device_sdk: module.commonSdkLibraryProperties.Min_device_sdk,
+ Max_device_sdk: module.commonSdkLibraryProperties.Max_device_sdk,
+ Sdk_library_min_api_level: &moduleMinApiLevelStr,
+ Uses_libs_dependencies: module.usesLibraryProperties.Uses_libs.Clone(),
+ }
+
+ mctx.CreateModule(sdkLibraryXmlFactory, &props)
+}
+
+// ---------------------------------------------------------------------------------------------
+// Build rules of the submodules generated by java_sdk_library_import.
+// Note that the java_sdk_library_import module does not generate the implementation library.
+// Instead, it will create a dependency to the source implemenetation library if one exists.
+// java_sdk_library_import "framework-foo" generates the following submodules:
+//
+// - "framework-foo.stubs.<[apiScope.name]>" (type: [Import]): prebuilt stub library module that
+// provides the stub jar file checked in the tree.
+//
+// - "framework-foo.stubs.source.<[apiScope.name]>" (type: [PrebuiltStubsSources]): prebuilt
+// droidstubs module that provides the stub source jar file checked in the tree.
+//
+// - "framework-foo.stubs.source.<[apiScope.name]>.api.contribution"
+// (type [JavaApiContributionImport]): prebuilt java_api_contribution module that provides
+// the prebuilt api file for previously released from-text stub generation.
+// ---------------------------------------------------------------------------------------------
+
+// Creates the prebuilt stub [Import] with ".stubs.<[apiScope.name]>" suffix.
+func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
+ // Creates a java import for the jar with ".stubs" suffix
+ props := struct {
+ Name *string
+ Source_module_name *string
+ Created_by_java_sdk_library_name *string
+ Sdk_version *string
+ Libs []string
+ Jars []string
+ Compile_dex *bool
+ Is_stubs_module *bool
+
+ android.UserSuppliedPrebuiltProperties
+ }{}
+ props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
+ props.Source_module_name = proptools.StringPtr(apiScope.stubsLibraryModuleName(module.BaseModuleName()))
+ props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName())
+ props.Sdk_version = scopeProperties.Sdk_version
+ // Prepend any of the libs from the legacy public properties to the libs for each of the
+ // scopes to avoid having to duplicate them in each scope.
+ props.Libs = append(module.properties.Libs, scopeProperties.Libs...)
+ props.Jars = scopeProperties.Jars
+
+ // The imports are preferred if the java_sdk_library_import is preferred.
+ props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt)
+
+ // The imports need to be compiled to dex if the java_sdk_library_import requests it.
+ compileDex := module.properties.Compile_dex
+ if module.stubLibrariesCompiledForDex() {
+ compileDex = proptools.BoolPtr(true)
+ }
+ props.Compile_dex = compileDex
+ props.Is_stubs_module = proptools.BoolPtr(true)
+
+ mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
+}
+
+func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
+ props := struct {
+ Name *string
+ Source_module_name *string
+ Created_by_java_sdk_library_name *string
+ Srcs []string
+
+ android.UserSuppliedPrebuiltProperties
+ }{}
+ props.Name = proptools.StringPtr(module.droidstubsModuleName(apiScope))
+ props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName()))
+ props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName())
+ props.Srcs = scopeProperties.Stub_srcs
+
+ // The stubs source is preferred if the java_sdk_library_import is preferred.
+ props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt)
+
+ mctx.CreateModule(PrebuiltStubsSourcesFactory, &props, module.sdkComponentPropertiesForChildLibrary())
+}
+
+// Creates the prebuilt api contribution [JavaApiContributionImport] with
+// ".stubs.source.<[apiScope.name]>.api.contribution" suffix.
+func (module *SdkLibraryImport) createPrebuiltApiContribution(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
+ api_file := scopeProperties.Current_api
+ api_surface := &apiScope.name
+
+ props := struct {
+ Name *string
+ Source_module_name *string
+ Created_by_java_sdk_library_name *string
+ Api_surface *string
+ Api_file *string
+ Visibility []string
+ }{}
+
+ props.Name = proptools.StringPtr(module.droidstubsModuleName(apiScope) + ".api.contribution")
+ props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName()) + ".api.contribution")
+ props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName())
+ props.Api_surface = api_surface
+ props.Api_file = api_file
+ props.Visibility = []string{"//visibility:override", "//visibility:public"}
+
+ mctx.CreateModule(ApiContributionImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
+}
+
+// ---------------------------------------------------------------------------------------------
+// End of the build rules of the submodules generated by java_sdk_library_import.
+// ---------------------------------------------------------------------------------------------
+
+// Definition of the [sdkLibraryXml] module. The module generates the permissions xml file,
+// so that the apps can specify the java_sdk_library using <uses-permission> tag in the
+// AndroidManifest.xml file.
+type sdkLibraryXml struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+ android.ApexModuleBase
+
+ properties sdkLibraryXmlProperties
+
+ outputFilePath android.OutputPath
+ installDirPath android.InstallPath
+
+ hideApexVariantFromMake bool
+}
+
+type sdkLibraryXmlProperties struct {
+ // canonical name of the lib
+ Lib_name *string
+
+ // Signals that this shared library is part of the bootclasspath starting
+ // on the version indicated in this attribute.
+ //
+ // This will make platforms at this level and above to ignore
+ // <uses-library> tags with this library name because the library is already
+ // available
+ On_bootclasspath_since *string
+
+ // Signals that this shared library was part of the bootclasspath before
+ // (but not including) the version indicated in this attribute.
+ //
+ // The system will automatically add a <uses-library> tag with this library to
+ // apps that target any SDK less than the version indicated in this attribute.
+ On_bootclasspath_before *string
+
+ // Indicates that PackageManager should ignore this shared library if the
+ // platform is below the version indicated in this attribute.
+ //
+ // This means that the device won't recognise this library as installed.
+ Min_device_sdk *string
+
+ // Indicates that PackageManager should ignore this shared library if the
+ // platform is above the version indicated in this attribute.
+ //
+ // This means that the device won't recognise this library as installed.
+ Max_device_sdk *string
+
+ // The SdkLibrary's min api level as a string
+ //
+ // This value comes from the ApiLevel of the MinSdkVersion property.
+ Sdk_library_min_api_level *string
+
+ // Uses-libs dependencies that the shared library requires to work correctly.
+ //
+ // This will add dependency="foo:bar" to the <library> section.
+ Uses_libs_dependencies proptools.Configurable[[]string]
+}
+
+// java_sdk_library_xml builds the permission xml file for a java_sdk_library.
+// Not to be used directly by users. java_sdk_library internally uses this.
+func sdkLibraryXmlFactory() android.Module {
+ module := &sdkLibraryXml{}
+
+ module.AddProperties(&module.properties)
+
+ android.InitApexModule(module)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+
+ return module
+}
+
+func (module *sdkLibraryXml) UniqueApexVariations() bool {
+ // sdkLibraryXml needs a unique variation per APEX because the generated XML file contains the path to the
+ // mounted APEX, which contains the name of the APEX.
+ return true
+}
+
+// from android.PrebuiltEtcModule
+func (module *sdkLibraryXml) BaseDir() string {
+ return "etc"
+}
+
+// from android.PrebuiltEtcModule
+func (module *sdkLibraryXml) SubDir() string {
+ return "permissions"
+}
+
+var _ etc.PrebuiltEtcModule = (*sdkLibraryXml)(nil)
+
+// from android.ApexModule
+func (module *sdkLibraryXml) AvailableFor(what string) bool {
+ return android.CheckAvailableForApex(what, module.ApexAvailableFor())
+}
+
+func (module *sdkLibraryXml) ApexAvailableFor() []string {
+ return []string{android.AvailableToPlatform, android.AvailableToAnyApex}
+}
+
+func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) {
+ // do nothing
+}
+
+var _ android.ApexModule = (*sdkLibraryXml)(nil)
+
+// Implements android.ApexModule
+func (module *sdkLibraryXml) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
+ sdkVersion android.ApiLevel) error {
+ // sdkLibraryXml doesn't need to be checked separately because java_sdk_library is checked
+ return nil
+}
+
+// File path to the runtime implementation library
+func (module *sdkLibraryXml) implPath(ctx android.ModuleContext) string {
+ implName := proptools.String(module.properties.Lib_name)
+ if apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider); !apexInfo.IsForPlatform() {
+ // TODO(b/146468504): ApexVariationName() is only a soong module name, not apex name.
+ // In most cases, this works fine. But when apex_name is set or override_apex is used
+ // this can be wrong.
+ return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexInfo.BaseApexName, implName)
+ }
+ partition := "system"
+ if module.SocSpecific() {
+ partition = "vendor"
+ } else if module.DeviceSpecific() {
+ partition = "odm"
+ } else if module.ProductSpecific() {
+ partition = "product"
+ } else if module.SystemExtSpecific() {
+ partition = "system_ext"
+ }
+ return "/" + partition + "/framework/" + implName + ".jar"
+}
+
+func formattedOptionalSdkLevelAttribute(ctx android.ModuleContext, attrName string, value *string) string {
+ if value == nil {
+ return ""
+ }
+ apiLevel, err := android.ApiLevelFromUser(ctx, *value)
+ if err != nil {
+ // attributes in bp files have underscores but in the xml have dashes.
+ ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"), err.Error())
+ return ""
+ }
+ if apiLevel.IsCurrent() {
+ // passing "current" would always mean a future release, never the current (or the current in
+ // progress) which means some conditions would never be triggered.
+ ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"),
+ `"current" is not an allowed value for this attribute`)
+ return ""
+ }
+ // "safeValue" is safe because it translates finalized codenames to a string
+ // with their SDK int.
+ safeValue := apiLevel.String()
+ return formattedOptionalAttribute(attrName, &safeValue)
+}
+
+// formats an attribute for the xml permissions file if the value is not null
+// returns empty string otherwise
+func formattedOptionalAttribute(attrName string, value *string) string {
+ if value == nil {
+ return ""
+ }
+ return fmt.Sprintf(" %s=\"%s\"\n", attrName, *value)
+}
+
+func formattedDependenciesAttribute(dependencies []string) string {
+ if dependencies == nil {
+ return ""
+ }
+ return fmt.Sprintf(" dependency=\"%s\"\n", strings.Join(dependencies, ":"))
+}
+
+func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) string {
+ libName := proptools.String(module.properties.Lib_name)
+ libNameAttr := formattedOptionalAttribute("name", &libName)
+ filePath := module.implPath(ctx)
+ filePathAttr := formattedOptionalAttribute("file", &filePath)
+ implicitFromAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-since", module.properties.On_bootclasspath_since)
+ implicitUntilAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-before", module.properties.On_bootclasspath_before)
+ minSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "min-device-sdk", module.properties.Min_device_sdk)
+ maxSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "max-device-sdk", module.properties.Max_device_sdk)
+ dependenciesAttr := formattedDependenciesAttribute(module.properties.Uses_libs_dependencies.GetOrDefault(ctx, nil))
+ // <library> is understood in all android versions whereas <apex-library> is only understood from API T (and ignored before that).
+ // similarly, min_device_sdk is only understood from T. So if a library is using that, we need to use the apex-library to make sure this library is not loaded before T
+ var libraryTag string
+ if module.properties.Min_device_sdk != nil {
+ libraryTag = " <apex-library\n"
+ } else {
+ libraryTag = " <library\n"
+ }
+
+ return strings.Join([]string{
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n",
+ "<!-- Copyright (C) 2018 The Android Open Source Project\n",
+ "\n",
+ " Licensed under the Apache License, Version 2.0 (the \"License\");\n",
+ " you may not use this file except in compliance with the License.\n",
+ " You may obtain a copy of the License at\n",
+ "\n",
+ " http://www.apache.org/licenses/LICENSE-2.0\n",
+ "\n",
+ " Unless required by applicable law or agreed to in writing, software\n",
+ " distributed under the License is distributed on an \"AS IS\" BASIS,\n",
+ " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
+ " See the License for the specific language governing permissions and\n",
+ " limitations under the License.\n",
+ "-->\n",
+ "<permissions>\n",
+ libraryTag,
+ libNameAttr,
+ filePathAttr,
+ implicitFromAttr,
+ implicitUntilAttr,
+ minSdkAttr,
+ maxSdkAttr,
+ dependenciesAttr,
+ " />\n",
+ "</permissions>\n",
+ }, "")
+}
+
+func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+ module.hideApexVariantFromMake = !apexInfo.IsForPlatform()
+
+ libName := proptools.String(module.properties.Lib_name)
+ module.selfValidate(ctx)
+ xmlContent := module.permissionsContents(ctx)
+
+ module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath
+ android.WriteFileRuleVerbatim(ctx, module.outputFilePath, xmlContent)
+
+ module.installDirPath = android.PathForModuleInstall(ctx, "etc", module.SubDir())
+ ctx.PackageFile(module.installDirPath, libName+".xml", module.outputFilePath)
+
+ ctx.SetOutputFiles(android.OutputPaths{module.outputFilePath}.Paths(), "")
+}
+
+func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries {
+ if module.hideApexVariantFromMake {
+ return []android.AndroidMkEntries{{
+ Disabled: true,
+ }}
+ }
+
+ return []android.AndroidMkEntries{{
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(module.outputFilePath),
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE_TAGS", "optional")
+ entries.SetString("LOCAL_MODULE_PATH", module.installDirPath.String())
+ entries.SetString("LOCAL_INSTALLED_MODULE_STEM", module.outputFilePath.Base())
+ },
+ },
+ }}
+}
+
+func (module *sdkLibraryXml) selfValidate(ctx android.ModuleContext) {
+ module.validateAtLeastTAttributes(ctx)
+ module.validateMinAndMaxDeviceSdk(ctx)
+ module.validateMinMaxDeviceSdkAndModuleMinSdk(ctx)
+ module.validateOnBootclasspathBeforeRequirements(ctx)
+}
+
+func (module *sdkLibraryXml) validateAtLeastTAttributes(ctx android.ModuleContext) {
+ t := android.ApiLevelOrPanic(ctx, "Tiramisu")
+ module.attrAtLeastT(ctx, t, module.properties.Min_device_sdk, "min_device_sdk")
+ module.attrAtLeastT(ctx, t, module.properties.Max_device_sdk, "max_device_sdk")
+ module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_before, "on_bootclasspath_before")
+ module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_since, "on_bootclasspath_since")
+}
+
+func (module *sdkLibraryXml) attrAtLeastT(ctx android.ModuleContext, t android.ApiLevel, attr *string, attrName string) {
+ if attr != nil {
+ if level, err := android.ApiLevelFromUser(ctx, *attr); err == nil {
+ // we will inform the user of invalid inputs when we try to write the
+ // permissions xml file so we don't need to do it here
+ if t.GreaterThan(level) {
+ ctx.PropertyErrorf(attrName, "Attribute value needs to be at least T")
+ }
+ }
+ }
+}
+
+func (module *sdkLibraryXml) validateMinAndMaxDeviceSdk(ctx android.ModuleContext) {
+ if module.properties.Min_device_sdk != nil && module.properties.Max_device_sdk != nil {
+ min, minErr := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk)
+ max, maxErr := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk)
+ if minErr == nil && maxErr == nil {
+ // we will inform the user of invalid inputs when we try to write the
+ // permissions xml file so we don't need to do it here
+ if min.GreaterThan(max) {
+ ctx.ModuleErrorf("min_device_sdk can't be greater than max_device_sdk")
+ }
+ }
+ }
+}
+
+func (module *sdkLibraryXml) validateMinMaxDeviceSdkAndModuleMinSdk(ctx android.ModuleContext) {
+ moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level)
+ if module.properties.Min_device_sdk != nil {
+ api, err := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk)
+ if err == nil {
+ if moduleMinApi.GreaterThan(api) {
+ ctx.PropertyErrorf("min_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi)
+ }
+ }
+ }
+ if module.properties.Max_device_sdk != nil {
+ api, err := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk)
+ if err == nil {
+ if moduleMinApi.GreaterThan(api) {
+ ctx.PropertyErrorf("max_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi)
+ }
+ }
+ }
+}
+
+func (module *sdkLibraryXml) validateOnBootclasspathBeforeRequirements(ctx android.ModuleContext) {
+ moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level)
+ if module.properties.On_bootclasspath_before != nil {
+ t := android.ApiLevelOrPanic(ctx, "Tiramisu")
+ // if we use the attribute, then we need to do this validation
+ if moduleMinApi.LessThan(t) {
+ // if minAPi is < T, then we need to have min_device_sdk (which only accepts T+)
+ if module.properties.Min_device_sdk == nil {
+ ctx.PropertyErrorf("on_bootclasspath_before", "Using this property requires that the module's min_sdk_version or the shared library's min_device_sdk is at least T")
+ }
+ }
+ }
+}
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 52d4af0..0aed4b8 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -22,11 +22,10 @@
"testing"
"android/soong/android"
-
- "github.com/google/blueprint/proptools"
)
func TestJavaSdkLibrary(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -55,7 +54,7 @@
java_library {
name: "baz",
srcs: ["c.java"],
- libs: ["foo", "bar.stubs"],
+ libs: ["foo.stubs.system", "bar.stubs"],
sdk_version: "system_current",
}
java_sdk_library {
@@ -92,25 +91,25 @@
java_library {
name: "qux",
srcs: ["c.java"],
- libs: ["baz", "fred", "quuz.stubs", "wilma", "barney", "betty"],
+ libs: ["baz", "fred.stubs", "quuz.stubs", "wilma.stubs", "barney.stubs.system", "betty.stubs.system"],
sdk_version: "system_current",
}
java_library {
name: "baz-test",
srcs: ["c.java"],
- libs: ["foo"],
+ libs: ["foo.stubs.test"],
sdk_version: "test_current",
}
java_library {
name: "baz-29",
srcs: ["c.java"],
- libs: ["foo"],
+ libs: ["sdk_system_29_foo"],
sdk_version: "system_29",
}
java_library {
name: "baz-module-30",
srcs: ["c.java"],
- libs: ["foo"],
+ libs: ["sdk_module-lib_30_foo"],
sdk_version: "module_30",
}
`)
@@ -162,11 +161,11 @@
baz29Javac := result.ModuleForTests("baz-29", "android_common").Rule("javac")
// tests if baz-29 is actually linked to the system 29 stubs lib
- android.AssertStringDoesContain(t, "baz-29 javac classpath", baz29Javac.Args["classpath"], "prebuilts/sdk/29/system/foo.jar")
+ android.AssertStringDoesContain(t, "baz-29 javac classpath", baz29Javac.Args["classpath"], "prebuilts/sdk/sdk_system_29_foo/android_common/combined/sdk_system_29_foo.jar")
bazModule30Javac := result.ModuleForTests("baz-module-30", "android_common").Rule("javac")
// tests if "baz-module-30" is actually linked to the module 30 stubs lib
- android.AssertStringDoesContain(t, "baz-module-30 javac classpath", bazModule30Javac.Args["classpath"], "prebuilts/sdk/30/module-lib/foo.jar")
+ android.AssertStringDoesContain(t, "baz-module-30 javac classpath", bazModule30Javac.Args["classpath"], "prebuilts/sdk/sdk_module-lib_30_foo/android_common/combined/sdk_module-lib_30_foo.jar")
// test if baz has exported SDK lib names foo and bar to qux
qux := result.ModuleForTests("qux", "android_common")
@@ -189,6 +188,7 @@
}
func TestJavaSdkLibrary_UpdatableLibrary(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -238,6 +238,7 @@
}
func TestJavaSdkLibrary_UpdatableLibrary_Validation_ValidVersion(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -265,6 +266,7 @@
}
func TestJavaSdkLibrary_UpdatableLibrary_Validation_AtLeastTAttributes(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -294,6 +296,7 @@
}
func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdk(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -321,6 +324,7 @@
}
func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdkAndModuleMinSdk(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -349,6 +353,7 @@
}
func TestJavaSdkLibrary_UpdatableLibrary_usesNewTag(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -372,6 +377,7 @@
}
func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -422,12 +428,13 @@
for _, expectation := range expectations {
verify("sdklib.impl", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined)
- stubName := apiScopePublic.sourceStubLibraryModuleName("sdklib")
+ stubName := apiScopePublic.sourceStubsLibraryModuleName("sdklib")
verify(stubName, expectation.lib, expectation.on_stub_classpath, expectation.in_stub_combined)
}
}
func TestJavaSdkLibrary_DoNotAccessImplWhenItIsNotBuilt(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -445,7 +452,7 @@
java_library {
name: "bar",
srcs: ["b.java"],
- libs: ["foo"],
+ libs: ["foo.stubs"],
}
`)
@@ -457,6 +464,7 @@
}
func TestJavaSdkLibrary_AccessOutputFiles(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -480,6 +488,7 @@
}
func TestJavaSdkLibrary_AccessOutputFiles_NoAnnotations(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -505,6 +514,7 @@
}
func TestJavaSdkLibrary_AccessOutputFiles_MissingScope(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -529,6 +539,7 @@
}
func TestJavaSdkLibrary_Deps(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -559,6 +570,7 @@
}
func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) {
+ t.Parallel()
prepareForJavaTest.RunTestWithBp(t, `
java_sdk_library_import {
name: "foo",
@@ -584,6 +596,7 @@
}
func TestJavaSdkLibraryImport_AccessOutputFiles_Invalid(t *testing.T) {
+ t.Parallel()
bp := `
java_sdk_library_import {
name: "foo",
@@ -594,6 +607,7 @@
`
t.Run("stubs.source", func(t *testing.T) {
+ t.Parallel()
prepareForJavaTest.
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo" is not a SourceFileProducer or having valid output file for tag ".public.stubs.source"`)).
RunTestWithBp(t, bp+`
@@ -609,6 +623,7 @@
})
t.Run("api.txt", func(t *testing.T) {
+ t.Parallel()
prepareForJavaTest.
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo" is not a SourceFileProducer or having valid output file for tag ".public.api.txt"`)).
RunTestWithBp(t, bp+`
@@ -623,6 +638,7 @@
})
t.Run("removed-api.txt", func(t *testing.T) {
+ t.Parallel()
prepareForJavaTest.
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo" is not a SourceFileProducer or having valid output file for tag ".public.removed-api.txt"`)).
RunTestWithBp(t, bp+`
@@ -638,6 +654,7 @@
}
func TestJavaSdkLibrary_InvalidScopes(t *testing.T) {
+ t.Parallel()
prepareForJavaTest.
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo": enabled api scope "system" depends on disabled scope "public"`)).
RunTestWithBp(t, `
@@ -658,6 +675,7 @@
}
func TestJavaSdkLibrary_SdkVersion_ForScope(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -676,6 +694,7 @@
}
func TestJavaSdkLibrary_ModuleLib(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -696,6 +715,7 @@
}
func TestJavaSdkLibrary_SystemServer(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -716,6 +736,7 @@
}
func TestJavaSdkLibrary_SystemServer_AccessToStubScopeLibs(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -763,7 +784,7 @@
java_library {
name: "bar",
srcs: ["a.java"],
- libs: ["foo-public", "foo-system", "foo-module-lib", "foo-system-server"],
+ libs: ["foo-public.stubs", "foo-system.stubs.system", "foo-module-lib.stubs.module_lib", "foo-system-server.stubs.system_server"],
sdk_version: "system_server_current",
}
`)
@@ -789,102 +810,27 @@
}
}
-func TestJavaSdkLibrary_MissingScope(t *testing.T) {
- prepareForJavaTest.
- ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`requires api scope module-lib from foo but it only has \[\] available`)).
- RunTestWithBp(t, `
- java_sdk_library {
- name: "foo",
- srcs: ["a.java"],
- public: {
- enabled: false,
- },
- }
-
- java_library {
- name: "baz",
- srcs: ["a.java"],
- libs: ["foo"],
- sdk_version: "module_current",
- }
- `)
-}
-
-func TestJavaSdkLibrary_FallbackScope(t *testing.T) {
- android.GroupFixturePreparers(
- prepareForJavaTest,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("foo"),
- ).RunTestWithBp(t, `
- java_sdk_library {
- name: "foo",
- srcs: ["a.java"],
- system: {
- enabled: true,
- },
- }
-
- java_library {
- name: "baz",
- srcs: ["a.java"],
- libs: ["foo"],
- // foo does not have module-lib scope so it should fallback to system
- sdk_version: "module_current",
- }
- `)
-}
-
-func TestJavaSdkLibrary_DefaultToStubs(t *testing.T) {
- result := android.GroupFixturePreparers(
- prepareForJavaTest,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("foo"),
- ).RunTestWithBp(t, `
- java_sdk_library {
- name: "foo",
- srcs: ["a.java"],
- system: {
- enabled: true,
- },
- default_to_stubs: true,
- }
-
- java_library {
- name: "baz",
- srcs: ["a.java"],
- libs: ["foo"],
- // does not have sdk_version set, should fallback to module,
- // which will then fallback to system because the module scope
- // is not enabled.
- }
- `)
- // The baz library should depend on the system stubs jar.
- bazLibrary := result.ModuleForTests("baz", "android_common").Rule("javac")
- if expected, actual := `^-classpath .*:out/soong/[^:]*/turbine-combined/foo\.stubs.system\.jar$`, bazLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
- t.Errorf("expected %q, found %#q", expected, actual)
- }
-}
-
func TestJavaSdkLibraryImport(t *testing.T) {
+ t.Parallel()
result := prepareForJavaTest.RunTestWithBp(t, `
java_library {
name: "foo",
srcs: ["a.java"],
- libs: ["sdklib"],
+ libs: ["sdklib.stubs"],
sdk_version: "current",
}
java_library {
name: "foo.system",
srcs: ["a.java"],
- libs: ["sdklib"],
+ libs: ["sdklib.stubs.system"],
sdk_version: "system_current",
}
java_library {
name: "foo.test",
srcs: ["a.java"],
- libs: ["sdklib"],
+ libs: ["sdklib.stubs.test"],
sdk_version: "test_current",
}
@@ -907,7 +853,7 @@
fooModule := result.ModuleForTests("foo"+scope, "android_common")
javac := fooModule.Rule("javac")
- sdklibStubsJar := result.ModuleForTests("sdklib.stubs"+scope, "android_common").Rule("combineJar").Output
+ sdklibStubsJar := result.ModuleForTests("sdklib.stubs"+scope, "android_common").Output("combined/sdklib.stubs" + scope + ".jar").Output
android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], sdklibStubsJar.String())
}
@@ -922,6 +868,7 @@
}
func TestJavaSdkLibraryImport_WithSource(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -1017,7 +964,7 @@
java_library {
name: "public",
srcs: ["a.java"],
- libs: ["sdklib"],
+ libs: ["sdklib.stubs"],
sdk_version: "current",
}
`)
@@ -1064,7 +1011,9 @@
}
func TestJavaSdkLibraryImport_Preferred(t *testing.T) {
+ t.Parallel()
t.Run("prefer", func(t *testing.T) {
+ t.Parallel()
testJavaSdkLibraryImport_Preferred(t, "prefer: true,", android.NullFixturePreparer)
})
}
@@ -1072,6 +1021,7 @@
// If a module is listed in `mainline_module_contributions, it should be used
// It will supersede any other source vs prebuilt selection mechanism like `prefer` attribute
func TestSdkLibraryImport_MetadataModuleSupersedesPreferred(t *testing.T) {
+ t.Parallel()
bp := `
apex_contributions {
name: "my_mainline_module_contributions",
@@ -1190,156 +1140,8 @@
}
}
-func TestJavaSdkLibraryEnforce(t *testing.T) {
- partitionToBpOption := func(partition string) string {
- switch partition {
- case "system":
- return ""
- case "vendor":
- return "soc_specific: true,"
- case "product":
- return "product_specific: true,"
- default:
- panic("Invalid partition group name: " + partition)
- }
- }
-
- type testConfigInfo struct {
- libraryType string
- fromPartition string
- toPartition string
- enforceProductInterface bool
- enforceJavaSdkLibraryCheck bool
- allowList []string
- }
-
- createPreparer := func(info testConfigInfo) android.FixturePreparer {
- bpFileTemplate := `
- java_library {
- name: "foo",
- srcs: ["foo.java"],
- libs: ["bar"],
- sdk_version: "current",
- %s
- }
-
- %s {
- name: "bar",
- srcs: ["bar.java"],
- sdk_version: "current",
- %s
- }
- `
-
- bpFile := fmt.Sprintf(bpFileTemplate,
- partitionToBpOption(info.fromPartition),
- info.libraryType,
- partitionToBpOption(info.toPartition))
-
- return android.GroupFixturePreparers(
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("bar"),
- android.FixtureWithRootAndroidBp(bpFile),
- android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.EnforceProductPartitionInterface = proptools.BoolPtr(info.enforceProductInterface)
- variables.EnforceInterPartitionJavaSdkLibrary = proptools.BoolPtr(info.enforceJavaSdkLibraryCheck)
- variables.InterPartitionJavaLibraryAllowList = info.allowList
- }),
- )
- }
-
- runTest := func(t *testing.T, info testConfigInfo, expectedErrorPattern string) {
- t.Run(fmt.Sprintf("%v", info), func(t *testing.T) {
- errorHandler := android.FixtureExpectsNoErrors
- if expectedErrorPattern != "" {
- errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorPattern)
- }
- android.GroupFixturePreparers(
- prepareForJavaTest,
- createPreparer(info),
- ).
- ExtendWithErrorHandler(errorHandler).
- RunTest(t)
- })
- }
-
- errorMessage := "is not allowed across the partitions"
-
- runTest(t, testConfigInfo{
- libraryType: "java_library",
- fromPartition: "product",
- toPartition: "system",
- enforceProductInterface: true,
- enforceJavaSdkLibraryCheck: false,
- }, "")
-
- runTest(t, testConfigInfo{
- libraryType: "java_library",
- fromPartition: "product",
- toPartition: "system",
- enforceProductInterface: false,
- enforceJavaSdkLibraryCheck: true,
- }, "")
-
- runTest(t, testConfigInfo{
- libraryType: "java_library",
- fromPartition: "product",
- toPartition: "system",
- enforceProductInterface: true,
- enforceJavaSdkLibraryCheck: true,
- }, errorMessage)
-
- runTest(t, testConfigInfo{
- libraryType: "java_library",
- fromPartition: "vendor",
- toPartition: "system",
- enforceProductInterface: true,
- enforceJavaSdkLibraryCheck: true,
- }, errorMessage)
-
- runTest(t, testConfigInfo{
- libraryType: "java_library",
- fromPartition: "vendor",
- toPartition: "system",
- enforceProductInterface: true,
- enforceJavaSdkLibraryCheck: true,
- allowList: []string{"bar"},
- }, "")
-
- runTest(t, testConfigInfo{
- libraryType: "java_library",
- fromPartition: "vendor",
- toPartition: "product",
- enforceProductInterface: true,
- enforceJavaSdkLibraryCheck: true,
- }, errorMessage)
-
- runTest(t, testConfigInfo{
- libraryType: "java_sdk_library",
- fromPartition: "product",
- toPartition: "system",
- enforceProductInterface: true,
- enforceJavaSdkLibraryCheck: true,
- }, "")
-
- runTest(t, testConfigInfo{
- libraryType: "java_sdk_library",
- fromPartition: "vendor",
- toPartition: "system",
- enforceProductInterface: true,
- enforceJavaSdkLibraryCheck: true,
- }, "")
-
- runTest(t, testConfigInfo{
- libraryType: "java_sdk_library",
- fromPartition: "vendor",
- toPartition: "product",
- enforceProductInterface: true,
- enforceJavaSdkLibraryCheck: true,
- }, "")
-}
-
func TestJavaSdkLibraryDist(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
PrepareForTestWithJavaBuildComponents,
PrepareForTestWithJavaDefaultModules,
@@ -1406,6 +1208,7 @@
for _, tt := range testCases {
t.Run(tt.module, func(t *testing.T) {
+ t.Parallel()
m := result.ModuleForTests(apiScopePublic.exportableStubsLibraryModuleName(tt.module), "android_common").Module().(*Library)
dists := m.Dists()
if len(dists) != 1 {
@@ -1422,6 +1225,7 @@
}
func TestSdkLibrary_CheckMinSdkVersion(t *testing.T) {
+ t.Parallel()
preparer := android.GroupFixturePreparers(
PrepareForTestWithJavaBuildComponents,
PrepareForTestWithJavaDefaultModules,
@@ -1506,6 +1310,7 @@
}
func TestJavaSdkLibrary_StubOnlyLibs_PassedToDroidstubs(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -1528,10 +1333,12 @@
// The foo.stubs.source should depend on bar-lib
fooStubsSources := result.ModuleForTests("foo.stubs.source", "android_common").Module().(*Droidstubs)
- android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs, "bar-lib")
+ eval := fooStubsSources.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+ android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs.GetOrDefault(eval, nil), "bar-lib")
}
func TestJavaSdkLibrary_Scope_Libs_PassedToDroidstubs(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -1554,10 +1361,12 @@
// The foo.stubs.source should depend on bar-lib
fooStubsSources := result.ModuleForTests("foo.stubs.source", "android_common").Module().(*Droidstubs)
- android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs, "bar-lib")
+ eval := fooStubsSources.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+ android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs.GetOrDefault(eval, nil), "bar-lib")
}
func TestJavaSdkLibrary_ApiLibrary(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -1608,6 +1417,7 @@
}
func TestStaticDepStubLibrariesVisibility(t *testing.T) {
+ t.Parallel()
android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -1637,6 +1447,7 @@
}
func TestSdkLibraryDependency(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -1655,7 +1466,7 @@
name: "bar",
srcs: ["c.java", "b.java"],
libs: [
- "foo",
+ "foo.stubs",
],
uses_libs: [
"foo",
@@ -1669,6 +1480,7 @@
}
func TestSdkLibraryExportableStubsLibrary(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -1705,23 +1517,21 @@
exportableSourceStubsLibraryModuleName := apiScopePublic.exportableSourceStubsLibraryModuleName("foo")
// Check modules generation
- topLevelModule := result.ModuleForTests(exportableStubsLibraryModuleName, "android_common")
+ result.ModuleForTests(exportableStubsLibraryModuleName, "android_common")
result.ModuleForTests(exportableSourceStubsLibraryModuleName, "android_common")
// Check static lib dependency
android.AssertBoolEquals(t, "exportable top level stubs library module depends on the"+
"exportable source stubs library module", true,
- CheckModuleHasDependency(t, result.TestContext, exportableStubsLibraryModuleName,
- "android_common", exportableSourceStubsLibraryModuleName),
+ CheckModuleHasDependencyWithTag(t, result.TestContext, exportableStubsLibraryModuleName,
+ "android_common", staticLibTag, exportableSourceStubsLibraryModuleName),
)
- android.AssertArrayString(t, "exportable source stub library is a static lib of the"+
- "top level exportable stubs library", []string{exportableSourceStubsLibraryModuleName},
- topLevelModule.Module().(*Library).properties.Static_libs)
}
// For java libraries depending on java_sdk_library(_import) via libs, assert that
// rdep gets stubs of source if source is listed in apex_contributions and prebuilt has prefer (legacy mechanism)
func TestStubResolutionOfJavaSdkLibraryInLibs(t *testing.T) {
+ t.Parallel()
bp := `
apex_contributions {
name: "my_mainline_module_contributions",
@@ -1753,7 +1563,7 @@
name: "mymodule",
srcs: ["a.java"],
sdk_version: "current",
- libs: ["sdklib",], // this should be dynamically resolved to sdklib.stubs (source) or prebuilt_sdklib.stubs (prebuilt)
+ libs: ["sdklib.stubs",], // this should be dynamically resolved to sdklib.stubs (source) or prebuilt_sdklib.stubs (prebuilt)
}
`
@@ -1775,6 +1585,7 @@
// test that rdep gets resolved to the correct version of a java_sdk_library (source or a specific prebuilt)
func TestMultipleSdkLibraryPrebuilts(t *testing.T) {
+ t.Parallel()
bp := `
apex_contributions {
name: "my_mainline_module_contributions",
@@ -1858,3 +1669,150 @@
android.AssertStringListContains(t, "Could not find the expected stub on classpath", inputs, tc.expectedStubPath)
}
}
+
+func TestStubLinkType(t *testing.T) {
+ t.Parallel()
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(
+ `module "baz" variant "android_common": compiles against system API, but dependency `+
+ `"bar.stubs.system" is compiling against module API. In order to fix this, `+
+ `consider adjusting sdk_version: OR platform_apis: property of the source or `+
+ `target module so that target module is built with the same or smaller API set `+
+ `when compared to the source.`),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ }
+ java_library {
+ name: "bar.stubs.system",
+ srcs: ["a.java"],
+ sdk_version: "module_current",
+ is_stubs_module: false,
+ }
+
+ java_library {
+ name: "baz",
+ srcs: ["b.java"],
+ libs: [
+ "foo.stubs.system",
+ "bar.stubs.system",
+ ],
+ sdk_version: "system_current",
+ }
+ `)
+}
+
+func TestSdkLibDirectDependency(t *testing.T) {
+ t.Parallel()
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo", "bar"),
+ ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern([]string{
+ `module "baz" variant "android_common": cannot depend directly on java_sdk_library ` +
+ `"foo"; try depending on "foo.stubs", or "foo.impl" instead`,
+ `module "baz" variant "android_common": cannot depend directly on java_sdk_library ` +
+ `"prebuilt_bar"; try depending on "bar.stubs", or "bar.impl" instead`,
+ }),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ public: {
+ enabled: true,
+ },
+ }
+
+ java_sdk_library_import {
+ name: "foo",
+ public: {
+ jars: ["a.jar"],
+ stub_srcs: ["a.java"],
+ current_api: "current.txt",
+ removed_api: "removed.txt",
+ annotations: "annotations.zip",
+ },
+ }
+
+ java_sdk_library {
+ name: "bar",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ public: {
+ enabled: true,
+ },
+ }
+
+ java_sdk_library_import {
+ name: "bar",
+ prefer: true,
+ public: {
+ jars: ["a.jar"],
+ stub_srcs: ["a.java"],
+ current_api: "current.txt",
+ removed_api: "removed.txt",
+ annotations: "annotations.zip",
+ },
+ }
+
+ java_library {
+ name: "baz",
+ srcs: ["b.java"],
+ libs: [
+ "foo",
+ "bar",
+ ],
+ }
+ `)
+}
+
+func TestSdkLibDirectDependencyWithPrebuiltSdk(t *testing.T) {
+ t.Parallel()
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Platform_sdk_version = intPtr(34)
+ variables.Platform_sdk_codename = stringPtr("VanillaIceCream")
+ variables.Platform_version_active_codenames = []string{"VanillaIceCream"}
+ variables.Platform_systemsdk_versions = []string{"33", "34", "VanillaIceCream"}
+ variables.DeviceSystemSdkVersions = []string{"VanillaIceCream"}
+ }),
+ FixtureWithPrebuiltApis(map[string][]string{
+ "33": {"foo"},
+ "34": {"foo"},
+ "35": {"foo"},
+ }),
+ ).ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(
+ `module "baz" variant "android_common": cannot depend directly on java_sdk_library "foo"; `+
+ `try depending on "sdk_public_33_foo", "sdk_system_33_foo", "sdk_test_33_foo", `+
+ `"sdk_module-lib_33_foo", or "sdk_system-server_33_foo" instead`),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ public: {
+ enabled: true,
+ },
+ system: {
+ enabled: true,
+ },
+ }
+
+ java_library {
+ name: "baz",
+ srcs: ["b.java"],
+ libs: [
+ "foo",
+ ],
+ sdk_version: "system_33",
+ }
+ `)
+}
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 2dac27a..e926307 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -53,6 +53,7 @@
}
func TestClasspath(t *testing.T) {
+ t.Parallel()
const frameworkAidl = "-I" + defaultJavaDir + "/framework/aidl"
var classpathTestcases = []classpathTestCase{
{
@@ -388,18 +389,23 @@
},
}
- t.Parallel()
t.Run("basic", func(t *testing.T) {
t.Parallel()
- testClasspathTestCases(t, classpathTestcases, false)
+ testClasspathTestCases(t, classpathTestcases, false, false)
})
t.Run("Always_use_prebuilt_sdks=true", func(t *testing.T) {
- testClasspathTestCases(t, classpathTestcases, true)
+ t.Parallel()
+ testClasspathTestCases(t, classpathTestcases, true, false)
+ })
+
+ t.Run("UseTransitiveJarsInClasspath", func(t *testing.T) {
+ t.Parallel()
+ testClasspathTestCases(t, classpathTestcases, false, true)
})
}
-func testClasspathTestCases(t *testing.T, classpathTestcases []classpathTestCase, alwaysUsePrebuiltSdks bool) {
+func testClasspathTestCases(t *testing.T, classpathTestcases []classpathTestCase, alwaysUsePrebuiltSdks, useTransitiveJarsInClasspath bool) {
for _, testcase := range classpathTestcases {
if testcase.forAlwaysUsePrebuiltSdks != nil && *testcase.forAlwaysUsePrebuiltSdks != alwaysUsePrebuiltSdks {
continue
@@ -437,7 +443,14 @@
convertModulesToPaths := func(cp []string) []string {
ret := make([]string, len(cp))
for i, e := range cp {
- ret[i] = defaultModuleToPath(e)
+ switch {
+ case e == `""`, strings.HasSuffix(e, ".jar"):
+ ret[i] = e
+ case useTransitiveJarsInClasspath:
+ ret[i] = filepath.Join("out", "soong", ".intermediates", defaultJavaDir, e, "android_common", "turbine", e+".jar")
+ default:
+ ret[i] = filepath.Join("out", "soong", ".intermediates", defaultJavaDir, e, "android_common", "turbine-combined", e+".jar")
+ }
}
return ret
}
@@ -531,6 +544,9 @@
variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
})
}
+ if useTransitiveJarsInClasspath {
+ preparer = PrepareForTestWithTransitiveClasspathEnabled
+ }
fixtureFactory := android.GroupFixturePreparers(
prepareForJavaTest,
@@ -557,6 +573,7 @@
// Test with legacy javac -source 1.8 -target 1.8
t.Run("Java language level 8", func(t *testing.T) {
+ t.Parallel()
result := fixtureFactory.RunTestWithBp(t, bpJava8)
checkClasspath(t, result, true /* isJava8 */)
@@ -570,6 +587,7 @@
// Test with default javac -source 9 -target 9
t.Run("Java language level 9", func(t *testing.T) {
+ t.Parallel()
result := fixtureFactory.RunTestWithBp(t, bp)
checkClasspath(t, result, false /* isJava8 */)
@@ -588,6 +606,7 @@
// Test again with PLATFORM_VERSION_CODENAME=REL, javac -source 8 -target 8
t.Run("REL + Java language level 8", func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
fixtureFactory, prepareWithPlatformVersionRel).RunTestWithBp(t, bpJava8)
@@ -596,6 +615,7 @@
// Test again with PLATFORM_VERSION_CODENAME=REL, javac -source 9 -target 9
t.Run("REL + Java language level 9", func(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
fixtureFactory, prepareWithPlatformVersionRel).RunTestWithBp(t, bp)
diff --git a/java/sdk_version_test.go b/java/sdk_version_test.go
index 88351d2..6f0370a 100644
--- a/java/sdk_version_test.go
+++ b/java/sdk_version_test.go
@@ -25,6 +25,7 @@
}
func TestSystemSdkFromVendor(t *testing.T) {
+ t.Parallel()
fixtures := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
diff --git a/java/system_modules.go b/java/system_modules.go
index 5b00079..e955aec 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -19,6 +19,7 @@
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/depset"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -127,6 +128,9 @@
OutputDir android.Path
OutputDirDeps android.Paths
+
+ // depset of header jars for this module and all transitive static dependencies
+ TransitiveStaticLibsHeaderJars depset.DepSet[android.Path]
}
var SystemModulesProvider = blueprint.NewProvider[*SystemModulesProviderInfo]()
@@ -149,18 +153,21 @@
func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleContext) {
var jars android.Paths
+ var transitiveStaticLibsHeaderJars []depset.DepSet[android.Path]
ctx.VisitDirectDepsWithTag(systemModulesLibsTag, func(module android.Module) {
if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
jars = append(jars, dep.HeaderJars...)
+ transitiveStaticLibsHeaderJars = append(transitiveStaticLibsHeaderJars, dep.TransitiveStaticLibsHeaderJars)
}
})
system.outputDir, system.outputDeps = TransformJarsToSystemModules(ctx, jars)
android.SetProvider(ctx, SystemModulesProvider, &SystemModulesProviderInfo{
- HeaderJars: jars,
- OutputDir: system.outputDir,
- OutputDirDeps: system.outputDeps,
+ HeaderJars: jars,
+ OutputDir: system.outputDir,
+ OutputDirDeps: system.outputDeps,
+ TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, nil, transitiveStaticLibsHeaderJars),
})
}
@@ -307,7 +314,7 @@
// implement the following interface for IDE completion.
var _ android.IDEInfo = (*SystemModules)(nil)
-func (s *SystemModules) IDEInfo(ideInfo *android.IdeInfo) {
+func (s *SystemModules) IDEInfo(ctx android.BaseModuleContext, ideInfo *android.IdeInfo) {
ideInfo.Deps = append(ideInfo.Deps, s.properties.Libs...)
ideInfo.Libs = append(ideInfo.Libs, s.properties.Libs...)
}
diff --git a/java/system_modules_test.go b/java/system_modules_test.go
index b05b0e4..b7a99b5 100644
--- a/java/system_modules_test.go
+++ b/java/system_modules_test.go
@@ -51,6 +51,7 @@
`)
func TestJavaSystemModules(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(prepareForJavaTest, addSourceSystemModules).RunTest(t)
// check the existence of the source module
@@ -78,6 +79,7 @@
`)
func TestJavaSystemModulesImport(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(prepareForJavaTest, addPrebuiltSystemModules).RunTest(t)
// check the existence of the renamed prebuilt module
@@ -90,6 +92,7 @@
}
func TestJavaSystemModulesMixSourceAndPrebuilt(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForJavaTest,
addSourceSystemModules,
@@ -114,6 +117,7 @@
}
func TestMultipleSystemModulesPrebuilts(t *testing.T) {
+ t.Parallel()
bp := `
// an rdep
java_library {
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index bad2cf1..3176ad9 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -19,6 +19,7 @@
"android/soong/dexpreopt"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
)
func init() {
@@ -98,12 +99,12 @@
// List of system_server classpath jars, could be either java_library, or java_sdk_library.
//
// The order of this list matters as it is the order that is used in the SYSTEMSERVERCLASSPATH.
- Contents []string
+ Contents proptools.Configurable[[]string] `android:"arch_variant"`
// List of jars that system_server loads dynamically using separate classloaders.
//
// The order does not matter.
- Standalone_contents []string
+ Standalone_contents proptools.Configurable[[]string] `android:"arch_variant"`
}
func systemServerClasspathFactory() android.Module {
@@ -116,7 +117,7 @@
}
func (s *SystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- if len(s.properties.Contents) == 0 && len(s.properties.Standalone_contents) == 0 {
+ if len(s.properties.Contents.GetOrDefault(ctx, nil)) == 0 && len(s.properties.Standalone_contents.GetOrDefault(ctx, nil)) == 0 {
ctx.PropertyErrorf("contents", "Either contents or standalone_contents needs to be non-empty")
}
@@ -127,12 +128,32 @@
configuredJars = configuredJars.AppendList(&standaloneConfiguredJars)
classpathJars = append(classpathJars, standaloneClasspathJars...)
s.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars)
+ s.setPartitionInfoOfLibraries(ctx)
+}
+
+// Map of java library name to their install partition.
+type LibraryNameToPartitionInfo struct {
+ LibraryNameToPartition map[string]string
+}
+
+// LibraryNameToPartitionInfoProvider will be used by the top-level apex to enforce that dexpreopt files
+// of apex system server jars are installed in the same partition as the top-level apex.
+var LibraryNameToPartitionInfoProvider = blueprint.NewProvider[LibraryNameToPartitionInfo]()
+
+func (s *SystemServerClasspathModule) setPartitionInfoOfLibraries(ctx android.ModuleContext) {
+ libraryNameToPartition := map[string]string{}
+ ctx.VisitDirectDepsWithTag(systemServerClasspathFragmentContentDepTag, func(m android.Module) {
+ libraryNameToPartition[m.Name()] = m.PartitionTag(ctx.DeviceConfig())
+ })
+ android.SetProvider(ctx, LibraryNameToPartitionInfoProvider, LibraryNameToPartitionInfo{
+ LibraryNameToPartition: libraryNameToPartition,
+ })
}
func (s *SystemServerClasspathModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList {
global := dexpreopt.GetGlobalConfig(ctx)
- possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, s.properties.Contents, systemServerClasspathFragmentContentDepTag)
+ possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, s.properties.Contents.GetOrDefault(ctx, nil), systemServerClasspathFragmentContentDepTag)
jars, unknown := global.ApexSystemServerJars.Filter(possibleUpdatableModules)
// TODO(satayev): remove geotz ssc_fragment, since geotz is not part of SSCP anymore.
_, unknown = android.RemoveFromList("geotz", unknown)
@@ -164,7 +185,7 @@
func (s *SystemServerClasspathModule) standaloneConfiguredJars(ctx android.ModuleContext) android.ConfiguredJarList {
global := dexpreopt.GetGlobalConfig(ctx)
- possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, s.properties.Standalone_contents, systemServerClasspathFragmentContentDepTag)
+ possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, s.properties.Standalone_contents.GetOrDefault(ctx, nil), systemServerClasspathFragmentContentDepTag)
jars, _ := global.ApexStandaloneSystemServerJars.Filter(possibleUpdatableModules)
// TODO(jiakaiz): add a check to ensure that the contents are declared in make.
@@ -197,16 +218,11 @@
return true
}
-// Contents of system server fragments in an apex are considered to be directly in the apex, as if
-// they were listed in java_libs.
-func (systemServerClasspathFragmentContentDependencyTag) CopyDirectlyInAnyApex() {}
-
// Contents of system server fragments require files from prebuilt apex files.
func (systemServerClasspathFragmentContentDependencyTag) RequiresFilesFromPrebuiltApex() {}
var _ android.ReplaceSourceWithPrebuilt = systemServerClasspathFragmentContentDepTag
var _ android.SdkMemberDependencyTag = systemServerClasspathFragmentContentDepTag
-var _ android.CopyDirectlyInAnyApexTag = systemServerClasspathFragmentContentDepTag
var _ android.RequiresFilesFromPrebuiltApexTag = systemServerClasspathFragmentContentDepTag
// The tag used for the dependency between the systemserverclasspath_fragment module and its contents.
@@ -216,12 +232,17 @@
return tag == systemServerClasspathFragmentContentDepTag
}
+// The dexpreopt artifacts of apex system server jars are installed onto system image.
+func (s systemServerClasspathFragmentContentDependencyTag) InstallDepNeeded() bool {
+ return true
+}
+
func (s *SystemServerClasspathModule) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
module := ctx.Module()
_, isSourceModule := module.(*SystemServerClasspathModule)
var deps []string
- deps = append(deps, s.properties.Contents...)
- deps = append(deps, s.properties.Standalone_contents...)
+ deps = append(deps, s.properties.Contents.GetOrDefault(ctx, nil)...)
+ deps = append(deps, s.properties.Standalone_contents.GetOrDefault(ctx, nil)...)
for _, name := range deps {
// A systemserverclasspath_fragment must depend only on other source modules, while the
@@ -234,9 +255,9 @@
}
// Collect information for opening IDE project files in java/jdeps.go.
-func (s *SystemServerClasspathModule) IDEInfo(dpInfo *android.IdeInfo) {
- dpInfo.Deps = append(dpInfo.Deps, s.properties.Contents...)
- dpInfo.Deps = append(dpInfo.Deps, s.properties.Standalone_contents...)
+func (s *SystemServerClasspathModule) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
+ dpInfo.Deps = append(dpInfo.Deps, s.properties.Contents.GetOrDefault(ctx, nil)...)
+ dpInfo.Deps = append(dpInfo.Deps, s.properties.Standalone_contents.GetOrDefault(ctx, nil)...)
}
type systemServerClasspathFragmentMemberType struct {
@@ -277,8 +298,8 @@
func (s *systemServerClasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
module := variant.(*SystemServerClasspathModule)
- s.Contents = module.properties.Contents
- s.Standalone_contents = module.properties.Standalone_contents
+ s.Contents = module.properties.Contents.GetOrDefault(ctx.SdkModuleContext(), nil)
+ s.Standalone_contents = module.properties.Standalone_contents.GetOrDefault(ctx.SdkModuleContext(), nil)
}
func (s *systemServerClasspathFragmentSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
diff --git a/java/systemserver_classpath_fragment_test.go b/java/systemserver_classpath_fragment_test.go
index ba328e7..704f5a4 100644
--- a/java/systemserver_classpath_fragment_test.go
+++ b/java/systemserver_classpath_fragment_test.go
@@ -25,6 +25,7 @@
)
func TestPlatformSystemServerClasspathVariant(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithSystemServerClasspath,
android.FixtureWithRootAndroidBp(`
@@ -39,6 +40,7 @@
}
func TestPlatformSystemServerClasspath_ClasspathFragmentPaths(t *testing.T) {
+ t.Parallel()
result := android.GroupFixturePreparers(
prepareForTestWithSystemServerClasspath,
android.FixtureWithRootAndroidBp(`
@@ -50,10 +52,11 @@
p := result.Module("platform-systemserverclasspath", "android_common").(*platformSystemServerClasspathModule)
android.AssertStringEquals(t, "output filepath", "systemserverclasspath.pb", p.ClasspathFragmentBase.outputFilepath.Base())
- android.AssertPathRelativeToTopEquals(t, "install filepath", "out/soong/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath)
+ android.AssertPathRelativeToTopEquals(t, "install filepath", "out/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath)
}
func TestPlatformSystemServerClasspathModule_AndroidMkEntries(t *testing.T) {
+ t.Parallel()
preparer := android.GroupFixturePreparers(
prepareForTestWithSystemServerClasspath,
android.FixtureWithRootAndroidBp(`
@@ -97,6 +100,7 @@
}
func TestSystemServerClasspathFragmentWithoutContents(t *testing.T) {
+ t.Parallel()
prepareForTestWithSystemServerClasspath.
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
`\QEither contents or standalone_contents needs to be non-empty\E`)).
diff --git a/java/test_spec_test.go b/java/test_spec_test.go
deleted file mode 100644
index f0a5fdb..0000000
--- a/java/test_spec_test.go
+++ /dev/null
@@ -1,122 +0,0 @@
-package java
-
-import (
- "strings"
- "testing"
-
- "android/soong/android"
- soongTesting "android/soong/testing"
- "android/soong/testing/test_spec_proto"
- "google.golang.org/protobuf/proto"
-)
-
-func TestTestSpec(t *testing.T) {
- bp := `test_spec {
- name: "module-name",
- teamId: "12345",
- tests: [
- "java-test-module-name-one",
- "java-test-module-name-two"
- ]
- }
-
- java_test {
- name: "java-test-module-name-one",
- }
-
- java_test {
- name: "java-test-module-name-two",
- }`
- result := runTestSpecTest(t, android.FixtureExpectsNoErrors, bp)
-
- module := result.ModuleForTests("module-name", "")
-
- // Check that the provider has the right contents
- data, _ := android.OtherModuleProvider(result, module.Module(), soongTesting.TestSpecProviderKey)
- if !strings.HasSuffix(
- data.IntermediatePath.String(), "/intermediateTestSpecMetadata.pb",
- ) {
- t.Errorf(
- "Missing intermediates path in provider: %s",
- data.IntermediatePath.String(),
- )
- }
-
- metadata := android.ContentFromFileRuleForTests(t, result.TestContext,
- module.Output(data.IntermediatePath.String()))
-
- metadataList := make([]*test_spec_proto.TestSpec_OwnershipMetadata, 0, 2)
- teamId := "12345"
- bpFilePath := "Android.bp"
- targetNames := []string{
- "java-test-module-name-one", "java-test-module-name-two",
- }
-
- for _, test := range targetNames {
- targetName := test
- metadata := test_spec_proto.TestSpec_OwnershipMetadata{
- TrendyTeamId: &teamId,
- TargetName: &targetName,
- Path: &bpFilePath,
- }
- metadataList = append(metadataList, &metadata)
- }
- testSpecMetadata := test_spec_proto.TestSpec{OwnershipMetadataList: metadataList}
- protoData, _ := proto.Marshal(&testSpecMetadata)
- expectedMetadata := string(protoData)
-
- if metadata != expectedMetadata {
- t.Errorf(
- "Retrieved metadata: %s doesn't contain expectedMetadata: %s", metadata,
- expectedMetadata,
- )
- }
-
- // Tests for all_test_spec singleton.
- singleton := result.SingletonForTests("all_test_specs")
- rule := singleton.Rule("all_test_specs_rule")
- prebuiltOs := result.Config.PrebuiltOS()
- expectedCmd := "out/soong/host/" + prebuiltOs + "/bin/metadata -rule test_spec -inputFile out/soong/all_test_spec_paths.rsp -outputFile out/soong/ownership/all_test_specs.pb"
- expectedOutputFile := "out/soong/ownership/all_test_specs.pb"
- expectedInputFile := "out/soong/.intermediates/module-name/intermediateTestSpecMetadata.pb"
- if !strings.Contains(
- strings.TrimSpace(rule.Output.String()),
- expectedOutputFile,
- ) {
- t.Errorf(
- "Retrieved singletonOutputFile: %s is not equal to expectedSingletonOutputFile: %s",
- rule.Output.String(), expectedOutputFile,
- )
- }
-
- if !strings.Contains(
- strings.TrimSpace(rule.Inputs[0].String()),
- expectedInputFile,
- ) {
- t.Errorf(
- "Retrieved singletonInputFile: %s is not equal to expectedSingletonInputFile: %s",
- rule.Inputs[0].String(), expectedInputFile,
- )
- }
-
- if !strings.Contains(
- strings.TrimSpace(rule.RuleParams.Command),
- expectedCmd,
- ) {
- t.Errorf(
- "Retrieved cmd: %s is not equal to expectedCmd: %s",
- rule.RuleParams.Command, expectedCmd,
- )
- }
-}
-
-func runTestSpecTest(
- t *testing.T, errorHandler android.FixtureErrorHandler, bp string,
-) *android.TestResult {
- return android.GroupFixturePreparers(
- soongTesting.PrepareForTestWithTestingBuildComponents,
- PrepareForIntegrationTestWithJava,
- ).
- ExtendWithErrorHandler(errorHandler).
- RunTestWithBp(t, bp)
-}
diff --git a/java/testing.go b/java/testing.go
index 0e85022..0ea4e64 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -30,6 +30,7 @@
)
const defaultJavaDir = "default/java"
+const testDefaultUpdatableModuleVersion = "340090000"
// Test fixture preparer that will register most java build components.
//
@@ -61,6 +62,7 @@
// Needed for the global lint checks provided from frameworks/base
"prebuilts/cmdline-tools/AndroidGlobalLintChecker.jar": nil,
}.AddToFixture(),
+ android.PrepareForTestWithBuildFlag("RELEASE_DEFAULT_UPDATABLE_MODULE_VERSION", testDefaultUpdatableModuleVersion),
)
var prepareForTestWithFrameworkDeps = android.GroupFixturePreparers(
@@ -184,6 +186,11 @@
host_supported: true,
srcs: ["Test.java"],
sdk_version: "current",
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
+ compile_dex: true,
}
`)),
)
@@ -384,7 +391,6 @@
RegisterStubsBuildComponents(ctx)
RegisterSystemModulesBuildComponents(ctx)
registerSystemserverClasspathBuildComponents(ctx)
- registerLintBuildComponents(ctx)
android.RegisterApexContributionsBuildComponents(ctx)
}
@@ -408,7 +414,6 @@
"core.current.stubs",
"legacy.core.platform.api.stubs",
"stable.core.platform.api.stubs",
-
"android_stubs_current_exportable",
"android_system_stubs_current_exportable",
"android_test_stubs_current_exportable",
@@ -416,7 +421,6 @@
"android_system_server_stubs_current_exportable",
"core.current.stubs.exportable",
"legacy.core.platform.api.stubs.exportable",
-
"kotlin-stdlib",
"kotlin-stdlib-jdk7",
"kotlin-stdlib-jdk8",
@@ -424,6 +428,7 @@
"stub-annotations",
"aconfig-annotations-lib",
+ "aconfig_storage_stub",
"unsupportedappusage",
}
@@ -435,6 +440,7 @@
sdk_version: "none",
system_modules: "stable-core-platform-api-stubs-system-modules",
compile_dex: true,
+ is_stubs_module: true,
}
`, extra)
}
@@ -579,6 +585,7 @@
name: "%[1]s-lib",
sdk_version: "none",
system_modules: "none",
+ srcs: ["a.java"],
}
`, extra)
}
@@ -630,6 +637,18 @@
return false
}
+// CheckModuleHasDependency returns true if the module depends on the expected dependency.
+func CheckModuleHasDependencyWithTag(t *testing.T, ctx *android.TestContext, name, variant string, desiredTag blueprint.DependencyTag, expected string) bool {
+ module := ctx.ModuleForTests(name, variant).Module()
+ found := false
+ ctx.VisitDirectDepsWithTags(module, func(m blueprint.Module, tag blueprint.DependencyTag) {
+ if tag == desiredTag && m.Name() == expected {
+ found = true
+ }
+ })
+ return found
+}
+
// CheckPlatformBootclasspathModules returns the apex:module pair for the modules depended upon by
// the platform-bootclasspath module.
func CheckPlatformBootclasspathModules(t *testing.T, result *android.TestResult, name string, expected []string) {
@@ -778,3 +797,5 @@
config.installDir = installDir
})
}
+
+var PrepareForTestWithTransitiveClasspathEnabled = android.PrepareForTestWithBuildFlag("RELEASE_USE_TRANSITIVE_JARS_IN_CLASSPATH", "true")
diff --git a/kernel/prebuilt_kernel_modules.go b/kernel/prebuilt_kernel_modules.go
index e200ee2..1225da0 100644
--- a/kernel/prebuilt_kernel_modules.go
+++ b/kernel/prebuilt_kernel_modules.go
@@ -32,7 +32,7 @@
}
func registerKernelBuildComponents(ctx android.RegistrationContext) {
- ctx.RegisterModuleType("prebuilt_kernel_modules", prebuiltKernelModulesFactory)
+ ctx.RegisterModuleType("prebuilt_kernel_modules", PrebuiltKernelModulesFactory)
}
type prebuiltKernelModules struct {
@@ -47,18 +47,36 @@
// List or filegroup of prebuilt kernel module files. Should have .ko suffix.
Srcs []string `android:"path,arch_variant"`
+ // List of system_dlkm kernel modules that the local kernel modules depend on.
+ // The deps will be assembled into intermediates directory for running depmod
+ // but will not be added to the current module's installed files.
+ System_deps []string `android:"path,arch_variant"`
+
+ // If false, then srcs will not be included in modules.load.
+ // This feature is used by system_dlkm
+ Load_by_default *bool
+
+ Blocklist_file *string `android:"path"`
+
+ // Path to the kernel module options file
+ Options_file *string `android:"path"`
+
// Kernel version that these modules are for. Kernel modules are installed to
// /lib/modules/<kernel_version> directory in the corresponding partition. Default is "".
Kernel_version *string
// Whether this module is directly installable to one of the partitions. Default is true
Installable *bool
+
+ // Whether debug symbols should be stripped from the *.ko files.
+ // Defaults to true.
+ Strip_debug_symbols *bool
}
// prebuilt_kernel_modules installs a set of prebuilt kernel module files to the correct directory.
// In addition, this module builds modules.load, modules.dep, modules.softdep and modules.alias
// using depmod and installs them as well.
-func prebuiltKernelModulesFactory() android.Module {
+func PrebuiltKernelModulesFactory() android.Module {
module := &prebuiltKernelModules{}
module.AddProperties(&module.properties)
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
@@ -81,23 +99,66 @@
if !pkm.installable() {
pkm.SkipInstall()
}
- modules := android.PathsForModuleSrc(ctx, pkm.properties.Srcs)
- depmodOut := runDepmod(ctx, modules)
- strippedModules := stripDebugSymbols(ctx, modules)
+ modules := android.PathsForModuleSrc(ctx, pkm.properties.Srcs)
+ systemModules := android.PathsForModuleSrc(ctx, pkm.properties.System_deps)
+
+ depmodOut := pkm.runDepmod(ctx, modules, systemModules)
+ if proptools.BoolDefault(pkm.properties.Strip_debug_symbols, true) {
+ modules = stripDebugSymbols(ctx, modules)
+ }
installDir := android.PathForModuleInstall(ctx, "lib", "modules")
+ // Kernel module is installed to vendor_ramdisk/lib/modules regardless of product
+ // configuration. This matches the behavior in make and prevents the files from being
+ // installed in `vendor_ramdisk/first_stage_ramdisk`.
+ if pkm.InstallInVendorRamdisk() {
+ installDir = android.PathForModuleInPartitionInstall(ctx, "vendor_ramdisk", "lib", "modules")
+ }
+
if pkm.KernelVersion() != "" {
installDir = installDir.Join(ctx, pkm.KernelVersion())
}
- for _, m := range strippedModules {
+ for _, m := range modules {
ctx.InstallFile(installDir, filepath.Base(m.String()), m)
}
ctx.InstallFile(installDir, "modules.load", depmodOut.modulesLoad)
ctx.InstallFile(installDir, "modules.dep", depmodOut.modulesDep)
ctx.InstallFile(installDir, "modules.softdep", depmodOut.modulesSoftdep)
ctx.InstallFile(installDir, "modules.alias", depmodOut.modulesAlias)
+ pkm.installBlocklistFile(ctx, installDir)
+ pkm.installOptionsFile(ctx, installDir)
+
+ ctx.SetOutputFiles(modules, ".modules")
+}
+
+func (pkm *prebuiltKernelModules) installBlocklistFile(ctx android.ModuleContext, installDir android.InstallPath) {
+ if pkm.properties.Blocklist_file == nil {
+ return
+ }
+ blocklistOut := android.PathForModuleOut(ctx, "modules.blocklist")
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: processBlocklistFile,
+ Input: android.PathForModuleSrc(ctx, proptools.String(pkm.properties.Blocklist_file)),
+ Output: blocklistOut,
+ })
+ ctx.InstallFile(installDir, "modules.blocklist", blocklistOut)
+}
+
+func (pkm *prebuiltKernelModules) installOptionsFile(ctx android.ModuleContext, installDir android.InstallPath) {
+ if pkm.properties.Options_file == nil {
+ return
+ }
+ optionsOut := android.PathForModuleOut(ctx, "modules.options")
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: processOptionsFile,
+ Input: android.PathForModuleSrc(ctx, proptools.String(pkm.properties.Options_file)),
+ Output: optionsOut,
+ })
+ ctx.InstallFile(installDir, "modules.options", optionsOut)
}
var (
@@ -110,9 +171,9 @@
}, "stripCmd")
)
-func stripDebugSymbols(ctx android.ModuleContext, modules android.Paths) android.OutputPaths {
+func stripDebugSymbols(ctx android.ModuleContext, modules android.Paths) android.Paths {
dir := android.PathForModuleOut(ctx, "stripped").OutputPath
- var outputs android.OutputPaths
+ var outputs android.Paths
for _, m := range modules {
stripped := dir.Join(ctx, filepath.Base(m.String()))
@@ -137,35 +198,108 @@
modulesAlias android.OutputPath
}
-func runDepmod(ctx android.ModuleContext, modules android.Paths) depmodOutputs {
+var (
+ // system/lib/modules/foo.ko: system/lib/modules/bar.ko
+ // will be converted to
+ // /system/lib/modules/foo.ko: /system/lib/modules/bar.ko
+ addLeadingSlashToPaths = pctx.AndroidStaticRule("add_leading_slash",
+ blueprint.RuleParams{
+ Command: `sed -e 's|\([^: ]*lib/modules/[^: ]*\)|/\1|g' $in > $out`,
+ },
+ )
+ // Remove empty lines. Raise an exception if line is _not_ formatted as `blocklist $name.ko`
+ processBlocklistFile = pctx.AndroidStaticRule("process_blocklist_file",
+ blueprint.RuleParams{
+ Command: `rm -rf $out && awk <$in > $out` +
+ ` '/^#/ { print; next }` +
+ ` NF == 0 { next }` +
+ ` NF != 2 || $$1 != "blocklist"` +
+ ` { print "Invalid blocklist line " FNR ": " $$0 >"/dev/stderr";` +
+ ` exit_status = 1; next }` +
+ ` { $$1 = $$1; print }` +
+ ` END { exit exit_status }'`,
+ },
+ )
+ // Remove empty lines. Raise an exception if line is _not_ formatted as `options $name.ko`
+ processOptionsFile = pctx.AndroidStaticRule("process_options_file",
+ blueprint.RuleParams{
+ Command: `rm -rf $out && awk <$in > $out` +
+ ` '/^#/ { print; next }` +
+ ` NF == 0 { next }` +
+ ` NF < 2 || $$1 != "options"` +
+ ` { print "Invalid options line " FNR ": " $$0 >"/dev/stderr";` +
+ ` exit_status = 1; next }` +
+ ` { $$1 = $$1; print }` +
+ ` END { exit exit_status }'`,
+ },
+ )
+)
+
+// This is the path in soong intermediates where the .ko files will be copied.
+// The layout should match the layout on device so that depmod can create meaningful modules.* files.
+func modulesDirForAndroidDlkm(ctx android.ModuleContext, modulesDir android.OutputPath, system bool) android.OutputPath {
+ if ctx.InstallInSystemDlkm() || system {
+ // The first component can be either system or system_dlkm
+ // system works because /system/lib/modules is a symlink to /system_dlkm/lib/modules.
+ // system was chosen to match the contents of the kati built modules.dep
+ return modulesDir.Join(ctx, "system", "lib", "modules")
+ } else if ctx.InstallInVendorDlkm() {
+ return modulesDir.Join(ctx, "vendor", "lib", "modules")
+ } else if ctx.InstallInOdmDlkm() {
+ return modulesDir.Join(ctx, "odm", "lib", "modules")
+ } else if ctx.InstallInVendorRamdisk() {
+ return modulesDir.Join(ctx, "lib", "modules")
+ } else {
+ // not an android dlkm module.
+ return modulesDir
+ }
+}
+
+func (pkm *prebuiltKernelModules) runDepmod(ctx android.ModuleContext, modules android.Paths, systemModules android.Paths) depmodOutputs {
baseDir := android.PathForModuleOut(ctx, "depmod").OutputPath
fakeVer := "0.0" // depmod demands this anyway
modulesDir := baseDir.Join(ctx, "lib", "modules", fakeVer)
+ modulesCpDir := modulesDirForAndroidDlkm(ctx, modulesDir, false)
builder := android.NewRuleBuilder(pctx, ctx)
// Copy the module files to a temporary dir
- builder.Command().Text("rm").Flag("-rf").Text(modulesDir.String())
- builder.Command().Text("mkdir").Flag("-p").Text(modulesDir.String())
+ builder.Command().Text("rm").Flag("-rf").Text(modulesCpDir.String())
+ builder.Command().Text("mkdir").Flag("-p").Text(modulesCpDir.String())
for _, m := range modules {
- builder.Command().Text("cp").Input(m).Text(modulesDir.String())
+ builder.Command().Text("cp").Input(m).Text(modulesCpDir.String())
+ }
+
+ modulesDirForSystemDlkm := modulesDirForAndroidDlkm(ctx, modulesDir, true)
+ if len(systemModules) > 0 {
+ builder.Command().Text("mkdir").Flag("-p").Text(modulesDirForSystemDlkm.String())
+ }
+ for _, m := range systemModules {
+ builder.Command().Text("cp").Input(m).Text(modulesDirForSystemDlkm.String())
}
// Enumerate modules to load
modulesLoad := modulesDir.Join(ctx, "modules.load")
- var basenames []string
- for _, m := range modules {
- basenames = append(basenames, filepath.Base(m.String()))
+ // If Load_by_default is set to false explicitly, create an empty modules.load
+ if pkm.properties.Load_by_default != nil && !*pkm.properties.Load_by_default {
+ builder.Command().Text("rm").Flag("-rf").Text(modulesLoad.String())
+ builder.Command().Text("touch").Output(modulesLoad)
+ } else {
+ var basenames []string
+ for _, m := range modules {
+ basenames = append(basenames, filepath.Base(m.String()))
+ }
+ builder.Command().
+ Text("echo").Flag("\"" + strings.Join(basenames, " ") + "\"").
+ Text("|").Text("tr").Flag("\" \"").Flag("\"\\n\"").
+ Text(">").Output(modulesLoad)
}
- builder.Command().
- Text("echo").Flag("\"" + strings.Join(basenames, " ") + "\"").
- Text("|").Text("tr").Flag("\" \"").Flag("\"\\n\"").
- Text(">").Output(modulesLoad)
// Run depmod to build modules.dep/softdep/alias files
modulesDep := modulesDir.Join(ctx, "modules.dep")
modulesSoftdep := modulesDir.Join(ctx, "modules.softdep")
modulesAlias := modulesDir.Join(ctx, "modules.alias")
+ builder.Command().Text("mkdir").Flag("-p").Text(modulesDir.String())
builder.Command().
BuiltTool("depmod").
FlagWithArg("-b ", baseDir.String()).
@@ -176,5 +310,16 @@
builder.Build("depmod", fmt.Sprintf("depmod %s", ctx.ModuleName()))
- return depmodOutputs{modulesLoad, modulesDep, modulesSoftdep, modulesAlias}
+ finalModulesDep := modulesDep
+ // Add a leading slash to paths in modules.dep of android dlkm and vendor ramdisk
+ if ctx.InstallInSystemDlkm() || ctx.InstallInVendorDlkm() || ctx.InstallInOdmDlkm() || ctx.InstallInVendorRamdisk() {
+ finalModulesDep = modulesDep.ReplaceExtension(ctx, "intermediates")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: addLeadingSlashToPaths,
+ Input: modulesDep,
+ Output: finalModulesDep,
+ })
+ }
+
+ return depmodOutputs{modulesLoad, finalModulesDep, modulesSoftdep, modulesAlias}
}
diff --git a/licenses/Android.bp b/licenses/Android.bp
index e4e5da7..f420110 100644
--- a/licenses/Android.bp
+++ b/licenses/Android.bp
@@ -32,6 +32,17 @@
}
license_kind {
+ name: "BSD-Binary-Only",
+ conditions: [
+ "notice",
+ "by_exception_only",
+ "proprietary",
+ ],
+}
+
+// Deprecated. All users of the following license should be changed to
+// BSD-Binary-Only and it should be removed.
+license_kind {
name: "BSD-Like-Binary-Only",
conditions: [
"notice",
diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go
index 533ec62..4f1ef9d 100644
--- a/linkerconfig/linkerconfig.go
+++ b/linkerconfig/linkerconfig.go
@@ -76,9 +76,7 @@
input := android.PathForModuleSrc(ctx, android.String(l.properties.Src))
output := android.PathForModuleOut(ctx, "linker.config.pb").OutputPath
- builder := android.NewRuleBuilder(pctx, ctx)
- BuildLinkerConfig(ctx, builder, input, nil, nil, output)
- builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String())
+ BuildLinkerConfig(ctx, android.Paths{input}, nil, nil, output)
l.outputFilePath = output
l.installDirPath = android.PathForModuleInstall(ctx, "etc")
@@ -90,23 +88,32 @@
ctx.SetOutputFiles(android.Paths{l.outputFilePath}, "")
}
-func BuildLinkerConfig(ctx android.ModuleContext, builder *android.RuleBuilder,
- input android.Path, provideModules []android.Module, requireModules []android.Module, output android.OutputPath) {
-
+func BuildLinkerConfig(
+ ctx android.ModuleContext,
+ inputs android.Paths,
+ provideModules []android.ModuleProxy,
+ requireModules []android.ModuleProxy,
+ output android.WritablePath,
+) {
// First, convert the input json to protobuf format
+ builder := android.NewRuleBuilder(pctx, ctx)
interimOutput := android.PathForModuleOut(ctx, "temp.pb")
- builder.Command().
+ cmd := builder.Command().
BuiltTool("conv_linker_config").
Flag("proto").
- FlagWithInput("-s ", input).
- FlagWithOutput("-o ", interimOutput)
+ Flag("--force")
+ for _, input := range inputs {
+ cmd.FlagWithInput("-s ", input)
+ }
+ cmd.FlagWithOutput("-o ", interimOutput)
// Secondly, if there's provideLibs gathered from provideModules, append them
var provideLibs []string
for _, m := range provideModules {
- if c, ok := m.(*cc.Module); ok && (cc.IsStubTarget(c) || c.HasLlndkStubs()) {
+ ccInfo, ok := android.OtherModuleProvider(ctx, m, cc.CcInfoProvider)
+ if ok && (cc.IsStubTarget(android.OtherModuleProviderOrDefault(ctx, m, cc.LinkableInfoProvider)) || ccInfo.HasLlndkStubs) {
for _, ps := range android.OtherModuleProviderOrDefault(
- ctx, c, android.InstallFilesProvider).PackagingSpecs {
+ ctx, m, android.InstallFilesProvider).PackagingSpecs {
provideLibs = append(provideLibs, ps.FileName())
}
}
@@ -116,8 +123,15 @@
var requireLibs []string
for _, m := range requireModules {
- if c, ok := m.(*cc.Module); ok && c.HasStubsVariants() && !c.Host() {
- requireLibs = append(requireLibs, c.ImplementationModuleName(ctx)+".so")
+ if _, ok := android.OtherModuleProvider(ctx, m, cc.CcInfoProvider); ok {
+ if android.OtherModuleProviderOrDefault(ctx, m, cc.LinkableInfoProvider).HasStubsVariants &&
+ !android.OtherModuleProviderOrDefault(ctx, m, android.CommonModuleInfoKey).Host {
+ name := ctx.OtherModuleName(m)
+ if ccInfo, ok := android.OtherModuleProvider(ctx, m, cc.CcInfoProvider); ok && ccInfo.LinkerInfo != nil && ccInfo.LinkerInfo.ImplementationModuleName != nil {
+ name = *ccInfo.LinkerInfo.ImplementationModuleName
+ }
+ requireLibs = append(requireLibs, name+".so")
+ }
}
}
@@ -154,6 +168,7 @@
builder.Temporary(interimOutput)
builder.DeleteTemporaryFiles()
+ builder.Build("conv_linker_config_"+output.String(), "Generate linker config protobuf "+output.String())
}
// linker_config generates protobuf file from json file. This protobuf file will be used from
diff --git a/linkerconfig/proto/Android.bp b/linkerconfig/proto/Android.bp
index 754e7bf..a930502 100644
--- a/linkerconfig/proto/Android.bp
+++ b/linkerconfig/proto/Android.bp
@@ -15,6 +15,7 @@
"//apex_available:platform",
"//apex_available:anyapex",
],
+ visibility: ["//system/linkerconfig"],
}
python_library_host {
diff --git a/multitree/Android.bp b/multitree/Android.bp
deleted file mode 100644
index 78c4962..0000000
--- a/multitree/Android.bp
+++ /dev/null
@@ -1,20 +0,0 @@
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-bootstrap_go_package {
- name: "soong-multitree",
- pkgPath: "android/soong/multitree",
- deps: [
- "blueprint",
- "soong-android",
- ],
- srcs: [
- "api_imports.go",
- "api_surface.go",
- "export.go",
- "metadata.go",
- "import.go",
- ],
- pluginFor: ["soong_build"],
-}
diff --git a/multitree/api_imports.go b/multitree/api_imports.go
deleted file mode 100644
index 51b9e07..0000000
--- a/multitree/api_imports.go
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package multitree
-
-import (
- "android/soong/android"
- "strings"
-
- "github.com/google/blueprint"
-)
-
-var (
- apiImportNameSuffix = ".apiimport"
-)
-
-func init() {
- RegisterApiImportsModule(android.InitRegistrationContext)
- android.RegisterMakeVarsProvider(pctx, makeVarsProvider)
-}
-
-func RegisterApiImportsModule(ctx android.RegistrationContext) {
- ctx.RegisterModuleType("api_imports", apiImportsFactory)
-}
-
-type ApiImports struct {
- android.ModuleBase
- properties apiImportsProperties
-}
-
-type apiImportsProperties struct {
- Shared_libs []string // List of C shared libraries from API surfaces
- Header_libs []string // List of C header libraries from API surfaces
- Apex_shared_libs []string // List of C shared libraries with APEX stubs
-}
-
-// 'api_imports' is a module which describes modules available from API surfaces.
-// This module is required to get the list of all imported API modules, because
-// it is discouraged to loop and fetch all modules from its type information. The
-// only module with name 'api_imports' will be used from the build.
-func apiImportsFactory() android.Module {
- module := &ApiImports{}
- module.AddProperties(&module.properties)
- android.InitAndroidModule(module)
- return module
-}
-
-func (imports *ApiImports) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- // ApiImport module does not generate any build actions
-}
-
-type ApiImportInfo struct {
- SharedLibs, HeaderLibs, ApexSharedLibs map[string]string
-}
-
-var ApiImportsProvider = blueprint.NewMutatorProvider[ApiImportInfo]("deps")
-
-// Store module lists into ApiImportInfo and share it over mutator provider.
-func (imports *ApiImports) DepsMutator(ctx android.BottomUpMutatorContext) {
- generateNameMapWithSuffix := func(names []string) map[string]string {
- moduleNameMap := make(map[string]string)
- for _, name := range names {
- moduleNameMap[name] = name + apiImportNameSuffix
- }
-
- return moduleNameMap
- }
-
- sharedLibs := generateNameMapWithSuffix(imports.properties.Shared_libs)
- headerLibs := generateNameMapWithSuffix(imports.properties.Header_libs)
- apexSharedLibs := generateNameMapWithSuffix(imports.properties.Apex_shared_libs)
-
- android.SetProvider(ctx, ApiImportsProvider, ApiImportInfo{
- SharedLibs: sharedLibs,
- HeaderLibs: headerLibs,
- ApexSharedLibs: apexSharedLibs,
- })
-}
-
-func GetApiImportSuffix() string {
- return apiImportNameSuffix
-}
-
-func makeVarsProvider(ctx android.MakeVarsContext) {
- ctx.VisitAllModules(func(m android.Module) {
- if i, ok := m.(*ApiImports); ok {
- ctx.Strict("API_IMPORTED_SHARED_LIBRARIES", strings.Join(i.properties.Shared_libs, " "))
- ctx.Strict("API_IMPORTED_HEADER_LIBRARIES", strings.Join(i.properties.Header_libs, " "))
- }
- })
-}
diff --git a/multitree/api_surface.go b/multitree/api_surface.go
deleted file mode 100644
index 0f605d8..0000000
--- a/multitree/api_surface.go
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package multitree
-
-import (
- "android/soong/android"
- "github.com/google/blueprint"
-)
-
-var (
- pctx = android.NewPackageContext("android/soong/multitree")
-)
-
-func init() {
- RegisterApiSurfaceBuildComponents(android.InitRegistrationContext)
-}
-
-var PrepareForTestWithApiSurface = android.FixtureRegisterWithContext(RegisterApiSurfaceBuildComponents)
-
-func RegisterApiSurfaceBuildComponents(ctx android.RegistrationContext) {
- ctx.RegisterModuleType("api_surface", ApiSurfaceFactory)
-}
-
-type ApiSurface struct {
- android.ModuleBase
- ExportableModuleBase
- properties apiSurfaceProperties
-
- taggedOutputs map[string]android.Paths
-}
-
-type apiSurfaceProperties struct {
- Contributions []string
-}
-
-func ApiSurfaceFactory() android.Module {
- module := &ApiSurface{}
- module.AddProperties(&module.properties)
- android.InitAndroidModule(module)
- InitExportableModule(module)
- return module
-}
-
-func (surface *ApiSurface) DepsMutator(ctx android.BottomUpMutatorContext) {
- if surface.properties.Contributions != nil {
- ctx.AddVariationDependencies(nil, nil, surface.properties.Contributions...)
- }
-
-}
-func (surface *ApiSurface) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- contributionFiles := make(map[string]android.Paths)
- var allOutputs android.Paths
- ctx.WalkDeps(func(child, parent android.Module) bool {
- if contribution, ok := child.(ApiContribution); ok {
- copied := contribution.CopyFilesWithTag(ctx)
- for tag, files := range copied {
- contributionFiles[child.Name()+"#"+tag] = files
- }
- for _, paths := range copied {
- allOutputs = append(allOutputs, paths...)
- }
- return false // no transitive dependencies
- }
- return false
- })
-
- // phony target
- ctx.Build(pctx, android.BuildParams{
- Rule: blueprint.Phony,
- Output: android.PathForPhony(ctx, ctx.ModuleName()),
- Inputs: allOutputs,
- })
-
- surface.taggedOutputs = contributionFiles
-
- ctx.SetOutputFiles(allOutputs, "")
-}
-
-func (surface *ApiSurface) TaggedOutputs() map[string]android.Paths {
- return surface.taggedOutputs
-}
-
-func (surface *ApiSurface) Exportable() bool {
- return true
-}
-
-var _ Exportable = (*ApiSurface)(nil)
-
-type ApiContribution interface {
- // copy files necessaryt to construct an API surface
- // For C, it will be map.txt and .h files
- // For Java, it will be api.txt
- CopyFilesWithTag(ctx android.ModuleContext) map[string]android.Paths // output paths
-
- // Generate Android.bp in out/ to use the exported .txt files
- // GenerateBuildFiles(ctx ModuleContext) Paths //output paths
-}
diff --git a/multitree/export.go b/multitree/export.go
deleted file mode 100644
index 8be8f70..0000000
--- a/multitree/export.go
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package multitree
-
-import (
- "android/soong/android"
-
- "github.com/google/blueprint/proptools"
-)
-
-type moduleExportProperty struct {
- // True if the module is exported to the other components in a multi-tree.
- // Any components in the multi-tree can import this module to use.
- Export *bool
-}
-
-type ExportableModuleBase struct {
- properties moduleExportProperty
-}
-
-type Exportable interface {
- // Properties for the exporable module.
- exportableModuleProps() *moduleExportProperty
-
- // Check if this module can be exported.
- // If this returns false, the module will not be exported regardless of the 'export' value.
- Exportable() bool
-
- // Returns 'true' if this module has 'export: true'
- // This module will not be exported if it returns 'false' to 'Exportable()' interface even if
- // it has 'export: true'.
- IsExported() bool
-
- // Map from tags to outputs.
- // Each module can tag their outputs for convenience.
- TaggedOutputs() map[string]android.Paths
-}
-
-type ExportableModule interface {
- android.Module
- Exportable
-}
-
-func InitExportableModule(module ExportableModule) {
- module.AddProperties(module.exportableModuleProps())
-}
-
-func (m *ExportableModuleBase) exportableModuleProps() *moduleExportProperty {
- return &m.properties
-}
-
-func (m *ExportableModuleBase) IsExported() bool {
- return proptools.Bool(m.properties.Export)
-}
diff --git a/multitree/import.go b/multitree/import.go
deleted file mode 100644
index 1e5c421..0000000
--- a/multitree/import.go
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package multitree
-
-import (
- "android/soong/android"
-)
-
-var (
- nameSuffix = ".imported"
-)
-
-type MultitreeImportedModuleInterface interface {
- GetMultitreeImportedModuleName() string
-}
-
-func init() {
- android.RegisterModuleType("imported_filegroup", importedFileGroupFactory)
-
- android.PreArchMutators(RegisterMultitreePreArchMutators)
-}
-
-type importedFileGroupProperties struct {
- // Imported modules from the other components in a multi-tree
- Imported []string
-}
-
-type importedFileGroup struct {
- android.ModuleBase
-
- properties importedFileGroupProperties
- srcs android.Paths
-}
-
-func (ifg *importedFileGroup) Name() string {
- return ifg.BaseModuleName() + nameSuffix
-}
-
-func importedFileGroupFactory() android.Module {
- module := &importedFileGroup{}
- module.AddProperties(&module.properties)
-
- android.InitAndroidModule(module)
- return module
-}
-
-var _ MultitreeImportedModuleInterface = (*importedFileGroup)(nil)
-
-func (ifg *importedFileGroup) GetMultitreeImportedModuleName() string {
- // The base module name of the imported filegroup is used as the imported module name
- return ifg.BaseModuleName()
-}
-
-var _ android.SourceFileProducer = (*importedFileGroup)(nil)
-
-func (ifg *importedFileGroup) Srcs() android.Paths {
- return ifg.srcs
-}
-
-func (ifg *importedFileGroup) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- // srcs from this module must not be used. Adding a dot path to avoid the empty
- // source failure. Still soong returns error when a module wants to build against
- // this source, which is intended.
- ifg.srcs = android.PathsForModuleSrc(ctx, []string{"."})
-}
-
-func RegisterMultitreePreArchMutators(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("multitree_imported_rename", MultitreeImportedRenameMutator).Parallel()
-}
-
-func MultitreeImportedRenameMutator(ctx android.BottomUpMutatorContext) {
- if m, ok := ctx.Module().(MultitreeImportedModuleInterface); ok {
- name := m.GetMultitreeImportedModuleName()
- if !ctx.OtherModuleExists(name) {
- // Provide an empty filegroup not to break the build while updating the metadata.
- // In other cases, soong will report an error to guide users to run 'm update-meta'
- // first.
- if !ctx.Config().TargetMultitreeUpdateMeta() {
- ctx.ModuleErrorf("\"%s\" filegroup must be imported.\nRun 'm update-meta' first to import the filegroup.", name)
- }
- ctx.Rename(name)
- }
- }
-}
diff --git a/multitree/metadata.go b/multitree/metadata.go
deleted file mode 100644
index 0eb0efc..0000000
--- a/multitree/metadata.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package multitree
-
-import (
- "android/soong/android"
- "encoding/json"
-)
-
-func init() {
- android.RegisterParallelSingletonType("update-meta", UpdateMetaSingleton)
-}
-
-func UpdateMetaSingleton() android.Singleton {
- return &updateMetaSingleton{}
-}
-
-type jsonImported struct {
- FileGroups map[string][]string `json:",omitempty"`
-}
-
-type metadataJsonFlags struct {
- Imported jsonImported `json:",omitempty"`
- Exported map[string][]string `json:",omitempty"`
-}
-
-type updateMetaSingleton struct {
- importedModules []string
- generatedMetadataFile android.OutputPath
-}
-
-func (s *updateMetaSingleton) GenerateBuildActions(ctx android.SingletonContext) {
- metadata := metadataJsonFlags{
- Imported: jsonImported{
- FileGroups: make(map[string][]string),
- },
- Exported: make(map[string][]string),
- }
- ctx.VisitAllModules(func(module android.Module) {
- if ifg, ok := module.(*importedFileGroup); ok {
- metadata.Imported.FileGroups[ifg.BaseModuleName()] = ifg.properties.Imported
- }
- if e, ok := module.(ExportableModule); ok {
- if e.IsExported() && e.Exportable() {
- for tag, files := range e.TaggedOutputs() {
- // TODO(b/219846705): refactor this to a dictionary
- metadata.Exported[e.Name()+":"+tag] = append(metadata.Exported[e.Name()+":"+tag], files.Strings()...)
- }
- }
- }
- })
- jsonStr, err := json.Marshal(metadata)
- if err != nil {
- ctx.Errorf(err.Error())
- }
- s.generatedMetadataFile = android.PathForOutput(ctx, "multitree", "metadata.json")
- android.WriteFileRule(ctx, s.generatedMetadataFile, string(jsonStr))
-}
-
-func (s *updateMetaSingleton) MakeVars(ctx android.MakeVarsContext) {
- ctx.Strict("MULTITREE_METADATA", s.generatedMetadataFile.String())
-}
diff --git a/phony/Android.bp b/phony/Android.bp
index db5efc9..2e250c6 100644
--- a/phony/Android.bp
+++ b/phony/Android.bp
@@ -13,4 +13,5 @@
"phony.go",
],
pluginFor: ["soong_build"],
+ visibility: ["//visibility:public"],
}
diff --git a/provenance/provenance_singleton.go b/provenance/provenance_singleton.go
index 679632c..c372db2 100644
--- a/provenance/provenance_singleton.go
+++ b/provenance/provenance_singleton.go
@@ -46,7 +46,7 @@
)
type ProvenanceMetadata interface {
- ProvenanceMetaDataFile() android.OutputPath
+ ProvenanceMetaDataFile() android.Path
}
func init() {
@@ -74,7 +74,7 @@
return false
}
if p, ok := module.(ProvenanceMetadata); ok {
- return p.ProvenanceMetaDataFile().String() != ""
+ return p.ProvenanceMetaDataFile() != nil
}
return false
}
@@ -101,7 +101,7 @@
context.Phony("droidcore", android.PathForPhony(context, "provenance_metadata"))
}
-func GenerateArtifactProvenanceMetaData(ctx android.ModuleContext, artifactPath android.Path, installedFile android.InstallPath) android.OutputPath {
+func GenerateArtifactProvenanceMetaData(ctx android.ModuleContext, artifactPath android.Path, installedFile android.InstallPath) android.Path {
onDevicePathOfInstalledFile := android.InstallPathToOnDevicePath(ctx, installedFile)
artifactMetaDataFile := android.PathForIntermediates(ctx, "provenance_metadata", ctx.ModuleDir(), ctx.ModuleName(), "provenance_metadata.textproto")
ctx.Build(pctx, android.BuildParams{
diff --git a/python/Android.bp b/python/Android.bp
index 14e83c1..3b54455 100644
--- a/python/Android.bp
+++ b/python/Android.bp
@@ -10,7 +10,6 @@
"soong-android",
"soong-tradefed",
"soong-cc",
- "soong-testing",
],
srcs: [
"binary.go",
diff --git a/python/binary.go b/python/binary.go
index 5f60761..a3acb34 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -22,8 +22,14 @@
"strings"
"android/soong/android"
+ "android/soong/cc"
+ "github.com/google/blueprint"
)
+type PythonBinaryInfo struct{}
+
+var PythonBinaryInfoProvider = blueprint.NewProvider[PythonBinaryInfo]()
+
func init() {
registerPythonBinaryComponents(android.InitRegistrationContext)
}
@@ -103,6 +109,9 @@
p.buildBinary(ctx)
p.installedDest = ctx.InstallFile(installDir(ctx, "bin", "", ""),
p.installSource.Base(), p.installSource)
+
+ android.SetProvider(ctx, PythonBinaryInfoProvider, PythonBinaryInfo{})
+
ctx.SetOutputFiles(android.Paths{p.installSource}, "")
}
@@ -116,13 +125,13 @@
var launcherPath android.OptionalPath
if embeddedLauncher {
- ctx.VisitDirectDepsWithTag(launcherTag, func(m android.Module) {
- if provider, ok := m.(IntermPathProvider); ok {
+ ctx.VisitDirectDepsProxyWithTag(launcherTag, func(m android.ModuleProxy) {
+ if provider, ok := android.OtherModuleProvider(ctx, m, cc.LinkableInfoProvider); ok {
if launcherPath.Valid() {
panic(fmt.Errorf("launcher path was found before: %q",
launcherPath))
}
- launcherPath = provider.IntermPathForModuleOut()
+ launcherPath = provider.OutputFile
}
})
}
@@ -140,7 +149,7 @@
var sharedLibs []string
// if embedded launcher is enabled, we need to collect the shared library dependencies of the
// launcher
- for _, dep := range ctx.GetDirectDepsWithTag(launcherSharedLibTag) {
+ for _, dep := range ctx.GetDirectDepsProxyWithTag(launcherSharedLibTag) {
sharedLibs = append(sharedLibs, ctx.OtherModuleName(dep))
}
p.androidMkSharedLibs = sharedLibs
diff --git a/python/python.go b/python/python.go
index 8726f02..09af62e 100644
--- a/python/python.go
+++ b/python/python.go
@@ -22,12 +22,23 @@
"regexp"
"strings"
+ "android/soong/cc"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
)
+type PythonLibraryInfo struct {
+ SrcsPathMappings []pathMapping
+ DataPathMappings []pathMapping
+ SrcsZip android.Path
+ PrecompiledSrcsZip android.Path
+ PkgPath string
+}
+
+var PythonLibraryInfoProvider = blueprint.NewProvider[PythonLibraryInfo]()
+
func init() {
registerPythonMutators(android.InitRegistrationContext)
}
@@ -90,6 +101,16 @@
// the test. the file extension can be arbitrary except for (.py).
Data []string `android:"path,arch_variant"`
+ // Same as data, but will add dependencies on modules using the device's os variation and
+ // the common arch variation. Useful for a host test that wants to embed a module built for
+ // device.
+ Device_common_data []string `android:"path_device_common"`
+
+ // Same as data, but will add dependencies on modules via a device os variation and the
+ // device's first supported arch's variation. Useful for a host test that wants to embed a
+ // module built for device.
+ Device_first_data []string `android:"path_device_first"`
+
// list of java modules that provide data that should be installed alongside the test.
Java_data []string
@@ -163,16 +184,6 @@
}
}
-// interface implemented by Python modules to provide source and data mappings and zip to python
-// modules that depend on it
-type pythonDependency interface {
- getSrcsPathMappings() []pathMapping
- getDataPathMappings() []pathMapping
- getSrcsZip() android.Path
- getPrecompiledSrcsZip() android.Path
- getPkgPath() string
-}
-
// getSrcsPathMappings gets this module's path mapping of src source path : runfiles destination
func (p *PythonLibraryModule) getSrcsPathMappings() []pathMapping {
return p.srcsPathMappings
@@ -202,8 +213,6 @@
return &p.properties
}
-var _ pythonDependency = (*PythonLibraryModule)(nil)
-
func (p *PythonLibraryModule) init() android.Module {
p.AddProperties(&p.properties, &p.protoProperties, &p.sourceProperties)
android.InitAndroidArchModule(p, p.hod, p.multilib)
@@ -264,10 +273,9 @@
variants = append(variants, pyVersion3)
}
if proptools.BoolDefault(props.Version.Py2.Enabled, false) {
- if !ctx.DeviceConfig().BuildBrokenUsesSoongPython2Modules() &&
- ctx.ModuleName() != "py2-cmd" &&
+ if ctx.ModuleName() != "py2-cmd" &&
ctx.ModuleName() != "py2-stdlib" {
- ctx.PropertyErrorf("version.py2.enabled", "Python 2 is no longer supported, please convert to python 3. This error can be temporarily overridden by setting BUILD_BROKEN_USES_SOONG_PYTHON2_MODULES := true in the product configuration")
+ ctx.PropertyErrorf("version.py2.enabled", "Python 2 is no longer supported, please convert to python 3.")
}
variants = append(variants, pyVersion2)
}
@@ -443,7 +451,6 @@
// GenerateAndroidBuildActions performs build actions common to all Python modules
func (p *PythonLibraryModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
expandedSrcs := android.PathsForModuleSrcExcludes(ctx, p.properties.Srcs, p.properties.Exclude_srcs)
- android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: expandedSrcs.Strings()})
// Keep before any early returns.
android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{
TestOnly: Bool(p.sourceProperties.Test_only),
@@ -452,9 +459,11 @@
// expand data files from "data" property.
expandedData := android.PathsForModuleSrc(ctx, p.properties.Data)
+ expandedData = append(expandedData, android.PathsForModuleSrc(ctx, p.properties.Device_common_data)...)
+ expandedData = append(expandedData, android.PathsForModuleSrc(ctx, p.properties.Device_first_data)...)
// Emulate the data property for java_data dependencies.
- for _, javaData := range ctx.GetDirectDepsWithTag(javaDataTag) {
+ for _, javaData := range ctx.GetDirectDepsProxyWithTag(javaDataTag) {
expandedData = append(expandedData, android.OutputFilesForModule(ctx, javaData, "")...)
}
@@ -482,6 +491,14 @@
// generate the zipfile of all source and data files
p.srcsZip = p.createSrcsZip(ctx, pkgPath)
p.precompiledSrcsZip = p.precompileSrcs(ctx)
+
+ android.SetProvider(ctx, PythonLibraryInfoProvider, PythonLibraryInfo{
+ SrcsPathMappings: p.getSrcsPathMappings(),
+ DataPathMappings: p.getDataPathMappings(),
+ SrcsZip: p.getSrcsZip(),
+ PkgPath: p.getPkgPath(),
+ PrecompiledSrcsZip: p.getPrecompiledSrcsZip(),
+ })
}
func isValidPythonPath(path string) error {
@@ -647,16 +664,16 @@
stdLib = p.srcsZip
stdLibPkg = p.getPkgPath()
} else {
- ctx.VisitDirectDepsWithTag(hostStdLibTag, func(module android.Module) {
- if dep, ok := module.(pythonDependency); ok {
- stdLib = dep.getPrecompiledSrcsZip()
- stdLibPkg = dep.getPkgPath()
+ ctx.VisitDirectDepsProxyWithTag(hostStdLibTag, func(module android.ModuleProxy) {
+ if dep, ok := android.OtherModuleProvider(ctx, module, PythonLibraryInfoProvider); ok {
+ stdLib = dep.PrecompiledSrcsZip
+ stdLibPkg = dep.PkgPath
}
})
}
- ctx.VisitDirectDepsWithTag(hostLauncherTag, func(module android.Module) {
- if dep, ok := module.(IntermPathProvider); ok {
- optionalLauncher := dep.IntermPathForModuleOut()
+ ctx.VisitDirectDepsProxyWithTag(hostLauncherTag, func(module android.ModuleProxy) {
+ if dep, ok := android.OtherModuleProvider(ctx, module, cc.LinkableInfoProvider); ok {
+ optionalLauncher := dep.OutputFile
if optionalLauncher.Valid() {
launcher = optionalLauncher.Path()
}
@@ -664,9 +681,9 @@
})
var launcherSharedLibs android.Paths
var ldLibraryPath []string
- ctx.VisitDirectDepsWithTag(hostlauncherSharedLibTag, func(module android.Module) {
- if dep, ok := module.(IntermPathProvider); ok {
- optionalPath := dep.IntermPathForModuleOut()
+ ctx.VisitDirectDepsProxyWithTag(hostlauncherSharedLibTag, func(module android.ModuleProxy) {
+ if dep, ok := android.OtherModuleProvider(ctx, module, cc.LinkableInfoProvider); ok {
+ optionalPath := dep.OutputFile
if optionalPath.Valid() {
launcherSharedLibs = append(launcherSharedLibs, optionalPath.Path())
ldLibraryPath = append(ldLibraryPath, filepath.Dir(optionalPath.Path().String()))
@@ -697,16 +714,6 @@
return out
}
-// isPythonLibModule returns whether the given module is a Python library PythonLibraryModule or not
-func isPythonLibModule(module blueprint.Module) bool {
- if _, ok := module.(*PythonLibraryModule); ok {
- if _, ok := module.(*PythonBinaryModule); !ok {
- return true
- }
- }
- return false
-}
-
// collectPathsFromTransitiveDeps checks for source/data files for duplicate paths
// for module and its transitive dependencies and collects list of data/source file
// zips for transitive dependencies.
@@ -727,7 +734,7 @@
var result android.Paths
// visit all its dependencies in depth first.
- ctx.WalkDeps(func(child, parent android.Module) bool {
+ ctx.WalkDepsProxy(func(child, _ android.ModuleProxy) bool {
// we only collect dependencies tagged as python library deps
if ctx.OtherModuleDependencyTag(child) != pythonLibTag {
return false
@@ -737,27 +744,29 @@
}
seen[child] = true
// Python modules only can depend on Python libraries.
- if !isPythonLibModule(child) {
+ dep, isLibrary := android.OtherModuleProvider(ctx, child, PythonLibraryInfoProvider)
+ _, isBinary := android.OtherModuleProvider(ctx, child, PythonBinaryInfoProvider)
+ if !isLibrary || isBinary {
ctx.PropertyErrorf("libs",
"the dependency %q of module %q is not Python library!",
ctx.OtherModuleName(child), ctx.ModuleName())
}
// collect source and data paths, checking that there are no duplicate output file conflicts
- if dep, ok := child.(pythonDependency); ok {
- srcs := dep.getSrcsPathMappings()
+ if isLibrary {
+ srcs := dep.SrcsPathMappings
for _, path := range srcs {
checkForDuplicateOutputPath(ctx, destToPySrcs,
path.dest, path.src.String(), ctx.ModuleName(), ctx.OtherModuleName(child))
}
- data := dep.getDataPathMappings()
+ data := dep.DataPathMappings
for _, path := range data {
checkForDuplicateOutputPath(ctx, destToPyData,
path.dest, path.src.String(), ctx.ModuleName(), ctx.OtherModuleName(child))
}
if precompiled {
- result = append(result, dep.getPrecompiledSrcsZip())
+ result = append(result, dep.PrecompiledSrcsZip)
} else {
- result = append(result, dep.getSrcsZip())
+ result = append(result, dep.SrcsZip)
}
}
return true
diff --git a/python/test.go b/python/test.go
index 85decf9..5e70fc1 100644
--- a/python/test.go
+++ b/python/test.go
@@ -17,8 +17,6 @@
import (
"fmt"
- "android/soong/testing"
-
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -65,6 +63,16 @@
// the test
Data []string `android:"path,arch_variant"`
+ // Same as data, but will add dependencies on modules using the device's os variation and
+ // the common arch variation. Useful for a host test that wants to embed a module built for
+ // device.
+ Device_common_data []string `android:"path_device_common"`
+
+ // Same as data, but will add dependencies on modules via a device os variation and the
+ // device's first supported arch's variation. Useful for a host test that wants to embed a
+ // module built for device.
+ Device_first_data []string `android:"path_device_first"`
+
// list of java modules that provide data that should be installed alongside the test.
Java_data []string
@@ -183,15 +191,21 @@
for _, dataSrcPath := range android.PathsForModuleSrc(ctx, p.testProperties.Data) {
p.data = append(p.data, android.DataPath{SrcPath: dataSrcPath})
}
+ for _, dataSrcPath := range android.PathsForModuleSrc(ctx, p.testProperties.Device_common_data) {
+ p.data = append(p.data, android.DataPath{SrcPath: dataSrcPath})
+ }
+ for _, dataSrcPath := range android.PathsForModuleSrc(ctx, p.testProperties.Device_first_data) {
+ p.data = append(p.data, android.DataPath{SrcPath: dataSrcPath})
+ }
if p.isTestHost() && len(p.testProperties.Data_device_bins_both) > 0 {
- ctx.VisitDirectDepsWithTag(dataDeviceBinsTag, func(dep android.Module) {
+ ctx.VisitDirectDepsProxyWithTag(dataDeviceBinsTag, func(dep android.ModuleProxy) {
p.data = append(p.data, android.DataPath{SrcPath: android.OutputFileForModule(ctx, dep, "")})
})
}
// Emulate the data property for java_data dependencies.
- for _, javaData := range ctx.GetDirectDepsWithTag(javaDataTag) {
+ for _, javaData := range ctx.GetDirectDepsProxyWithTag(javaDataTag) {
for _, javaDataSrcPath := range android.OutputFilesForModule(ctx, javaData, "") {
p.data = append(p.data, android.DataPath{SrcPath: javaDataSrcPath})
}
@@ -201,7 +215,45 @@
installedData := ctx.InstallTestData(installDir, p.data)
p.installedDest = ctx.InstallFile(installDir, p.installSource.Base(), p.installSource, installedData...)
- android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+ // TODO: Remove the special case for kati
+ if !ctx.Config().KatiEnabled() {
+ // Install the test config in testcases/ directory for atest.
+ // Install configs in the root of $PRODUCT_OUT/testcases/$module
+ testCases := android.PathForModuleInPartitionInstall(ctx, "testcases", ctx.ModuleName())
+ if ctx.PrimaryArch() {
+ if p.testConfig != nil {
+ ctx.InstallFile(testCases, ctx.ModuleName()+".config", p.testConfig)
+ }
+ }
+ // Install tests and data in arch specific subdir $PRODUCT_OUT/testcases/$module/$arch
+ testCases = testCases.Join(ctx, ctx.Target().Arch.ArchType.String())
+ installedData := ctx.InstallTestData(testCases, p.data)
+ ctx.InstallFile(testCases, p.installSource.Base(), p.installSource, installedData...)
+ }
+
+ moduleInfoJSON := ctx.ModuleInfoJSON()
+ moduleInfoJSON.Class = []string{"NATIVE_TESTS"}
+ if len(p.binaryProperties.Test_suites) > 0 {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, p.binaryProperties.Test_suites...)
+ } else {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite")
+ }
+ if p.testConfig != nil {
+ moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, p.testConfig.String())
+ }
+ if _, ok := p.testConfig.(android.WritablePath); ok {
+ moduleInfoJSON.AutoTestConfig = []string{"true"}
+ }
+ moduleInfoJSON.TestOptionsTags = append(moduleInfoJSON.TestOptionsTags, p.testProperties.Test_options.Tags...)
+ moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, p.androidMkSharedLibs...)
+ moduleInfoJSON.SharedLibs = append(moduleInfoJSON.Dependencies, p.androidMkSharedLibs...)
+ moduleInfoJSON.SystemSharedLibs = []string{"none"}
+ if proptools.Bool(p.testProperties.Test_options.Unit_test) {
+ moduleInfoJSON.IsUnitTest = "true"
+ if p.isTestHost() {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "host-unit-tests")
+ }
+ }
}
func (p *PythonTestModule) AndroidMkEntries() []android.AndroidMkEntries {
diff --git a/python/tests/runtest.sh b/python/tests/runtest.sh
index c44ec58..9167561 100755
--- a/python/tests/runtest.sh
+++ b/python/tests/runtest.sh
@@ -25,15 +25,9 @@
if [[ ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test/par_test ) ||
( ! -f $ANDROID_HOST_OUT/bin/py3-cmd )]]; then
- echo "Run 'm par_test py2-cmd py3-cmd' first"
+ echo "Run 'm par_test py3-cmd' first"
exit 1
fi
-if [ $(uname -s) = Linux ]; then
- if [[ ! -f $ANDROID_HOST_OUT/bin/py2-cmd ]]; then
- echo "Run 'm par_test py2-cmd py3-cmd' first"
- exit 1
- fi
-fi
export LD_LIBRARY_PATH=$ANDROID_HOST_OUT/lib64
@@ -47,16 +41,8 @@
cd $(dirname ${BASH_SOURCE[0]})
-if [ $(uname -s) = Linux ]; then
- PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py
-fi
PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py
-if [ $(uname -s) = Linux ]; then
- ARGTEST=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py arg1 arg2
- ARGTEST2=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py --arg1 arg2
-fi
-
ARGTEST=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py arg1 arg2
ARGTEST2=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py --arg1 arg2
diff --git a/response/Android.bp b/response/Android.bp
index e19981f..2f319fe 100644
--- a/response/Android.bp
+++ b/response/Android.bp
@@ -13,4 +13,8 @@
testSrcs: [
"response_test.go",
],
+ visibility: [
+ "//build/make/tools/compliance",
+ "//build/soong:__subpackages__",
+ ],
}
diff --git a/rust/Android.bp b/rust/Android.bp
index 53c9462..54ba9d4 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -12,7 +12,6 @@
"soong-bloaty",
"soong-cc",
"soong-rust-config",
- "soong-testing",
],
srcs: [
"afdo.go",
@@ -61,4 +60,5 @@
"test_test.go",
],
pluginFor: ["soong_build"],
+ visibility: ["//visibility:public"],
}
diff --git a/rust/afdo.go b/rust/afdo.go
index 6bd4bae..1bec709 100644
--- a/rust/afdo.go
+++ b/rust/afdo.go
@@ -66,7 +66,7 @@
return flags, deps
}
- ctx.VisitDirectDepsWithTag(cc.FdoProfileTag, func(m android.Module) {
+ ctx.VisitDirectDepsProxyWithTag(cc.FdoProfileTag, func(m android.ModuleProxy) {
if info, ok := android.OtherModuleProvider(ctx, m, cc.FdoProfileProvider); ok {
path := info.Path
profileUseFlag := fmt.Sprintf(afdoFlagFormat, path.String())
diff --git a/rust/benchmark.go b/rust/benchmark.go
index 8c3e515..daba964 100644
--- a/rust/benchmark.go
+++ b/rust/benchmark.go
@@ -89,7 +89,7 @@
return rlibAutoDep
}
-func (benchmark *benchmarkDecorator) stdLinkage(ctx *depsContext) RustLinkage {
+func (benchmark *benchmarkDecorator) stdLinkage(device bool) RustLinkage {
return RlibLinkage
}
@@ -130,3 +130,20 @@
benchmark.binaryDecorator.install(ctx)
}
+
+func (benchmark *benchmarkDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+ benchmark.binaryDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+ moduleInfoJSON.Class = []string{"NATIVE_TESTS"}
+ if benchmark.testConfig != nil {
+ if _, ok := benchmark.testConfig.(android.WritablePath); ok {
+ moduleInfoJSON.AutoTestConfig = []string{"true"}
+ }
+ moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, benchmark.testConfig.String())
+ }
+
+ if len(benchmark.Properties.Test_suites) > 0 {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, benchmark.Properties.Test_suites...)
+ } else {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite")
+ }
+}
diff --git a/rust/binary.go b/rust/binary.go
index cba29a0..3c7a482 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -165,11 +165,11 @@
}
}
-func (binary *binaryDecorator) stdLinkage(ctx *depsContext) RustLinkage {
+func (binary *binaryDecorator) stdLinkage(device bool) RustLinkage {
if binary.preferRlib() {
return RlibLinkage
}
- return binary.baseCompiler.stdLinkage(ctx)
+ return binary.baseCompiler.stdLinkage(device)
}
func (binary *binaryDecorator) binary() bool {
@@ -183,3 +183,8 @@
func (binary *binaryDecorator) testBinary() bool {
return false
}
+
+func (binary *binaryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+ binary.baseCompiler.moduleInfoJSON(ctx, moduleInfoJSON)
+ moduleInfoJSON.Class = []string{"EXECUTABLES"}
+}
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 31aa137..8accd03 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -186,7 +186,7 @@
// Default clang flags
cflags = append(cflags, "${cc_config.CommonGlobalCflags}")
if ctx.Device() {
- cflags = append(cflags, "${cc_config.DeviceGlobalCflags}")
+ cflags = append(cflags, "${cc_config.DeviceGlobalCflags}", "-nostdlibinc")
}
// Toolchain clang flags
@@ -198,18 +198,20 @@
cflags = append(cflags, "-D__ANDROID_VNDK__")
if ctx.RustModule().InVendor() {
cflags = append(cflags, "-D__ANDROID_VENDOR__")
-
- vendorApiLevel := ctx.Config().VendorApiLevel()
- if vendorApiLevel == "" {
- // TODO(b/314036847): This is a fallback for UDC targets.
- // This must be a build failure when UDC is no longer built
- // from this source tree.
- vendorApiLevel = ctx.Config().PlatformSdkVersion().String()
- }
- cflags = append(cflags, "-D__ANDROID_VENDOR_API__="+vendorApiLevel)
} else if ctx.RustModule().InProduct() {
cflags = append(cflags, "-D__ANDROID_PRODUCT__")
}
+
+ // Define __ANDROID_VENDOR_API__ for both product and vendor variants
+ // because they both use the same LLNDK libraries.
+ vendorApiLevel := ctx.Config().VendorApiLevel()
+ if vendorApiLevel == "" {
+ // TODO(b/314036847): This is a fallback for UDC targets.
+ // This must be a build failure when UDC is no longer built
+ // from this source tree.
+ vendorApiLevel = ctx.Config().PlatformSdkVersion().String()
+ }
+ cflags = append(cflags, "-D__ANDROID_VENDOR_API__="+vendorApiLevel)
}
if ctx.RustModule().InRecovery() {
@@ -250,7 +252,7 @@
// Module defined clang flags and include paths
cflags = append(cflags, esc(cflagsProp)...)
- for _, include := range b.ClangProperties.Local_include_dirs {
+ for _, include := range b.ClangProperties.Local_include_dirs.GetOrDefault(ctx, nil) {
cflags = append(cflags, "-I"+android.PathForModuleSrc(ctx, include).String())
implicits = append(implicits, android.PathForModuleSrc(ctx, include))
}
@@ -298,11 +300,17 @@
// it cannot recognize. Turn off unknown warning flags warning.
cflags = append(cflags, "-Wno-unknown-warning-option")
+ // Suppress warnings while testing a new compiler.
+ if ctx.Config().IsEnvTrue("LLVM_NEXT") {
+ cflags = append(cflags, "-Wno-everything")
+ }
+
outputFile := android.PathForModuleOut(ctx, b.BaseSourceProvider.getStem(ctx)+".rs")
var cmd, cmdDesc string
if b.Properties.Custom_bindgen != "" {
- cmd = ctx.GetDirectDepWithTag(b.Properties.Custom_bindgen, customBindgenDepTag).(android.HostToolProvider).HostToolPath().String()
+ m := ctx.GetDirectDepProxyWithTag(b.Properties.Custom_bindgen, customBindgenDepTag)
+ cmd = android.OtherModuleProviderOrDefault(ctx, m, android.HostToolProviderInfoProvider).HostToolPath.String()
cmdDesc = b.Properties.Custom_bindgen
} else {
cmd = "$bindgenCmd"
diff --git a/rust/builder.go b/rust/builder.go
index f469f56..8a869aa 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -30,11 +30,11 @@
rustc = pctx.AndroidStaticRule("rustc",
blueprint.RuleParams{
Command: "$envVars $rustcCmd " +
- "-C linker=${config.RustLinker} " +
- "-C link-args=\"${crtBegin} ${earlyLinkFlags} ${linkFlags} ${crtEnd}\" " +
+ "-C linker=${RustcLinkerCmd} " +
+ "-C link-args=\"--android-clang-bin=${config.ClangCmd} ${crtBegin} ${earlyLinkFlags} ${linkFlags} ${crtEnd}\" " +
"--emit link -o $out --emit dep-info=$out.d.raw $in ${libFlags} $rustcFlags" +
" && grep ^$out: $out.d.raw > $out.d",
- CommandDeps: []string{"$rustcCmd"},
+ CommandDeps: []string{"$rustcCmd", "${RustcLinkerCmd}", "${config.ClangCmd}"},
// Rustc deps-info writes out make compatible dep files: https://github.com/rust-lang/rust/issues/7633
// Rustc emits unneeded dependency lines for the .d and input .rs files.
// Those extra lines cause ninja warning:
@@ -102,10 +102,10 @@
`KYTHE_CANONICALIZE_VNAME_PATHS=prefer-relative ` +
`$rustExtractor $envVars ` +
`$rustcCmd ` +
- `-C linker=${config.RustLinker} ` +
- `-C link-args="${crtBegin} ${linkFlags} ${crtEnd}" ` +
+ `-C linker=${RustcLinkerCmd} ` +
+ `-C link-args="--android-clang-bin=${config.ClangCmd} ${crtBegin} ${linkFlags} ${crtEnd}" ` +
`$in ${libFlags} $rustcFlags`,
- CommandDeps: []string{"$rustExtractor", "$kytheVnames"},
+ CommandDeps: []string{"$rustExtractor", "$kytheVnames", "${RustcLinkerCmd}", "${config.ClangCmd}"},
Rspfile: "${out}.rsp",
RspfileContent: "$in",
},
@@ -119,6 +119,7 @@
func init() {
pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
+ pctx.HostBinToolVariable("RustcLinkerCmd", "rustc_linker")
cc.TransformRlibstoStaticlib = TransformRlibstoStaticlib
}
@@ -170,6 +171,9 @@
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "rlib"))
}
+// TransformRlibstoStaticlib is assumed to be called from the cc module, and
+// thus needs to reconstruct the common set of flags which need to be passed
+// to the rustc compiler.
func TransformRlibstoStaticlib(ctx android.ModuleContext, mainSrc android.Path, deps []cc.RustRlibDep,
outputFile android.WritablePath) android.Path {
@@ -260,7 +264,7 @@
libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
}
for _, lib := range deps.DyLibs {
- libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
+ libFlags = append(libFlags, "--extern force:"+lib.CrateName+"="+lib.Path.String())
}
for _, proc_macro := range deps.ProcMacros {
libFlags = append(libFlags, "--extern "+proc_macro.CrateName+"="+proc_macro.Path.String())
@@ -408,6 +412,7 @@
implicits = append(implicits, deps.SharedLibDeps...)
implicits = append(implicits, deps.srcProviderFiles...)
implicits = append(implicits, deps.AfdoProfiles...)
+ implicits = append(implicits, deps.LinkerDeps...)
implicits = append(implicits, deps.CrtBegin...)
implicits = append(implicits, deps.CrtEnd...)
diff --git a/rust/builder_test.go b/rust/builder_test.go
index ae5ccde..b4b022e 100644
--- a/rust/builder_test.go
+++ b/rust/builder_test.go
@@ -85,7 +85,7 @@
"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/libfizz_buzz.dylib.so",
"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/libfizz_buzz.dylib.so.clippy",
"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/unstripped/libfizz_buzz.dylib.so",
- "out/soong/target/product/test_device/system/lib64/libfizz_buzz.dylib.so",
+ "out/target/product/test_device/system/lib64/libfizz_buzz.dylib.so",
"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/meta_lic",
},
},
@@ -118,7 +118,7 @@
"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/fizz_buzz",
"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/fizz_buzz.clippy",
"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/unstripped/fizz_buzz",
- "out/soong/target/product/test_device/system/bin/fizz_buzz",
+ "out/target/product/test_device/system/bin/fizz_buzz",
"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/meta_lic",
},
},
@@ -154,7 +154,7 @@
"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/unstripped/librust_ffi.so.toc",
"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/meta_lic",
"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/rustdoc.timestamp",
- "out/soong/target/product/test_device/system/lib64/librust_ffi.so",
+ "out/target/product/test_device/system/lib64/librust_ffi.so",
},
},
}
diff --git a/rust/clippy.go b/rust/clippy.go
index 6f0ed7f..426fd73 100644
--- a/rust/clippy.go
+++ b/rust/clippy.go
@@ -38,11 +38,14 @@
}
func (c *clippy) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
- enabled, lints, err := config.ClippyLintsForDir(ctx.ModuleDir(), c.Properties.Clippy_lints)
+ dirEnabled, lints, err := config.ClippyLintsForDir(ctx.ModuleDir(), c.Properties.Clippy_lints)
if err != nil {
ctx.PropertyErrorf("clippy_lints", err.Error())
}
- flags.Clippy = enabled
+
+ envDisable := ctx.Config().IsEnvTrue("SOONG_DISABLE_CLIPPY")
+
+ flags.Clippy = dirEnabled && !envDisable
flags.ClippyFlags = append(flags.ClippyFlags, lints)
return flags, deps
}
diff --git a/rust/compiler.go b/rust/compiler.go
index a2546a1..f186ef3 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -30,22 +30,22 @@
type RustLinkage int
const (
- DefaultLinkage RustLinkage = iota
+ DylibLinkage RustLinkage = iota
RlibLinkage
- DylibLinkage
)
type compiler interface {
initialize(ctx ModuleContext)
compilerFlags(ctx ModuleContext, flags Flags) Flags
cfgFlags(ctx ModuleContext, flags Flags) Flags
- featureFlags(ctx ModuleContext, flags Flags) Flags
+ featureFlags(ctx ModuleContext, module *Module, flags Flags) Flags
+ baseCompilerProps() BaseCompilerProperties
compilerProps() []interface{}
compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput
compilerDeps(ctx DepsContext, deps Deps) Deps
crateName() string
edition() string
- features() []string
+ features(ctx android.ConfigurableEvaluatorContext, module *Module) []string
rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath
Thinlto() bool
@@ -69,7 +69,7 @@
Disabled() bool
SetDisabled()
- stdLinkage(ctx *depsContext) RustLinkage
+ stdLinkage(device bool) RustLinkage
noStdlibs() bool
unstrippedOutputFilePath() android.Path
@@ -78,6 +78,8 @@
checkedCrateRootPath() (android.Path, error)
Aliases() map[string]string
+
+ moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON)
}
func (compiler *baseCompiler) edition() string {
@@ -150,21 +152,21 @@
Aliases []string
// list of rust rlib crate dependencies
- Rlibs []string `android:"arch_variant"`
+ Rlibs proptools.Configurable[[]string] `android:"arch_variant"`
// list of rust automatic crate dependencies.
// Rustlibs linkage is rlib for host targets and dylib for device targets.
- Rustlibs []string `android:"arch_variant"`
+ Rustlibs proptools.Configurable[[]string] `android:"arch_variant"`
// list of rust proc_macro crate dependencies
- Proc_macros []string `android:"arch_variant"`
+ Proc_macros proptools.Configurable[[]string] `android:"arch_variant"`
// list of C shared library dependencies
- Shared_libs []string `android:"arch_variant"`
+ Shared_libs proptools.Configurable[[]string] `android:"arch_variant"`
// list of C static library dependencies. These dependencies do not normally propagate to dependents
// and may need to be redeclared. See whole_static_libs for bundling static dependencies into a library.
- Static_libs []string `android:"arch_variant"`
+ Static_libs proptools.Configurable[[]string] `android:"arch_variant"`
// Similar to static_libs, but will bundle the static library dependency into a library. This is helpful
// to avoid having to redeclare the dependency for dependents of this library, but in some cases may also
@@ -179,13 +181,13 @@
//
// For rust_library rlib variants, these libraries will be bundled into the resulting rlib library. This will
// include all of the static libraries symbols in any dylibs or binaries which use this rlib as well.
- Whole_static_libs []string `android:"arch_variant"`
+ Whole_static_libs proptools.Configurable[[]string] `android:"arch_variant"`
// list of Rust system library dependencies.
//
// This is usually only needed when `no_stdlibs` is true, in which case it can be used to depend on system crates
// like `core` and `alloc`.
- Stdlibs []string `android:"arch_variant"`
+ Stdlibs proptools.Configurable[[]string] `android:"arch_variant"`
// crate name, required for modules which produce Rust libraries: rust_library, rust_ffi and SourceProvider
// modules which create library variants (rust_bindgen). This must be the expected extern crate name used in
@@ -194,7 +196,7 @@
Crate_name string `android:"arch_variant"`
// list of features to enable for this crate
- Features []string `android:"arch_variant"`
+ Features proptools.Configurable[[]string] `android:"arch_variant"`
// list of configuration options to enable for this crate. To enable features, use the "features" property.
Cfgs proptools.Configurable[[]string] `android:"arch_variant"`
@@ -316,17 +318,42 @@
return aliases
}
-func (compiler *baseCompiler) stdLinkage(ctx *depsContext) RustLinkage {
+func (compiler *baseCompiler) stdLinkage(device bool) RustLinkage {
// For devices, we always link stdlibs in as dylibs by default.
if compiler.preferRlib() {
return RlibLinkage
- } else if ctx.Device() {
+ } else if device {
return DylibLinkage
} else {
return RlibLinkage
}
}
+func (compiler *baseCompiler) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+ moduleInfoJSON.Class = []string{"ETC"}
+
+ mod := ctx.Module().(*Module)
+
+ moduleInfoJSON.SharedLibs = mod.transitiveAndroidMkSharedLibs.ToList()
+ moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, mod.transitiveAndroidMkSharedLibs.ToList()...)
+ moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, mod.Properties.AndroidMkDylibs...)
+ moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, mod.Properties.AndroidMkHeaderLibs...)
+ moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, mod.Properties.AndroidMkProcMacroLibs...)
+ moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, mod.Properties.AndroidMkRlibs...)
+ moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, mod.Properties.AndroidMkStaticLibs...)
+ moduleInfoJSON.SystemSharedLibs = []string{"none"}
+ moduleInfoJSON.StaticLibs = mod.Properties.AndroidMkStaticLibs
+
+ if mod.sourceProvider != nil {
+ moduleInfoJSON.SubName += mod.sourceProvider.getSubName()
+ }
+ moduleInfoJSON.SubName += mod.AndroidMkSuffix()
+
+ if mod.Properties.IsSdkVariant {
+ moduleInfoJSON.Uninstallable = true
+ }
+}
+
var _ compiler = (*baseCompiler)(nil)
func (compiler *baseCompiler) inData() bool {
@@ -337,6 +364,10 @@
return []interface{}{&compiler.Properties}
}
+func (compiler *baseCompiler) baseCompilerProps() BaseCompilerProperties {
+ return compiler.Properties
+}
+
func cfgsToFlags(cfgs []string) []string {
flags := make([]string, 0, len(cfgs))
for _, cfg := range cfgs {
@@ -346,22 +377,23 @@
return flags
}
-func (compiler *baseCompiler) features() []string {
- return compiler.Properties.Features
+func (compiler *baseCompiler) features(ctx android.ConfigurableEvaluatorContext, module *Module) []string {
+ eval := module.ConfigurableEvaluator(ctx)
+ return compiler.Properties.Features.GetOrDefault(eval, nil)
}
-func (compiler *baseCompiler) featuresToFlags() []string {
+func (compiler *baseCompiler) featuresToFlags(ctx android.ConfigurableEvaluatorContext, module *Module) []string {
flags := []string{}
- for _, feature := range compiler.features() {
+ for _, feature := range compiler.features(ctx, module) {
flags = append(flags, "--cfg 'feature=\""+feature+"\"'")
}
return flags
}
-func (compiler *baseCompiler) featureFlags(ctx ModuleContext, flags Flags) Flags {
- flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags()...)
- flags.RustdocFlags = append(flags.RustdocFlags, compiler.featuresToFlags()...)
+func (compiler *baseCompiler) featureFlags(ctx ModuleContext, module *Module, flags Flags) Flags {
+ flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(ctx, module)...)
+ flags.RustdocFlags = append(flags.RustdocFlags, compiler.featuresToFlags(ctx, module)...)
return flags
}
@@ -495,13 +527,13 @@
}
func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps {
- deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...)
- deps.Rustlibs = append(deps.Rustlibs, compiler.Properties.Rustlibs...)
- deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...)
- deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...)
- deps.WholeStaticLibs = append(deps.WholeStaticLibs, compiler.Properties.Whole_static_libs...)
- deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs...)
- deps.Stdlibs = append(deps.Stdlibs, compiler.Properties.Stdlibs...)
+ deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs.GetOrDefault(ctx, nil)...)
+ deps.Rustlibs = append(deps.Rustlibs, compiler.Properties.Rustlibs.GetOrDefault(ctx, nil)...)
+ deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros.GetOrDefault(ctx, nil)...)
+ deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs.GetOrDefault(ctx, nil)...)
+ deps.WholeStaticLibs = append(deps.WholeStaticLibs, compiler.Properties.Whole_static_libs.GetOrDefault(ctx, nil)...)
+ deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs.GetOrDefault(ctx, nil)...)
+ deps.Stdlibs = append(deps.Stdlibs, compiler.Properties.Stdlibs.GetOrDefault(ctx, nil)...)
if !Bool(compiler.Properties.No_stdlibs) {
for _, stdlib := range config.Stdlibs {
diff --git a/rust/config/Android.bp b/rust/config/Android.bp
index 79ea7a1..25f7580 100644
--- a/rust/config/Android.bp
+++ b/rust/config/Android.bp
@@ -24,4 +24,8 @@
"x86_64_device.go",
"arm64_linux_host.go",
],
+ visibility: [
+ "//build/soong:__subpackages__",
+ "//prebuilts/rust/soong",
+ ],
}
diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go
index 9850570..94a4457 100644
--- a/rust/config/arm64_device.go
+++ b/rust/config/arm64_device.go
@@ -35,8 +35,13 @@
},
"armv8-2a": []string{},
"armv8-2a-dotprod": []string{},
+
+ // branch-protection=bti,pac-ret is equivalent to Clang's mbranch-protection=standard
"armv9-a": []string{
- // branch-protection=bti,pac-ret is equivalent to Clang's mbranch-protection=standard
+ "-Z branch-protection=bti,pac-ret",
+ "-Z stack-protector=none",
+ },
+ "armv9-2a": []string{
"-Z branch-protection=bti,pac-ret",
"-Z stack-protector=none",
},
diff --git a/rust/config/global.go b/rust/config/global.go
index 0c5eb85..2623a5c 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -15,6 +15,7 @@
package config
import (
+ "fmt"
"strings"
"android/soong/android"
@@ -24,7 +25,7 @@
var (
pctx = android.NewPackageContext("android/soong/rust/config")
- RustDefaultVersion = "1.79.0"
+ RustDefaultVersion = "1.82.0"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2021"
Stdlibs = []string{
@@ -41,6 +42,8 @@
}
GlobalRustFlags = []string{
+ // Allow `--extern force:foo` for dylib support
+ "-Z unstable-options",
"-Z stack-protector=strong",
"-Z remap-cwd-prefix=.",
"-C debuginfo=2",
@@ -93,6 +96,16 @@
}
)
+func RustPath(ctx android.PathContext) string {
+ // I can't see any way to flatten the static variable inside Soong, so this
+ // reproduces the init logic.
+ var RustBase string = RustDefaultBase
+ if override := ctx.Config().Getenv("RUST_PREBUILTS_BASE"); override != "" {
+ RustBase = override
+ }
+ return fmt.Sprintf("%s/%s/%s", RustBase, HostPrebuiltTag(ctx.Config()), GetRustVersion(ctx))
+}
+
func init() {
pctx.SourcePathVariable("RustDefaultBase", RustDefaultBase)
pctx.VariableConfigMethod("HostPrebuiltTag", HostPrebuiltTag)
@@ -110,7 +123,7 @@
pctx.StaticVariable("RustBin", "${RustPath}/bin")
pctx.ImportAs("cc_config", "android/soong/cc/config")
- pctx.StaticVariable("RustLinker", "${cc_config.ClangBin}/clang++")
+ pctx.StaticVariable("ClangCmd", "${cc_config.ClangBin}/clang++")
pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " "))
diff --git a/rust/config/lints.go b/rust/config/lints.go
index 735aa16..715e8aa 100644
--- a/rust/config/lints.go
+++ b/rust/config/lints.go
@@ -55,6 +55,7 @@
defaultClippyLints = []string{
// Let people hack in peace. ;)
"-A clippy::disallowed_names",
+ "-A clippy::empty_line_after_doc_comments",
"-A clippy::type-complexity",
"-A clippy::unnecessary_fallible_conversions",
"-A clippy::unnecessary-wraps",
diff --git a/rust/config/x86_64_device.go b/rust/config/x86_64_device.go
index fee1923..3c484d8 100644
--- a/rust/config/x86_64_device.go
+++ b/rust/config/x86_64_device.go
@@ -29,6 +29,7 @@
x86_64ArchVariantRustFlags = map[string][]string{
"": []string{},
+ "alderlake": []string{"-C target-cpu=alderlake"},
"broadwell": []string{"-C target-cpu=broadwell"},
"goldmont": []string{"-C target-cpu=goldmont"},
"goldmont-plus": []string{"-C target-cpu=goldmont-plus"},
diff --git a/rust/config/x86_device.go b/rust/config/x86_device.go
index 5d9d88a..3c597cc 100644
--- a/rust/config/x86_device.go
+++ b/rust/config/x86_device.go
@@ -27,6 +27,7 @@
x86ArchVariantRustFlags = map[string][]string{
"": []string{},
+ "alderlake": []string{"-C target-cpu=alderlake"},
"atom": []string{"-C target-cpu=atom"},
"broadwell": []string{"-C target-cpu=broadwell"},
"goldmont": []string{"-C target-cpu=goldmont"},
diff --git a/rust/coverage.go b/rust/coverage.go
index 91a7806..ae95e46 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -15,6 +15,7 @@
package rust
import (
+ "android/soong/android"
"github.com/google/blueprint"
"android/soong/cc"
@@ -65,16 +66,18 @@
flags.RustFlags = append(flags.RustFlags,
"-C instrument-coverage", "-g")
if ctx.Device() {
- coverage := ctx.GetDirectDepWithTag(CovLibraryName, cc.CoverageDepTag).(cc.LinkableInterface)
+ m := ctx.GetDirectDepProxyWithTag(CovLibraryName, cc.CoverageDepTag)
+ coverage := android.OtherModuleProviderOrDefault(ctx, m, cc.LinkableInfoProvider)
flags.LinkFlags = append(flags.LinkFlags,
- profileInstrFlag, "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,open")
- deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path())
+ profileInstrFlag, "-g", coverage.OutputFile.Path().String(), "-Wl,--wrap,open")
+ deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile.Path())
}
// no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency.
if rustModule, ok := ctx.Module().(*Module); ok && rustModule.compiler.noStdlibs() {
- profiler_builtins := ctx.GetDirectDepWithTag(ProfilerBuiltins, rlibDepTag).(*Module)
- deps.RLibs = append(deps.RLibs, RustLibrary{Path: profiler_builtins.OutputFile().Path(), CrateName: profiler_builtins.CrateName()})
+ m := ctx.GetDirectDepProxyWithTag(ProfilerBuiltins, rlibDepTag)
+ profiler_builtins := android.OtherModuleProviderOrDefault(ctx, m, cc.LinkableInfoProvider)
+ deps.RLibs = append(deps.RLibs, RustLibrary{Path: profiler_builtins.OutputFile.Path(), CrateName: profiler_builtins.CrateName})
}
if cc.EnableContinuousCoverage(ctx) {
@@ -87,10 +90,6 @@
}
func (cov *coverage) begin(ctx BaseModuleContext) {
- if ctx.Host() {
- // Host coverage not yet supported.
- } else {
- // Update useSdk and sdkVersion args if Rust modules become SDK aware.
- cov.Properties = cc.SetCoverageProperties(ctx, cov.Properties, ctx.RustModule().nativeCoverage(), false, "")
- }
+ // Update useSdk and sdkVersion args if Rust modules become SDK aware.
+ cov.Properties = cc.SetCoverageProperties(ctx, cov.Properties, ctx.RustModule().nativeCoverage(), false, "")
}
diff --git a/rust/fuzz.go b/rust/fuzz.go
index 1770d2e..9e8efd7 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -121,7 +121,7 @@
return out
}
-func (fuzzer *fuzzDecorator) stdLinkage(ctx *depsContext) RustLinkage {
+func (fuzzer *fuzzDecorator) stdLinkage(device bool) RustLinkage {
return RlibLinkage
}
@@ -130,7 +130,7 @@
}
func (fuzz *fuzzDecorator) install(ctx ModuleContext) {
- fuzz.fuzzPackagedModule = cc.PackageFuzzModule(ctx, fuzz.fuzzPackagedModule, pctx)
+ fuzz.fuzzPackagedModule = cc.PackageFuzzModule(ctx, fuzz.fuzzPackagedModule)
installBase := "fuzz"
diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go
index 6cb8b93..3598c99 100644
--- a/rust/fuzz_test.go
+++ b/rust/fuzz_test.go
@@ -145,6 +145,6 @@
t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_static ('libcc_transitive_dep'): %#v", fuzz_static_libtest.FuzzSharedLibraries().String())
}
if !strings.Contains(fuzz_staticffi_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") {
- t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_rlib ('libcc_transitive_dep'): %#v", fuzz_staticffi_libtest.FuzzSharedLibraries().String())
+ t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_static ('libcc_transitive_dep'): %#v", fuzz_staticffi_libtest.FuzzSharedLibraries().String())
}
}
diff --git a/rust/image.go b/rust/image.go
index 26929b1..51b8289 100644
--- a/rust/image.go
+++ b/rust/image.go
@@ -85,7 +85,7 @@
mod.Properties.VendorVariantNeeded = b
}
-func (mod *Module) SnapshotVersion(mctx android.BaseModuleContext) string {
+func (mod *Module) SnapshotVersion(mctx android.ImageInterfaceContext) string {
if snapshot, ok := mod.compiler.(cc.SnapshotInterface); ok {
return snapshot.Version()
} else {
@@ -94,35 +94,35 @@
}
}
-func (mod *Module) VendorVariantNeeded(ctx android.BaseModuleContext) bool {
+func (mod *Module) VendorVariantNeeded(ctx android.ImageInterfaceContext) bool {
return mod.Properties.VendorVariantNeeded
}
-func (mod *Module) ProductVariantNeeded(ctx android.BaseModuleContext) bool {
+func (mod *Module) ProductVariantNeeded(ctx android.ImageInterfaceContext) bool {
return mod.Properties.ProductVariantNeeded
}
-func (mod *Module) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (mod *Module) VendorRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return mod.Properties.VendorRamdiskVariantNeeded
}
-func (mod *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+func (mod *Module) CoreVariantNeeded(ctx android.ImageInterfaceContext) bool {
return mod.Properties.CoreVariantNeeded
}
-func (mod *Module) RamdiskVariantNeeded(android.BaseModuleContext) bool {
+func (mod *Module) RamdiskVariantNeeded(android.ImageInterfaceContext) bool {
return mod.Properties.RamdiskVariantNeeded
}
-func (mod *Module) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (mod *Module) DebugRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return false
}
-func (mod *Module) RecoveryVariantNeeded(android.BaseModuleContext) bool {
+func (mod *Module) RecoveryVariantNeeded(android.ImageInterfaceContext) bool {
return mod.Properties.RecoveryVariantNeeded
}
-func (mod *Module) ExtraImageVariations(android.BaseModuleContext) []string {
+func (mod *Module) ExtraImageVariations(android.ImageInterfaceContext) []string {
return mod.Properties.ExtraVariants
}
@@ -213,7 +213,7 @@
return mod.InVendor() || mod.InProduct()
}
-func (mod *Module) SetImageVariation(ctx android.BaseModuleContext, variant string) {
+func (mod *Module) SetImageVariation(ctx android.ImageInterfaceContext, variant string) {
if variant == android.VendorRamdiskVariation {
mod.MakeAsPlatform()
} else if variant == android.RecoveryVariation {
@@ -231,7 +231,7 @@
}
}
-func (mod *Module) ImageMutatorBegin(mctx android.BaseModuleContext) {
+func (mod *Module) ImageMutatorBegin(mctx android.ImageInterfaceContext) {
if Bool(mod.VendorProperties.Double_loadable) {
mctx.PropertyErrorf("double_loadable",
"Rust modules do not yet support double loading")
diff --git a/rust/image_test.go b/rust/image_test.go
index d84eb10..0581fa7 100644
--- a/rust/image_test.go
+++ b/rust/image_test.go
@@ -22,14 +22,13 @@
"android/soong/cc"
)
-// Test that cc modules can depend on vendor_available rust_ffi_rlib/rust_ffi_static libraries.
+// Test that cc modules can depend on vendor_available rust_ffi_static libraries.
func TestVendorLinkage(t *testing.T) {
ctx := testRust(t, `
cc_binary {
name: "fizz_vendor_available",
static_libs: [
"libfoo_vendor",
- "libfoo_vendor_static"
],
vendor_available: true,
}
@@ -38,14 +37,8 @@
static_libs: ["libfoo_vendor"],
soc_specific: true,
}
- rust_ffi_rlib {
- name: "libfoo_vendor",
- crate_name: "foo",
- srcs: ["foo.rs"],
- vendor_available: true,
- }
rust_ffi_static {
- name: "libfoo_vendor_static",
+ name: "libfoo_vendor",
crate_name: "foo",
srcs: ["foo.rs"],
vendor_available: true,
@@ -54,8 +47,8 @@
vendorBinary := ctx.ModuleForTests("fizz_vendor_available", "android_vendor_arm64_armv8-a").Module().(*cc.Module)
- if android.InList("libfoo_vendor_static.vendor", vendorBinary.Properties.AndroidMkStaticLibs) {
- t.Errorf("vendorBinary should not have a staticlib dependency on libfoo_vendor_static.vendor: %#v", vendorBinary.Properties.AndroidMkStaticLibs)
+ if android.InList("libfoo_vendor.vendor", vendorBinary.Properties.AndroidMkStaticLibs) {
+ t.Errorf("vendorBinary should not have a staticlib dependency on libfoo_vendor.vendor: %#v", vendorBinary.Properties.AndroidMkStaticLibs)
}
}
@@ -107,26 +100,19 @@
}
-// Test that cc modules can link against vendor_ramdisk_available rust_ffi_rlib and rust_ffi_static libraries.
+// Test that cc modules can link against vendor_ramdisk_available rust_ffi_static libraries.
func TestVendorRamdiskLinkage(t *testing.T) {
ctx := testRust(t, `
cc_library_shared {
name: "libcc_vendor_ramdisk",
static_libs: [
"libfoo_vendor_ramdisk",
- "libfoo_static_vendor_ramdisk"
],
system_shared_libs: [],
vendor_ramdisk_available: true,
}
- rust_ffi_rlib {
- name: "libfoo_vendor_ramdisk",
- crate_name: "foo",
- srcs: ["foo.rs"],
- vendor_ramdisk_available: true,
- }
rust_ffi_static {
- name: "libfoo_static_vendor_ramdisk",
+ name: "libfoo_vendor_ramdisk",
crate_name: "foo",
srcs: ["foo.rs"],
vendor_ramdisk_available: true,
@@ -135,8 +121,8 @@
vendorRamdiskLibrary := ctx.ModuleForTests("libcc_vendor_ramdisk", "android_vendor_ramdisk_arm64_armv8-a_shared").Module().(*cc.Module)
- if android.InList("libfoo_static_vendor_ramdisk.vendor_ramdisk", vendorRamdiskLibrary.Properties.AndroidMkStaticLibs) {
- t.Errorf("libcc_vendor_ramdisk should not have a dependency on the libfoo_static_vendor_ramdisk static library")
+ if android.InList("libfoo_vendor_ramdisk.vendor_ramdisk", vendorRamdiskLibrary.Properties.AndroidMkStaticLibs) {
+ t.Errorf("libcc_vendor_ramdisk should not have a dependency on the libfoo_vendor_ramdisk static library")
}
}
diff --git a/rust/library.go b/rust/library.go
index 50d5a72..95e7099 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -21,9 +21,11 @@
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/depset"
"android/soong/android"
"android/soong/cc"
+ cc_config "android/soong/cc/config"
)
var (
@@ -39,15 +41,10 @@
android.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
android.RegisterModuleType("rust_ffi", RustFFIFactory)
android.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
- android.RegisterModuleType("rust_ffi_rlib", RustFFIRlibFactory)
android.RegisterModuleType("rust_ffi_host", RustFFIHostFactory)
android.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
- android.RegisterModuleType("rust_ffi_host_rlib", RustFFIRlibHostFactory)
-
- // TODO: Remove when all instances of rust_ffi_static have been switched to rust_ffi_rlib
- // Alias rust_ffi_static to the rust_ffi_rlib factory
- android.RegisterModuleType("rust_ffi_static", RustFFIRlibFactory)
- android.RegisterModuleType("rust_ffi_host_static", RustFFIRlibHostFactory)
+ android.RegisterModuleType("rust_ffi_static", RustLibraryRlibFactory)
+ android.RegisterModuleType("rust_ffi_host_static", RustLibraryRlibHostFactory)
}
type VariantLibraryProperties struct {
@@ -68,8 +65,28 @@
// path to include directories to export to cc_* modules, only relevant for static/shared variants.
Export_include_dirs []string `android:"path,arch_variant"`
+ // Version script to pass to the linker. By default this will replace the
+ // implicit rustc emitted version script to mirror expected behavior in CC.
+ // This is only relevant for rust_ffi_shared modules which are exposing a
+ // versioned C API.
+ Version_script *string `android:"path,arch_variant"`
+
+ // A version_script formatted text file with additional symbols to export
+ // for rust shared or dylibs which the rustc compiler does not automatically
+ // export, e.g. additional symbols from whole_static_libs. Unlike
+ // Version_script, this is not meant to imply a stable API.
+ Extra_exported_symbols *string `android:"path,arch_variant"`
+
// Whether this library is part of the Rust toolchain sysroot.
Sysroot *bool
+
+ // Deprecated - exclude this rust_ffi target from being included in APEXes.
+ // TODO(b/362509506): remove this once all apex_exclude uses are switched to stubs.
+ Apex_exclude *bool
+
+ // Generate stubs to make this library accessible to APEXes.
+ // Can only be set for modules producing shared libraries.
+ Stubs cc.StubsProperties `android:"arch_variant"`
}
type LibraryMutatedProperties struct {
@@ -97,6 +114,15 @@
// Whether this library variant should be link libstd via rlibs
VariantIsStaticStd bool `blueprint:"mutated"`
+
+ // This variant is a stubs lib
+ BuildStubs bool `blueprint:"mutated"`
+ // This variant is the latest version
+ IsLatestVersion bool `blueprint:"mutated"`
+ // Version of the stubs lib
+ StubsVersion string `blueprint:"mutated"`
+ // List of all stubs versions associated with an implementation lib
+ AllStubsVersions []string `blueprint:"mutated"`
}
type libraryDecorator struct {
@@ -109,19 +135,37 @@
includeDirs android.Paths
sourceProvider SourceProvider
- isFFI bool
-
// table-of-contents file for cdylib crates to optimize out relinking when possible
tocFile android.OptionalPath
+
+ // Path to the file containing the APIs exported by this library
+ stubsSymbolFilePath android.Path
+ apiListCoverageXmlPath android.ModuleOutPath
+ versionScriptPath android.OptionalPath
+}
+
+func (library *libraryDecorator) stubs() bool {
+ return library.MutatedProperties.BuildStubs
+}
+
+func (library *libraryDecorator) setAPIListCoverageXMLPath(xml android.ModuleOutPath) {
+ library.apiListCoverageXmlPath = xml
+}
+
+func (library *libraryDecorator) libraryProperties() LibraryCompilerProperties {
+ return library.Properties
}
type libraryInterface interface {
+ cc.VersionedInterface
+
rlib() bool
dylib() bool
static() bool
shared() bool
sysroot() bool
source() bool
+ apexExclude() bool
// Returns true if the build options for the module have selected a particular build type
buildRlib() bool
@@ -151,7 +195,10 @@
toc() android.OptionalPath
- isFFILibrary() bool
+ IsStubsImplementationRequired() bool
+ setAPIListCoverageXMLPath(out android.ModuleOutPath)
+
+ libraryProperties() LibraryCompilerProperties
}
func (library *libraryDecorator) nativeCoverage() bool {
@@ -186,6 +233,10 @@
return library.MutatedProperties.VariantIsSource
}
+func (library *libraryDecorator) apexExclude() bool {
+ return Bool(library.Properties.Apex_exclude)
+}
+
func (library *libraryDecorator) buildRlib() bool {
return library.MutatedProperties.BuildRlib && BoolDefault(library.Properties.Rlib.Enabled, true)
}
@@ -252,18 +303,96 @@
}
}
-func (library *libraryDecorator) stdLinkage(ctx *depsContext) RustLinkage {
- if library.static() || library.MutatedProperties.VariantIsStaticStd || (library.rlib() && library.isFFILibrary()) {
+func (library *libraryDecorator) stdLinkage(device bool) RustLinkage {
+ if library.static() || library.MutatedProperties.VariantIsStaticStd {
return RlibLinkage
} else if library.baseCompiler.preferRlib() {
return RlibLinkage
}
- return DefaultLinkage
+ return DylibLinkage
}
var _ compiler = (*libraryDecorator)(nil)
var _ libraryInterface = (*libraryDecorator)(nil)
+var _ cc.VersionedInterface = (*libraryDecorator)(nil)
var _ exportedFlagsProducer = (*libraryDecorator)(nil)
+var _ cc.VersionedInterface = (*libraryDecorator)(nil)
+
+func (library *libraryDecorator) HasLLNDKStubs() bool {
+ // Rust LLNDK is currently unsupported
+ return false
+}
+
+func (library *libraryDecorator) HasVendorPublicLibrary() bool {
+ // Rust does not support vendor_public_library yet.
+ return false
+}
+
+func (library *libraryDecorator) HasLLNDKHeaders() bool {
+ // Rust LLNDK is currently unsupported
+ return false
+}
+
+func (library *libraryDecorator) HasStubsVariants() bool {
+ // Just having stubs.symbol_file is enough to create a stub variant. In that case
+ // the stub for the future API level is created.
+ return library.Properties.Stubs.Symbol_file != nil ||
+ len(library.Properties.Stubs.Versions) > 0
+}
+
+func (library *libraryDecorator) IsStubsImplementationRequired() bool {
+ return BoolDefault(library.Properties.Stubs.Implementation_installable, true)
+}
+
+func (library *libraryDecorator) GetAPIListCoverageXMLPath() android.ModuleOutPath {
+ return library.apiListCoverageXmlPath
+}
+
+func (library *libraryDecorator) AllStubsVersions() []string {
+ return library.MutatedProperties.AllStubsVersions
+}
+
+func (library *libraryDecorator) SetAllStubsVersions(versions []string) {
+ library.MutatedProperties.AllStubsVersions = versions
+}
+
+func (library *libraryDecorator) SetStubsVersion(version string) {
+ library.MutatedProperties.StubsVersion = version
+}
+
+func (library *libraryDecorator) SetBuildStubs(isLatest bool) {
+ library.MutatedProperties.BuildStubs = true
+ library.MutatedProperties.IsLatestVersion = isLatest
+}
+
+func (library *libraryDecorator) BuildStubs() bool {
+ return library.MutatedProperties.BuildStubs
+}
+
+func (library *libraryDecorator) ImplementationModuleName(name string) string {
+ return name
+}
+
+func (library *libraryDecorator) IsLLNDKMovedToApex() bool {
+ // Rust does not support LLNDK.
+ return false
+}
+
+func (library *libraryDecorator) StubsVersion() string {
+ return library.MutatedProperties.StubsVersion
+}
+
+// stubsVersions implements cc.VersionedInterface.
+func (library *libraryDecorator) StubsVersions(ctx android.BaseModuleContext) []string {
+ if !library.HasStubsVariants() {
+ return nil
+ }
+
+ // Future API level is implicitly added if there isn't
+ versions := cc.AddCurrentVersionIfNotPresent(library.Properties.Stubs.Versions)
+ cc.NormalizeVersions(ctx, versions)
+ return versions
+}
// rust_library produces all Rust variants (rust_library_dylib and
// rust_library_rlib).
@@ -273,8 +402,7 @@
return module.Init()
}
-// rust_ffi produces all FFI variants (rust_ffi_shared, rust_ffi_static, and
-// rust_ffi_rlib).
+// rust_ffi produces all FFI variants (rust_ffi_shared, rust_ffi_static).
func RustFFIFactory() android.Module {
module, library := NewRustLibrary(android.HostAndDeviceSupported)
library.BuildOnlyFFI()
@@ -288,7 +416,7 @@
return module.Init()
}
-// rust_library_rlib produces an rlib (Rust crate type "rlib").
+// rust_library_rlib and rust_ffi_static produces an rlib (Rust crate type "rlib").
func RustLibraryRlibFactory() android.Module {
module, library := NewRustLibrary(android.HostAndDeviceSupported)
library.BuildOnlyRlib()
@@ -312,7 +440,7 @@
}
// rust_ffi_host produces all FFI variants for the host
-// (rust_ffi_rlib_host, rust_ffi_static_host, and rust_ffi_shared_host).
+// (rust_ffi_static_host and rust_ffi_shared_host).
func RustFFIHostFactory() android.Module {
module, library := NewRustLibrary(android.HostSupported)
library.BuildOnlyFFI()
@@ -327,8 +455,8 @@
return module.Init()
}
-// rust_library_rlib_host produces an rlib for the host (Rust crate
-// type "rlib").
+// rust_library_rlib_host and rust_ffi_static_host produces an rlib for the host
+// (Rust crate type "rlib").
func RustLibraryRlibHostFactory() android.Module {
module, library := NewRustLibrary(android.HostSupported)
library.BuildOnlyRlib()
@@ -343,23 +471,16 @@
return module.Init()
}
-// rust_ffi_rlib_host produces an rlib for the host (Rust crate
-// type "rlib").
-func RustFFIRlibHostFactory() android.Module {
- module, library := NewRustLibrary(android.HostSupported)
- library.BuildOnlyRlib()
+func CheckRustLibraryProperties(mctx android.DefaultableHookContext) {
+ lib := mctx.Module().(*Module).compiler.(libraryInterface)
+ if !lib.buildShared() {
+ if lib.libraryProperties().Stubs.Symbol_file != nil ||
+ lib.libraryProperties().Stubs.Implementation_installable != nil ||
+ len(lib.libraryProperties().Stubs.Versions) > 0 {
- library.isFFI = true
- return module.Init()
-}
-
-// rust_ffi_rlib produces an rlib (Rust crate type "rlib").
-func RustFFIRlibFactory() android.Module {
- module, library := NewRustLibrary(android.HostAndDeviceSupported)
- library.BuildOnlyRlib()
-
- library.isFFI = true
- return module.Init()
+ mctx.PropertyErrorf("stubs", "stubs properties can only be set for rust_ffi or rust_ffi_shared modules")
+ }
+ }
}
func (library *libraryDecorator) BuildOnlyFFI() {
@@ -368,8 +489,6 @@
library.MutatedProperties.BuildRlib = true
library.MutatedProperties.BuildShared = true
library.MutatedProperties.BuildStatic = false
-
- library.isFFI = true
}
func (library *libraryDecorator) BuildOnlyRust() {
@@ -398,8 +517,6 @@
library.MutatedProperties.BuildDylib = false
library.MutatedProperties.BuildShared = false
library.MutatedProperties.BuildStatic = true
-
- library.isFFI = true
}
func (library *libraryDecorator) BuildOnlyShared() {
@@ -407,12 +524,6 @@
library.MutatedProperties.BuildDylib = false
library.MutatedProperties.BuildStatic = false
library.MutatedProperties.BuildShared = true
-
- library.isFFI = true
-}
-
-func (library *libraryDecorator) isFFILibrary() bool {
- return library.isFFI
}
func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
@@ -431,6 +542,7 @@
module.compiler = library
+ module.SetDefaultableHook(CheckRustLibraryProperties)
return module, library
}
@@ -474,13 +586,6 @@
cfgs := library.baseCompiler.Properties.Cfgs.GetOrDefault(ctx, nil)
- if library.dylib() {
- // We need to add a dependency on std in order to link crates as dylibs.
- // The hack to add this dependency is guarded by the following cfg so
- // that we don't force a dependency when it isn't needed.
- cfgs = append(cfgs, "android_dylib")
- }
-
cfgFlags := cfgsToFlags(cfgs)
flags.RustFlags = append(flags.RustFlags, cfgFlags...)
@@ -501,7 +606,9 @@
flags = CommonLibraryCompilerFlags(ctx, flags)
- if library.isFFI {
+ if library.rlib() || library.shared() {
+ // rlibs collect include dirs as well since they are used to
+ // produce staticlibs in the final C linkages
library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...)
library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Export_include_dirs)...)
}
@@ -566,7 +673,31 @@
flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
+ if String(library.Properties.Version_script) != "" {
+ if String(library.Properties.Extra_exported_symbols) != "" {
+ ctx.ModuleErrorf("version_script and extra_exported_symbols cannot both be set.")
+ }
+
+ if library.shared() {
+ // "-Wl,--android-version-script" signals to the rustcLinker script
+ // that the default version script should be removed.
+ flags.LinkFlags = append(flags.LinkFlags, "-Wl,--android-version-script="+android.PathForModuleSrc(ctx, String(library.Properties.Version_script)).String())
+ deps.LinkerDeps = append(deps.LinkerDeps, android.PathForModuleSrc(ctx, String(library.Properties.Version_script)))
+ } else if !library.static() && !library.rlib() {
+ // We include rlibs here because rust_ffi produces rlib variants
+ ctx.PropertyErrorf("version_script", "can only be set for rust_ffi modules")
+ }
+ }
+
+ if String(library.Properties.Extra_exported_symbols) != "" {
+ // Passing a second version script (rustc calculates and emits a
+ // default version script) will concatenate the first version script.
+ flags.LinkFlags = append(flags.LinkFlags, "-Wl,--version-script="+android.PathForModuleSrc(ctx, String(library.Properties.Extra_exported_symbols)).String())
+ deps.LinkerDeps = append(deps.LinkerDeps, android.PathForModuleSrc(ctx, String(library.Properties.Extra_exported_symbols)))
+ }
+
if library.dylib() {
+
// We need prefer-dynamic for now to avoid linking in the static stdlib. See:
// https://github.com/rust-lang/rust/issues/19680
// https://github.com/rust-lang/rust/issues/34909
@@ -574,7 +705,11 @@
}
// Call the appropriate builder for this library type
- if library.rlib() {
+ if library.stubs() {
+ ccFlags := library.getApiStubsCcFlags(ctx)
+ stubObjs := library.compileModuleLibApiStubs(ctx, ccFlags)
+ cc.BuildRustStubs(ctx, outputFile, stubObjs, ccFlags)
+ } else if library.rlib() {
ret.kytheFile = TransformSrctoRlib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
} else if library.dylib() {
ret.kytheFile = TransformSrctoDylib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
@@ -590,13 +725,13 @@
}
// Since we have FFI rlibs, we need to collect their includes as well
- if library.static() || library.shared() || library.rlib() {
+ if library.static() || library.shared() || library.rlib() || library.stubs() {
android.SetProvider(ctx, cc.FlagExporterInfoProvider, cc.FlagExporterInfo{
IncludeDirs: android.FirstUniquePaths(library.includeDirs),
})
}
- if library.shared() {
+ if library.shared() || library.stubs() {
// Optimize out relinking against shared libraries whose interface hasn't changed by
// depending on a table of contents file instead of the library itself.
tocFile := outputFile.ReplaceExtension(ctx, flags.Toolchain.SharedLibSuffix()[1:]+".toc")
@@ -607,17 +742,19 @@
TableOfContents: android.OptionalPathForPath(tocFile),
SharedLibrary: outputFile,
Target: ctx.Target(),
+ IsStubs: library.BuildStubs(),
})
}
if library.static() {
- depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(outputFile).Build()
+ depSet := depset.NewBuilder[android.Path](depset.TOPOLOGICAL).Direct(outputFile).Build()
android.SetProvider(ctx, cc.StaticLibraryInfoProvider, cc.StaticLibraryInfo{
StaticLibrary: outputFile,
TransitiveStaticLibrariesForOrdering: depSet,
})
}
+ cc.AddStubDependencyProviders(ctx)
library.flagExporter.setProvider(ctx)
@@ -637,6 +774,53 @@
}
}
+func (library *libraryDecorator) getApiStubsCcFlags(ctx ModuleContext) cc.Flags {
+ ccFlags := cc.Flags{}
+ toolchain := cc_config.FindToolchain(ctx.Os(), ctx.Arch())
+
+ platformSdkVersion := ""
+ if ctx.Device() {
+ platformSdkVersion = ctx.Config().PlatformSdkVersion().String()
+ }
+ minSdkVersion := cc.MinSdkVersion(ctx.RustModule(), cc.CtxIsForPlatform(ctx), ctx.Device(), platformSdkVersion)
+
+ // Collect common CC compilation flags
+ ccFlags = cc.CommonLinkerFlags(ctx, ccFlags, true, toolchain, false)
+ ccFlags = cc.CommonLibraryLinkerFlags(ctx, ccFlags, toolchain, library.getStem(ctx))
+ ccFlags = cc.AddStubLibraryCompilerFlags(ccFlags)
+ ccFlags = cc.AddTargetFlags(ctx, ccFlags, toolchain, minSdkVersion, false)
+
+ return ccFlags
+}
+
+func (library *libraryDecorator) compileModuleLibApiStubs(ctx ModuleContext, ccFlags cc.Flags) cc.Objects {
+ mod := ctx.RustModule()
+
+ symbolFile := String(library.Properties.Stubs.Symbol_file)
+ library.stubsSymbolFilePath = android.PathForModuleSrc(ctx, symbolFile)
+
+ apiParams := cc.ApiStubsParams{
+ NotInPlatform: mod.NotInPlatform(),
+ IsNdk: mod.IsNdk(ctx.Config()),
+ BaseModuleName: mod.BaseModuleName(),
+ ModuleName: ctx.ModuleName(),
+ }
+ flag := cc.GetApiStubsFlags(apiParams)
+
+ nativeAbiResult := cc.ParseNativeAbiDefinition(ctx, symbolFile,
+ android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), flag)
+ objs := cc.CompileStubLibrary(ctx, ccFlags, nativeAbiResult.StubSrc, mod.getSharedFlags())
+
+ library.versionScriptPath = android.OptionalPathForPath(nativeAbiResult.VersionScript)
+
+ // Parse symbol file to get API list for coverage
+ if library.StubsVersion() == "current" && ctx.PrimaryArch() && !mod.InRecovery() && !mod.InProduct() && !mod.InVendor() {
+ library.apiListCoverageXmlPath = cc.ParseSymbolFileForAPICoverage(ctx, symbolFile)
+ }
+
+ return objs
+}
+
func (library *libraryDecorator) rustdoc(ctx ModuleContext, flags Flags,
deps PathDeps) android.OptionalPath {
// rustdoc has builtin support for documenting config specific information
@@ -674,6 +858,20 @@
library.MutatedProperties.VariantIsDisabled = true
}
+func (library *libraryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+ library.baseCompiler.moduleInfoJSON(ctx, moduleInfoJSON)
+
+ if library.rlib() {
+ moduleInfoJSON.Class = []string{"RLIB_LIBRARIES"}
+ } else if library.dylib() {
+ moduleInfoJSON.Class = []string{"DYLIB_LIBRARIES"}
+ } else if library.static() {
+ moduleInfoJSON.Class = []string{"STATIC_LIBRARIES"}
+ } else if library.shared() {
+ moduleInfoJSON.Class = []string{"SHARED_LIBRARIES"}
+ }
+}
+
var validCrateName = regexp.MustCompile("[^a-zA-Z0-9_]+")
func validateLibraryStem(ctx BaseModuleContext, filename string, crate_name string) {
@@ -808,11 +1006,7 @@
// Only create a variant if a library is actually being built.
if library, ok := m.compiler.(libraryInterface); ok {
if library.rlib() && !library.sysroot() {
- if library.isFFILibrary() {
- return []string{"rlib-std"}
- } else {
- return []string{"rlib-std", "dylib-std"}
- }
+ return []string{"rlib-std", "dylib-std"}
}
}
}
diff --git a/rust/library_test.go b/rust/library_test.go
index 35a420c..1198fcc 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -89,22 +89,6 @@
}
}
-// Check that we are passing the android_dylib config flag
-func TestAndroidDylib(t *testing.T) {
- ctx := testRust(t, `
- rust_library_host_dylib {
- name: "libfoo",
- srcs: ["foo.rs"],
- crate_name: "foo",
- }`)
-
- libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
-
- if !strings.Contains(libfooDylib.Args["rustcFlags"], "--cfg 'android_dylib'") {
- t.Errorf("missing android_dylib cfg flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
- }
-}
-
func TestValidateLibraryStem(t *testing.T) {
testRustError(t, "crate_name must be defined.", `
rust_library_host {
@@ -202,9 +186,9 @@
func TestNativeDependencyOfRlib(t *testing.T) {
ctx := testRust(t, `
- rust_ffi_rlib {
- name: "libffi_rlib",
- crate_name: "ffi_rlib",
+ rust_ffi_static {
+ name: "libffi_static",
+ crate_name: "ffi_static",
rlibs: ["librust_rlib"],
srcs: ["foo.rs"],
}
@@ -227,7 +211,7 @@
rustRlibRlibStd := ctx.ModuleForTests("librust_rlib", "android_arm64_armv8-a_rlib_rlib-std")
rustRlibDylibStd := ctx.ModuleForTests("librust_rlib", "android_arm64_armv8-a_rlib_dylib-std")
- ffiRlib := ctx.ModuleForTests("libffi_rlib", "android_arm64_armv8-a_rlib_rlib-std")
+ ffiRlib := ctx.ModuleForTests("libffi_static", "android_arm64_armv8-a_rlib_rlib-std")
modules := []android.TestingModule{
rustRlibRlibStd,
@@ -412,10 +396,10 @@
t.Errorf("Device rust_ffi_shared does not link libstd as an dylib")
}
if !android.InList("libstd", libbarFFIRlib.Properties.AndroidMkRlibs) {
- t.Errorf("Device rust_ffi_rlib does not link libstd as an rlib")
+ t.Errorf("Device rust_ffi_static does not link libstd as an rlib")
}
if !android.InList("libfoo.rlib-std", libbarFFIRlib.Properties.AndroidMkRlibs) {
- t.Errorf("Device rust_ffi_rlib does not link dependent rustlib rlib-std variant")
+ t.Errorf("Device rust_ffi_static does not link dependent rustlib rlib-std variant")
}
if !android.InList("libstd", libbarRlibStd.Properties.AndroidMkRlibs) {
t.Errorf("rust_ffi with prefer_rlib does not link libstd as an rlib")
@@ -441,3 +425,346 @@
libfooStatic := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_static").Rule("cc")
android.AssertStringDoesContain(t, "cFlags for lib module", libfooStatic.Args["cFlags"], " -Irust_includes ")
}
+
+func TestRustVersionScript(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library {
+ name: "librs",
+ srcs: ["bar.rs"],
+ crate_name: "rs",
+ extra_exported_symbols: "librs.map.txt",
+ }
+ rust_ffi {
+ name: "libffi",
+ srcs: ["foo.rs"],
+ crate_name: "ffi",
+ version_script: "libffi.map.txt",
+ }
+ `)
+
+ //linkFlags
+ librs := ctx.ModuleForTests("librs", "android_arm64_armv8-a_dylib").Rule("rustc")
+ libffi := ctx.ModuleForTests("libffi", "android_arm64_armv8-a_shared").Rule("rustc")
+
+ if !strings.Contains(librs.Args["linkFlags"], "-Wl,--version-script=librs.map.txt") {
+ t.Errorf("missing expected -Wl,--version-script= linker flag for libextended shared lib, linkFlags: %#v",
+ librs.Args["linkFlags"])
+ }
+ if strings.Contains(librs.Args["linkFlags"], "-Wl,--android-version-script=librs.map.txt") {
+ t.Errorf("unexpected -Wl,--android-version-script= linker flag for libextended shared lib, linkFlags: %#v",
+ librs.Args["linkFlags"])
+ }
+
+ if !strings.Contains(libffi.Args["linkFlags"], "-Wl,--android-version-script=libffi.map.txt") {
+ t.Errorf("missing -Wl,--android-version-script= linker flag for libreplaced shared lib, linkFlags: %#v",
+ libffi.Args["linkFlags"])
+ }
+ if strings.Contains(libffi.Args["linkFlags"], "-Wl,--version-script=libffi.map.txt") {
+ t.Errorf("unexpected -Wl,--version-script= linker flag for libextended shared lib, linkFlags: %#v",
+ libffi.Args["linkFlags"])
+ }
+}
+
+func TestRustVersionScriptPropertyErrors(t *testing.T) {
+ testRustError(t, "version_script: can only be set for rust_ffi modules", `
+ rust_library {
+ name: "librs",
+ srcs: ["bar.rs"],
+ crate_name: "rs",
+ version_script: "libbar.map.txt",
+ }`)
+ testRustError(t, "version_script and extra_exported_symbols", `
+ rust_ffi {
+ name: "librs",
+ srcs: ["bar.rs"],
+ crate_name: "rs",
+ version_script: "libbar.map.txt",
+ extra_exported_symbols: "libbar.map.txt",
+ }`)
+}
+
+func TestStubsVersions(t *testing.T) {
+ t.Parallel()
+ bp := `
+ rust_ffi {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.rs"],
+ stubs: {
+ versions: ["29", "R", "current"],
+ },
+ }
+ `
+ ctx := android.GroupFixturePreparers(
+ prepareForRustTest,
+ android.PrepareForTestWithVisibility,
+ rustMockedFiles.AddToFixture(),
+ android.FixtureModifyConfigAndContext(func(config android.Config, ctx *android.TestContext) {
+ config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
+ })).RunTestWithBp(t, bp)
+
+ variants := ctx.ModuleVariantsForTests("libfoo")
+ for _, expectedVer := range []string{"29", "R", "current"} {
+ expectedVariant := "android_arm_armv7-a-neon_shared_" + expectedVer
+ if !android.InList(expectedVariant, variants) {
+ t.Errorf("missing expected variant: %q", expectedVariant)
+ }
+ }
+}
+
+func TestStubsVersions_NotSorted(t *testing.T) {
+ t.Parallel()
+ bp := `
+ rust_ffi_shared {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.rs"],
+ stubs: {
+ versions: ["29", "current", "R"],
+ },
+ }
+ `
+ fixture := android.GroupFixturePreparers(
+ prepareForRustTest,
+ android.PrepareForTestWithVisibility,
+ rustMockedFiles.AddToFixture(),
+
+ android.FixtureModifyConfigAndContext(func(config android.Config, ctx *android.TestContext) {
+ config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
+ }))
+
+ fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(`"libfoo" .*: versions: not sorted`)).RunTestWithBp(t, bp)
+}
+
+func TestStubsVersions_ParseError(t *testing.T) {
+ t.Parallel()
+ bp := `
+ rust_ffi_shared {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.rs"],
+ stubs: {
+ versions: ["29", "current", "X"],
+ },
+ }
+ `
+ fixture := android.GroupFixturePreparers(
+ prepareForRustTest,
+ android.PrepareForTestWithVisibility,
+ rustMockedFiles.AddToFixture(),
+
+ android.FixtureModifyConfigAndContext(func(config android.Config, ctx *android.TestContext) {
+ config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
+ }))
+
+ fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(`"libfoo" .*: versions: "X" could not be parsed as an integer and is not a recognized codename`)).RunTestWithBp(t, bp)
+}
+
+func TestVersionedStubs(t *testing.T) {
+ t.Parallel()
+ bp := `
+ rust_ffi_shared {
+ name: "libFoo",
+ crate_name: "Foo",
+ srcs: ["foo.rs"],
+ stubs: {
+ symbol_file: "foo.map.txt",
+ versions: ["1", "2", "3"],
+ },
+ }
+
+ cc_library_shared {
+ name: "libBar",
+ srcs: ["bar.c"],
+ shared_libs: ["libFoo#1"],
+ }
+
+ rust_library {
+ name: "libbar_rs",
+ crate_name: "bar_rs",
+ srcs: ["bar.rs"],
+ shared_libs: ["libFoo#1"],
+ }
+ rust_ffi {
+ name: "libbar_ffi_rs",
+ crate_name: "bar_ffi_rs",
+ srcs: ["bar.rs"],
+ shared_libs: ["libFoo#1"],
+ }
+ `
+
+ ctx := android.GroupFixturePreparers(
+ prepareForRustTest,
+ android.PrepareForTestWithVisibility,
+ rustMockedFiles.AddToFixture()).RunTestWithBp(t, bp)
+
+ variants := ctx.ModuleVariantsForTests("libFoo")
+ expectedVariants := []string{
+ "android_arm64_armv8-a_shared",
+ "android_arm64_armv8-a_shared_1",
+ "android_arm64_armv8-a_shared_2",
+ "android_arm64_armv8-a_shared_3",
+ "android_arm64_armv8-a_shared_current",
+ "android_arm_armv7-a-neon_shared",
+ "android_arm_armv7-a-neon_shared_1",
+ "android_arm_armv7-a-neon_shared_2",
+ "android_arm_armv7-a-neon_shared_3",
+ "android_arm_armv7-a-neon_shared_current",
+ }
+ variantsMismatch := false
+ if len(variants) != len(expectedVariants) {
+ variantsMismatch = true
+ } else {
+ for _, v := range expectedVariants {
+ if !android.InList(v, variants) {
+ variantsMismatch = false
+ }
+ }
+ }
+ if variantsMismatch {
+ t.Errorf("variants of libFoo expected:\n")
+ for _, v := range expectedVariants {
+ t.Errorf("%q\n", v)
+ }
+ t.Errorf(", but got:\n")
+ for _, v := range variants {
+ t.Errorf("%q\n", v)
+ }
+ }
+
+ libBarLinkRule := ctx.ModuleForTests("libBar", "android_arm64_armv8-a_shared").Rule("ld")
+ libBarFlags := libBarLinkRule.Args["libFlags"]
+
+ libBarRsRustcRule := ctx.ModuleForTests("libbar_rs", "android_arm64_armv8-a_dylib").Rule("rustc")
+ libBarRsFlags := libBarRsRustcRule.Args["linkFlags"]
+
+ libBarFfiRsRustcRule := ctx.ModuleForTests("libbar_ffi_rs", "android_arm64_armv8-a_shared").Rule("rustc")
+ libBarFfiRsFlags := libBarFfiRsRustcRule.Args["linkFlags"]
+
+ libFoo1StubPath := "libFoo/android_arm64_armv8-a_shared_1/unstripped/libFoo.so"
+ if !strings.Contains(libBarFlags, libFoo1StubPath) {
+ t.Errorf("%q is not found in %q", libFoo1StubPath, libBarFlags)
+ }
+ if !strings.Contains(libBarRsFlags, libFoo1StubPath) {
+ t.Errorf("%q is not found in %q", libFoo1StubPath, libBarRsFlags)
+ }
+ if !strings.Contains(libBarFfiRsFlags, libFoo1StubPath) {
+ t.Errorf("%q is not found in %q", libFoo1StubPath, libBarFfiRsFlags)
+ }
+}
+
+func TestCheckConflictingExplicitVersions(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library_shared {
+ name: "libbar",
+ srcs: ["bar.c"],
+ shared_libs: ["libfoo", "libfoo#impl"],
+ }
+
+ rust_ffi_shared {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.rs"],
+ stubs: {
+ versions: ["29", "current"],
+ },
+ }
+ `
+ fixture := android.GroupFixturePreparers(
+ prepareForRustTest,
+ android.PrepareForTestWithVisibility,
+ rustMockedFiles.AddToFixture())
+
+ fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(`duplicate shared libraries with different explicit versions`)).RunTestWithBp(t, bp)
+}
+
+func TestAddnoOverride64GlobalCflags(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library_shared {
+ name: "libclient",
+ srcs: ["foo.c"],
+ shared_libs: ["libfoo#1"],
+ }
+
+ rust_ffi_shared {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.c"],
+ shared_libs: ["libbar"],
+ stubs: {
+ symbol_file: "foo.map.txt",
+ versions: ["1", "2", "3"],
+ },
+ }
+
+ cc_library_shared {
+ name: "libbar",
+ export_include_dirs: ["include/libbar"],
+ srcs: ["foo.c"],
+ }`
+ ctx := android.GroupFixturePreparers(
+ prepareForRustTest,
+ android.PrepareForTestWithVisibility,
+ rustMockedFiles.AddToFixture()).RunTestWithBp(t, bp)
+
+ cFlags := ctx.ModuleForTests("libclient", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"]
+
+ if !strings.Contains(cFlags, "${config.NoOverride64GlobalCflags}") {
+ t.Errorf("expected %q in cflags, got %q", "${config.NoOverride64GlobalCflags}", cFlags)
+ }
+}
+
+// Make sure the stubs properties can only be used in modules producing shared libs
+func TestRustStubsFFIOnly(t *testing.T) {
+ testRustError(t, "stubs properties", `
+ rust_library {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.c"],
+ shared_libs: ["libbar"],
+ stubs: {
+ symbol_file: "foo.map.txt",
+ },
+ }
+ `)
+
+ testRustError(t, "stubs properties", `
+ rust_library {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.c"],
+ shared_libs: ["libbar"],
+ stubs: {
+ versions: ["1"],
+ },
+ }
+ `)
+
+ testRustError(t, "stubs properties", `
+ rust_ffi_static {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.c"],
+ shared_libs: ["libbar"],
+ stubs: {
+ symbol_file: "foo.map.txt",
+ },
+ }
+ `)
+ testRustError(t, "stubs properties", `
+ rust_ffi_static {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.c"],
+ shared_libs: ["libbar"],
+ stubs: {
+ versions: ["1"],
+ },
+ }
+ `)
+}
+
+// TODO: When rust_ffi libraries support export_*_lib_headers,
+// add a test similar to cc.TestStubsLibReexportsHeaders
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 1ff6637..837e1a6 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -67,6 +67,7 @@
func (procMacro *procMacroDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
flags = procMacro.baseCompiler.compilerFlags(ctx, flags)
flags.RustFlags = append(flags.RustFlags, "--extern proc_macro")
+ flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName())
return flags
}
@@ -99,3 +100,9 @@
// Proc_macros are never installed
return false
}
+
+func (library *procMacroDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+ library.baseCompiler.moduleInfoJSON(ctx, moduleInfoJSON)
+
+ moduleInfoJSON.Class = []string{"PROC_MACRO_LIBRARIES"}
+}
diff --git a/rust/project_json.go b/rust/project_json.go
index 24dcc89..6e8cebe 100644
--- a/rust/project_json.go
+++ b/rust/project_json.go
@@ -19,6 +19,7 @@
"fmt"
"android/soong/android"
+ "android/soong/rust/config"
)
// This singleton collects Rust crate definitions and generates a JSON file
@@ -44,17 +45,19 @@
}
type rustProjectCrate struct {
- DisplayName string `json:"display_name"`
- RootModule string `json:"root_module"`
- Edition string `json:"edition,omitempty"`
- Deps []rustProjectDep `json:"deps"`
- Cfg []string `json:"cfg"`
- Env map[string]string `json:"env"`
- ProcMacro bool `json:"is_proc_macro"`
+ DisplayName string `json:"display_name"`
+ RootModule string `json:"root_module"`
+ Edition string `json:"edition,omitempty"`
+ Deps []rustProjectDep `json:"deps"`
+ Cfg []string `json:"cfg"`
+ Env map[string]string `json:"env"`
+ ProcMacro bool `json:"is_proc_macro"`
+ ProcMacroDylib *string `json:"proc_macro_dylib_path"`
}
type rustProjectJson struct {
- Crates []rustProjectCrate `json:"crates"`
+ Sysroot string `json:"sysroot"`
+ Crates []rustProjectCrate `json:"crates"`
}
// crateInfo is used during the processing to keep track of the known crates.
@@ -135,23 +138,28 @@
return 0, false
}
- _, procMacro := rModule.compiler.(*procMacroDecorator)
+ var procMacroDylib *string = nil
+ if procDec, procMacro := rModule.compiler.(*procMacroDecorator); procMacro {
+ procMacroDylib = new(string)
+ *procMacroDylib = procDec.baseCompiler.unstrippedOutputFilePath().String()
+ }
crate := rustProjectCrate{
- DisplayName: rModule.Name(),
- RootModule: rootModule.String(),
- Edition: rModule.compiler.edition(),
- Deps: make([]rustProjectDep, 0),
- Cfg: make([]string, 0),
- Env: make(map[string]string),
- ProcMacro: procMacro,
+ DisplayName: rModule.Name(),
+ RootModule: rootModule.String(),
+ Edition: rModule.compiler.edition(),
+ Deps: make([]rustProjectDep, 0),
+ Cfg: make([]string, 0),
+ Env: make(map[string]string),
+ ProcMacro: procMacroDylib != nil,
+ ProcMacroDylib: procMacroDylib,
}
if rModule.compiler.cargoOutDir().Valid() {
crate.Env["OUT_DIR"] = rModule.compiler.cargoOutDir().String()
}
- for _, feature := range rModule.compiler.features() {
+ for _, feature := range rModule.compiler.features(ctx, rModule) {
crate.Cfg = append(crate.Cfg, "feature=\""+feature+"\"")
}
@@ -197,6 +205,8 @@
return
}
+ singleton.project.Sysroot = config.RustPath(ctx)
+
singleton.knownCrates = make(map[string]crateInfo)
ctx.VisitAllModules(func(module android.Module) {
singleton.appendCrateAndDependencies(ctx, module)
diff --git a/rust/rust.go b/rust/rust.go
index 3402adc..5cc8c07 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -20,21 +20,50 @@
"strings"
"android/soong/bloaty"
- "android/soong/testing"
"github.com/google/blueprint"
+ "github.com/google/blueprint/depset"
"github.com/google/blueprint/proptools"
"android/soong/android"
"android/soong/cc"
cc_config "android/soong/cc/config"
"android/soong/fuzz"
- "android/soong/multitree"
"android/soong/rust/config"
)
var pctx = android.NewPackageContext("android/soong/rust")
+type LibraryInfo struct {
+ Rlib bool
+ Dylib bool
+}
+
+type CompilerInfo struct {
+ StdLinkageForDevice RustLinkage
+ StdLinkageForNonDevice RustLinkage
+ NoStdlibs bool
+ LibraryInfo *LibraryInfo
+}
+
+type ProtobufDecoratorInfo struct{}
+
+type SourceProviderInfo struct {
+ Srcs android.Paths
+ ProtobufDecoratorInfo *ProtobufDecoratorInfo
+}
+
+type RustInfo struct {
+ AndroidMkSuffix string
+ RustSubName string
+ TransitiveAndroidMkSharedLibs depset.DepSet[string]
+ CompilerInfo *CompilerInfo
+ SnapshotInfo *cc.SnapshotInfo
+ SourceProviderInfo *SourceProviderInfo
+}
+
+var RustInfoProvider = blueprint.NewProvider[*RustInfo]()
+
func init() {
android.RegisterModuleType("rust_defaults", defaultsFactory)
android.PreDepsMutators(registerPreDepsMutators)
@@ -48,11 +77,11 @@
func registerPreDepsMutators(ctx android.RegisterMutatorsContext) {
ctx.Transition("rust_libraries", &libraryTransitionMutator{})
ctx.Transition("rust_stdlinkage", &libstdTransitionMutator{})
- ctx.BottomUp("rust_begin", BeginMutator).Parallel()
+ ctx.BottomUp("rust_begin", BeginMutator)
}
func registerPostDepsMutators(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel()
+ ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator)
}
type Flags struct {
@@ -134,9 +163,36 @@
// Make this module available when building for recovery
Recovery_available *bool
- // Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
+ // The API level that this module is built against. The APIs of this API level will be
+ // visible at build time, but use of any APIs newer than min_sdk_version will render the
+ // module unloadable on older devices. In the future it will be possible to weakly-link new
+ // APIs, making the behavior match Java: such modules will load on older devices, but
+ // calling new APIs on devices that do not support them will result in a crash.
+ //
+ // This property has the same behavior as sdk_version does for Java modules. For those
+ // familiar with Android Gradle, the property behaves similarly to how compileSdkVersion
+ // does for Java code.
+ //
+ // In addition, setting this property causes two variants to be built, one for the platform
+ // and one for apps.
+ Sdk_version *string
+
+ // Minimum OS API level supported by this C or C++ module. This property becomes the value
+ // of the __ANDROID_API__ macro. When the C or C++ module is included in an APEX or an APK,
+ // this property is also used to ensure that the min_sdk_version of the containing module is
+ // not older (i.e. less) than this module's min_sdk_version. When not set, this property
+ // defaults to the value of sdk_version. When this is set to "apex_inherit", this tracks
+ // min_sdk_version of the containing APEX. When the module
+ // is not built for an APEX, "apex_inherit" defaults to sdk_version.
Min_sdk_version *string
+ // Variant is an SDK variant created by sdkMutator
+ IsSdkVariant bool `blueprint:"mutated"`
+
+ // Set by factories of module types that can only be referenced from variants compiled against
+ // the SDK.
+ AlwaysSdk bool `blueprint:"mutated"`
+
HideFromMake bool `blueprint:"mutated"`
PreventInstall bool `blueprint:"mutated"`
@@ -180,7 +236,10 @@
// For apex variants, this is set as apex.min_sdk_version
apexSdkVersion android.ApiLevel
- transitiveAndroidMkSharedLibs *android.DepSet[string]
+ transitiveAndroidMkSharedLibs depset.DepSet[string]
+
+ // Shared flags among stubs build rules of this module
+ sharedFlags cc.SharedFlags
}
func (mod *Module) Header() bool {
@@ -294,6 +353,15 @@
return mod.StaticallyLinked()
}
+func (mod *Module) ApexExclude() bool {
+ if mod.compiler != nil {
+ if library, ok := mod.compiler.(libraryInterface); ok {
+ return library.apexExclude()
+ }
+ }
+ return false
+}
+
func (mod *Module) Object() bool {
// Rust has no modules which produce only object files.
return false
@@ -337,7 +405,8 @@
}
func (mod *Module) IsVendorPublicLibrary() bool {
- return mod.VendorProperties.IsVendorPublicLibrary
+ // Rust modules do not currently support vendor_public_library
+ return false
}
func (mod *Module) SdkAndPlatformVariantVisibleToMake() bool {
@@ -346,10 +415,12 @@
}
func (c *Module) IsVndkPrivate() bool {
+ // Rust modules do not currently support VNDK variants
return false
}
func (c *Module) IsLlndk() bool {
+ // Rust modules do not currently support LLNDK variants
return false
}
@@ -358,35 +429,34 @@
}
func (m *Module) NeedsLlndkVariants() bool {
+ // Rust modules do not currently support LLNDK variants
return false
}
func (m *Module) NeedsVendorPublicLibraryVariants() bool {
+ // Rust modules do not currently support vendor_public_library
return false
}
func (mod *Module) HasLlndkStubs() bool {
+ // Rust modules do not currently support LLNDK stubs
return false
}
-func (mod *Module) StubsVersion() string {
- panic(fmt.Errorf("StubsVersion called on non-versioned module: %q", mod.BaseModuleName()))
-}
-
func (mod *Module) SdkVersion() string {
- return ""
+ return String(mod.Properties.Sdk_version)
}
func (mod *Module) AlwaysSdk() bool {
- return false
+ return mod.Properties.AlwaysSdk
}
func (mod *Module) IsSdkVariant() bool {
- return false
+ return mod.Properties.IsSdkVariant
}
func (mod *Module) SplitPerApiLevel() bool {
- return false
+ return cc.CanUseSdk(mod) && mod.IsCrt()
}
func (mod *Module) XrefRustFiles() android.Paths {
@@ -419,6 +489,7 @@
StaticLibs android.Paths
ProcMacros RustLibraries
AfdoProfiles android.Paths
+ LinkerDeps android.Paths
// depFlags and depLinkFlags are rustc and linker (clang) flags.
depFlags []string
@@ -446,6 +517,9 @@
// Paths to generated source files
SrcDeps android.Paths
srcProviderFiles android.Paths
+
+ directImplementationDeps android.Paths
+ transitiveImplementationDeps []depset.DepSet[android.Path]
}
type RustLibraries []RustLibrary
@@ -520,6 +594,9 @@
func (mod *Module) PreventInstall() bool {
return mod.Properties.PreventInstall
}
+func (c *Module) ForceDisableSanitizers() {
+ c.sanitize.Properties.ForceDisable = true
+}
func (mod *Module) MarkAsCoverageVariant(coverage bool) {
mod.coverage.Properties.IsCoverageVariant = coverage
@@ -583,7 +660,7 @@
if mod.compiler != nil {
// use build{Static,Shared}() instead of {static,shared}() here because this might be called before
// VariantIs{Static,Shared} is set.
- if lib, ok := mod.compiler.(libraryInterface); ok && (lib.buildShared() || lib.buildStatic()) {
+ if lib, ok := mod.compiler.(libraryInterface); ok && (lib.buildShared() || lib.buildStatic() || lib.buildRlib()) {
return true
}
}
@@ -669,15 +746,6 @@
panic(fmt.Errorf("BuildRlibVariant called on non-library module: %q", mod.BaseModuleName()))
}
-func (mod *Module) IsRustFFI() bool {
- if mod.compiler != nil {
- if library, ok := mod.compiler.(libraryInterface); ok {
- return library.isFFILibrary()
- }
- }
- return false
-}
-
func (mod *Module) BuildSharedVariant() bool {
if mod.compiler != nil {
if library, ok := mod.compiler.(libraryInterface); ok {
@@ -712,6 +780,50 @@
}
func (mod *Module) IsStubs() bool {
+ if lib, ok := mod.compiler.(libraryInterface); ok {
+ return lib.BuildStubs()
+ }
+ return false
+}
+
+func (mod *Module) HasStubsVariants() bool {
+ if lib, ok := mod.compiler.(libraryInterface); ok {
+ return lib.HasStubsVariants()
+ }
+ return false
+}
+
+func (mod *Module) ApexSdkVersion() android.ApiLevel {
+ return mod.apexSdkVersion
+}
+
+func (mod *Module) RustApexExclude() bool {
+ return mod.ApexExclude()
+}
+
+func (mod *Module) getSharedFlags() *cc.SharedFlags {
+ shared := &mod.sharedFlags
+ if shared.FlagsMap == nil {
+ shared.NumSharedFlags = 0
+ shared.FlagsMap = make(map[string]string)
+ }
+ return shared
+}
+
+func (mod *Module) ImplementationModuleNameForMake(ctx android.BaseModuleContext) string {
+ name := mod.BaseModuleName()
+ if versioned, ok := mod.compiler.(cc.VersionedInterface); ok {
+ name = versioned.ImplementationModuleName(name)
+ }
+ return name
+}
+
+func (mod *Module) Multilib() string {
+ return mod.Arch().ArchType.Multilib
+}
+
+func (mod *Module) IsCrt() bool {
+ // Rust does not currently provide any crt modules.
return false
}
@@ -735,6 +847,7 @@
}
var _ cc.LinkableInterface = (*Module)(nil)
+var _ cc.VersionedLinkableInterface = (*Module)(nil)
func (mod *Module) Init() android.Module {
mod.AddProperties(&mod.Properties)
@@ -845,6 +958,25 @@
return mod.compiler != nil && mod.compiler.nativeCoverage()
}
+func (mod *Module) SetStl(s string) {
+ // STL is a CC concept; do nothing for Rust
+}
+
+func (mod *Module) SetSdkVersion(s string) {
+ mod.Properties.Sdk_version = StringPtr(s)
+}
+
+func (mod *Module) SetMinSdkVersion(s string) {
+ mod.Properties.Min_sdk_version = StringPtr(s)
+}
+
+func (mod *Module) VersionedInterface() cc.VersionedInterface {
+ if _, ok := mod.compiler.(cc.VersionedInterface); ok {
+ return mod.compiler.(cc.VersionedInterface)
+ }
+ return nil
+}
+
func (mod *Module) EverInstallable() bool {
return mod.compiler != nil &&
// Check to see whether the module is actually ever installable.
@@ -912,7 +1044,7 @@
if mod.compiler != nil {
flags = mod.compiler.compilerFlags(ctx, flags)
flags = mod.compiler.cfgFlags(ctx, flags)
- flags = mod.compiler.featureFlags(ctx, flags)
+ flags = mod.compiler.featureFlags(ctx, mod, flags)
}
if mod.coverage != nil {
flags, deps = mod.coverage.flags(ctx, flags, deps)
@@ -934,11 +1066,11 @@
mod.sourceProvider.GenerateSource(ctx, deps)
mod.sourceProvider.setSubName(ctx.ModuleSubDir())
} else {
- sourceMod := actx.GetDirectDepWithTag(mod.Name(), sourceDepTag)
- sourceLib := sourceMod.(*Module).compiler.(*libraryDecorator)
- mod.sourceProvider.setOutputFiles(sourceLib.sourceProvider.Srcs())
+ sourceMod := actx.GetDirectDepProxyWithTag(mod.Name(), sourceDepTag)
+ sourceLib := android.OtherModuleProviderOrDefault(ctx, sourceMod, RustInfoProvider).SourceProviderInfo
+ mod.sourceProvider.setOutputFiles(sourceLib.Srcs)
}
- android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: mod.sourceProvider.Srcs().Strings()})
+ ctx.CheckbuildFile(mod.sourceProvider.Srcs()...)
}
if mod.compiler != nil && !mod.compiler.Disabled() {
@@ -948,15 +1080,13 @@
return
}
mod.outputFile = android.OptionalPathForPath(buildOutput.outputFile)
+ ctx.CheckbuildFile(buildOutput.outputFile)
if buildOutput.kytheFile != nil {
mod.kytheFiles = append(mod.kytheFiles, buildOutput.kytheFile)
}
bloaty.MeasureSizeForPaths(ctx, mod.compiler.strippedOutputFilePath(), android.OptionalPathForPath(mod.compiler.unstrippedOutputFilePath()))
mod.docTimestampFile = mod.compiler.rustdoc(ctx, flags, deps)
- if mod.docTimestampFile.Valid() {
- ctx.CheckbuildFile(mod.docTimestampFile.Path())
- }
apexInfo, _ := android.ModuleProvider(actx, android.ApexInfoProvider)
if !proptools.BoolDefault(mod.Installable(), mod.EverInstallable()) && !mod.ProcMacro() {
@@ -967,6 +1097,7 @@
// side dependencies. In particular, proc-macros need to be captured in the
// host snapshot.
mod.HideFromMake()
+ mod.SkipInstall()
} else if !mod.installable(apexInfo) {
mod.SkipInstall()
}
@@ -983,15 +1114,80 @@
}
+ android.SetProvider(ctx, cc.ImplementationDepInfoProvider, &cc.ImplementationDepInfo{
+ ImplementationDeps: depset.New(depset.PREORDER, deps.directImplementationDeps, deps.transitiveImplementationDeps),
+ })
+
ctx.Phony("rust", ctx.RustModule().OutputFile().Path())
}
- if mod.testModule {
- android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+
+ linkableInfo := cc.CreateCommonLinkableInfo(ctx, mod)
+ linkableInfo.Static = mod.Static()
+ linkableInfo.Shared = mod.Shared()
+ linkableInfo.CrateName = mod.CrateName()
+ linkableInfo.ExportedCrateLinkDirs = mod.ExportedCrateLinkDirs()
+ if lib, ok := mod.compiler.(cc.VersionedInterface); ok {
+ linkableInfo.StubsVersion = lib.StubsVersion()
}
+ android.SetProvider(ctx, cc.LinkableInfoProvider, linkableInfo)
+
+ rustInfo := &RustInfo{
+ AndroidMkSuffix: mod.AndroidMkSuffix(),
+ RustSubName: mod.Properties.RustSubName,
+ TransitiveAndroidMkSharedLibs: mod.transitiveAndroidMkSharedLibs,
+ }
+ if mod.compiler != nil {
+ rustInfo.CompilerInfo = &CompilerInfo{
+ NoStdlibs: mod.compiler.noStdlibs(),
+ StdLinkageForDevice: mod.compiler.stdLinkage(true),
+ StdLinkageForNonDevice: mod.compiler.stdLinkage(false),
+ }
+ if lib, ok := mod.compiler.(libraryInterface); ok {
+ rustInfo.CompilerInfo.LibraryInfo = &LibraryInfo{
+ Dylib: lib.dylib(),
+ Rlib: lib.rlib(),
+ }
+ }
+ if lib, ok := mod.compiler.(cc.SnapshotInterface); ok {
+ rustInfo.SnapshotInfo = &cc.SnapshotInfo{
+ SnapshotAndroidMkSuffix: lib.SnapshotAndroidMkSuffix(),
+ }
+ }
+ }
+ if mod.sourceProvider != nil {
+ rustInfo.SourceProviderInfo = &SourceProviderInfo{
+ Srcs: mod.sourceProvider.Srcs(),
+ }
+ if _, ok := mod.sourceProvider.(*protobufDecorator); ok {
+ rustInfo.SourceProviderInfo.ProtobufDecoratorInfo = &ProtobufDecoratorInfo{}
+ }
+ }
+ android.SetProvider(ctx, RustInfoProvider, rustInfo)
+
+ ccInfo := &cc.CcInfo{
+ IsPrebuilt: mod.IsPrebuilt(),
+ }
+
+ // Define the linker info if compiler != nil because Rust currently
+ // does compilation and linking in one step. If this changes in the future,
+ // move this as appropriate.
+ ccInfo.LinkerInfo = &cc.LinkerInfo{
+ WholeStaticLibs: mod.compiler.baseCompilerProps().Whole_static_libs,
+ StaticLibs: mod.compiler.baseCompilerProps().Static_libs,
+ SharedLibs: mod.compiler.baseCompilerProps().Shared_libs,
+ }
+
+ android.SetProvider(ctx, cc.CcInfoProvider, ccInfo)
+
mod.setOutputFiles(ctx)
buildComplianceMetadataInfo(ctx, mod, deps)
+
+ moduleInfoJSON := ctx.ModuleInfoJSON()
+ if mod.compiler != nil {
+ mod.compiler.moduleInfoJSON(ctx, moduleInfoJSON)
+ }
}
func (mod *Module) setOutputFiles(ctx ModuleContext) {
@@ -1014,12 +1210,12 @@
metadataInfo.SetStringValue(android.ComplianceMetadataProp.BUILT_FILES, mod.outputFile.String())
// Static libs
- staticDeps := ctx.GetDirectDepsWithTag(rlibDepTag)
+ staticDeps := ctx.GetDirectDepsProxyWithTag(rlibDepTag)
staticDepNames := make([]string, 0, len(staticDeps))
for _, dep := range staticDeps {
staticDepNames = append(staticDepNames, dep.Name())
}
- ccStaticDeps := ctx.GetDirectDepsWithTag(cc.StaticDepTag(false))
+ ccStaticDeps := ctx.GetDirectDepsProxyWithTag(cc.StaticDepTag(false))
for _, dep := range ccStaticDeps {
staticDepNames = append(staticDepNames, dep.Name())
}
@@ -1037,7 +1233,7 @@
metadataInfo.SetListValue(android.ComplianceMetadataProp.STATIC_DEP_FILES, android.FirstUniqueStrings(staticDepPaths))
// C Whole static libs
- ccWholeStaticDeps := ctx.GetDirectDepsWithTag(cc.StaticDepTag(true))
+ ccWholeStaticDeps := ctx.GetDirectDepsProxyWithTag(cc.StaticDepTag(true))
wholeStaticDepNames := make([]string, 0, len(ccWholeStaticDeps))
for _, dep := range ccStaticDeps {
wholeStaticDepNames = append(wholeStaticDepNames, dep.Name())
@@ -1150,6 +1346,21 @@
if mod.sanitize != nil {
mod.sanitize.begin(ctx)
}
+
+ if mod.UseSdk() && mod.IsSdkVariant() {
+ sdkVersion := ""
+ if ctx.Device() {
+ sdkVersion = mod.SdkVersion()
+ }
+ version, err := cc.NativeApiLevelFromUser(ctx, sdkVersion)
+ if err != nil {
+ ctx.PropertyErrorf("sdk_version", err.Error())
+ mod.Properties.Sdk_version = nil
+ } else {
+ mod.Properties.Sdk_version = StringPtr(version.String())
+ }
+ }
+
}
func (mod *Module) Prebuilt() *android.Prebuilt {
@@ -1164,21 +1375,21 @@
return nil
}
-func rustMakeLibName(ctx android.ModuleContext, c cc.LinkableInterface, dep cc.LinkableInterface, depName string) string {
- if rustDep, ok := dep.(*Module); ok {
+func rustMakeLibName(rustInfo *RustInfo, linkableInfo *cc.LinkableInfo, commonInfo *android.CommonModuleInfo, depName string) string {
+ if rustInfo != nil {
// Use base module name for snapshots when exporting to Makefile.
- if snapshotPrebuilt, ok := rustDep.compiler.(cc.SnapshotInterface); ok {
- baseName := rustDep.BaseModuleName()
- return baseName + snapshotPrebuilt.SnapshotAndroidMkSuffix() + rustDep.AndroidMkSuffix()
+ if rustInfo.SnapshotInfo != nil {
+ baseName := linkableInfo.BaseModuleName
+ return baseName + rustInfo.SnapshotInfo.SnapshotAndroidMkSuffix + rustInfo.AndroidMkSuffix
}
}
- return cc.MakeLibName(ctx, c, dep, depName)
+ return cc.MakeLibName(nil, linkableInfo, commonInfo, depName)
}
-func collectIncludedProtos(mod *Module, dep *Module) {
+func collectIncludedProtos(mod *Module, rustInfo *RustInfo, linkableInfo *cc.LinkableInfo) {
if protoMod, ok := mod.sourceProvider.(*protobufDecorator); ok {
- if _, ok := dep.sourceProvider.(*protobufDecorator); ok {
- protoMod.additionalCrates = append(protoMod.additionalCrates, dep.CrateName())
+ if rustInfo.SourceProviderInfo.ProtobufDecoratorInfo != nil {
+ protoMod.additionalCrates = append(protoMod.additionalCrates, linkableInfo.CrateName)
}
}
}
@@ -1186,13 +1397,13 @@
func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
var depPaths PathDeps
- directRlibDeps := []*Module{}
- directDylibDeps := []*Module{}
- directProcMacroDeps := []*Module{}
+ directRlibDeps := []*cc.LinkableInfo{}
+ directDylibDeps := []*cc.LinkableInfo{}
+ directProcMacroDeps := []*cc.LinkableInfo{}
directSharedLibDeps := []cc.SharedLibraryInfo{}
- directStaticLibDeps := [](cc.LinkableInterface){}
- directSrcProvidersDeps := []*Module{}
- directSrcDeps := [](android.SourceFileProducer){}
+ directStaticLibDeps := [](*cc.LinkableInfo){}
+ directSrcProvidersDeps := []*android.ModuleProxy{}
+ directSrcDeps := []android.SourceFilesInfo{}
// For the dependency from platform to apex, use the latest stubs
mod.apexSdkVersion = android.FutureApiLevel
@@ -1210,53 +1421,14 @@
skipModuleList := map[string]bool{}
- var apiImportInfo multitree.ApiImportInfo
- hasApiImportInfo := false
-
- ctx.VisitDirectDeps(func(dep android.Module) {
- if dep.Name() == "api_imports" {
- apiImportInfo, _ = android.OtherModuleProvider(ctx, dep, multitree.ApiImportsProvider)
- hasApiImportInfo = true
- }
- })
-
- if hasApiImportInfo {
- targetStubModuleList := map[string]string{}
- targetOrigModuleList := map[string]string{}
-
- // Search for dependency which both original module and API imported library with APEX stub exists
- ctx.VisitDirectDeps(func(dep android.Module) {
- depName := ctx.OtherModuleName(dep)
- if apiLibrary, ok := apiImportInfo.ApexSharedLibs[depName]; ok {
- targetStubModuleList[apiLibrary] = depName
- }
- })
- ctx.VisitDirectDeps(func(dep android.Module) {
- depName := ctx.OtherModuleName(dep)
- if origLibrary, ok := targetStubModuleList[depName]; ok {
- targetOrigModuleList[origLibrary] = depName
- }
- })
-
- // Decide which library should be used between original and API imported library
- ctx.VisitDirectDeps(func(dep android.Module) {
- depName := ctx.OtherModuleName(dep)
- if apiLibrary, ok := targetOrigModuleList[depName]; ok {
- if cc.ShouldUseStubForApex(ctx, dep) {
- skipModuleList[depName] = true
- } else {
- skipModuleList[apiLibrary] = true
- }
- }
- })
- }
-
- var transitiveAndroidMkSharedLibs []*android.DepSet[string]
+ var transitiveAndroidMkSharedLibs []depset.DepSet[string]
var directAndroidMkSharedLibs []string
- ctx.VisitDirectDeps(func(dep android.Module) {
+ ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) {
depName := ctx.OtherModuleName(dep)
depTag := ctx.OtherModuleDependencyTag(dep)
+ modStdLinkage := mod.compiler.stdLinkage(ctx.Device())
+
if _, exists := skipModuleList[depName]; exists {
return
}
@@ -1265,45 +1437,81 @@
return
}
- if rustDep, ok := dep.(*Module); ok && !rustDep.Static() && !rustDep.Shared() {
+ rustInfo, hasRustInfo := android.OtherModuleProvider(ctx, dep, RustInfoProvider)
+ ccInfo, _ := android.OtherModuleProvider(ctx, dep, cc.CcInfoProvider)
+ linkableInfo, hasLinkableInfo := android.OtherModuleProvider(ctx, dep, cc.LinkableInfoProvider)
+ commonInfo := android.OtherModuleProviderOrDefault(ctx, dep, android.CommonModuleInfoKey)
+ if hasRustInfo && !linkableInfo.Static && !linkableInfo.Shared {
//Handle Rust Modules
- makeLibName := rustMakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName)
+ makeLibName := rustMakeLibName(rustInfo, linkableInfo, &commonInfo, depName+rustInfo.RustSubName)
switch {
case depTag == dylibDepTag:
- dylib, ok := rustDep.compiler.(libraryInterface)
- if !ok || !dylib.dylib() {
+ dylib := rustInfo.CompilerInfo.LibraryInfo
+ if dylib == nil || !dylib.Dylib {
ctx.ModuleErrorf("mod %q not an dylib library", depName)
return
}
- directDylibDeps = append(directDylibDeps, rustDep)
+ directDylibDeps = append(directDylibDeps, linkableInfo)
mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, makeLibName)
mod.Properties.SnapshotDylibs = append(mod.Properties.SnapshotDylibs, cc.BaseLibName(depName))
+ depPaths.directImplementationDeps = append(depPaths.directImplementationDeps, android.OutputFileForModule(ctx, dep, ""))
+ if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok {
+ depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps)
+ }
+
+ if !rustInfo.CompilerInfo.NoStdlibs {
+ rustDepStdLinkage := rustInfo.CompilerInfo.StdLinkageForNonDevice
+ if ctx.Device() {
+ rustDepStdLinkage = rustInfo.CompilerInfo.StdLinkageForDevice
+ }
+ if rustDepStdLinkage != modStdLinkage {
+ ctx.ModuleErrorf("Rust dependency %q has the wrong StdLinkage; expected %#v, got %#v", depName, modStdLinkage, rustDepStdLinkage)
+ return
+ }
+ }
+
case depTag == rlibDepTag:
- rlib, ok := rustDep.compiler.(libraryInterface)
- if !ok || !rlib.rlib() {
+ rlib := rustInfo.CompilerInfo.LibraryInfo
+ if rlib == nil || !rlib.Rlib {
ctx.ModuleErrorf("mod %q not an rlib library", makeLibName)
return
}
- directRlibDeps = append(directRlibDeps, rustDep)
+ directRlibDeps = append(directRlibDeps, linkableInfo)
mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, makeLibName)
mod.Properties.SnapshotRlibs = append(mod.Properties.SnapshotRlibs, cc.BaseLibName(depName))
// rust_ffi rlibs may export include dirs, so collect those here.
exportedInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider)
depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
- depPaths.exportedLinkDirs = append(depPaths.exportedLinkDirs, linkPathFromFilePath(rustDep.OutputFile().Path()))
+ depPaths.exportedLinkDirs = append(depPaths.exportedLinkDirs, linkPathFromFilePath(linkableInfo.OutputFile.Path()))
+
+ // rlibs are not installed, so don't add the output file to directImplementationDeps
+ if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok {
+ depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps)
+ }
+
+ if !rustInfo.CompilerInfo.NoStdlibs {
+ rustDepStdLinkage := rustInfo.CompilerInfo.StdLinkageForNonDevice
+ if ctx.Device() {
+ rustDepStdLinkage = rustInfo.CompilerInfo.StdLinkageForDevice
+ }
+ if rustDepStdLinkage != modStdLinkage {
+ ctx.ModuleErrorf("Rust dependency %q has the wrong StdLinkage; expected %#v, got %#v", depName, modStdLinkage, rustDepStdLinkage)
+ return
+ }
+ }
case depTag == procMacroDepTag:
- directProcMacroDeps = append(directProcMacroDeps, rustDep)
+ directProcMacroDeps = append(directProcMacroDeps, linkableInfo)
mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName)
// proc_macro link dirs need to be exported, so collect those here.
- depPaths.exportedLinkDirs = append(depPaths.exportedLinkDirs, linkPathFromFilePath(rustDep.OutputFile().Path()))
+ depPaths.exportedLinkDirs = append(depPaths.exportedLinkDirs, linkPathFromFilePath(linkableInfo.OutputFile.Path()))
case depTag == sourceDepTag:
if _, ok := mod.sourceProvider.(*protobufDecorator); ok {
- collectIncludedProtos(mod, rustDep)
+ collectIncludedProtos(mod, rustInfo, linkableInfo)
}
case cc.IsStaticDepTag(depTag):
// Rust FFI rlibs should not be declared in a Rust modules
@@ -1316,7 +1524,7 @@
}
- transitiveAndroidMkSharedLibs = append(transitiveAndroidMkSharedLibs, rustDep.transitiveAndroidMkSharedLibs)
+ transitiveAndroidMkSharedLibs = append(transitiveAndroidMkSharedLibs, rustInfo.TransitiveAndroidMkSharedLibs)
if android.IsSourceDepTagWithOutputTag(depTag, "") {
// Since these deps are added in path_properties.go via AddDependencies, we need to ensure the correct
@@ -1328,14 +1536,14 @@
helper = "device module defined?"
}
- if dep.Target().Os != ctx.Os() {
+ if commonInfo.Target.Os != ctx.Os() {
ctx.ModuleErrorf("OS mismatch on dependency %q (%s)", dep.Name(), helper)
return
- } else if dep.Target().Arch.ArchType != ctx.Arch().ArchType {
+ } else if commonInfo.Target.Arch.ArchType != ctx.Arch().ArchType {
ctx.ModuleErrorf("Arch mismatch on dependency %q (%s)", dep.Name(), helper)
return
}
- directSrcProvidersDeps = append(directSrcProvidersDeps, rustDep)
+ directSrcProvidersDeps = append(directSrcProvidersDeps, &dep)
}
exportedInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider)
@@ -1347,7 +1555,7 @@
}
if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
- linkFile := rustDep.UnstrippedOutputFile()
+ linkFile := linkableInfo.UnstrippedOutputFile
linkDir := linkPathFromFilePath(linkFile)
if lib, ok := mod.compiler.(exportedFlagsProducer); ok {
lib.exportLinkDirs(linkDir)
@@ -1356,26 +1564,26 @@
if depTag == sourceDepTag {
if _, ok := mod.sourceProvider.(*protobufDecorator); ok && mod.Source() {
- if _, ok := rustDep.sourceProvider.(*protobufDecorator); ok {
+ if rustInfo.SourceProviderInfo.ProtobufDecoratorInfo != nil {
exportedInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider)
depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
}
}
}
- } else if ccDep, ok := dep.(cc.LinkableInterface); ok {
+ } else if hasLinkableInfo {
//Handle C dependencies
- makeLibName := cc.MakeLibName(ctx, mod, ccDep, depName)
- if _, ok := ccDep.(*Module); !ok {
- if ccDep.Module().Target().Os != ctx.Os() {
+ makeLibName := cc.MakeLibName(ccInfo, linkableInfo, &commonInfo, depName)
+ if !hasRustInfo {
+ if commonInfo.Target.Os != ctx.Os() {
ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
return
}
- if ccDep.Module().Target().Arch.ArchType != ctx.Arch().ArchType {
+ if commonInfo.Target.Arch.ArchType != ctx.Arch().ArchType {
ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName)
return
}
}
- linkObject := ccDep.OutputFile()
+ linkObject := linkableInfo.OutputFile
if !linkObject.Valid() {
if !ctx.Config().AllowMissingDependencies() {
ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
@@ -1415,7 +1623,7 @@
depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...)
depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...)
depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, exportedInfo.GeneratedHeaders...)
- directStaticLibDeps = append(directStaticLibDeps, ccDep)
+ directStaticLibDeps = append(directStaticLibDeps, linkableInfo)
// Record baseLibName for snapshots.
mod.Properties.SnapshotStaticLibs = append(mod.Properties.SnapshotStaticLibs, cc.BaseLibName(depName))
@@ -1427,6 +1635,16 @@
// dependency crosses the APEX boundaries).
sharedLibraryInfo, exportedInfo := cc.ChooseStubOrImpl(ctx, dep)
+ if !sharedLibraryInfo.IsStubs {
+ // TODO(b/362509506): remove this additional check once all apex_exclude uses are switched to stubs.
+ if !linkableInfo.RustApexExclude {
+ depPaths.directImplementationDeps = append(depPaths.directImplementationDeps, android.OutputFileForModule(ctx, dep, ""))
+ if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok {
+ depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps)
+ }
+ }
+ }
+
// Re-get linkObject as ChooseStubOrImpl actually tells us which
// object (either from stub or non-stub) to use.
linkObject = android.OptionalPathForPath(sharedLibraryInfo.SharedLibrary)
@@ -1479,7 +1697,7 @@
}
}
- if srcDep, ok := dep.(android.SourceFileProducer); ok {
+ if srcDep, ok := android.OtherModuleProvider(ctx, dep, android.SourceFilesInfoProvider); ok {
if android.IsSourceDepTagWithOutputTag(depTag, "") {
// These are usually genrules which don't have per-target variants.
directSrcDeps = append(directSrcDeps, srcDep)
@@ -1487,37 +1705,37 @@
}
})
- mod.transitiveAndroidMkSharedLibs = android.NewDepSet[string](android.PREORDER, directAndroidMkSharedLibs, transitiveAndroidMkSharedLibs)
+ mod.transitiveAndroidMkSharedLibs = depset.New[string](depset.PREORDER, directAndroidMkSharedLibs, transitiveAndroidMkSharedLibs)
var rlibDepFiles RustLibraries
aliases := mod.compiler.Aliases()
for _, dep := range directRlibDeps {
- crateName := dep.CrateName()
+ crateName := dep.CrateName
if alias, aliased := aliases[crateName]; aliased {
crateName = alias
}
- rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: crateName})
+ rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile, CrateName: crateName})
}
var dylibDepFiles RustLibraries
for _, dep := range directDylibDeps {
- crateName := dep.CrateName()
+ crateName := dep.CrateName
if alias, aliased := aliases[crateName]; aliased {
crateName = alias
}
- dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: crateName})
+ dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile, CrateName: crateName})
}
var procMacroDepFiles RustLibraries
for _, dep := range directProcMacroDeps {
- crateName := dep.CrateName()
+ crateName := dep.CrateName
if alias, aliased := aliases[crateName]; aliased {
crateName = alias
}
- procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: crateName})
+ procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile, CrateName: crateName})
}
var staticLibDepFiles android.Paths
for _, dep := range directStaticLibDeps {
- staticLibDepFiles = append(staticLibDepFiles, dep.OutputFile().Path())
+ staticLibDepFiles = append(staticLibDepFiles, dep.OutputFile.Path())
}
var sharedLibFiles android.Paths
@@ -1533,11 +1751,11 @@
var srcProviderDepFiles android.Paths
for _, dep := range directSrcProvidersDeps {
- srcs := android.OutputFilesForModule(ctx, dep, "")
+ srcs := android.OutputFilesForModule(ctx, *dep, "")
srcProviderDepFiles = append(srcProviderDepFiles, srcs...)
}
for _, dep := range directSrcDeps {
- srcs := dep.Srcs()
+ srcs := dep.Srcs
srcProviderDepFiles = append(srcProviderDepFiles, srcs...)
}
@@ -1556,6 +1774,7 @@
depPaths.depClangFlags = android.FirstUniqueStrings(depPaths.depClangFlags)
depPaths.depIncludePaths = android.FirstUniquePaths(depPaths.depIncludePaths)
depPaths.depSystemIncludePaths = android.FirstUniquePaths(depPaths.depSystemIncludePaths)
+ depPaths.depLinkFlags = android.FirstUniqueStrings(depPaths.depLinkFlags)
return depPaths
}
@@ -1601,19 +1820,12 @@
deps := mod.deps(ctx)
var commonDepVariations []blueprint.Variation
- apiImportInfo := cc.GetApiImports(mod, actx)
- if mod.usePublicApi() || mod.useVendorApi() {
- for idx, lib := range deps.SharedLibs {
- deps.SharedLibs[idx] = cc.GetReplaceModuleName(lib, apiImportInfo.SharedLibs)
- }
- }
-
if ctx.Os() == android.Android {
deps.SharedLibs, _ = cc.FilterNdkLibs(mod, ctx.Config(), deps.SharedLibs)
}
stdLinkage := "dylib-std"
- if mod.compiler.stdLinkage(ctx) == RlibLinkage {
+ if mod.compiler.stdLinkage(ctx.Device()) == RlibLinkage {
stdLinkage = "rlib-std"
}
@@ -1680,7 +1892,7 @@
// stdlibs
if deps.Stdlibs != nil {
- if mod.compiler.stdLinkage(ctx) == RlibLinkage {
+ if mod.compiler.stdLinkage(ctx.Device()) == RlibLinkage {
for _, lib := range deps.Stdlibs {
actx.AddVariationDependencies(append(commonDepVariations, []blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}...),
rlibDepTag, lib)
@@ -1700,15 +1912,7 @@
variations := []blueprint.Variation{
{Mutator: "link", Variation: "shared"},
}
- // For core variant, add a dep on the implementation (if it exists) and its .apiimport (if it exists)
- // GenerateAndroidBuildActions will pick the correct impl/stub based on the api_domain boundary
- if _, ok := apiImportInfo.ApexSharedLibs[name]; !ok || ctx.OtherModuleExists(name) {
- cc.AddSharedLibDependenciesWithVersions(ctx, mod, variations, depTag, name, version, false)
- }
-
- if apiLibraryName, ok := apiImportInfo.ApexSharedLibs[name]; ok {
- cc.AddSharedLibDependenciesWithVersions(ctx, mod, variations, depTag, apiLibraryName, version, false)
- }
+ cc.AddSharedLibDependenciesWithVersions(ctx, mod, variations, depTag, name, version, false)
}
for _, lib := range deps.WholeStaticLibs {
@@ -1805,6 +2009,16 @@
var _ android.ApexModule = (*Module)(nil)
+// If a module is marked for exclusion from apexes, don't provide apex variants.
+// TODO(b/362509506): remove this once all apex_exclude usages are removed.
+func (m *Module) CanHaveApexVariants() bool {
+ if m.ApexExclude() {
+ return false
+ } else {
+ return m.ApexModuleBase.CanHaveApexVariants()
+ }
+}
+
func (mod *Module) MinSdkVersion() string {
return String(mod.Properties.Min_sdk_version)
}
@@ -1833,44 +2047,74 @@
}
// Implements android.ApexModule
-func (mod *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
- depTag := ctx.OtherModuleDependencyTag(dep)
+func (mod *Module) AlwaysRequiresPlatformApexVariant() bool {
+ // stub libraries and native bridge libraries are always available to platform
+ // TODO(b/362509506): remove the ApexExclude() check once all apex_exclude uses are switched to stubs.
+ return mod.IsStubs() || mod.Target().NativeBridge == android.NativeBridgeEnabled || mod.ApexExclude()
+}
- if ccm, ok := dep.(*cc.Module); ok {
- if ccm.HasStubsVariants() {
- if cc.IsSharedDepTag(depTag) {
- // dynamic dep to a stubs lib crosses APEX boundary
- return false
- }
- if cc.IsRuntimeDepTag(depTag) {
- // runtime dep to a stubs lib also crosses APEX boundary
- return false
- }
-
- if cc.IsHeaderDepTag(depTag) {
- return false
- }
- }
- if mod.Static() && cc.IsSharedDepTag(depTag) {
- // shared_lib dependency from a static lib is considered as crossing
- // the APEX boundary because the dependency doesn't actually is
- // linked; the dependency is used only during the compilation phase.
- return false
- }
+// Implements android.ApexModule
+func (mod *Module) OutgoingDepIsInSameApex(depTag blueprint.DependencyTag) bool {
+ if depTag == procMacroDepTag || depTag == customBindgenDepTag {
+ return false
}
- if depTag == procMacroDepTag || depTag == customBindgenDepTag {
+ if mod.Static() && cc.IsSharedDepTag(depTag) {
+ // shared_lib dependency from a static lib is considered as crossing
+ // the APEX boundary because the dependency doesn't actually is
+ // linked; the dependency is used only during the compilation phase.
+ return false
+ }
+
+ if depTag == cc.StubImplDepTag {
+ // We don't track from an implementation library to its stubs.
+ return false
+ }
+
+ if cc.ExcludeInApexDepTag(depTag) {
+ return false
+ }
+
+ // TODO(b/362509506): remove once all apex_exclude uses are switched to stubs.
+ if mod.ApexExclude() {
return false
}
return true
}
+func (mod *Module) IncomingDepIsInSameApex(depTag blueprint.DependencyTag) bool {
+ // TODO(b/362509506): remove once all apex_exclude uses are switched to stubs.
+ if mod.ApexExclude() {
+ return false
+ }
+
+ if mod.HasStubsVariants() {
+ if cc.IsSharedDepTag(depTag) {
+ // dynamic dep to a stubs lib crosses APEX boundary
+ return false
+ }
+ if cc.IsRuntimeDepTag(depTag) {
+ // runtime dep to a stubs lib also crosses APEX boundary
+ return false
+ }
+ if cc.IsHeaderDepTag(depTag) {
+ return false
+ }
+ }
+ return true
+}
+
// Overrides ApexModule.IsInstallabeToApex()
func (mod *Module) IsInstallableToApex() bool {
+ // TODO(b/362509506): remove once all apex_exclude uses are switched to stubs.
+ if mod.ApexExclude() {
+ return false
+ }
+
if mod.compiler != nil {
- if lib, ok := mod.compiler.(libraryInterface); ok && (lib.shared() || lib.dylib()) {
- return true
+ if lib, ok := mod.compiler.(libraryInterface); ok {
+ return (lib.shared() || lib.dylib()) && !lib.BuildStubs()
}
if _, ok := mod.compiler.(*binaryDecorator); ok {
return true
diff --git a/rust/rust_test.go b/rust/rust_test.go
index eeedf3f..9f65dec 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -424,31 +424,31 @@
}`)
fooRustc := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
- if !strings.Contains(fooRustc.Args["libFlags"], "--extern bar_renamed=out/soong/.intermediates/libbar/android_arm64_armv8-a_dylib/unstripped/libbar.dylib.so") {
- t.Errorf("--extern bar_renamed=out/soong/.intermediates/libbar/android_arm64_armv8-a_dylib/unstripped/libbar.dylib.so flag not being passed to rustc for rust_binary with aliases. libFlags: %#v", fooRustc.Args["libFlags"])
+ if !strings.Contains(fooRustc.Args["libFlags"], "--extern force:bar_renamed=out/soong/.intermediates/libbar/android_arm64_armv8-a_dylib/unstripped/libbar.dylib.so") {
+ t.Errorf("--extern force:bar_renamed=out/soong/.intermediates/libbar/android_arm64_armv8-a_dylib/unstripped/libbar.dylib.so flag not being passed to rustc for rust_binary with aliases. libFlags: %#v", fooRustc.Args["libFlags"])
}
- if !strings.Contains(fooRustc.Args["libFlags"], "--extern baz=out/soong/.intermediates/libbaz/android_arm64_armv8-a_dylib/unstripped/libbaz.dylib.so") {
- t.Errorf("--extern baz=out/soong/.intermediates/libbaz/android_arm64_armv8-a_dylib/unstripped/libbaz.dylib.so flag not being passed to rustc for rust_binary with aliases. libFlags: %#v", fooRustc.Args["libFlags"])
+ if !strings.Contains(fooRustc.Args["libFlags"], "--extern force:baz=out/soong/.intermediates/libbaz/android_arm64_armv8-a_dylib/unstripped/libbaz.dylib.so") {
+ t.Errorf("--extern force:baz=out/soong/.intermediates/libbaz/android_arm64_armv8-a_dylib/unstripped/libbaz.dylib.so flag not being passed to rustc for rust_binary with aliases. libFlags: %#v", fooRustc.Args["libFlags"])
}
}
func TestRustRlibs(t *testing.T) {
ctx := testRust(t, `
- rust_ffi_rlib {
+ rust_ffi_static {
name: "libbar",
crate_name: "bar",
srcs: ["src/lib.rs"],
export_include_dirs: ["bar_includes"]
}
- rust_ffi_rlib {
+ rust_ffi_static {
name: "libfoo",
crate_name: "foo",
srcs: ["src/lib.rs"],
export_include_dirs: ["foo_includes"]
}
- rust_ffi_rlib {
+ rust_ffi_static {
name: "libbuzz",
crate_name: "buzz",
srcs: ["src/lib.rs"],
@@ -494,7 +494,7 @@
}
// Make sure the static lib is included in the ld command
- if !strings.Contains(libcc_shared_ld.Args["libFlags"], "generated_rust_staticlib/liblibcc_shared_rust_staticlib.a") {
+ if !strings.Contains(libcc_shared_ld.Args["libFlags"], "generated_rust_staticlib/librustlibs.a") {
t.Errorf("missing generated static library in linker step libFlags %#v, libFlags: %#v",
"libcc_shared.generated_rust_staticlib.a", libcc_shared_ld.Args["libFlags"])
}
@@ -511,7 +511,7 @@
}
// Make sure the static lib is included in the cc command
- if !strings.Contains(ccbin_ld.Args["libFlags"], "generated_rust_staticlib/libccBin_rust_staticlib.a") {
+ if !strings.Contains(ccbin_ld.Args["libFlags"], "generated_rust_staticlib/librustlibs.a") {
t.Errorf("missing generated static library in linker step libFlags, expecting %#v, libFlags: %#v",
"ccBin.generated_rust_staticlib.a", ccbin_ld.Args["libFlags"])
}
@@ -547,3 +547,31 @@
t.Errorf("expected %q got %q", expected, got)
}
}
+
+func TestStdLinkMismatch(t *testing.T) {
+ // Test that we catch cases where the std linkage mismatches. This leads to
+ // a confusing rustc error where a crate is declared missing despite being
+ // passed in as a rustlib dependency / via the --extern flag. Thus, we want
+ // to make sure we detect it in Soong.
+
+ // libfoo depends on libbar as an rlib, but does not link libstd as an rlib.
+ // libbar only links libstd as an rlib (prefer_rlib).
+ testRustError(t, "wrong StdLinkage", `
+ rust_library {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: [
+ "foo.rs",
+ ],
+ rlibs: ["libbar"],
+ }
+ rust_library {
+ name: "libbar",
+ crate_name: "bar",
+ srcs: [
+ "bar.rs",
+ ],
+ prefer_rlib: true,
+ }
+ `)
+}
diff --git a/rust/sanitize.go b/rust/sanitize.go
index c086880..50f55ce 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -53,6 +53,9 @@
// Used when we need to place libraries in their own directory, such as ASAN.
InSanitizerDir bool `blueprint:"mutated"`
+
+ // ForceDisable is set by the version mutator to disable sanitization of stubs variants
+ ForceDisable bool `blueprint:"mutated"`
}
var fuzzerFlags = []string{
@@ -94,14 +97,6 @@
"-C llvm-args=--hwasan-with-ifunc",
}
-func boolPtr(v bool) *bool {
- if v {
- return &v
- } else {
- return nil
- }
-}
-
func init() {
}
func (sanitize *sanitize) props() []interface{} {
@@ -111,6 +106,15 @@
func (sanitize *sanitize) begin(ctx BaseModuleContext) {
s := &sanitize.Properties.Sanitize
+ if sanitize.Properties.ForceDisable {
+ return
+ }
+
+ // Disable sanitizers for musl x86 modules, rustc does not support any sanitizers.
+ if ctx.Os() == android.LinuxMusl && ctx.Arch().ArchType == android.X86 {
+ s.Never = proptools.BoolPtr(true)
+ }
+
// Never always wins.
if Bool(s.Never) {
return
@@ -212,11 +216,6 @@
s.Memtag_heap = nil
}
- // Disable sanitizers for musl x86 modules, rustc does not support any sanitizers.
- if ctx.Os() == android.LinuxMusl && ctx.Arch().ArchType == android.X86 {
- s.Never = boolPtr(true)
- }
-
// TODO:(b/178369775)
// For now sanitizing is only supported on non-windows targets
if ctx.Os() != android.Windows && (Bool(s.Hwaddress) || Bool(s.Address) || Bool(s.Memtag_heap) || Bool(s.Fuzzer)) {
@@ -229,6 +228,10 @@
}
func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
+ if sanitize.Properties.ForceDisable {
+ return flags, deps
+ }
+
if !sanitize.Properties.SanitizerEnabled {
return flags, deps
}
@@ -261,6 +264,9 @@
if !mod.Enabled(mctx) {
return
}
+ if mod.sanitize.Properties.ForceDisable {
+ return
+ }
if Bool(mod.sanitize.Properties.Sanitize.Memtag_heap) && mod.Binary() {
noteDep := "note_memtag_heap_async"
@@ -318,16 +324,16 @@
sanitizerSet := false
switch t {
case cc.Fuzzer:
- sanitize.Properties.Sanitize.Fuzzer = boolPtr(b)
+ sanitize.Properties.Sanitize.Fuzzer = proptools.BoolPtr(b)
sanitizerSet = true
case cc.Asan:
- sanitize.Properties.Sanitize.Address = boolPtr(b)
+ sanitize.Properties.Sanitize.Address = proptools.BoolPtr(b)
sanitizerSet = true
case cc.Hwasan:
- sanitize.Properties.Sanitize.Hwaddress = boolPtr(b)
+ sanitize.Properties.Sanitize.Hwaddress = proptools.BoolPtr(b)
sanitizerSet = true
case cc.Memtag_heap:
- sanitize.Properties.Sanitize.Memtag_heap = boolPtr(b)
+ sanitize.Properties.Sanitize.Memtag_heap = proptools.BoolPtr(b)
sanitizerSet = true
default:
panic(fmt.Errorf("setting unsupported sanitizerType %d", t))
@@ -372,7 +378,7 @@
// distinguish between the cases. It isn't needed though - both cases can be
// treated identically.
func (sanitize *sanitize) isSanitizerEnabled(t cc.SanitizerType) bool {
- if sanitize == nil || !sanitize.Properties.SanitizerEnabled {
+ if sanitize == nil || !sanitize.Properties.SanitizerEnabled || sanitize.Properties.ForceDisable {
return false
}
@@ -461,7 +467,7 @@
}
func (mod *Module) SanitizeNever() bool {
- return Bool(mod.sanitize.Properties.Sanitize.Never)
+ return Bool(mod.sanitize.Properties.Sanitize.Never) || mod.sanitize.Properties.ForceDisable
}
var _ cc.PlatformSanitizeable = (*Module)(nil)
diff --git a/rust/source_provider.go b/rust/source_provider.go
index 3236bce..27c62c2 100644
--- a/rust/source_provider.go
+++ b/rust/source_provider.go
@@ -43,6 +43,7 @@
SourceProviderProps() []interface{}
SourceProviderDeps(ctx DepsContext, deps Deps) Deps
setSubName(subName string)
+ getSubName() string
setOutputFiles(outputFiles android.Paths)
}
@@ -100,6 +101,10 @@
sp.subName = subName
}
+func (sp *BaseSourceProvider) getSubName() string {
+ return sp.subName
+}
+
func (sp *BaseSourceProvider) setOutputFiles(outputFiles android.Paths) {
sp.OutputFiles = outputFiles
}
diff --git a/rust/test.go b/rust/test.go
index b7ddd06..b658ae2 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -46,6 +46,9 @@
// the test
Data []string `android:"path,arch_variant"`
+ // Same as data, but will add dependencies on the device's
+ Device_common_data []string `android:"path_device_common"`
+
// list of shared library modules that should be installed alongside the test
Data_libs []string `android:"arch_variant"`
@@ -143,36 +146,38 @@
})
dataSrcPaths := android.PathsForModuleSrc(ctx, test.Properties.Data)
+ dataSrcPaths = append(dataSrcPaths, android.PathsForModuleSrc(ctx, test.Properties.Device_common_data)...)
- ctx.VisitDirectDepsWithTag(dataLibDepTag, func(dep android.Module) {
+ ctx.VisitDirectDepsProxyWithTag(dataLibDepTag, func(dep android.ModuleProxy) {
depName := ctx.OtherModuleName(dep)
- linkableDep, ok := dep.(cc.LinkableInterface)
+ linkableDep, ok := android.OtherModuleProvider(ctx, dep, cc.LinkableInfoProvider)
if !ok {
ctx.ModuleErrorf("data_lib %q is not a linkable module", depName)
}
- if linkableDep.OutputFile().Valid() {
+ if linkableDep.OutputFile.Valid() {
// Copy the output in "lib[64]" so that it's compatible with
// the default rpath values.
+ commonInfo := android.OtherModuleProviderOrDefault(ctx, dep, android.CommonModuleInfoKey)
libDir := "lib"
- if linkableDep.Target().Arch.ArchType.Multilib == "lib64" {
+ if commonInfo.Target.Arch.ArchType.Multilib == "lib64" {
libDir = "lib64"
}
test.data = append(test.data,
- android.DataPath{SrcPath: linkableDep.OutputFile().Path(),
- RelativeInstallPath: filepath.Join(libDir, linkableDep.RelativeInstallPath())})
+ android.DataPath{SrcPath: linkableDep.OutputFile.Path(),
+ RelativeInstallPath: filepath.Join(libDir, linkableDep.RelativeInstallPath)})
}
})
- ctx.VisitDirectDepsWithTag(dataBinDepTag, func(dep android.Module) {
+ ctx.VisitDirectDepsProxyWithTag(dataBinDepTag, func(dep android.ModuleProxy) {
depName := ctx.OtherModuleName(dep)
- linkableDep, ok := dep.(cc.LinkableInterface)
+ linkableDep, ok := android.OtherModuleProvider(ctx, dep, cc.LinkableInfoProvider)
if !ok {
ctx.ModuleErrorf("data_bin %q is not a linkable module", depName)
}
- if linkableDep.OutputFile().Valid() {
+ if linkableDep.OutputFile.Valid() {
test.data = append(test.data,
- android.DataPath{SrcPath: linkableDep.OutputFile().Path(),
- RelativeInstallPath: linkableDep.RelativeInstallPath()})
+ android.DataPath{SrcPath: linkableDep.OutputFile.Path(),
+ RelativeInstallPath: linkableDep.RelativeInstallPath})
}
})
@@ -190,6 +195,27 @@
if ctx.Host() && test.Properties.Test_options.Unit_test == nil {
test.Properties.Test_options.Unit_test = proptools.BoolPtr(true)
}
+
+ if !ctx.Config().KatiEnabled() { // TODO(spandandas): Remove the special case for kati
+ // Install the test config in testcases/ directory for atest.
+ r, ok := ctx.Module().(*Module)
+ if !ok {
+ ctx.ModuleErrorf("Not a rust test module")
+ }
+ // Install configs in the root of $PRODUCT_OUT/testcases/$module
+ testCases := android.PathForModuleInPartitionInstall(ctx, "testcases", ctx.ModuleName()+r.SubName())
+ if ctx.PrimaryArch() {
+ if test.testConfig != nil {
+ ctx.InstallFile(testCases, ctx.ModuleName()+".config", test.testConfig)
+ }
+ }
+ // Install tests and data in arch specific subdir $PRODUCT_OUT/testcases/$module/$arch
+ testCases = testCases.Join(ctx, ctx.Target().Arch.ArchType.String())
+ ctx.InstallTestData(testCases, test.data)
+ testPath := ctx.RustModule().OutputFile().Path()
+ ctx.InstallFile(testCases, testPath.Base(), testPath)
+ }
+
test.binaryDecorator.installTestData(ctx, test.data)
test.binaryDecorator.install(ctx)
}
@@ -198,6 +224,7 @@
flags = test.binaryDecorator.compilerFlags(ctx, flags)
if test.testHarness() {
flags.RustFlags = append(flags.RustFlags, "--test")
+ flags.RustFlags = append(flags.RustFlags, "-A missing-docs")
}
if ctx.Device() {
flags.RustFlags = append(flags.RustFlags, "-Z panic_abort_tests")
@@ -234,7 +261,7 @@
return module.Init()
}
-func (test *testDecorator) stdLinkage(ctx *depsContext) RustLinkage {
+func (test *testDecorator) stdLinkage(device bool) RustLinkage {
return RlibLinkage
}
@@ -253,6 +280,32 @@
return true
}
+func (test *testDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+ test.binaryDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+ moduleInfoJSON.Class = []string{"NATIVE_TESTS"}
+ if Bool(test.Properties.Test_options.Unit_test) {
+ moduleInfoJSON.IsUnitTest = "true"
+ if ctx.Host() {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "host-unit-tests")
+ }
+ }
+ moduleInfoJSON.TestOptionsTags = append(moduleInfoJSON.TestOptionsTags, test.Properties.Test_options.Tags...)
+ if test.testConfig != nil {
+ if _, ok := test.testConfig.(android.WritablePath); ok {
+ moduleInfoJSON.AutoTestConfig = []string{"true"}
+ }
+ moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, test.testConfig.String())
+ }
+
+ moduleInfoJSON.DataDependencies = append(moduleInfoJSON.DataDependencies, test.Properties.Data_bins...)
+
+ if len(test.Properties.Test_suites) > 0 {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, test.Properties.Test_suites...)
+ } else {
+ moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite")
+ }
+}
+
func rustTestHostMultilib(ctx android.LoadHookContext) {
type props struct {
Target struct {
diff --git a/rust/testing.go b/rust/testing.go
index 32cc823..2082b52 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -80,7 +80,6 @@
no_libcrt: true,
nocrt: true,
system_shared_libs: [],
- apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
min_sdk_version: "29",
vendor_available: true,
host_supported: true,
@@ -88,6 +87,13 @@
llndk: {
symbol_file: "liblog.map.txt",
},
+ stubs: {
+ symbol_file: "liblog.map.txt",
+ versions: [
+ "29",
+ "30",
+ ],
+ },
}
cc_library {
name: "libprotobuf-cpp-full",
@@ -188,12 +194,10 @@
ctx.RegisterModuleType("rust_fuzz_host", RustFuzzHostFactory)
ctx.RegisterModuleType("rust_ffi", RustFFIFactory)
ctx.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
- ctx.RegisterModuleType("rust_ffi_rlib", RustFFIRlibFactory)
- ctx.RegisterModuleType("rust_ffi_static", RustFFIRlibFactory)
+ ctx.RegisterModuleType("rust_ffi_static", RustLibraryRlibFactory)
ctx.RegisterModuleType("rust_ffi_host", RustFFIHostFactory)
ctx.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
- ctx.RegisterModuleType("rust_ffi_host_rlib", RustFFIRlibHostFactory)
- ctx.RegisterModuleType("rust_ffi_host_static", RustFFIRlibHostFactory)
+ ctx.RegisterModuleType("rust_ffi_host_static", RustLibraryRlibHostFactory)
ctx.RegisterModuleType("rust_proc_macro", ProcMacroFactory)
ctx.RegisterModuleType("rust_protobuf", RustProtobufFactory)
ctx.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory)
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 3d81b83..94163a5 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -184,12 +184,21 @@
libs: ["ninja_rsp"],
}
-python_test_host {
- name: "lint_project_xml_test",
- main: "lint_project_xml_test.py",
+python_binary_host {
+ name: "lint_strict_updatability_checks",
+ main: "lint_strict_updatability_checks.py",
srcs: [
- "lint_project_xml_test.py",
- "lint_project_xml.py",
+ "lint_strict_updatability_checks.py",
+ ],
+ libs: ["ninja_rsp"],
+}
+
+python_test_host {
+ name: "lint_strict_updatability_checks_test",
+ main: "lint_strict_updatability_checks_test.py",
+ srcs: [
+ "lint_strict_updatability_checks_test.py",
+ "lint_strict_updatability_checks.py",
],
libs: ["ninja_rsp"],
test_suites: ["general-tests"],
@@ -284,14 +293,6 @@
}
python_binary_host {
- name: "merge_directories",
- main: "merge_directories.py",
- srcs: [
- "merge_directories.py",
- ],
-}
-
-python_binary_host {
name: "merge_json",
main: "merge_json.py",
srcs: [
@@ -310,3 +311,11 @@
main: "extra_install_zips_file_list.py",
srcs: ["extra_install_zips_file_list.py"],
}
+
+python_binary_host {
+ name: "rustc_linker",
+ main: "rustc_linker.py",
+ srcs: [
+ "rustc_linker.py",
+ ],
+}
diff --git a/scripts/build-apex-bundle.py b/scripts/build-apex-bundle.py
index dcdd9ef..277e112 100644
--- a/scripts/build-apex-bundle.py
+++ b/scripts/build-apex-bundle.py
@@ -16,8 +16,6 @@
#
"""A tool to create an APEX bundle out of Soong-built base.zip"""
-from __future__ import print_function
-
import argparse
import sys
import tempfile
diff --git a/scripts/check_boot_jars/check_boot_jars.py b/scripts/check_boot_jars/check_boot_jars.py
index b711f9d..174b96e 100755
--- a/scripts/check_boot_jars/check_boot_jars.py
+++ b/scripts/check_boot_jars/check_boot_jars.py
@@ -4,7 +4,6 @@
Usage: check_boot_jars.py <dexdump_path> <package_allow_list_file> <jar1> \
<jar2> ...
"""
-from __future__ import print_function
import logging
import re
import subprocess
diff --git a/scripts/check_boot_jars/package_allowed_list.txt b/scripts/check_boot_jars/package_allowed_list.txt
index bb88cce..1d2fc64 100644
--- a/scripts/check_boot_jars/package_allowed_list.txt
+++ b/scripts/check_boot_jars/package_allowed_list.txt
@@ -3,7 +3,52 @@
###################################################
# core-libart.jar & core-oj.jar
-java(\..*)?
+java\.awt\.font
+java\.beans
+java\.io
+java\.lang
+java\.lang\.annotation
+java\.lang\.constant
+java\.lang\.invoke
+java\.lang\.ref
+java\.lang\.reflect
+java\.lang\.runtime
+java\.math
+java\.net
+java\.nio
+java\.nio\.file
+java\.nio\.file\.spi
+java\.nio\.file\.attribute
+java\.nio\.channels
+java\.nio\.channels\.spi
+java\.nio\.charset
+java\.nio\.charset\.spi
+java\.security
+java\.security\.acl
+java\.security\.cert
+java\.security\.interfaces
+java\.security\.spec
+java\.sql
+java\.text
+java\.text\.spi
+java\.time
+java\.time\.chrono
+java\.time\.format
+java\.time\.temporal
+java\.time\.zone
+java\.util
+java\.util\.concurrent
+java\.util\.concurrent\.atomic
+java\.util\.concurrent\.locks
+java\.util\.function
+java\.util\.jar
+java\.util\.logging
+java\.util\.prefs
+java\.util\.random
+java\.util\.regex
+java\.util\.spi
+java\.util\.stream
+java\.util\.zip
# TODO: Remove javax.annotation.processing if possible, see http://b/132338110:
javax\.annotation\.processing
javax\.crypto
@@ -27,7 +72,20 @@
javax\.xml\.transform\.stream
javax\.xml\.validation
javax\.xml\.xpath
-jdk\..*
+jdk\.internal
+jdk\.internal\.access
+jdk\.internal\.event
+jdk\.internal\.math
+jdk\.internal\.misc
+jdk\.internal\.ref
+jdk\.internal\.reflect
+jdk\.internal\.util
+jdk\.internal\.util\.jar
+jdk\.internal\.util\.random
+jdk\.internal\.vm
+jdk\.internal\.vm\.annotation
+jdk\.net
+jdk\.random
org\.w3c\.dom
org\.w3c\.dom\.ls
org\.w3c\.dom\.traversal
diff --git a/scripts/check_prebuilt_presigned_apk.py b/scripts/check_prebuilt_presigned_apk.py
index abab2e1..db64f90 100755
--- a/scripts/check_prebuilt_presigned_apk.py
+++ b/scripts/check_prebuilt_presigned_apk.py
@@ -36,7 +36,7 @@
if fail:
sys.exit(args.apk + ': Contains compressed JNI libraries')
return True
- # It's ok for non-privileged apps to have compressed dex files, see go/gms-uncompressed-jni-slides
+ # It's ok for non-privileged apps to have compressed dex files
if args.privileged and args.uncompress_priv_app_dex:
if info.filename.endswith('.dex') and info.compress_type != zipfile.ZIP_STORED:
if fail:
@@ -46,6 +46,10 @@
def main():
+ # This script enforces requirements for presigned apps as documented in:
+ # go/gms-uncompressed-jni-slides
+ # https://docs.partner.android.com/gms/building/integrating/jni-libs
+ # https://docs.partner.android.com/gms/policies/domains/mba#jni-lib
parser = argparse.ArgumentParser()
parser.add_argument('--aapt2', help = "the path to the aapt2 executable")
parser.add_argument('--zipalign', help = "the path to the zipalign executable")
diff --git a/scripts/construct_context.py b/scripts/construct_context.py
index fc3a89e..882c2db 100755
--- a/scripts/construct_context.py
+++ b/scripts/construct_context.py
@@ -16,8 +16,6 @@
#
"""A tool for constructing class loader context."""
-from __future__ import print_function
-
import argparse
import json
import sys
diff --git a/scripts/diff_build_graphs.sh b/scripts/diff_build_graphs.sh
deleted file mode 100755
index 8d01124..0000000
--- a/scripts/diff_build_graphs.sh
+++ /dev/null
@@ -1,170 +0,0 @@
-#!/bin/bash -eu
-#
-# Copyright 2017 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.
-
-set -e
-
-# This file makes it easy to confirm that a set of changes in source code don't result in any
-# changes to the generated ninja files. This is to reduce the effort required to be confident
-# in the correctness of refactorings
-
-function die() {
- echo "$@" >&2
- exit 1
-}
-
-function usage() {
- violation="$1"
- die "$violation
-
- Usage: diff_build_graphs.sh [--products=product1,product2...] <OLD_VERSIONS> <NEW_VERSIONS>
-
- This file builds and parses the build files (Android.mk, Android.bp, etc) for each requested
- product and for both sets of versions, and checks whether the ninja files (which implement
- the build graph) changed between the two versions.
-
- Example: diff_build_graphs.sh 'build/soong:work^ build/blueprint:work^' 'build/soong:work build/blueprint:work'
-
- Options:
- --products=PRODUCTS comma-separated list of products to check"
-}
-
-PRODUCTS_ARG=""
-OLD_VERSIONS=""
-NEW_VERSIONS=""
-function parse_args() {
- # parse optional arguments
- while true; do
- arg="${1-}"
- case "$arg" in
- --products=*) PRODUCTS_ARG="$arg";;
- *) break;;
- esac
- shift
- done
- # parse required arguments
- if [ "$#" != "2" ]; then
- usage ""
- fi
- #argument validation
- OLD_VERSIONS="$1"
- NEW_VERSIONS="$2"
-
-}
-parse_args "$@"
-
-
-# find some file paths
-cd "$(dirname $0)"
-SCRIPT_DIR="$PWD"
-cd ../../..
-CHECKOUT_ROOT="$PWD"
-OUT_DIR="${OUT_DIR-}"
-if [ -z "$OUT_DIR" ]; then
- OUT_DIR=out
-fi
-WORK_DIR="$OUT_DIR/diff"
-OUT_DIR_OLD="$WORK_DIR/out_old"
-OUT_DIR_NEW="$WORK_DIR/out_new"
-OUT_DIR_TEMP="$WORK_DIR/out_temp"
-
-
-function checkout() {
- versionSpecs="$1"
- for versionSpec in $versionSpecs; do
- project="$(echo $versionSpec | sed 's|\([^:]*\):\([^:]*\)|\1|')"
- ref="$(echo $versionSpec | sed 's|\([^:]*\):\([^:]*\)|\2|')"
- echo "checking out ref $ref in project $project"
- git -C "$project" checkout "$ref"
- done
-}
-
-function run_build() {
- echo
- echo "Starting build"
- # rebuild multiproduct_kati, in case it was missing before,
- # or in case it is affected by some of the changes we're testing
- make blueprint_tools
- # find multiproduct_kati and have it build the ninja files for each product
- builder="$(echo $OUT_DIR/host/*/bin/multiproduct_kati)"
- BUILD_NUMBER=sample "$builder" $PRODUCTS_ARG --keep --out "$OUT_DIR_TEMP" || true
- echo
-}
-
-function diffProduct() {
- product="$1"
-
- zip1="$OUT_DIR_OLD/${product}.zip"
- unzipped1="$OUT_DIR_OLD/$product"
-
- zip2="$OUT_DIR_NEW/${product}.zip"
- unzipped2="$OUT_DIR_NEW/$product"
-
- unzip -qq "$zip1" -d "$unzipped1"
- unzip -qq "$zip2" -d "$unzipped2"
-
- #do a diff of the ninja files
- diffFile="$WORK_DIR/diff.txt"
- diff -r "$unzipped1" "$unzipped2" -x build_date.txt -x build_number.txt -x '\.*' -x '*.log' -x build_fingerprint.txt -x build.ninja.d -x '*.zip' > $diffFile || true
- if [[ -s "$diffFile" ]]; then
- # outputs are different, so remove the unzipped versions but keep the zipped versions
- echo "First few differences (total diff linecount=$(wc -l $diffFile)) for product $product:"
- cat "$diffFile" | head -n 10
- echo "End of differences for product $product"
- rm -rf "$unzipped1" "$unzipped2"
- else
- # outputs are the same, so remove all of the outputs
- rm -rf "$zip1" "$unzipped1" "$zip2" "$unzipped2"
- fi
-}
-
-function do_builds() {
- #reset work dir
- rm -rf "$WORK_DIR"
- mkdir "$WORK_DIR"
-
- #build new code
- checkout "$NEW_VERSIONS"
- run_build
- mv "$OUT_DIR_TEMP" "$OUT_DIR_NEW"
-
- #build old code
- #TODO do we want to cache old results? Maybe by the time we care to cache old results this will
- #be running on a remote server somewhere and be completely different
- checkout "$OLD_VERSIONS"
- run_build
- mv "$OUT_DIR_TEMP" "$OUT_DIR_OLD"
-
- #cleanup
- echo created "$OUT_DIR_OLD" and "$OUT_DIR_NEW"
-}
-
-function main() {
- do_builds
- checkout "$NEW_VERSIONS"
-
- #find all products
- productsFile="$WORK_DIR/all_products.txt"
- find $OUT_DIR_OLD $OUT_DIR_NEW -mindepth 1 -maxdepth 1 -name "*.zip" | sed "s|^$OUT_DIR_OLD/||" | sed "s|^$OUT_DIR_NEW/||" | sed "s|\.zip$||" | sort | uniq > "$productsFile"
- echo Diffing products
- for product in $(cat $productsFile); do
- diffProduct "$product"
- done
- echo Done diffing products
- echo "Any differing outputs can be seen at $OUT_DIR_OLD/*.zip and $OUT_DIR_NEW/*.zip"
- echo "See $WORK_DIR/diff.txt for the full list of differences for the latest product checked"
-}
-
-main
diff --git a/scripts/gen_build_prop.py b/scripts/gen_build_prop.py
index c08a3fd..355f33d 100644
--- a/scripts/gen_build_prop.py
+++ b/scripts/gen_build_prop.py
@@ -108,7 +108,7 @@
def generate_common_build_props(args):
print("####################################")
- print("# from generate_common_build_props")
+ print("# from generate-common-build-props")
print("# These properties identify this partition image.")
print("####################################")
@@ -243,9 +243,15 @@
print(f"# end build properties")
def write_properties_from_file(file):
+ # Make and Soong use different intermediate files to build vendor/build.prop.
+ # Although the sysprop contents are same, the absolute paths of these
+ # intermediate files are different.
+ # Print the filename for the intermediate files (files in OUT_DIR).
+ # This helps with validating mk->soong migration of android partitions.
+ filename = os.path.basename(file.name) if file.name.startswith(os.environ.get("OUT_DIR")) else file.name
print()
print("####################################")
- print(f"# from {file.name}")
+ print(f"# from {filename}")
print("####################################")
print(file.read(), end="")
@@ -302,7 +308,15 @@
props.append(f"ro.sanitize.{sanitize_target}=true")
# Sets the default value of ro.postinstall.fstab.prefix to /system.
- # Device board config should override the value to /product when needed by:
+ #
+ # Device board configs can override this to /product to use a
+ # product-specific fstab.postinstall file (installed to
+ # /product/etc/fstab.postinstall). If not overridden, the
+ # system/extras/cppreopts/fstab.postinstall file (installed to
+ # /system/etc/fstab.postinstall) will be used.
+ # Note: The default fstab.postinstall is generic and may be slower
+ # because it tries different mount options line by line to ensure
+ # compatibility across various devices.
#
# PRODUCT_PRODUCT_PROPERTIES += ro.postinstall.fstab.prefix=/product
#
@@ -429,7 +443,9 @@
# Build system set BOARD_API_LEVEL to show the api level of the vendor API surface.
# This must not be altered outside of build system.
if config["VendorApiLevel"]:
- props.append(f"ro.board.api_level={config['VendorApiLevel']}")
+ props.append(f"ro.board.api_level?={config['VendorApiLevel']}")
+ if config["VendorApiLevelPropOverride"]:
+ props.append(f"ro.board.api_level={config['VendorApiLevelPropOverride']}")
# RELEASE_BOARD_API_LEVEL_FROZEN is true when the vendor API surface is frozen.
if build_flags["RELEASE_BOARD_API_LEVEL_FROZEN"]:
@@ -448,7 +464,7 @@
props.append(f"ro.vendor.build.security_patch={config['VendorSecurityPatch']}")
props.append(f"ro.product.board={config['BootloaderBoardName']}")
props.append(f"ro.board.platform={config['BoardPlatform']}")
- props.append(f"ro.hwui.use_vulkan={'true' if config['UsesVulkan'] else 'false'}")
+ props.append(f"ro.hwui.use_vulkan={config['UsesVulkan']}")
if config["ScreenDensity"]:
props.append(f"ro.sf.lcd_density={config['ScreenDensity']}")
@@ -522,7 +538,6 @@
build_prop(args, gen_build_info=False, gen_common_build_props=True, variables=variables)
-'''
def build_vendor_prop(args):
config = args.config
@@ -539,7 +554,6 @@
]
build_prop(args, gen_build_info=False, gen_common_build_props=True, variables=variables)
-'''
def build_product_prop(args):
config = args.config
@@ -606,8 +620,10 @@
build_odm_prop(args)
case "product":
build_product_prop(args)
- # case "vendor": # NOT IMPLEMENTED
- # build_vendor_prop(args)
+ case "vendor":
+ build_vendor_prop(args)
+ case "system_dlkm" | "vendor_dlkm" | "odm_dlkm" | "bootimage":
+ build_prop(args, gen_build_info=False, gen_common_build_props=True, variables=[])
case _:
sys.exit(f"not supported partition {args.partition}")
diff --git a/scripts/hiddenapi/Android.bp b/scripts/hiddenapi/Android.bp
index 43edf44..061af19 100644
--- a/scripts/hiddenapi/Android.bp
+++ b/scripts/hiddenapi/Android.bp
@@ -27,6 +27,12 @@
libs: [
"signature_trie",
],
+ target: {
+ windows: {
+ // go modules (bpmodify) don't support windows
+ enabled: false,
+ },
+ },
}
python_test_host {
@@ -44,6 +50,12 @@
test_options: {
unit_test: true,
},
+ target: {
+ windows: {
+ // go modules (bpmodify) don't support windows
+ enabled: false,
+ },
+ },
}
python_binary_host {
diff --git a/scripts/keep-flagged-apis.sh b/scripts/keep-flagged-apis.sh
index 9c48fdb..48efb7a 100755
--- a/scripts/keep-flagged-apis.sh
+++ b/scripts/keep-flagged-apis.sh
@@ -25,21 +25,12 @@
# Convert the list of feature flags in the input file to Metalava options
# of the form `--revert-annotation !android.annotation.FlaggedApi("<flag>")`
# to prevent the annotated APIs from being hidden, i.e. include the annotated
-# APIs in the SDK snapshots. This also preserves the line comments, they will
-# be ignored by Metalava but might be useful when debugging.
+# APIs in the SDK snapshots.
while read -r line; do
- key=$(echo "$line" | cut -d= -f1)
- value=$(echo "$line" | cut -d= -f2)
-
- # Skip if value is not true and line does not start with '#'
- if [[ ( $value != "true" ) && ( $line =~ ^[^#] )]]; then
- continue
- fi
-
# Escape and quote the key for sed
- escaped_key=$(echo "$key" | sed "s/'/\\\'/g; s/ /\\ /g")
+ escaped_line=$(echo "$line" | sed "s/'/\\\'/g; s/ /\\ /g")
- echo $line | sed "s|^[^#].*$|--revert-annotation '!$FLAGGED(\"$escaped_key\")'|"
+ echo "--revert-annotation '!$FLAGGED(\"$escaped_line\")'"
done < "$FLAGS"
# Revert all flagged APIs, unless listed above.
diff --git a/scripts/lint_project_xml.py b/scripts/lint_project_xml.py
index c40b07d..ce6aa21 100755
--- a/scripts/lint_project_xml.py
+++ b/scripts/lint_project_xml.py
@@ -75,8 +75,6 @@
help='file containing the module\'s manifest.')
parser.add_argument('--merged_manifest', dest='merged_manifest',
help='file containing merged manifest for the module and its dependencies.')
- parser.add_argument('--baseline', dest='baseline_path',
- help='file containing baseline lint issues.')
parser.add_argument('--library', dest='library', action='store_true',
help='mark the module as a library.')
parser.add_argument('--test', dest='test', action='store_true',
@@ -94,8 +92,6 @@
help='treat a lint issue as a warning.')
group.add_argument('--disable_check', dest='checks', action=check_action('ignore'), default=[],
help='disable a lint issue.')
- group.add_argument('--disallowed_issues', dest='disallowed_issues', default=[],
- help='lint issues disallowed in the baseline file')
return parser.parse_args()
@@ -140,30 +136,10 @@
f.write("</lint>\n")
-def check_baseline_for_disallowed_issues(baseline, forced_checks):
- issues_element = baseline.documentElement
- if issues_element.tagName != 'issues':
- raise RuntimeError('expected issues tag at root')
- issues = issues_element.getElementsByTagName('issue')
- disallowed = set()
- for issue in issues:
- id = issue.getAttribute('id')
- if id in forced_checks:
- disallowed.add(id)
- return disallowed
-
-
def main():
"""Program entry point."""
args = parse_args()
- if args.baseline_path:
- baseline = minidom.parse(args.baseline_path)
- disallowed_issues = check_baseline_for_disallowed_issues(baseline, args.disallowed_issues)
- if disallowed_issues:
- sys.exit('disallowed issues %s found in lint baseline file %s for module %s'
- % (disallowed_issues, args.baseline_path, args.name))
-
if args.project_out:
with open(args.project_out, 'w') as f:
write_project_xml(f, args)
diff --git a/scripts/lint_strict_updatability_checks.py b/scripts/lint_strict_updatability_checks.py
new file mode 100755
index 0000000..5b5dfd8
--- /dev/null
+++ b/scripts/lint_strict_updatability_checks.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""This file checks baselines passed to Android Lint for checks that must not be baselined."""
+
+import argparse
+import sys
+from xml.dom import minidom
+
+from ninja_rsp import NinjaRspFileReader
+
+
+def parse_args():
+ """Parse commandline arguments."""
+
+ def convert_arg_line_to_args(arg_line):
+ for arg in arg_line.split():
+ if arg.startswith('#'):
+ return
+ if not arg.strip():
+ continue
+ yield arg
+
+ parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
+ parser.convert_arg_line_to_args = convert_arg_line_to_args
+ parser.add_argument('--name', dest='name',
+ help='name of the module.')
+ parser.add_argument('--baselines', dest='baselines', action='append', default=[],
+ help='file containing whitespace separated list of baseline files.')
+ parser.add_argument('--disallowed_issues', dest='disallowed_issues', default=[],
+ help='lint issues disallowed in the baseline file')
+ return parser.parse_args()
+
+
+def check_baseline_for_disallowed_issues(baseline, forced_checks):
+ issues_element = baseline.documentElement
+ if issues_element.tagName != 'issues':
+ raise RuntimeError('expected issues tag at root')
+ issues = issues_element.getElementsByTagName('issue')
+ disallowed = set()
+ for issue in issues:
+ id = issue.getAttribute('id')
+ if id in forced_checks:
+ disallowed.add(id)
+ return disallowed
+
+
+def main():
+ """Program entry point."""
+ args = parse_args()
+
+ error = False
+ for baseline_rsp_file in args.baselines:
+ for baseline_path in NinjaRspFileReader(baseline_rsp_file):
+ baseline = minidom.parse(baseline_path)
+ disallowed_issues = check_baseline_for_disallowed_issues(baseline, args.disallowed_issues)
+ if disallowed_issues:
+ print('disallowed issues %s found in lint baseline file %s for module %s'
+ % (disallowed_issues, baseline_path, args.name))
+ error = True
+
+ if error:
+ sys.exit(1)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/lint_project_xml_test.py b/scripts/lint_strict_updatability_checks_test.py
old mode 100644
new mode 100755
similarity index 88%
rename from scripts/lint_project_xml_test.py
rename to scripts/lint_strict_updatability_checks_test.py
index 344691d..fd8610f
--- a/scripts/lint_project_xml_test.py
+++ b/scripts/lint_strict_updatability_checks_test.py
@@ -15,12 +15,12 @@
# limitations under the License.
#
-"""Unit tests for lint_project_xml.py."""
+"""Unit tests for lint_strict_updatability_checks.py."""
import unittest
from xml.dom import minidom
-import lint_project_xml
+import lint_strict_updatability_checks
class CheckBaselineForDisallowedIssuesTest(unittest.TestCase):
@@ -44,7 +44,7 @@
'</issues>\n')
def test_check_baseline_for_disallowed_issues(self):
- disallowed_issues = lint_project_xml.check_baseline_for_disallowed_issues(self.baseline_xml, ["foo", "bar", "qux"])
+ disallowed_issues = lint_strict_updatability_checks.check_baseline_for_disallowed_issues(self.baseline_xml, ["foo", "bar", "qux"])
self.assertEqual({"foo", "bar"}, disallowed_issues)
diff --git a/scripts/manifest.py b/scripts/manifest.py
index 81f9c61..87f4f0c 100755
--- a/scripts/manifest.py
+++ b/scripts/manifest.py
@@ -16,16 +16,46 @@
#
"""A tool for inserting values from the build system into a manifest or a test config."""
-from __future__ import print_function
from xml.dom import minidom
android_ns = 'http://schemas.android.com/apk/res/android'
+def get_or_create_applications(doc, manifest):
+ """Get all <application> tags from the manifest, or create one if none exist.
+ Multiple <application> tags may exist when manifest feature flagging is used.
+ """
+ applications = get_children_with_tag(manifest, 'application')
+ if len(applications) == 0:
+ application = doc.createElement('application')
+ indent = get_indent(manifest.firstChild, 1)
+ first = manifest.firstChild
+ manifest.insertBefore(doc.createTextNode(indent), first)
+ manifest.insertBefore(application, first)
+ applications.append(application)
+ return applications
+
+
+def get_or_create_uses_sdks(doc, manifest):
+ """Get all <uses-sdk> tags from the manifest, or create one if none exist.
+ Multiple <uses-sdk> tags may exist when manifest feature flagging is used.
+ """
+ uses_sdks = get_children_with_tag(manifest, 'uses-sdk')
+ if len(uses_sdks) == 0:
+ uses_sdk = doc.createElement('uses-sdk')
+ indent = get_indent(manifest.firstChild, 1)
+ manifest.insertBefore(uses_sdk, manifest.firstChild)
+
+ # Insert an indent before uses-sdk to line it up with the indentation of the
+ # other children of the <manifest> tag.
+ manifest.insertBefore(doc.createTextNode(indent), manifest.firstChild)
+ uses_sdks.append(uses_sdk)
+ return uses_sdks
+
def get_children_with_tag(parent, tag_name):
children = []
- for child in parent.childNodes:
+ for child in parent.childNodes:
if child.nodeType == minidom.Node.ELEMENT_NODE and \
child.tagName == tag_name:
children.append(child)
diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py
index b101259..175451e 100755
--- a/scripts/manifest_check.py
+++ b/scripts/manifest_check.py
@@ -16,8 +16,6 @@
#
"""A tool for checking that a manifest agrees with the build system."""
-from __future__ import print_function
-
import argparse
import json
import re
@@ -25,10 +23,7 @@
import sys
from xml.dom import minidom
-from manifest import android_ns
-from manifest import get_children_with_tag
-from manifest import parse_manifest
-from manifest import write_xml
+from manifest import *
class ManifestMismatchError(Exception):
@@ -122,7 +117,7 @@
# handles module names specified in Android.bp properties. However not all
# <uses-library> entries in the manifest correspond to real modules: some of
# the optional libraries may be missing at build time. Therefor this script
- # accepts raw module names as spelled in Android.bp/Amdroid.mk and trims the
+ # accepts raw module names as spelled in Android.bp/Android.mk and trims the
# optional namespace part manually.
required = trim_namespace_parts(required)
optional = trim_namespace_parts(optional)
@@ -205,15 +200,9 @@
"""Extract <uses-library> tags from the manifest."""
manifest = parse_manifest(xml)
- elems = get_children_with_tag(manifest, 'application')
- if len(elems) > 1:
- raise RuntimeError('found multiple <application> tags')
- if not elems:
- return [], [], []
-
- application = elems[0]
-
- libs = get_children_with_tag(application, 'uses-library')
+ libs = [child
+ for application in get_or_create_applications(xml, manifest)
+ for child in get_children_with_tag(application, 'uses-library')]
required = [uses_library_name(x) for x in libs if uses_library_required(x)]
optional = [
@@ -266,7 +255,7 @@
manifest: manifest (either parsed XML or aapt dump of APK)
is_apk: if the manifest comes from an APK or an XML file
"""
- if is_apk: #pylint: disable=no-else-return
+ if is_apk: #pylint: disable=no-else-return
return extract_target_sdk_version_apk(manifest)
else:
return extract_target_sdk_version_xml(manifest)
@@ -376,7 +365,7 @@
# Create a status file that is empty on success, or contains an
# error message on failure. When exceptions are suppressed,
- # dexpreopt command command will check file size to determine if
+ # dexpreopt command will check file size to determine if
# the check has failed.
if args.enforce_uses_libraries_status:
with open(args.enforce_uses_libraries_status, 'w') as f:
@@ -386,7 +375,7 @@
if args.extract_target_sdk_version:
try:
print(extract_target_sdk_version(manifest, is_apk))
- except: #pylint: disable=bare-except
+ except: #pylint: disable=bare-except
# Failed; don't crash, return "any" SDK version. This will
# result in dexpreopt not adding any compatibility libraries.
print(10000)
diff --git a/scripts/manifest_check_test.py b/scripts/manifest_check_test.py
index 8003b3e..abe0d8b 100755
--- a/scripts/manifest_check_test.py
+++ b/scripts/manifest_check_test.py
@@ -44,8 +44,8 @@
class EnforceUsesLibrariesTest(unittest.TestCase):
"""Unit tests for add_extract_native_libs function."""
- def run_test(self, xml, apk, uses_libraries=[], optional_uses_libraries=[],
- missing_optional_uses_libraries=[]): #pylint: disable=dangerous-default-value
+ def run_test(self, xml, apk, uses_libraries=(), optional_uses_libraries=(),
+ missing_optional_uses_libraries=()): #pylint: disable=dangerous-default-value
doc = minidom.parseString(xml)
try:
relax = False
@@ -114,14 +114,14 @@
self.assertFalse(matches)
def test_missing_uses_library(self):
- xml = self.xml_tmpl % ('')
- apk = self.apk_tmpl % ('')
+ xml = self.xml_tmpl % ''
+ apk = self.apk_tmpl % ''
matches = self.run_test(xml, apk, uses_libraries=['foo'])
self.assertFalse(matches)
def test_missing_optional_uses_library(self):
- xml = self.xml_tmpl % ('')
- apk = self.apk_tmpl % ('')
+ xml = self.xml_tmpl % ''
+ apk = self.apk_tmpl % ''
matches = self.run_test(xml, apk, optional_uses_libraries=['foo'])
self.assertFalse(matches)
@@ -234,6 +234,32 @@
optional_uses_libraries=['//x/y/z:bar'])
self.assertTrue(matches)
+ def test_multiple_applications(self):
+ xml = """<?xml version="1.0" encoding="utf-8"?>
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
+ <application android:featureFlag="foo">
+ <uses-library android:name="foo" />
+ <uses-library android:name="bar" android:required="false" />
+ </application>
+ <application android:featureFlag="!foo">
+ <uses-library android:name="foo" />
+ <uses-library android:name="qux" android:required="false" />
+ </application>
+ </manifest>
+ """
+ apk = self.apk_tmpl % ('\n'.join([
+ uses_library_apk('foo'),
+ uses_library_apk('bar', required_apk(False)),
+ uses_library_apk('foo'),
+ uses_library_apk('qux', required_apk(False))
+ ]))
+ matches = self.run_test(
+ xml,
+ apk,
+ uses_libraries=['//x/y/z:foo'],
+ optional_uses_libraries=['//x/y/z:bar', '//x/y/z:qux'])
+ self.assertTrue(matches)
+
class ExtractTargetSdkVersionTest(unittest.TestCase):
@@ -256,12 +282,12 @@
"targetSdkVersion:'%s'\n"
"uses-permission: name='android.permission.ACCESS_NETWORK_STATE'\n")
- def test_targert_sdk_version_28(self):
+ def test_target_sdk_version_28(self):
xml = self.xml_tmpl % '28'
apk = self.apk_tmpl % '28'
self.run_test(xml, apk, '28')
- def test_targert_sdk_version_29(self):
+ def test_target_sdk_version_29(self):
xml = self.xml_tmpl % '29'
apk = self.apk_tmpl % '29'
self.run_test(xml, apk, '29')
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 58079aa..ad3b313 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -16,22 +16,12 @@
#
"""A tool for inserting values from the build system into a manifest."""
-from __future__ import print_function
-
import argparse
import sys
from xml.dom import minidom
-from manifest import android_ns
-from manifest import compare_version_gt
-from manifest import ensure_manifest_android_ns
-from manifest import find_child_with_attribute
-from manifest import get_children_with_tag
-from manifest import get_indent
-from manifest import parse_manifest
-from manifest import write_xml
-
+from manifest import *
def parse_args():
"""Parse commandline arguments."""
@@ -48,9 +38,9 @@
parser.add_argument('--library', dest='library', action='store_true',
help='manifest is for a static library')
parser.add_argument('--uses-library', dest='uses_libraries', action='append',
- help='specify additional <uses-library> tag to add. android:requred is set to true')
+ help='specify additional <uses-library> tag to add. android:required is set to true')
parser.add_argument('--optional-uses-library', dest='optional_uses_libraries', action='append',
- help='specify additional <uses-library> tag to add. android:requred is set to false')
+ help='specify additional <uses-library> tag to add. android:required is set to false')
parser.add_argument('--uses-non-sdk-api', dest='uses_non_sdk_api', action='store_true',
help='manifest is for a package built against the platform')
parser.add_argument('--logging-parent', dest='logging_parent', default='',
@@ -91,47 +81,33 @@
manifest = parse_manifest(doc)
- # Get or insert the uses-sdk element
- uses_sdk = get_children_with_tag(manifest, 'uses-sdk')
- if len(uses_sdk) > 1:
- raise RuntimeError('found multiple uses-sdk elements')
- elif len(uses_sdk) == 1:
- element = uses_sdk[0]
- else:
- element = doc.createElement('uses-sdk')
- indent = get_indent(manifest.firstChild, 1)
- manifest.insertBefore(element, manifest.firstChild)
-
- # Insert an indent before uses-sdk to line it up with the indentation of the
- # other children of the <manifest> tag.
- manifest.insertBefore(doc.createTextNode(indent), manifest.firstChild)
-
- # Get or insert the minSdkVersion attribute. If it is already present, make
- # sure it as least the requested value.
- min_attr = element.getAttributeNodeNS(android_ns, 'minSdkVersion')
- if min_attr is None:
- min_attr = doc.createAttributeNS(android_ns, 'android:minSdkVersion')
- min_attr.value = min_sdk_version
- element.setAttributeNode(min_attr)
- else:
- if compare_version_gt(min_sdk_version, min_attr.value):
+ for uses_sdk in get_or_create_uses_sdks(doc, manifest):
+ # Get or insert the minSdkVersion attribute. If it is already present, make
+ # sure it as least the requested value.
+ min_attr = uses_sdk.getAttributeNodeNS(android_ns, 'minSdkVersion')
+ if min_attr is None:
+ min_attr = doc.createAttributeNS(android_ns, 'android:minSdkVersion')
min_attr.value = min_sdk_version
-
- # Insert the targetSdkVersion attribute if it is missing. If it is already
- # present leave it as is.
- target_attr = element.getAttributeNodeNS(android_ns, 'targetSdkVersion')
- if target_attr is None:
- target_attr = doc.createAttributeNS(android_ns, 'android:targetSdkVersion')
- if library:
- # TODO(b/117122200): libraries shouldn't set targetSdkVersion at all, but
- # ManifestMerger treats minSdkVersion="Q" as targetSdkVersion="Q" if it
- # is empty. Set it to something low so that it will be overriden by the
- # main manifest, but high enough that it doesn't cause implicit
- # permissions grants.
- target_attr.value = '16'
+ uses_sdk.setAttributeNode(min_attr)
else:
- target_attr.value = target_sdk_version
- element.setAttributeNode(target_attr)
+ if compare_version_gt(min_sdk_version, min_attr.value):
+ min_attr.value = min_sdk_version
+
+ # Insert the targetSdkVersion attribute if it is missing. If it is already
+ # present leave it as is.
+ target_attr = uses_sdk.getAttributeNodeNS(android_ns, 'targetSdkVersion')
+ if target_attr is None:
+ target_attr = doc.createAttributeNS(android_ns, 'android:targetSdkVersion')
+ if library:
+ # TODO(b/117122200): libraries shouldn't set targetSdkVersion at all, but
+ # ManifestMerger treats minSdkVersion="Q" as targetSdkVersion="Q" if it
+ # is empty. Set it to something low so that it will be overridden by the
+ # main manifest, but high enough that it doesn't cause implicit
+ # permissions grants.
+ target_attr.value = '16'
+ else:
+ target_attr.value = target_sdk_version
+ uses_sdk.setAttributeNode(target_attr)
def add_logging_parent(doc, logging_parent_value):
@@ -147,37 +123,27 @@
manifest = parse_manifest(doc)
logging_parent_key = 'android.content.pm.LOGGING_PARENT'
- elems = get_children_with_tag(manifest, 'application')
- application = elems[0] if len(elems) == 1 else None
- if len(elems) > 1:
- raise RuntimeError('found multiple <application> tags')
- elif not elems:
- application = doc.createElement('application')
- indent = get_indent(manifest.firstChild, 1)
- first = manifest.firstChild
- manifest.insertBefore(doc.createTextNode(indent), first)
- manifest.insertBefore(application, first)
+ for application in get_or_create_applications(doc, manifest):
+ indent = get_indent(application.firstChild, 2)
- indent = get_indent(application.firstChild, 2)
-
- last = application.lastChild
- if last is not None and last.nodeType != minidom.Node.TEXT_NODE:
- last = None
-
- if not find_child_with_attribute(application, 'meta-data', android_ns,
- 'name', logging_parent_key):
- ul = doc.createElement('meta-data')
- ul.setAttributeNS(android_ns, 'android:name', logging_parent_key)
- ul.setAttributeNS(android_ns, 'android:value', logging_parent_value)
- application.insertBefore(doc.createTextNode(indent), last)
- application.insertBefore(ul, last)
last = application.lastChild
+ if last is not None and last.nodeType != minidom.Node.TEXT_NODE:
+ last = None
- # align the closing tag with the opening tag if it's not
- # indented
- if last and last.nodeType != minidom.Node.TEXT_NODE:
- indent = get_indent(application.previousSibling, 1)
- application.appendChild(doc.createTextNode(indent))
+ if not find_child_with_attribute(application, 'meta-data', android_ns,
+ 'name', logging_parent_key):
+ ul = doc.createElement('meta-data')
+ ul.setAttributeNS(android_ns, 'android:name', logging_parent_key)
+ ul.setAttributeNS(android_ns, 'android:value', logging_parent_value)
+ application.insertBefore(doc.createTextNode(indent), last)
+ application.insertBefore(ul, last)
+ last = application.lastChild
+
+ # align the closing tag with the opening tag if it's not
+ # indented
+ if last and last.nodeType != minidom.Node.TEXT_NODE:
+ indent = get_indent(application.previousSibling, 1)
+ application.appendChild(doc.createTextNode(indent))
def add_uses_libraries(doc, new_uses_libraries, required):
@@ -192,42 +158,32 @@
"""
manifest = parse_manifest(doc)
- elems = get_children_with_tag(manifest, 'application')
- application = elems[0] if len(elems) == 1 else None
- if len(elems) > 1:
- raise RuntimeError('found multiple <application> tags')
- elif not elems:
- application = doc.createElement('application')
- indent = get_indent(manifest.firstChild, 1)
- first = manifest.firstChild
- manifest.insertBefore(doc.createTextNode(indent), first)
- manifest.insertBefore(application, first)
+ for application in get_or_create_applications(doc, manifest):
+ indent = get_indent(application.firstChild, 2)
- indent = get_indent(application.firstChild, 2)
+ last = application.lastChild
+ if last is not None and last.nodeType != minidom.Node.TEXT_NODE:
+ last = None
- last = application.lastChild
- if last is not None and last.nodeType != minidom.Node.TEXT_NODE:
- last = None
+ for name in new_uses_libraries:
+ if find_child_with_attribute(application, 'uses-library', android_ns,
+ 'name', name) is not None:
+ # If the uses-library tag of the same 'name' attribute value exists,
+ # respect it.
+ continue
- for name in new_uses_libraries:
- if find_child_with_attribute(application, 'uses-library', android_ns,
- 'name', name) is not None:
- # If the uses-library tag of the same 'name' attribute value exists,
- # respect it.
- continue
+ ul = doc.createElement('uses-library')
+ ul.setAttributeNS(android_ns, 'android:name', name)
+ ul.setAttributeNS(android_ns, 'android:required', str(required).lower())
- ul = doc.createElement('uses-library')
- ul.setAttributeNS(android_ns, 'android:name', name)
- ul.setAttributeNS(android_ns, 'android:required', str(required).lower())
+ application.insertBefore(doc.createTextNode(indent), last)
+ application.insertBefore(ul, last)
- application.insertBefore(doc.createTextNode(indent), last)
- application.insertBefore(ul, last)
-
- # align the closing tag with the opening tag if it's not
- # indented
- if application.lastChild.nodeType != minidom.Node.TEXT_NODE:
- indent = get_indent(application.previousSibling, 1)
- application.appendChild(doc.createTextNode(indent))
+ # align the closing tag with the opening tag if it's not
+ # indented
+ if application.lastChild.nodeType != minidom.Node.TEXT_NODE:
+ indent = get_indent(application.previousSibling, 1)
+ application.appendChild(doc.createTextNode(indent))
def add_uses_non_sdk_api(doc):
@@ -240,111 +196,63 @@
"""
manifest = parse_manifest(doc)
- elems = get_children_with_tag(manifest, 'application')
- application = elems[0] if len(elems) == 1 else None
- if len(elems) > 1:
- raise RuntimeError('found multiple <application> tags')
- elif not elems:
- application = doc.createElement('application')
- indent = get_indent(manifest.firstChild, 1)
- first = manifest.firstChild
- manifest.insertBefore(doc.createTextNode(indent), first)
- manifest.insertBefore(application, first)
-
- attr = application.getAttributeNodeNS(android_ns, 'usesNonSdkApi')
- if attr is None:
- attr = doc.createAttributeNS(android_ns, 'android:usesNonSdkApi')
- attr.value = 'true'
- application.setAttributeNode(attr)
+ for application in get_or_create_applications(doc, manifest):
+ attr = application.getAttributeNodeNS(android_ns, 'usesNonSdkApi')
+ if attr is None:
+ attr = doc.createAttributeNS(android_ns, 'android:usesNonSdkApi')
+ attr.value = 'true'
+ application.setAttributeNode(attr)
def add_use_embedded_dex(doc):
manifest = parse_manifest(doc)
- elems = get_children_with_tag(manifest, 'application')
- application = elems[0] if len(elems) == 1 else None
- if len(elems) > 1:
- raise RuntimeError('found multiple <application> tags')
- elif not elems:
- application = doc.createElement('application')
- indent = get_indent(manifest.firstChild, 1)
- first = manifest.firstChild
- manifest.insertBefore(doc.createTextNode(indent), first)
- manifest.insertBefore(application, first)
-
- attr = application.getAttributeNodeNS(android_ns, 'useEmbeddedDex')
- if attr is None:
- attr = doc.createAttributeNS(android_ns, 'android:useEmbeddedDex')
- attr.value = 'true'
- application.setAttributeNode(attr)
- elif attr.value != 'true':
- raise RuntimeError('existing attribute mismatches the option of --use-embedded-dex')
+ for application in get_or_create_applications(doc, manifest):
+ attr = application.getAttributeNodeNS(android_ns, 'useEmbeddedDex')
+ if attr is None:
+ attr = doc.createAttributeNS(android_ns, 'android:useEmbeddedDex')
+ attr.value = 'true'
+ application.setAttributeNode(attr)
+ elif attr.value != 'true':
+ raise RuntimeError('existing attribute mismatches the option of --use-embedded-dex')
def add_extract_native_libs(doc, extract_native_libs):
manifest = parse_manifest(doc)
- elems = get_children_with_tag(manifest, 'application')
- application = elems[0] if len(elems) == 1 else None
- if len(elems) > 1:
- raise RuntimeError('found multiple <application> tags')
- elif not elems:
- application = doc.createElement('application')
- indent = get_indent(manifest.firstChild, 1)
- first = manifest.firstChild
- manifest.insertBefore(doc.createTextNode(indent), first)
- manifest.insertBefore(application, first)
-
- value = str(extract_native_libs).lower()
- attr = application.getAttributeNodeNS(android_ns, 'extractNativeLibs')
- if attr is None:
- attr = doc.createAttributeNS(android_ns, 'android:extractNativeLibs')
- attr.value = value
- application.setAttributeNode(attr)
- elif attr.value != value:
- raise RuntimeError('existing attribute extractNativeLibs="%s" conflicts with --extract-native-libs="%s"' %
- (attr.value, value))
+ for application in get_or_create_applications(doc, manifest):
+ value = str(extract_native_libs).lower()
+ attr = application.getAttributeNodeNS(android_ns, 'extractNativeLibs')
+ if attr is None:
+ attr = doc.createAttributeNS(android_ns, 'android:extractNativeLibs')
+ attr.value = value
+ application.setAttributeNode(attr)
+ elif attr.value != value:
+ raise RuntimeError('existing attribute extractNativeLibs="%s" conflicts with --extract-native-libs="%s"' %
+ (attr.value, value))
def set_has_code_to_false(doc):
manifest = parse_manifest(doc)
- elems = get_children_with_tag(manifest, 'application')
- application = elems[0] if len(elems) == 1 else None
- if len(elems) > 1:
- raise RuntimeError('found multiple <application> tags')
- elif not elems:
- application = doc.createElement('application')
- indent = get_indent(manifest.firstChild, 1)
- first = manifest.firstChild
- manifest.insertBefore(doc.createTextNode(indent), first)
- manifest.insertBefore(application, first)
+ for application in get_or_create_applications(doc, manifest):
+ attr = application.getAttributeNodeNS(android_ns, 'hasCode')
+ if attr is not None:
+ # Do nothing if the application already has a hasCode attribute.
+ continue
+ attr = doc.createAttributeNS(android_ns, 'android:hasCode')
+ attr.value = 'false'
+ application.setAttributeNode(attr)
- attr = application.getAttributeNodeNS(android_ns, 'hasCode')
- if attr is not None:
- # Do nothing if the application already has a hasCode attribute.
- return
- attr = doc.createAttributeNS(android_ns, 'android:hasCode')
- attr.value = 'false'
- application.setAttributeNode(attr)
def set_test_only_flag_to_true(doc):
manifest = parse_manifest(doc)
- elems = get_children_with_tag(manifest, 'application')
- application = elems[0] if len(elems) == 1 else None
- if len(elems) > 1:
- raise RuntimeError('found multiple <application> tags')
- elif not elems:
- application = doc.createElement('application')
- indent = get_indent(manifest.firstChild, 1)
- first = manifest.firstChild
- manifest.insertBefore(doc.createTextNode(indent), first)
- manifest.insertBefore(application, first)
+ for application in get_or_create_applications(doc, manifest):
+ attr = application.getAttributeNodeNS(android_ns, 'testOnly')
+ if attr is not None:
+ # Do nothing If the application already has a testOnly attribute.
+ continue
+ attr = doc.createAttributeNS(android_ns, 'android:testOnly')
+ attr.value = 'true'
+ application.setAttributeNode(attr)
- attr = application.getAttributeNodeNS(android_ns, 'testOnly')
- if attr is not None:
- # Do nothing If the application already has a testOnly attribute.
- return
- attr = doc.createAttributeNS(android_ns, 'android:testOnly')
- attr.value = 'true'
- application.setAttributeNode(attr)
def set_max_sdk_version(doc, max_sdk_version):
"""Replace the maxSdkVersion attribute value for permission and
@@ -364,6 +272,7 @@
if max_attr and max_attr.value == 'current':
max_attr.value = max_sdk_version
+
def override_placeholder_version(doc, new_version):
"""Replace the versionCode attribute value if it\'s currently
set to the placeholder version of 0.
@@ -374,9 +283,10 @@
"""
manifest = parse_manifest(doc)
version = manifest.getAttribute("android:versionCode")
- if (version == '0'):
+ if version == '0':
manifest.setAttribute("android:versionCode", new_version)
+
def main():
"""Program entry point."""
try:
@@ -427,5 +337,6 @@
print('error: ' + str(err), file=sys.stderr)
sys.exit(-1)
+
if __name__ == '__main__':
main()
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index 0a62b10..e4d8dc3 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -20,12 +20,13 @@
import sys
import unittest
from xml.dom import minidom
-import xml.etree.ElementTree as ET
+import xml.etree.ElementTree as ElementTree
import manifest_fixer
sys.dont_write_bytecode = True
+
class CompareVersionGtTest(unittest.TestCase):
"""Unit tests for compare_version_gt function."""
@@ -69,25 +70,24 @@
'%s'
'</manifest>\n')
- # pylint: disable=redefined-builtin
- def uses_sdk(self, min=None, target=None, extra=''):
+ def uses_sdk(self, min_sdk=None, target_sdk=None, extra=''):
attrs = ''
- if min:
- attrs += ' android:minSdkVersion="%s"' % (min)
- if target:
- attrs += ' android:targetSdkVersion="%s"' % (target)
+ if min_sdk:
+ attrs += ' android:minSdkVersion="%s"' % min_sdk
+ if target_sdk:
+ attrs += ' android:targetSdkVersion="%s"' % target_sdk
if extra:
attrs += ' ' + extra
- return ' <uses-sdk%s/>\n' % (attrs)
+ return ' <uses-sdk%s/>\n' % attrs
def assert_xml_equal(self, output, expected):
- self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+ self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
def test_no_uses_sdk(self):
"""Tests inserting a uses-sdk element into a manifest."""
manifest_input = self.manifest_tmpl % ''
- expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
+ expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='28')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
self.assert_xml_equal(output, expected)
@@ -95,7 +95,7 @@
"""Tests inserting a minSdkVersion attribute into a uses-sdk element."""
manifest_input = self.manifest_tmpl % ' <uses-sdk extra="foo"/>\n'
- expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28',
+ expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='28',
extra='extra="foo"')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
self.assert_xml_equal(output, expected)
@@ -103,64 +103,64 @@
def test_raise_min(self):
"""Tests inserting a minSdkVersion attribute into a uses-sdk element."""
- manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
- expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
+ manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='27')
+ expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='28')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
self.assert_xml_equal(output, expected)
def test_raise(self):
"""Tests raising a minSdkVersion attribute."""
- manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
- expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
+ manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='27')
+ expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='28')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
self.assert_xml_equal(output, expected)
def test_no_raise_min(self):
"""Tests a minSdkVersion that doesn't need raising."""
- manifest_input = self.manifest_tmpl % self.uses_sdk(min='28')
- expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
+ manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='28')
+ expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='27')
output = self.raise_min_sdk_version_test(manifest_input, '27', '27', False)
self.assert_xml_equal(output, expected)
def test_raise_codename(self):
"""Tests raising a minSdkVersion attribute to a codename."""
- manifest_input = self.manifest_tmpl % self.uses_sdk(min='28')
- expected = self.manifest_tmpl % self.uses_sdk(min='P', target='P')
+ manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='28')
+ expected = self.manifest_tmpl % self.uses_sdk(min_sdk='P', target_sdk='P')
output = self.raise_min_sdk_version_test(manifest_input, 'P', 'P', False)
self.assert_xml_equal(output, expected)
def test_no_raise_codename(self):
"""Tests a minSdkVersion codename that doesn't need raising."""
- manifest_input = self.manifest_tmpl % self.uses_sdk(min='P')
- expected = self.manifest_tmpl % self.uses_sdk(min='P', target='28')
+ manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='P')
+ expected = self.manifest_tmpl % self.uses_sdk(min_sdk='P', target_sdk='28')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
self.assert_xml_equal(output, expected)
def test_target(self):
"""Tests an existing targetSdkVersion is preserved."""
- manifest_input = self.manifest_tmpl % self.uses_sdk(min='26', target='27')
- expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
+ manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='26', target_sdk='27')
+ expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='27')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
self.assert_xml_equal(output, expected)
def test_no_target(self):
"""Tests inserting targetSdkVersion when minSdkVersion exists."""
- manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
- expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29')
+ manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='27')
+ expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='29')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
self.assert_xml_equal(output, expected)
def test_target_no_min(self):
""""Tests inserting targetSdkVersion when minSdkVersion exists."""
- manifest_input = self.manifest_tmpl % self.uses_sdk(target='27')
- expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
+ manifest_input = self.manifest_tmpl % self.uses_sdk(target_sdk='27')
+ expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='27')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
self.assert_xml_equal(output, expected)
@@ -168,23 +168,23 @@
"""Tests inserting targetSdkVersion when minSdkVersion does not exist."""
manifest_input = self.manifest_tmpl % ''
- expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29')
+ expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='29')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
self.assert_xml_equal(output, expected)
def test_library_no_target(self):
"""Tests inserting targetSdkVersion when minSdkVersion exists."""
- manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
- expected = self.manifest_tmpl % self.uses_sdk(min='28', target='16')
+ manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='27')
+ expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='16')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
self.assert_xml_equal(output, expected)
def test_library_target_no_min(self):
"""Tests inserting targetSdkVersion when minSdkVersion exists."""
- manifest_input = self.manifest_tmpl % self.uses_sdk(target='27')
- expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
+ manifest_input = self.manifest_tmpl % self.uses_sdk(target_sdk='27')
+ expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='27')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
self.assert_xml_equal(output, expected)
@@ -192,7 +192,7 @@
"""Tests inserting targetSdkVersion when minSdkVersion does not exist."""
manifest_input = self.manifest_tmpl % ''
- expected = self.manifest_tmpl % self.uses_sdk(min='28', target='16')
+ expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='16')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
self.assert_xml_equal(output, expected)
@@ -228,12 +228,24 @@
self.assert_xml_equal(output, expected)
+ def test_multiple_uses_sdks(self):
+ """Tests a manifest that contains multiple uses_sdks elements."""
+
+ manifest_input = self.manifest_tmpl % (
+ ' <uses-sdk android:featureFlag="foo" android:minSdkVersion="21" />\n'
+ ' <uses-sdk android:featureFlag="!foo" android:minSdkVersion="22" />\n')
+ expected = self.manifest_tmpl % (
+ ' <uses-sdk android:featureFlag="foo" android:minSdkVersion="28" android:targetSdkVersion="28" />\n'
+ ' <uses-sdk android:featureFlag="!foo" android:minSdkVersion="28" android:targetSdkVersion="28" />\n')
+
+ output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
+ self.assert_xml_equal(output, expected)
class AddLoggingParentTest(unittest.TestCase):
"""Unit tests for add_logging_parent function."""
def assert_xml_equal(self, output, expected):
- self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+ self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
def add_logging_parent_test(self, input_manifest, logging_parent=None):
doc = minidom.parseString(input_manifest)
@@ -253,8 +265,8 @@
attrs = ''
if logging_parent:
meta_text = ('<meta-data android:name="android.content.pm.LOGGING_PARENT" '
- 'android:value="%s"/>\n') % (logging_parent)
- attrs += ' <application>\n %s </application>\n' % (meta_text)
+ 'android:value="%s"/>\n') % logging_parent
+ attrs += ' <application>\n %s </application>\n' % meta_text
return attrs
@@ -277,7 +289,7 @@
"""Unit tests for add_uses_libraries function."""
def assert_xml_equal(self, output, expected):
- self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+ self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
def run_test(self, input_manifest, new_uses_libraries):
doc = minidom.parseString(input_manifest)
@@ -289,18 +301,16 @@
manifest_tmpl = (
'<?xml version="1.0" encoding="utf-8"?>\n'
'<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
- ' <application>\n'
'%s'
- ' </application>\n'
'</manifest>\n')
def uses_libraries(self, name_required_pairs):
- ret = ''
+ ret = ' <application>\n'
for name, required in name_required_pairs:
ret += (
' <uses-library android:name="%s" android:required="%s"/>\n'
) % (name, required)
-
+ ret += ' </application>\n'
return ret
def test_empty(self):
@@ -361,12 +371,23 @@
output = self.run_test(manifest_input, ['foo', 'bar'])
self.assert_xml_equal(output, expected)
+ def test_multiple_application(self):
+ """When there are multiple applications, the libs are added to each."""
+ manifest_input = self.manifest_tmpl % (
+ self.uses_libraries([('foo', 'false')]) +
+ self.uses_libraries([('bar', 'false')]))
+ expected = self.manifest_tmpl % (
+ self.uses_libraries([('foo', 'false'), ('bar', 'true')]) +
+ self.uses_libraries([('bar', 'false'), ('foo', 'true')]))
+ output = self.run_test(manifest_input, ['foo', 'bar'])
+ self.assert_xml_equal(output, expected)
+
class AddUsesNonSdkApiTest(unittest.TestCase):
"""Unit tests for add_uses_libraries function."""
def assert_xml_equal(self, output, expected):
- self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+ self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
def run_test(self, input_manifest):
doc = minidom.parseString(input_manifest)
@@ -378,11 +399,11 @@
manifest_tmpl = (
'<?xml version="1.0" encoding="utf-8"?>\n'
'<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
- ' <application%s/>\n'
+ ' %s\n'
'</manifest>\n')
def uses_non_sdk_api(self, value):
- return ' android:usesNonSdkApi="true"' if value else ''
+ return '<application %s/>' % ('android:usesNonSdkApi="true"' if value else '')
def test_set_true(self):
"""Empty new_uses_libraries must not touch the manifest."""
@@ -398,12 +419,19 @@
output = self.run_test(manifest_input)
self.assert_xml_equal(output, expected)
+ def test_multiple_applications(self):
+ """new_uses_libraries must be added to all applications."""
+ manifest_input = self.manifest_tmpl % (self.uses_non_sdk_api(True) + self.uses_non_sdk_api(False))
+ expected = self.manifest_tmpl % (self.uses_non_sdk_api(True) + self.uses_non_sdk_api(True))
+ output = self.run_test(manifest_input)
+ self.assert_xml_equal(output, expected)
+
class UseEmbeddedDexTest(unittest.TestCase):
"""Unit tests for add_use_embedded_dex function."""
def assert_xml_equal(self, output, expected):
- self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+ self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
def run_test(self, input_manifest):
doc = minidom.parseString(input_manifest)
@@ -415,14 +443,14 @@
manifest_tmpl = (
'<?xml version="1.0" encoding="utf-8"?>\n'
'<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
- ' <application%s/>\n'
+ ' %s\n'
'</manifest>\n')
def use_embedded_dex(self, value):
- return ' android:useEmbeddedDex="%s"' % value
+ return '<application android:useEmbeddedDex="%s" />' % value
def test_manifest_with_undeclared_preference(self):
- manifest_input = self.manifest_tmpl % ''
+ manifest_input = self.manifest_tmpl % '<application/>'
expected = self.manifest_tmpl % self.use_embedded_dex('true')
output = self.run_test(manifest_input)
self.assert_xml_equal(output, expected)
@@ -437,12 +465,24 @@
manifest_input = self.manifest_tmpl % self.use_embedded_dex('false')
self.assertRaises(RuntimeError, self.run_test, manifest_input)
+ def test_multiple_applications(self):
+ manifest_input = self.manifest_tmpl % (
+ self.use_embedded_dex('true') +
+ '<application/>'
+ )
+ expected = self.manifest_tmpl % (
+ self.use_embedded_dex('true') +
+ self.use_embedded_dex('true')
+ )
+ output = self.run_test(manifest_input)
+ self.assert_xml_equal(output, expected)
+
class AddExtractNativeLibsTest(unittest.TestCase):
"""Unit tests for add_extract_native_libs function."""
def assert_xml_equal(self, output, expected):
- self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+ self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
def run_test(self, input_manifest, value):
doc = minidom.parseString(input_manifest)
@@ -454,20 +494,20 @@
manifest_tmpl = (
'<?xml version="1.0" encoding="utf-8"?>\n'
'<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
- ' <application%s/>\n'
+ ' %s\n'
'</manifest>\n')
def extract_native_libs(self, value):
- return ' android:extractNativeLibs="%s"' % value
+ return '<application android:extractNativeLibs="%s" />' % value
def test_set_true(self):
- manifest_input = self.manifest_tmpl % ''
+ manifest_input = self.manifest_tmpl % '<application/>'
expected = self.manifest_tmpl % self.extract_native_libs('true')
output = self.run_test(manifest_input, True)
self.assert_xml_equal(output, expected)
def test_set_false(self):
- manifest_input = self.manifest_tmpl % ''
+ manifest_input = self.manifest_tmpl % '<application/>'
expected = self.manifest_tmpl % self.extract_native_libs('false')
output = self.run_test(manifest_input, False)
self.assert_xml_equal(output, expected)
@@ -482,12 +522,18 @@
manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
self.assertRaises(RuntimeError, self.run_test, manifest_input, False)
+ def test_multiple_applications(self):
+ manifest_input = self.manifest_tmpl % (self.extract_native_libs('true') + '<application/>')
+ expected = self.manifest_tmpl % (self.extract_native_libs('true') + self.extract_native_libs('true'))
+ output = self.run_test(manifest_input, True)
+ self.assert_xml_equal(output, expected)
+
class AddNoCodeApplicationTest(unittest.TestCase):
"""Unit tests for set_has_code_to_false function."""
def assert_xml_equal(self, output, expected):
- self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+ self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
def run_test(self, input_manifest):
doc = minidom.parseString(input_manifest)
@@ -515,7 +561,7 @@
self.assert_xml_equal(output, expected)
def test_has_application_has_code_false(self):
- """ Do nothing if there's already an application elemeent. """
+ """ Do nothing if there's already an application element. """
manifest_input = self.manifest_tmpl % ' <application android:hasCode="false"/>\n'
output = self.run_test(manifest_input)
self.assert_xml_equal(output, manifest_input)
@@ -527,12 +573,25 @@
output = self.run_test(manifest_input)
self.assert_xml_equal(output, manifest_input)
+ def test_multiple_applications(self):
+ """ Apply to all applications """
+ manifest_input = self.manifest_tmpl % (
+ ' <application android:hasCode="true" />\n' +
+ ' <application android:hasCode="false" />\n' +
+ ' <application/>\n')
+ expected = self.manifest_tmpl % (
+ ' <application android:hasCode="true" />\n' +
+ ' <application android:hasCode="false" />\n' +
+ ' <application android:hasCode="false" />\n')
+ output = self.run_test(manifest_input)
+ self.assert_xml_equal(output, expected)
+
class AddTestOnlyApplicationTest(unittest.TestCase):
"""Unit tests for set_test_only_flag_to_true function."""
def assert_xml_equal(self, output, expected):
- self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+ self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
def run_test(self, input_manifest):
doc = minidom.parseString(input_manifest)
@@ -571,12 +630,26 @@
output = self.run_test(manifest_input)
self.assert_xml_equal(output, manifest_input)
+ def test_multiple_applications(self):
+ manifest_input = self.manifest_tmpl % (
+ ' <application android:testOnly="true" />\n' +
+ ' <application android:testOnly="false" />\n' +
+ ' <application/>\n'
+ )
+ expected = self.manifest_tmpl % (
+ ' <application android:testOnly="true" />\n' +
+ ' <application android:testOnly="false" />\n' +
+ ' <application android:testOnly="true" />\n'
+ )
+ output = self.run_test(manifest_input)
+ self.assert_xml_equal(output, expected)
+
class SetMaxSdkVersionTest(unittest.TestCase):
"""Unit tests for set_max_sdk_version function."""
def assert_xml_equal(self, output, expected):
- self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+ self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
def run_test(self, input_manifest, max_sdk_version):
doc = minidom.parseString(input_manifest)
@@ -591,15 +664,15 @@
'%s'
'</manifest>\n')
- def permission(self, max=None):
- if max is None:
+ def permission(self, max_sdk=None):
+ if max_sdk is None:
return ' <permission/>'
- return ' <permission android:maxSdkVersion="%s"/>\n' % max
+ return ' <permission android:maxSdkVersion="%s"/>\n' % max_sdk
- def uses_permission(self, max=None):
- if max is None:
+ def uses_permission(self, max_sdk=None):
+ if max_sdk is None:
return ' <uses-permission/>'
- return ' <uses-permission android:maxSdkVersion="%s"/>\n' % max
+ return ' <uses-permission android:maxSdkVersion="%s"/>\n' % max_sdk
def test_permission_no_max_sdk_version(self):
"""Tests if permission has no maxSdkVersion attribute"""
@@ -643,11 +716,12 @@
output = self.run_test(manifest_input, '9000')
self.assert_xml_equal(output, expected)
+
class OverrideDefaultVersionTest(unittest.TestCase):
"""Unit tests for override_default_version function."""
def assert_xml_equal(self, output, expected):
- self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+ self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
def run_test(self, input_manifest, version):
doc = minidom.parseString(input_manifest)
diff --git a/scripts/merge_directories.py b/scripts/merge_directories.py
deleted file mode 100755
index 3f8631b..0000000
--- a/scripts/merge_directories.py
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/usr/bin/env python3
-import argparse
-import os
-import shutil
-import sys
-
-def main():
- parser = argparse.ArgumentParser(
- description="Given a list of directories, this script will copy the contents of all of "
- "them into the first directory, erroring out if any duplicate files are found."
- )
- parser.add_argument(
- "--ignore-duplicates",
- action="store_true",
- help="Don't error out on duplicate files, just skip them. The file from the earliest "
- "directory listed on the command line will be the winner."
- )
- parser.add_argument(
- "--file-list",
- help="Path to a text file containing paths relative to in_dir. Only these paths will be "
- "copied out of in_dir."
- )
- parser.add_argument("out_dir")
- parser.add_argument("in_dir")
- args = parser.parse_args()
-
- if not os.path.isdir(args.out_dir):
- sys.exit(f"error: {args.out_dir} must be a directory")
- if not os.path.isdir(args.in_dir):
- sys.exit(f"error: {args.in_dir} must be a directory")
-
- file_list = None
- if args.file_list:
- with open(file_list_file, "r") as f:
- file_list = f.read().strip().splitlines()
-
- in_dir = args.in_dir
- for root, dirs, files in os.walk(in_dir):
- rel_root = os.path.relpath(root, in_dir)
- dst_root = os.path.join(args.out_dir, rel_root)
- made_parent_dirs = False
- for f in files:
- src = os.path.join(root, f)
- dst = os.path.join(dst_root, f)
- p = os.path.normpath(os.path.join(rel_root, f))
- if file_list is not None and p not in file_list:
- continue
- if os.path.lexists(dst):
- if args.ignore_duplicates:
- continue
- sys.exit(f"error: {p} exists in both {args.out_dir} and {in_dir}")
-
- if not made_parent_dirs:
- os.makedirs(dst_root, exist_ok=True)
- made_parent_dirs = True
-
- shutil.copy2(src, dst, follow_symlinks=False)
-
-if __name__ == "__main__":
- main()
diff --git a/scripts/modify_permissions_allowlist.py b/scripts/modify_permissions_allowlist.py
index 38ec7ec..4a0ca8f 100755
--- a/scripts/modify_permissions_allowlist.py
+++ b/scripts/modify_permissions_allowlist.py
@@ -16,8 +16,6 @@
#
"""A tool for modifying privileged permission allowlists."""
-from __future__ import print_function
-
import argparse
import sys
from xml.dom import minidom
diff --git a/scripts/modify_permissions_allowlist_test.py b/scripts/modify_permissions_allowlist_test.py
index ee8b12c..577388f 100755
--- a/scripts/modify_permissions_allowlist_test.py
+++ b/scripts/modify_permissions_allowlist_test.py
@@ -16,8 +16,6 @@
#
"""Unit tests for modify_permissions_allowlist.py."""
-from __future__ import print_function
-
import unittest
from xml.dom import minidom
diff --git a/scripts/ninja_determinism_test.py b/scripts/ninja_determinism_test.py
new file mode 100755
index 0000000..e207b96
--- /dev/null
+++ b/scripts/ninja_determinism_test.py
@@ -0,0 +1,210 @@
+#!/usr/bin/env python3
+
+import asyncio
+import argparse
+import dataclasses
+import hashlib
+import os
+import re
+import socket
+import subprocess
+import sys
+import zipfile
+
+from typing import List
+
+def get_top() -> str:
+ path = '.'
+ while not os.path.isfile(os.path.join(path, 'build/soong/soong_ui.bash')):
+ if os.path.abspath(path) == '/':
+ sys.exit('Could not find android source tree root.')
+ path = os.path.join(path, '..')
+ return os.path.abspath(path)
+
+
+_PRODUCT_REGEX = re.compile(r'([a-zA-Z_][a-zA-Z0-9_]*)(?:(?:-([a-zA-Z_][a-zA-Z0-9_]*))?-(user|userdebug|eng))?')
+
+
+@dataclasses.dataclass(frozen=True)
+class Product:
+ """Represents a TARGET_PRODUCT and TARGET_BUILD_VARIANT."""
+ product: str
+ release: str
+ variant: str
+
+ def __post_init__(self):
+ if not _PRODUCT_REGEX.match(str(self)):
+ raise ValueError(f'Invalid product name: {self}')
+
+ def __str__(self):
+ return self.product + '-' + self.release + '-' + self.variant
+
+
+async def run_make_nothing(product: Product, out_dir: str) -> bool:
+ """Runs a build and returns if it succeeded or not."""
+ with open(os.path.join(out_dir, 'build.log'), 'wb') as f:
+ result = await asyncio.create_subprocess_exec(
+ 'prebuilts/build-tools/linux-x86/bin/nsjail',
+ '-q',
+ '--cwd',
+ os.getcwd(),
+ '-e',
+ '-B',
+ '/',
+ '-B',
+ f'{os.path.abspath(out_dir)}:{os.path.join(os.getcwd(), "out")}',
+ '--time_limit',
+ '0',
+ '--skip_setsid',
+ '--keep_caps',
+ '--disable_clone_newcgroup',
+ '--disable_clone_newnet',
+ '--rlimit_as',
+ 'soft',
+ '--rlimit_core',
+ 'soft',
+ '--rlimit_cpu',
+ 'soft',
+ '--rlimit_fsize',
+ 'soft',
+ '--rlimit_nofile',
+ 'soft',
+ '--proc_rw',
+ '--hostname',
+ socket.gethostname(),
+ '--',
+ 'build/soong/soong_ui.bash',
+ '--make-mode',
+ f'TARGET_PRODUCT={product.product}',
+ f'TARGET_RELEASE={product.release}',
+ f'TARGET_BUILD_VARIANT={product.variant}',
+ '--skip-ninja',
+ 'nothing', stdout=f, stderr=subprocess.STDOUT)
+ return await result.wait() == 0
+
+SUBNINJA_OR_INCLUDE_REGEX = re.compile(rb'\n(?:include|subninja) ')
+
+def find_subninjas_and_includes(contents) -> List[str]:
+ results = []
+ def get_path_from_directive(i):
+ j = contents.find(b'\n', i)
+ if j < 0:
+ path_bytes = contents[i:]
+ else:
+ path_bytes = contents[i:j]
+ path_bytes = path_bytes.removesuffix(b'\r')
+ path = path_bytes.decode()
+ if '$' in path:
+ sys.exit('includes/subninjas with variables are unsupported: '+path)
+ return path
+
+ if contents.startswith(b"include "):
+ results.append(get_path_from_directive(len(b"include ")))
+ elif contents.startswith(b"subninja "):
+ results.append(get_path_from_directive(len(b"subninja ")))
+
+ for match in SUBNINJA_OR_INCLUDE_REGEX.finditer(contents):
+ results.append(get_path_from_directive(match.end()))
+
+ return results
+
+
+def transitively_included_ninja_files(out_dir: str, ninja_file: str, seen):
+ with open(ninja_file, 'rb') as f:
+ contents = f.read()
+
+ results = [ninja_file]
+ seen[ninja_file] = True
+ sub_files = find_subninjas_and_includes(contents)
+ for sub_file in sub_files:
+ sub_file = os.path.join(out_dir, sub_file.removeprefix('out/'))
+ if sub_file not in seen:
+ results.extend(transitively_included_ninja_files(out_dir, sub_file, seen))
+
+ return results
+
+
+def hash_ninja_file(out_dir: str, ninja_file: str, hasher):
+ with open(ninja_file, 'rb') as f:
+ contents = f.read()
+
+ sub_files = find_subninjas_and_includes(contents)
+
+ hasher.update(contents)
+
+ for sub_file in sub_files:
+ hash_ninja_file(out_dir, os.path.join(out_dir, sub_file.removeprefix('out/')), hasher)
+
+
+def hash_files(files: List[str]) -> str:
+ hasher = hashlib.md5()
+ for file in files:
+ with open(file, 'rb') as f:
+ hasher.update(f.read())
+ return hasher.hexdigest()
+
+
+def dist_ninja_files(out_dir: str, zip_name: str, ninja_files: List[str]):
+ dist_dir = os.getenv('DIST_DIR', os.path.join(os.getenv('OUT_DIR', 'out'), 'dist'))
+ os.makedirs(dist_dir, exist_ok=True)
+
+ with open(os.path.join(dist_dir, zip_name), 'wb') as f:
+ with zipfile.ZipFile(f, mode='w') as zf:
+ for ninja_file in ninja_files:
+ zf.write(ninja_file, arcname=os.path.basename(out_dir)+'/out/' + os.path.relpath(ninja_file, out_dir))
+
+
+async def main():
+ parser = argparse.ArgumentParser()
+ args = parser.parse_args()
+
+ os.chdir(get_top())
+ subprocess.check_call(['touch', 'build/soong/Android.bp'])
+
+ product = Product(
+ 'aosp_cf_x86_64_phone',
+ 'trunk_staging',
+ 'userdebug',
+ )
+ os.environ['TARGET_PRODUCT'] = 'aosp_cf_x86_64_phone'
+ os.environ['TARGET_RELEASE'] = 'trunk_staging'
+ os.environ['TARGET_BUILD_VARIANT'] = 'userdebug'
+
+ out_dir1 = os.path.join(os.getenv('OUT_DIR', 'out'), 'determinism_test_out1')
+ out_dir2 = os.path.join(os.getenv('OUT_DIR', 'out'), 'determinism_test_out2')
+
+ os.makedirs(out_dir1, exist_ok=True)
+ os.makedirs(out_dir2, exist_ok=True)
+
+ success1, success2 = await asyncio.gather(
+ run_make_nothing(product, out_dir1),
+ run_make_nothing(product, out_dir2))
+
+ if not success1:
+ with open(os.path.join(out_dir1, 'build.log'), 'r') as f:
+ print(f.read(), file=sys.stderr)
+ sys.exit('build failed')
+ if not success2:
+ with open(os.path.join(out_dir2, 'build.log'), 'r') as f:
+ print(f.read(), file=sys.stderr)
+ sys.exit('build failed')
+
+ ninja_files1 = transitively_included_ninja_files(out_dir1, os.path.join(out_dir1, f'combined-{product.product}.ninja'), {})
+ ninja_files2 = transitively_included_ninja_files(out_dir2, os.path.join(out_dir2, f'combined-{product.product}.ninja'), {})
+
+ dist_ninja_files(out_dir1, 'determinism_test_files_1.zip', ninja_files1)
+ dist_ninja_files(out_dir2, 'determinism_test_files_2.zip', ninja_files2)
+
+ hash1 = hash_files(ninja_files1)
+ hash2 = hash_files(ninja_files2)
+
+ if hash1 != hash2:
+ sys.exit("ninja files were not deterministic! See disted determinism_test_files_1/2.zip")
+
+ print("Success, ninja files were deterministic")
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
+
+
diff --git a/scripts/run-soong-tests-with-go-tools.sh b/scripts/run-soong-tests-with-go-tools.sh
index 1fbb1fc..82efaa0 100755
--- a/scripts/run-soong-tests-with-go-tools.sh
+++ b/scripts/run-soong-tests-with-go-tools.sh
@@ -38,6 +38,11 @@
CLANG_VERSION=$(build/soong/scripts/get_clang_version.py)
export CC="${TOP}/prebuilts/clang/host/${OS}-x86/${CLANG_VERSION}/bin/clang"
export CXX="${TOP}/prebuilts/clang/host/${OS}-x86/${CLANG_VERSION}/bin/clang++"
+ glibc_dir="${TOP}/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8"
+ export CGO_CFLAGS="--sysroot ${glibc_dir}/sysroot/"
+ export CGO_CPPFLAGS="--sysroot ${glibc_dir}/sysroot/"
+ export CGO_CXXFLAGS="--sysroot ${glibc_dir}/sysroot/"
+ export CGO_LDFLAGS="--sysroot ${glibc_dir}/sysroot/ -B ${glibc_dir}/lib/gcc/x86_64-linux/4.8.3 -L ${glibc_dir}/lib/gcc/x86_64-linux/4.8.3 -L ${glibc_dir}/x86_64-linux/lib64"
fi
# androidmk_test.go gets confused if ANDROID_BUILD_TOP is set.
diff --git a/scripts/rustc_linker.py b/scripts/rustc_linker.py
new file mode 100755
index 0000000..3f60708
--- /dev/null
+++ b/scripts/rustc_linker.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""
+This script is used as a replacement for the Rust linker to allow fine-grained
+control over the what gets emitted to the linker.
+"""
+
+import os
+import shutil
+import subprocess
+import sys
+import argparse
+
+replacementVersionScript = None
+
+argparser = argparse.ArgumentParser()
+argparser.add_argument('--android-clang-bin', required=True)
+args = argparser.parse_known_args()
+clang_args = [args[0].android_clang_bin] + args[1]
+
+for i, arg in enumerate(clang_args):
+ if arg.startswith('-Wl,--android-version-script='):
+ replacementVersionScript = arg.split("=")[1]
+ del clang_args[i]
+ break
+
+if replacementVersionScript:
+ versionScriptFound = False
+ for i, arg in enumerate(clang_args):
+ if arg.startswith('-Wl,--version-script='):
+ clang_args[i] ='-Wl,--version-script=' + replacementVersionScript
+ versionScriptFound = True
+ break
+
+ if not versionScriptFound:
+ # If rustc did not emit a version script, just append the arg
+ clang_args.append('-Wl,--version-script=' + replacementVersionScript)
+try:
+ subprocess.run(clang_args, encoding='utf-8', check=True)
+except subprocess.CalledProcessError as e:
+ sys.exit(-1)
+
diff --git a/scripts/test_config_fixer.py b/scripts/test_config_fixer.py
index 2876bcb..91a83f2 100644
--- a/scripts/test_config_fixer.py
+++ b/scripts/test_config_fixer.py
@@ -16,8 +16,6 @@
#
"""A tool for modifying values in a test config."""
-from __future__ import print_function
-
import argparse
import json
import sys
diff --git a/scripts/text_file_processor.py b/scripts/text_file_processor.py
new file mode 100755
index 0000000..10186ce
--- /dev/null
+++ b/scripts/text_file_processor.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import argparse
+import re
+
+def main():
+ parser = argparse.ArgumentParser(description='This script looks for '
+ '`{CONTENTS_OF:path/to/file}` markers in the input file and replaces them with the actual '
+ 'contents of that file, with leading/trailing whitespace stripped. The idea is that this '
+ 'script could be extended to support more types of markers in the future.')
+ parser.add_argument('input')
+ parser.add_argument('output')
+ args = parser.parse_args()
+
+ with open(args.input, 'r') as f:
+ contents = f.read()
+
+ i = 0
+ replacedContents = ''
+ for m in re.finditer(r'{CONTENTS_OF:([a-zA-Z0-9 _/.-]+)}', contents):
+ replacedContents += contents[i:m.start()]
+ with open(m.group(1), 'r') as f:
+ replacedContents += f.read().strip()
+ i = m.end()
+ replacedContents += contents[i:]
+
+ with open(args.output, 'w') as f:
+ f.write(replacedContents)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/sdk/Android.bp b/sdk/Android.bp
index f436320..f42b478 100644
--- a/sdk/Android.bp
+++ b/sdk/Android.bp
@@ -18,7 +18,6 @@
"bp.go",
"build_release.go",
"exports.go",
- "genrule.go",
"member_trait.go",
"member_type.go",
"sdk.go",
@@ -31,7 +30,6 @@
"cc_sdk_test.go",
"compat_config_sdk_test.go",
"exports_test.go",
- "genrule_test.go",
"java_sdk_test.go",
"license_sdk_test.go",
"member_trait_test.go",
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index 7ee548f..34e11f0 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -46,8 +46,9 @@
],
}
`, apex, fragment, extraFragments)),
- android.FixtureAddFile("frameworks/base/config/boot-profile.txt", nil),
- android.FixtureAddFile("frameworks/base/config/boot-image-profile.txt", nil),
+ android.FixtureAddFile("frameworks/base/boot/boot-profile.txt", nil),
+ android.FixtureAddFile("frameworks/base/boot/boot-image-profile.txt", nil),
+ android.FixtureAddFile("art/build/boot/boot-image-profile.txt", nil),
android.FixtureAddFile("build/soong/scripts/check_boot_jars/package_allowed_list.txt", nil),
)
}
@@ -204,7 +205,19 @@
.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/core1.jar
.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/core2.jar
`),
- snapshotTestPreparer(checkSnapshotWithoutSource, preparerForSnapshot),
+ snapshotTestPreparer(checkSnapshotWithoutSource, android.GroupFixturePreparers(
+ preparerForSnapshot,
+ // Flag ART prebuilts
+ 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"),
+ )),
// Check the behavior of the snapshot without the source.
snapshotTestChecker(checkSnapshotWithoutSource, func(t *testing.T, result *android.TestResult) {
@@ -212,8 +225,8 @@
checkBootJarsPackageCheckRule(t, result,
append(
[]string{
- "out/soong/.intermediates/prebuilts/apex/prebuilt_com.android.art.deapexer/android_common/deapexer/javalib/core1.jar",
- "out/soong/.intermediates/prebuilts/apex/prebuilt_com.android.art.deapexer/android_common/deapexer/javalib/core2.jar",
+ "out/soong/.intermediates/prebuilts/apex/com.android.art/android_common_com.android.art/deapexer/javalib/core1.jar",
+ "out/soong/.intermediates/prebuilts/apex/com.android.art/android_common_com.android.art/deapexer/javalib/core2.jar",
"out/soong/.intermediates/default/java/framework/android_common/aligned/framework.jar",
},
java.ApexBootJarDexJarPaths...,
@@ -338,6 +351,7 @@
shared_library: false,
public: {enabled: true},
min_sdk_version: "2",
+ sdk_version: "current",
}
java_sdk_library {
@@ -348,6 +362,7 @@
public: {enabled: true},
min_sdk_version: "2",
permitted_packages: ["myothersdklibrary"],
+ sdk_version: "current",
}
java_sdk_library {
@@ -357,6 +372,7 @@
compile_dex: true,
public: {enabled: true},
min_sdk_version: "2",
+ sdk_version: "current",
}
`),
).RunTest(t)
@@ -624,6 +640,7 @@
min_sdk_version: "2",
permitted_packages: ["myothersdklibrary"],
compile_dex: true,
+ sdk_version: "current",
}
`),
@@ -655,6 +672,7 @@
shared_library: false,
public: {enabled: true},
min_sdk_version: "2",
+ sdk_version: "current",
}
`),
).RunTest(t)
@@ -877,6 +895,7 @@
public: {enabled: true},
permitted_packages: ["mysdklibrary"],
min_sdk_version: "current",
+ sdk_version: "current",
}
java_sdk_library {
@@ -895,6 +914,7 @@
package_prefixes: ["newlibrary.all.mine"],
single_packages: ["newlibrary.mine"],
},
+ sdk_version: "current",
}
`),
).RunTest(t)
@@ -1080,6 +1100,7 @@
shared_library: false,
public: {enabled: true},
min_sdk_version: "S",
+ sdk_version: "current",
}
java_sdk_library {
@@ -1090,6 +1111,7 @@
public: {enabled: true},
min_sdk_version: "Tiramisu",
permitted_packages: ["mynewsdklibrary"],
+ sdk_version: "current",
}
`),
).RunTest(t)
@@ -1287,6 +1309,7 @@
shared_library: false,
public: {enabled: true},
min_sdk_version: "Tiramisu",
+ sdk_version: "current",
}
java_sdk_library {
name: "mynewsdklibrary",
@@ -1296,6 +1319,7 @@
public: {enabled: true},
min_sdk_version: "Tiramisu",
permitted_packages: ["mynewsdklibrary"],
+ sdk_version: "current",
}
`),
).RunTest(t)
diff --git a/sdk/build_release.go b/sdk/build_release.go
index 6bb05a3..3656c98 100644
--- a/sdk/build_release.go
+++ b/sdk/build_release.go
@@ -101,6 +101,8 @@
buildReleaseS = initBuildRelease("S")
buildReleaseT = initBuildRelease("Tiramisu")
buildReleaseU = initBuildRelease("UpsideDownCake")
+ buildReleaseV = initBuildRelease("VanillaIceCream")
+ buildReleaseB = initBuildRelease("Baklava")
// Add the current build release which is always treated as being more recent than any other
// build release, including those added in tests.
diff --git a/sdk/build_release_test.go b/sdk/build_release_test.go
index 5bf57b5..07f99ee 100644
--- a/sdk/build_release_test.go
+++ b/sdk/build_release_test.go
@@ -42,7 +42,7 @@
android.AssertDeepEquals(t, "release", (*buildRelease)(nil), release)
// Uses a wildcard in the error message to allow for additional build releases to be added to
// the supported set without breaking this test.
- android.FailIfNoMatchingErrors(t, `unknown release "A", expected one of \[S,Tiramisu,UpsideDownCake,F1,F2,current\]`, []error{err})
+ android.FailIfNoMatchingErrors(t, `unknown release "A", expected one of \[S,Tiramisu,UpsideDownCake,VanillaIceCream,Baklava,F1,F2,current\]`, []error{err})
})
}
@@ -60,7 +60,7 @@
t.Run("closed range", func(t *testing.T) {
set, err := parseBuildReleaseSet("S-F1")
android.AssertDeepEquals(t, "errors", nil, err)
- android.AssertStringEquals(t, "set", "[S,Tiramisu,UpsideDownCake,F1]", set.String())
+ android.AssertStringEquals(t, "set", "[S,Tiramisu,UpsideDownCake,VanillaIceCream,Baklava,F1]", set.String())
})
invalidAReleaseMessage := `unknown release "A", expected one of ` + allBuildReleaseSet.String()
t.Run("invalid release", func(t *testing.T) {
diff --git a/sdk/genrule.go b/sdk/genrule.go
deleted file mode 100644
index 347ab05..0000000
--- a/sdk/genrule.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package sdk
-
-import (
- "android/soong/android"
- "android/soong/genrule"
-)
-
-func init() {
- registerGenRuleBuildComponents(android.InitRegistrationContext)
-}
-
-func registerGenRuleBuildComponents(ctx android.RegistrationContext) {
- ctx.RegisterModuleType("sdk_genrule", SdkGenruleFactory)
-}
-
-// sdk_genrule_host is a genrule that can depend on sdk and sdk_snapshot module types
-//
-// What this means is that it's a genrule with only the "common_os" variant.
-// sdk modules have 3 variants: host, android, and common_os. The common_os one depends
-// on the host/device ones and packages their result into a final snapshot zip.
-// Genrules probably want access to this snapshot zip when they depend on an sdk module,
-// which means they want to depend on the common_os variant and not the host/android
-// variants.
-func SdkGenruleFactory() android.Module {
- module := genrule.NewGenRule()
-
- android.InitCommonOSAndroidMultiTargetsArchModule(module, android.NeitherHostNorDeviceSupported, android.MultilibCommon)
- android.InitDefaultableModule(module)
-
- return module
-}
diff --git a/sdk/genrule_test.go b/sdk/genrule_test.go
deleted file mode 100644
index 6e52a3d..0000000
--- a/sdk/genrule_test.go
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2018 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package sdk
-
-import (
- "testing"
-
- "android/soong/android"
- "android/soong/genrule"
- "android/soong/java"
-)
-
-func TestSdkGenrule(t *testing.T) {
- // Test that an sdk_genrule can depend on an sdk, and that a genrule can depend on an sdk_genrule
- bp := `
- sdk {
- name: "my_sdk",
- }
- sdk_genrule {
- name: "my_sdk_genrule",
- tool_files: ["tool"],
- cmd: "$(location tool) $(in) $(out)",
- srcs: [":my_sdk"],
- out: ["out"],
- }
- genrule {
- name: "my_regular_genrule",
- srcs: [":my_sdk_genrule"],
- out: ["out"],
- cmd: "cp $(in) $(out)",
- }
- `
- android.GroupFixturePreparers(
- // if java components aren't registered, the sdk module doesn't create a snapshot for some reason.
- java.PrepareForTestWithJavaBuildComponents,
- genrule.PrepareForTestWithGenRuleBuildComponents,
- PrepareForTestWithSdkBuildComponents,
- android.FixtureRegisterWithContext(registerGenRuleBuildComponents),
- ).RunTestWithBp(t, bp)
-}
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 0fb5c70..4db163c 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -1360,10 +1360,9 @@
}
`),
snapshotTestChecker(checkSnapshotWithSourcePreferred, func(t *testing.T, result *android.TestResult) {
- ctx := android.ModuleInstallPathContextForTesting(result.Config)
dexJarBuildPath := func(name string, kind android.SdkKind) string {
- dep := result.Module(name, "android_common").(java.SdkLibraryDependency)
- path := dep.SdkApiExportableStubDexJar(ctx, kind).Path()
+ sdkLibInfo, _ := android.OtherModuleProvider(result.TestContext.OtherModuleProviderAdaptor(), result.Module(name, "android_common"), java.SdkLibraryInfoProvider)
+ path := sdkLibInfo.ExportableStubDexJarPaths[kind].Path()
return path.RelativeToTop().String()
}
@@ -1703,61 +1702,6 @@
)
}
-func TestSnapshotWithJavaSdkLibrary_NamingScheme(t *testing.T) {
- result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, `
- sdk {
- name: "mysdk",
- java_sdk_libs: ["myjavalib"],
- }
-
- java_sdk_library {
- name: "myjavalib",
- apex_available: ["//apex_available:anyapex"],
- srcs: ["Test.java"],
- sdk_version: "current",
- naming_scheme: "default",
- public: {
- enabled: true,
- },
- }
- `)
-
- CheckSnapshot(t, result, "mysdk", "",
- checkAndroidBpContents(`
-// This is auto-generated. DO NOT EDIT.
-
-apex_contributions_defaults {
- name: "mysdk.contributions",
- contents: ["prebuilt_myjavalib"],
-}
-
-java_sdk_library_import {
- name: "myjavalib",
- prefer: false,
- visibility: ["//visibility:public"],
- apex_available: ["//apex_available:anyapex"],
- naming_scheme: "default",
- shared_library: true,
- public: {
- jars: ["sdk_library/public/myjavalib-stubs.jar"],
- stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
- current_api: "sdk_library/public/myjavalib.txt",
- removed_api: "sdk_library/public/myjavalib-removed.txt",
- sdk_version: "current",
- },
-}
-`),
- checkAllCopyRules(`
-.intermediates/myjavalib.stubs.exportable/android_common/combined/myjavalib.stubs.exportable.jar -> sdk_library/public/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
-`),
- checkMergeZips(
- ".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
- ),
- )
-}
-
func TestSnapshotWithJavaSdkLibrary_DoctagFiles(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForSdkTestWithJavaSdkLibrary,
@@ -1780,7 +1724,7 @@
filegroup {
name: "mygroup",
- srcs: [":myjavalib{.doctags}"],
+ device_common_srcs: [":myjavalib{.doctags}"],
}
`)
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 5b644fd..aa82abb 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -84,20 +84,6 @@
// True if this is a module_exports (or module_exports_snapshot) module type.
Module_exports bool `blueprint:"mutated"`
-
- // The additional visibility to add to the prebuilt modules to allow them to
- // reference each other.
- //
- // This can only be used to widen the visibility of the members:
- //
- // * Specifying //visibility:public here will make all members visible and
- // essentially ignore their own visibility.
- // * Specifying //visibility:private here is an error.
- // * Specifying any other rule here will add it to the members visibility and
- // be output to the member prebuilt in the snapshot. Duplicates will be
- // dropped. Adding a rule to members that have //visibility:private will
- // cause the //visibility:private to be discarded.
- Prebuilt_visibility []string
}
// sdk defines an SDK which is a logical group of modules (e.g. native libs, headers, java libs, etc.)
@@ -130,8 +116,6 @@
s.AddProperties(&s.properties, s.dynamicMemberTypeListProperties, &traitsWrapper)
- // Make sure that the prebuilt visibility property is verified for errors.
- android.AddVisibilityProperty(s, "prebuilt_visibility", &s.properties.Prebuilt_visibility)
android.InitCommonOSAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(s)
android.AddLoadHook(s, func(ctx android.LoadHookContext) {
@@ -211,6 +195,11 @@
OutputFile: s.snapshotFile,
DistFiles: android.MakeDefaultDistFiles(s.snapshotFile.Path(), s.infoFile.Path()),
Include: "$(BUILD_PHONY_PACKAGE)",
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.SetBool("LOCAL_DONT_CHECK_MODULE", true)
+ },
+ },
ExtraFooters: []android.AndroidMkExtraFootersFunc{
func(w io.Writer, name, prefix, moduleDir string) {
// Allow the sdk to be built by simply passing its name on the command line.
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 057b370..2532a25 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -53,9 +53,6 @@
// generated sdk_snapshot.
":__subpackages__",
],
- prebuilt_visibility: [
- "//prebuilts/mysdk",
- ],
java_header_libs: [
"myjavalib",
"mypublicjavalib",
@@ -131,11 +128,7 @@
java_import {
name: "myjavalib",
prefer: false,
- visibility: [
- "//other/foo",
- "//package",
- "//prebuilts/mysdk",
- ],
+ visibility: ["//visibility:public"],
apex_available: ["//apex_available:platform"],
jars: ["java/myjavalib.jar"],
}
@@ -151,11 +144,7 @@
java_import {
name: "mydefaultedjavalib",
prefer: false,
- visibility: [
- "//other/bar",
- "//package",
- "//prebuilts/mysdk",
- ],
+ visibility: ["//visibility:public"],
apex_available: ["//apex_available:platform"],
jars: ["java/mydefaultedjavalib.jar"],
}
@@ -163,50 +152,13 @@
java_import {
name: "myprivatejavalib",
prefer: false,
- visibility: [
- "//package",
- "//prebuilts/mysdk",
- ],
+ visibility: ["//visibility:public"],
apex_available: ["//apex_available:platform"],
jars: ["java/myprivatejavalib.jar"],
}
`))
}
-func TestPrebuiltVisibilityProperty_IsValidated(t *testing.T) {
- testSdkError(t, `prebuilt_visibility: cannot mix "//visibility:private" with any other visibility rules`, `
- sdk {
- name: "mysdk",
- prebuilt_visibility: [
- "//foo",
- "//visibility:private",
- ],
- }
-`)
-}
-
-func TestPrebuiltVisibilityProperty_AddPrivate(t *testing.T) {
- testSdkError(t, `prebuilt_visibility: "//visibility:private" does not widen the visibility`, `
- sdk {
- name: "mysdk",
- prebuilt_visibility: [
- "//visibility:private",
- ],
- java_header_libs: [
- "myjavalib",
- ],
- }
-
- java_library {
- name: "myjavalib",
- // Uses package default visibility
- srcs: ["Test.java"],
- system_modules: "none",
- sdk_version: "none",
- }
-`)
-}
-
func TestSdkInstall(t *testing.T) {
sdk := `
sdk {
diff --git a/sdk/systemserverclasspath_fragment_sdk_test.go b/sdk/systemserverclasspath_fragment_sdk_test.go
index c1c4ed6..fd6c4e7 100644
--- a/sdk/systemserverclasspath_fragment_sdk_test.go
+++ b/sdk/systemserverclasspath_fragment_sdk_test.go
@@ -80,6 +80,7 @@
dex_preopt: {
profile: "art-profile",
},
+ sdk_version: "current",
}
`),
).RunTest(t)
@@ -110,12 +111,14 @@
apex_available: ["myapex"],
srcs: ["Test.java"],
min_sdk_version: "33", // Tiramisu
+ sdk_version: "current",
}
java_sdk_library {
name: "mysdklibrary-future",
apex_available: ["myapex"],
srcs: ["Test.java"],
min_sdk_version: "34", // UpsideDownCake
+ sdk_version: "current",
}
sdk {
name: "mysdk",
@@ -199,6 +202,7 @@
apex_available: ["myapex"],
srcs: ["Test.java"],
min_sdk_version: "34", // UpsideDownCake
+ sdk_version: "current",
}
sdk {
name: "mysdk",
diff --git a/sdk/testing.go b/sdk/testing.go
index f4e2b03..21d457c 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -144,7 +144,7 @@
seenBuildNumberFile := false
for _, bp := range buildParams {
switch bp.Rule.String() {
- case android.Cp.String():
+ case android.Cp.String(), android.CpWithBash.String():
output := bp.Output
// Get destination relative to the snapshot root
dest := output.Rel()
diff --git a/sdk/update.go b/sdk/update.go
index a4b1967..00352cb 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -22,7 +22,6 @@
"sort"
"strings"
- "android/soong/apex"
"android/soong/cc"
"android/soong/java"
@@ -563,11 +562,11 @@
}
builder.infoContents = string(output)
android.WriteFileRuleVerbatim(ctx, info, builder.infoContents)
- installedInfo := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), info.Base(), info)
+ installedInfo := ctx.InstallFileWithoutCheckbuild(android.PathForMainlineSdksInstall(ctx), info.Base(), info)
s.infoFile = android.OptionalPathForPath(installedInfo)
// Install the zip, making sure that the info file has been installed as well.
- installedZip := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), outputZipFile.Base(), outputZipFile, installedInfo)
+ installedZip := ctx.InstallFileWithoutCheckbuild(android.PathForMainlineSdksInstall(ctx), outputZipFile.Base(), outputZipFile, installedInfo)
s.snapshotFile = android.OptionalPathForPath(installedZip)
}
@@ -1109,20 +1108,24 @@
// same package so can be marked as private.
m.AddProperty("visibility", []string{"//visibility:private"})
} else {
- // Extract visibility information from a member variant. All variants have the same
- // visibility so it doesn't matter which one is used.
- visibilityRules := android.EffectiveVisibilityRules(s.ctx, variant)
-
- // Add any additional visibility rules needed for the prebuilts to reference each other.
- err := visibilityRules.Widen(s.sdk.properties.Prebuilt_visibility)
- if err != nil {
- s.ctx.PropertyErrorf("prebuilt_visibility", "%s", err)
- }
-
- visibility := visibilityRules.Strings()
- if len(visibility) != 0 {
- m.AddProperty("visibility", visibility)
- }
+ // Change the visibility of the module SDK prebuilts to public.
+ // This includes
+ // 1. Stub libraries of `sdk` modules
+ // 2. Binaries and libraries of `module_exports` modules
+ //
+ // This is a workaround to improve maintainlibility of the module SDK.
+ // Since module sdks are generated from release branches and dropped to development
+ // branches, there might be a visibility skew between the sources and prebuilts
+ // of a specific module.
+ // To reconcile this potential skew, change the visibility to public.
+ //
+ // This means dependencies can bypass visibility restrictions when prebuilts are used, so we rely
+ // on source builds in CI to check them.
+ //
+ // TODO (b/361303067): This special case for category (2) can be removed if existing usages
+ // of host/test prebuilts of modules like conscrypt,tzdata,i18n are switched to source builds.
+ // It will also require ART switching to full manifests.
+ m.AddProperty("visibility", []string{"//visibility:public"})
}
// Where available copy apex_available properties from the member.
@@ -1133,9 +1136,6 @@
apexAvailable = []string{android.AvailableToPlatform}
}
- // Add in any baseline apex available settings.
- apexAvailable = append(apexAvailable, apex.BaselineApexAvailable(member.Name())...)
-
// Remove duplicates and sort.
apexAvailable = android.FirstUniqueStrings(apexAvailable)
sort.Strings(apexAvailable)
@@ -1145,7 +1145,7 @@
// The licenses are the same for all variants.
mctx := s.ctx
- licenseInfo, _ := android.OtherModuleProvider(mctx, variant, android.LicenseInfoProvider)
+ licenseInfo, _ := android.OtherModuleProvider(mctx, variant, android.LicensesInfoProvider)
if len(licenseInfo.Licenses) > 0 {
m.AddPropertyWithTag("licenses", licenseInfo.Licenses, s.OptionalSdkMemberReferencePropertyTag())
}
@@ -1201,7 +1201,7 @@
// the snapshot.
func (s *snapshotBuilder) snapshotSdkMemberName(name string, required bool) string {
if _, ok := s.allMembersByName[name]; !ok {
- if required {
+ if required && !s.ctx.Config().AllowMissingDependencies() {
s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", name)
}
return name
@@ -1989,14 +1989,6 @@
return m.builder.targetBuildRelease.EarlierThan(buildReleaseT)
}
-func (m *memberContext) Config() android.Config {
- return m.sdkMemberContext.Config()
-}
-
-func (m *memberContext) OtherModulePropertyErrorf(module android.Module, property string, fmt string, args ...interface{}) {
- m.sdkMemberContext.OtherModulePropertyErrorf(module, property, fmt, args)
-}
-
var _ android.SdkMemberContext = (*memberContext)(nil)
func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule *bpModule) {
diff --git a/sh/Android.bp b/sh/Android.bp
index 930fcf5..1deedc7 100644
--- a/sh/Android.bp
+++ b/sh/Android.bp
@@ -11,7 +11,6 @@
"soong-android",
"soong-cc",
"soong-java",
- "soong-testing",
"soong-tradefed",
],
srcs: [
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 2e48d83..d753d24 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -15,11 +15,10 @@
package sh
import (
+ "fmt"
"path/filepath"
"strings"
- "android/soong/testing"
-
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -47,6 +46,7 @@
ctx.RegisterModuleType("sh_binary_host", ShBinaryHostFactory)
ctx.RegisterModuleType("sh_test", ShTestFactory)
ctx.RegisterModuleType("sh_test_host", ShTestHostFactory)
+ ctx.RegisterModuleType("sh_defaults", ShDefaultsFactory)
}
// Test fixture preparer that will register most sh build components.
@@ -120,6 +120,16 @@
// the test.
Data []string `android:"path,arch_variant"`
+ // same as data, but adds dependencies using the device's os variation and the common
+ // architecture's variation. Can be used to add a module built for device to the data of a
+ // host test.
+ Device_common_data []string `android:"path_device_common"`
+
+ // same as data, but adds dependencies using the device's os variation and the device's first
+ // architecture's variation. Can be used to add a module built for device to the data of a
+ // host test.
+ Device_first_data []string `android:"path_device_first"`
+
// Add RootTargetPreparer to auto generated test config. This guarantees the test to run
// with root permission.
Require_root *bool
@@ -155,10 +165,14 @@
// Test options.
Test_options android.CommonTestOptions
+
+ // a list of extra test configuration files that should be installed with the module.
+ Extra_test_configs []string `android:"path,arch_variant"`
}
type ShBinary struct {
android.ModuleBase
+ android.DefaultableModuleBase
properties shBinaryProperties
@@ -176,8 +190,9 @@
installDir android.InstallPath
- data []android.DataPath
- testConfig android.Path
+ data []android.DataPath
+ testConfig android.Path
+ extraTestConfigs android.Paths
dataModules map[string]android.Path
}
@@ -189,7 +204,7 @@
func (s *ShBinary) DepsMutator(ctx android.BottomUpMutatorContext) {
}
-func (s *ShBinary) OutputFile() android.OutputPath {
+func (s *ShBinary) OutputFile() android.Path {
return s.outputFilePath
}
@@ -210,41 +225,41 @@
var _ android.ImageInterface = (*ShBinary)(nil)
-func (s *ShBinary) ImageMutatorBegin(ctx android.BaseModuleContext) {}
+func (s *ShBinary) ImageMutatorBegin(ctx android.ImageInterfaceContext) {}
-func (s *ShBinary) VendorVariantNeeded(ctx android.BaseModuleContext) bool {
+func (s *ShBinary) VendorVariantNeeded(ctx android.ImageInterfaceContext) bool {
return s.InstallInVendor()
}
-func (s *ShBinary) ProductVariantNeeded(ctx android.BaseModuleContext) bool {
+func (s *ShBinary) ProductVariantNeeded(ctx android.ImageInterfaceContext) bool {
return s.InstallInProduct()
}
-func (s *ShBinary) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+func (s *ShBinary) CoreVariantNeeded(ctx android.ImageInterfaceContext) bool {
return !s.InstallInRecovery() && !s.InstallInRamdisk() && !s.InstallInVendorRamdisk() && !s.ModuleBase.InstallInVendor()
}
-func (s *ShBinary) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (s *ShBinary) RamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return proptools.Bool(s.properties.Ramdisk_available) || s.InstallInRamdisk()
}
-func (s *ShBinary) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (s *ShBinary) VendorRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return proptools.Bool(s.properties.Vendor_ramdisk_available) || s.InstallInVendorRamdisk()
}
-func (s *ShBinary) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (s *ShBinary) DebugRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
return false
}
-func (s *ShBinary) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
+func (s *ShBinary) RecoveryVariantNeeded(ctx android.ImageInterfaceContext) bool {
return proptools.Bool(s.properties.Recovery_available) || s.InstallInRecovery()
}
-func (s *ShBinary) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+func (s *ShBinary) ExtraImageVariations(ctx android.ImageInterfaceContext) []string {
return nil
}
-func (s *ShBinary) SetImageVariation(ctx android.BaseModuleContext, variation string) {
+func (s *ShBinary) SetImageVariation(ctx android.ImageInterfaceContext, variation string) {
s.properties.ImageVariation = variation
}
@@ -299,8 +314,6 @@
s.properties.SubName = s.GetSubname(ctx)
- android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: []string{s.sourceFilePath.String()}})
-
ctx.SetOutputFiles(android.Paths{s.outputFilePath}, "")
}
@@ -407,8 +420,10 @@
s.ShBinary.generateAndroidBuildActions(ctx)
expandedData := android.PathsForModuleSrc(ctx, s.testProperties.Data)
+ expandedData = append(expandedData, android.PathsForModuleSrc(ctx, s.testProperties.Device_common_data)...)
+ expandedData = append(expandedData, android.PathsForModuleSrc(ctx, s.testProperties.Device_first_data)...)
// Emulate the data property for java_data dependencies.
- for _, javaData := range ctx.GetDirectDepsWithTag(shTestJavaDataTag) {
+ for _, javaData := range ctx.GetDirectDepsProxyWithTag(shTestJavaDataTag) {
expandedData = append(expandedData, android.OutputFilesForModule(ctx, javaData, "")...)
}
for _, d := range expandedData {
@@ -459,22 +474,26 @@
HostTemplate: "${ShellTestConfigTemplate}",
})
+ s.extraTestConfigs = android.PathsForModuleSrc(ctx, s.testProperties.Extra_test_configs)
s.dataModules = make(map[string]android.Path)
- ctx.VisitDirectDeps(func(dep android.Module) {
+ ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) {
depTag := ctx.OtherModuleDependencyTag(dep)
switch depTag {
case shTestDataBinsTag, shTestDataDeviceBinsTag:
path := android.OutputFileForModule(ctx, dep, "")
s.addToDataModules(ctx, path.Base(), path)
case shTestDataLibsTag, shTestDataDeviceLibsTag:
- if cc, isCc := dep.(*cc.Module); isCc {
+ if _, isCc := android.OtherModuleProvider(ctx, dep, cc.CcInfoProvider); isCc {
// Copy to an intermediate output directory to append "lib[64]" to the path,
// so that it's compatible with the default rpath values.
var relPath string
- if cc.Arch().ArchType.Multilib == "lib64" {
- relPath = filepath.Join("lib64", cc.OutputFile().Path().Base())
+ linkableInfo := android.OtherModuleProviderOrDefault(ctx, dep, cc.LinkableInfoProvider)
+ commonInfo := android.OtherModuleProviderOrDefault(ctx, dep, android.CommonModuleInfoKey)
+
+ if commonInfo.Target.Arch.ArchType.Multilib == "lib64" {
+ relPath = filepath.Join("lib64", linkableInfo.OutputFile.Path().Base())
} else {
- relPath = filepath.Join("lib", cc.OutputFile().Path().Base())
+ relPath = filepath.Join("lib", linkableInfo.OutputFile.Path().Base())
}
if _, exist := s.dataModules[relPath]; exist {
return
@@ -482,7 +501,7 @@
relocatedLib := android.PathForModuleOut(ctx, "relocated").Join(ctx, relPath)
ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
- Input: cc.OutputFile().Path(),
+ Input: linkableInfo.OutputFile.Path(),
Output: relocatedLib,
})
s.addToDataModules(ctx, relPath, relocatedLib)
@@ -499,7 +518,26 @@
installedData := ctx.InstallTestData(s.installDir, s.data)
s.installedFile = ctx.InstallExecutable(s.installDir, s.outputFilePath.Base(), s.outputFilePath, installedData...)
- android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+ mkEntries := s.AndroidMkEntries()[0]
+ android.SetProvider(ctx, tradefed.BaseTestProviderKey, tradefed.BaseTestProviderData{
+ TestcaseRelDataFiles: addArch(ctx.Arch().ArchType.String(), installedData.Paths()),
+ OutputFile: s.outputFilePath,
+ TestConfig: s.testConfig,
+ TestSuites: s.testProperties.Test_suites,
+ IsHost: false,
+ IsUnitTest: Bool(s.testProperties.Test_options.Unit_test),
+ MkInclude: mkEntries.Include,
+ MkAppClass: mkEntries.Class,
+ InstallDir: s.installDir,
+ })
+}
+
+func addArch(archType string, paths android.Paths) []string {
+ archRelPaths := []string{}
+ for _, p := range paths {
+ archRelPaths = append(archRelPaths, fmt.Sprintf("%s/%s", archType, p.Rel()))
+ }
+ return archRelPaths
}
func (s *ShTest) InstallInData() bool {
@@ -523,6 +561,9 @@
entries.AddStrings("LOCAL_TEST_DATA_BINS", s.testProperties.Data_bins...)
}
entries.SetBoolIfTrue("LOCAL_COMPATIBILITY_PER_TESTCASE_DIRECTORY", Bool(s.testProperties.Per_testcase_directory))
+ if len(s.extraTestConfigs) > 0 {
+ entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", s.extraTestConfigs.Strings()...)
+ }
s.testProperties.Test_options.SetAndroidMkEntries(entries)
},
@@ -540,6 +581,7 @@
module := &ShBinary{}
initShBinaryModule(module)
android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst)
+ android.InitDefaultableModule(module)
return module
}
@@ -549,6 +591,7 @@
module := &ShBinary{}
initShBinaryModule(module)
android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
+ android.InitDefaultableModule(module)
return module
}
@@ -559,6 +602,7 @@
module.AddProperties(&module.testProperties)
android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst)
+ android.InitDefaultableModule(module)
return module
}
@@ -573,6 +617,21 @@
}
android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
+ android.InitDefaultableModule(module)
+ return module
+}
+
+type ShDefaults struct {
+ android.ModuleBase
+ android.DefaultsModuleBase
+}
+
+func ShDefaultsFactory() android.Module {
+ module := &ShDefaults{}
+
+ module.AddProperties(&shBinaryProperties{}, &TestProperties{})
+ android.InitDefaultsModule(module)
+
return module
}
diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go
index 37450b0..28f997d 100644
--- a/sh/sh_binary_test.go
+++ b/sh/sh_binary_test.go
@@ -176,6 +176,22 @@
android.AssertBoolEquals(t, "LOCAL_IS_UNIT_TEST", true, actualData)
}
+func TestShTestExtraTestConfig(t *testing.T) {
+ result, _ := testShBinary(t, `
+ sh_test {
+ name: "foo",
+ src: "test.sh",
+ filename: "test.sh",
+ extra_test_configs: ["config1.xml", "config2.xml"],
+ }
+ `)
+
+ mod := result.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
+ entries := android.AndroidMkEntriesForTest(t, result, mod)[0]
+ actualData := entries.EntryMap["LOCAL_EXTRA_FULL_TEST_CONFIGS"]
+ android.AssertStringPathsRelativeToTopEquals(t, "extra_configs", result.Config(), []string{"config1.xml", "config2.xml"}, actualData)
+}
+
func TestShTestHost_dataDeviceModules(t *testing.T) {
ctx, config := testShBinary(t, `
sh_test_host {
@@ -294,3 +310,92 @@
actualData := entries.EntryMap["LOCAL_TEST_DATA"]
android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData)
}
+
+func TestDefaultsForTests(t *testing.T) {
+ ctx, config := testShBinary(t, `
+ sh_defaults {
+ name: "defaults",
+ src: "test.sh",
+ filename: "test.sh",
+ data: [
+ "testdata/data1",
+ "testdata/sub/data2",
+ ],
+ }
+ sh_test_host {
+ name: "foo",
+ defaults: ["defaults"],
+ data: [
+ "testdata/more_data",
+ ],
+ java_data: [
+ "javalib",
+ ],
+ }
+
+ java_library_host {
+ name: "javalib",
+ srcs: [],
+ }
+
+ sh_test {
+ name: "sh-test",
+ defaults: ["defaults"],
+ }
+
+ `)
+ buildOS := ctx.Config().BuildOS.String()
+ mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest)
+ if !mod.Host() {
+ t.Errorf("host bit is not set for a sh_test_host module.")
+ }
+ expectedData := []string{
+ ":testdata/data1",
+ ":testdata/sub/data2",
+ ":testdata/more_data",
+ "out/soong/.intermediates/javalib/" + buildOS + "_common/combined/:javalib.jar",
+ }
+
+ entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
+ actualData := entries.EntryMap["LOCAL_TEST_DATA"]
+ android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData)
+
+ // Just the defaults
+ expectedData = []string{
+ ":testdata/data1",
+ ":testdata/sub/data2",
+ }
+ mod = ctx.ModuleForTests("sh-test", "android_arm64_armv8-a").Module().(*ShTest)
+ entries = android.AndroidMkEntriesForTest(t, ctx, mod)[0]
+ actualData = entries.EntryMap["LOCAL_TEST_DATA"]
+ android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData)
+}
+
+func TestDefaultsForBinaries(t *testing.T) {
+ ctx, _ := testShBinary(t, `
+ sh_defaults {
+ name: "defaults",
+ src: "test.sh",
+ filename: "test.sh",
+ }
+ sh_binary_host {
+ name: "the-host-binary",
+ defaults: ["defaults"],
+ }
+ sh_binary{
+ name: "the-binary",
+ defaults: ["defaults"],
+ }
+ `)
+ buildOS := ctx.Config().BuildOS.String()
+ mod := ctx.ModuleForTests("the-host-binary", buildOS+"_x86_64").Module().(*ShBinary)
+ if !mod.Host() {
+ t.Errorf("host bit is not set for a sh_binary_host module.")
+ }
+
+ expectedFilename := "test.sh"
+ android.AssertStringEquals(t, "Filename", expectedFilename, *mod.properties.Filename)
+
+ mod = ctx.ModuleForTests("the-binary", "android_arm64_armv8-a").Module().(*ShBinary)
+ android.AssertStringEquals(t, "Filename", expectedFilename, *mod.properties.Filename)
+}
diff --git a/shared/paths.go b/shared/paths.go
index 1ee66d5..64f94ba 100644
--- a/shared/paths.go
+++ b/shared/paths.go
@@ -20,14 +20,6 @@
"path/filepath"
)
-// A SharedPaths represents a list of paths that are shared between
-// soong_ui and soong.
-type SharedPaths interface {
- // BazelMetricsDir returns the path where a set of bazel profile
- // files are stored for later processed by the metrics pipeline.
- BazelMetricsDir() string
-}
-
// Joins the path strings in the argument list, taking absolute paths into
// account. That is, if one of the strings is an absolute path, the ones before
// are ignored.
diff --git a/snapshot/snapshot_base.go b/snapshot/snapshot_base.go
index 6bf3c87..510e9cf 100644
--- a/snapshot/snapshot_base.go
+++ b/snapshot/snapshot_base.go
@@ -45,14 +45,3 @@
LicenseKinds []string `json:",omitempty"`
LicenseTexts []string `json:",omitempty"`
}
-
-func (prop *SnapshotJsonFlags) InitBaseSnapshotPropsWithName(m android.Module, name string) {
- prop.ModuleName = name
-
- prop.LicenseKinds = m.EffectiveLicenseKinds()
- prop.LicenseTexts = m.EffectiveLicenseFiles().Strings()
-}
-
-func (prop *SnapshotJsonFlags) InitBaseSnapshotProps(m android.Module) {
- prop.InitBaseSnapshotPropsWithName(m, m.Name())
-}
diff --git a/soong_ui.bash b/soong_ui.bash
index 7737880..be78b68 100755
--- a/soong_ui.bash
+++ b/soong_ui.bash
@@ -14,18 +14,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../make/shell_utils.sh
+require_top
+
# To track how long we took to startup.
case $(uname -s) in
Darwin)
- export TRACE_BEGIN_SOONG=`$T/prebuilts/build-tools/path/darwin-x86/date +%s%3N`
+ export TRACE_BEGIN_SOONG=`$TOP/prebuilts/build-tools/path/darwin-x86/date +%s%3N`
;;
*)
export TRACE_BEGIN_SOONG=$(date +%s%N)
;;
esac
-source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../make/shell_utils.sh
-require_top
+setup_cog_env_if_needed
# Save the current PWD for use in soong_ui
export ORIGINAL_PWD=${PWD}
diff --git a/sysprop/Android.bp b/sysprop/Android.bp
index a00a5e4..22cba3b 100644
--- a/sysprop/Android.bp
+++ b/sysprop/Android.bp
@@ -21,4 +21,6 @@
"sysprop_test.go",
],
pluginFor: ["soong_build"],
+ // Used by plugins
+ visibility: ["//visibility:public"],
}
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 84f20c5..25fbc41 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -346,7 +346,6 @@
ctx.PropertyErrorf("srcs", "srcs contains non-sysprop file %q", syspropFile.String())
}
}
- android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
if ctx.Failed() {
return
@@ -680,7 +679,7 @@
Sysprop_srcs: m.properties.Srcs,
Scope: scope,
Check_api: proptools.StringPtr(ctx.ModuleName()),
- Installable: proptools.BoolPtr(false),
+ Installable: m.properties.Installable,
Crate_name: m.rustCrateName(),
Rustlibs: []string{
"liblog_rust",
diff --git a/systemfeatures/Android.bp b/systemfeatures/Android.bp
new file mode 100644
index 0000000..a65a6b6
--- /dev/null
+++ b/systemfeatures/Android.bp
@@ -0,0 +1,18 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-systemfeatures",
+ pkgPath: "android/soong/systemfeatures",
+ deps: [
+ "blueprint",
+ "blueprint-proptools",
+ "soong",
+ "soong-android",
+ "soong-java",
+ ],
+ srcs: ["system_features.go"],
+ testSrcs: ["system_features_test.go"],
+ pluginFor: ["soong_build"],
+}
diff --git a/systemfeatures/OWNERS b/systemfeatures/OWNERS
new file mode 100644
index 0000000..3e44806
--- /dev/null
+++ b/systemfeatures/OWNERS
@@ -0,0 +1,2 @@
+jdduke@google.com
+shayba@google.com
diff --git a/systemfeatures/system_features.go b/systemfeatures/system_features.go
new file mode 100644
index 0000000..b8dacfb
--- /dev/null
+++ b/systemfeatures/system_features.go
@@ -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 systemfeatures
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+
+ "android/soong/android"
+ "android/soong/genrule"
+
+ "github.com/google/blueprint/proptools"
+)
+
+var (
+ pctx = android.NewPackageContext("android/soong/systemfeatures")
+)
+
+func init() {
+ registerSystemFeaturesComponents(android.InitRegistrationContext)
+}
+
+func registerSystemFeaturesComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("java_system_features_srcs", JavaSystemFeaturesSrcsFactory)
+}
+
+type javaSystemFeaturesSrcs struct {
+ android.ModuleBase
+ properties struct {
+ // The fully qualified class name for the generated code, e.g., com.android.Foo
+ Full_class_name string
+ // Whether to generate only a simple metadata class with details about the full API surface.
+ // This is useful for tools that rely on the mapping from feature names to their generated
+ // method names, but don't want the fully generated API class (e.g., for linting).
+
+ Metadata_only *bool
+ }
+ outputFiles android.WritablePaths
+}
+
+var _ genrule.SourceFileGenerator = (*javaSystemFeaturesSrcs)(nil)
+var _ android.SourceFileProducer = (*javaSystemFeaturesSrcs)(nil)
+
+func (m *javaSystemFeaturesSrcs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // Create a file name appropriate for the given fully qualified (w/ package) class name.
+ classNameParts := strings.Split(m.properties.Full_class_name, ".")
+ outputDir := android.PathForModuleGen(ctx)
+ outputFileName := classNameParts[len(classNameParts)-1] + ".java"
+ outputFile := android.PathForModuleGen(ctx, outputFileName).OutputPath
+
+ // Collect all RELEASE_SYSTEM_FEATURE_$K:$V build flags into a list of "$K:$V" pairs.
+ var features []string
+ for k, v := range ctx.Config().ProductVariables().BuildFlags {
+ if strings.HasPrefix(k, "RELEASE_SYSTEM_FEATURE_") {
+ shortFeatureName := strings.TrimPrefix(k, "RELEASE_SYSTEM_FEATURE_")
+ features = append(features, fmt.Sprintf("%s:%s", shortFeatureName, v))
+ }
+ }
+ // Ensure sorted outputs for consistency of flag ordering in ninja outputs.
+ sort.Strings(features)
+
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().Text("rm -rf").Text(outputDir.String())
+ rule.Command().Text("mkdir -p").Text(outputDir.String())
+ rule.Command().
+ BuiltTool("systemfeatures-gen-tool").
+ Flag(m.properties.Full_class_name).
+ FlagForEachArg("--feature=", features).
+ FlagWithArg("--readonly=", fmt.Sprint(ctx.Config().ReleaseUseSystemFeatureBuildFlags())).
+ FlagWithArg("--metadata-only=", fmt.Sprint(proptools.Bool(m.properties.Metadata_only))).
+ FlagWithOutput(" > ", outputFile)
+ rule.Build(ctx.ModuleName(), "Generating systemfeatures srcs filegroup")
+
+ m.outputFiles = append(m.outputFiles, outputFile)
+}
+
+func (m *javaSystemFeaturesSrcs) Srcs() android.Paths {
+ return m.outputFiles.Paths()
+}
+
+func (m *javaSystemFeaturesSrcs) GeneratedSourceFiles() android.Paths {
+ return m.outputFiles.Paths()
+}
+
+func (m *javaSystemFeaturesSrcs) GeneratedDeps() android.Paths {
+ return m.outputFiles.Paths()
+}
+
+func (m *javaSystemFeaturesSrcs) GeneratedHeaderDirs() android.Paths {
+ return nil
+}
+
+func JavaSystemFeaturesSrcsFactory() android.Module {
+ module := &javaSystemFeaturesSrcs{}
+ module.AddProperties(&module.properties)
+ module.properties.Metadata_only = proptools.BoolPtr(false)
+ android.InitAndroidModule(module)
+ return module
+}
diff --git a/systemfeatures/system_features_test.go b/systemfeatures/system_features_test.go
new file mode 100644
index 0000000..558bb95
--- /dev/null
+++ b/systemfeatures/system_features_test.go
@@ -0,0 +1,51 @@
+// 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 systemfeatures
+
+import (
+ "android/soong/android"
+
+ "testing"
+)
+
+func TestJavaSystemFeaturesSrcs(t *testing.T) {
+ bp := `
+java_system_features_srcs {
+ name: "system-features-srcs",
+ full_class_name: "com.android.test.RoSystemFeatures",
+}
+`
+
+ res := android.GroupFixturePreparers(
+ android.FixtureRegisterWithContext(registerSystemFeaturesComponents),
+ android.PrepareForTestWithBuildFlag("RELEASE_USE_SYSTEM_FEATURE_BUILD_FLAGS", "true"),
+ android.PrepareForTestWithBuildFlag("RELEASE_SYSTEM_FEATURE_AUTOMOTIVE", "0"),
+ android.PrepareForTestWithBuildFlag("RELEASE_SYSTEM_FEATURE_TELEVISION", "UNAVAILABLE"),
+ android.PrepareForTestWithBuildFlag("RELEASE_SYSTEM_FEATURE_WATCH", ""),
+ android.PrepareForTestWithBuildFlag("RELEASE_NOT_SYSTEM_FEATURE_FOO", "BAR"),
+ ).RunTestWithBp(t, bp)
+
+ module := res.ModuleForTests("system-features-srcs", "")
+ cmd := module.Rule("system-features-srcs").RuleParams.Command
+ android.AssertStringDoesContain(t, "Expected fully class name", cmd, " com.android.test.RoSystemFeatures ")
+ android.AssertStringDoesContain(t, "Expected readonly flag", cmd, "--readonly=true")
+ android.AssertStringDoesContain(t, "Expected AUTOMOTIVE feature flag", cmd, "--feature=AUTOMOTIVE:0 ")
+ android.AssertStringDoesContain(t, "Expected TELEVISION feature flag", cmd, "--feature=TELEVISION:UNAVAILABLE ")
+ android.AssertStringDoesContain(t, "Expected WATCH feature flag", cmd, "--feature=WATCH: ")
+ android.AssertStringDoesNotContain(t, "Unexpected FOO arg from non-system feature flag", cmd, "FOO")
+
+ systemFeaturesModule := module.Module().(*javaSystemFeaturesSrcs)
+ expectedOutputPath := "out/soong/.intermediates/system-features-srcs/gen/RoSystemFeatures.java"
+ android.AssertPathsRelativeToTopEquals(t, "Expected output file", []string{expectedOutputPath}, systemFeaturesModule.Srcs())
+}
diff --git a/testing/Android.bp b/testing/Android.bp
deleted file mode 100644
index 43040b0..0000000
--- a/testing/Android.bp
+++ /dev/null
@@ -1,24 +0,0 @@
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-bootstrap_go_package {
- name: "soong-testing",
- pkgPath: "android/soong/testing",
- deps: [
- "blueprint",
- "soong-android",
- "soong-testing-code_metadata_internal_proto",
- "soong-testing-test_spec_proto",
-
- ],
- srcs: [
- "all_code_metadata.go",
- "all_test_specs.go",
- "code_metadata.go",
- "test_spec.go",
- "init.go",
- "test.go",
- ],
- pluginFor: ["soong_build"],
-}
diff --git a/testing/OWNERS b/testing/OWNERS
deleted file mode 100644
index 03bcdf1..0000000
--- a/testing/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-dariofreni@google.com
-joeo@google.com
-ronish@google.com
-caditya@google.com
diff --git a/testing/all_code_metadata.go b/testing/all_code_metadata.go
deleted file mode 100644
index e89b281..0000000
--- a/testing/all_code_metadata.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package testing
-
-import (
- "android/soong/android"
-)
-
-const fileContainingCodeMetadataFilePaths = "all_code_metadata_paths.rsp"
-const allCodeMetadataFile = "all_code_metadata.pb"
-
-func AllCodeMetadataFactory() android.Singleton {
- return &allCodeMetadataSingleton{}
-}
-
-type allCodeMetadataSingleton struct {
- // Path where the collected metadata is stored after successful validation.
- outputPath android.OutputPath
-}
-
-func (this *allCodeMetadataSingleton) GenerateBuildActions(ctx android.SingletonContext) {
- var intermediateMetadataPaths android.Paths
-
- ctx.VisitAllModules(
- func(module android.Module) {
- if metadata, ok := android.OtherModuleProvider(ctx, module, CodeMetadataProviderKey); ok {
- intermediateMetadataPaths = append(intermediateMetadataPaths, metadata.IntermediatePath)
- }
- },
- )
-
- rspFile := android.PathForOutput(ctx, fileContainingCodeMetadataFilePaths)
- this.outputPath = android.PathForOutput(ctx, ownershipDirectory, allCodeMetadataFile)
-
- rule := android.NewRuleBuilder(pctx, ctx)
- cmd := rule.Command().
- BuiltTool("metadata").
- FlagWithArg("-rule ", "code_metadata").
- FlagWithRspFileInputList("-inputFile ", rspFile, intermediateMetadataPaths)
- cmd.FlagWithOutput("-outputFile ", this.outputPath)
- rule.Build("all_code_metadata_rule", "Generate all code metadata")
-
- ctx.Phony("all_code_metadata", this.outputPath)
-}
-
-func (this *allCodeMetadataSingleton) MakeVars(ctx android.MakeVarsContext) {
- ctx.DistForGoal("code_metadata", this.outputPath)
-}
diff --git a/testing/all_test_specs.go b/testing/all_test_specs.go
deleted file mode 100644
index 68f24d1..0000000
--- a/testing/all_test_specs.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package testing
-
-import (
- "android/soong/android"
-)
-
-const ownershipDirectory = "ownership"
-const fileContainingFilePaths = "all_test_spec_paths.rsp"
-const allTestSpecsFile = "all_test_specs.pb"
-
-func AllTestSpecsFactory() android.Singleton {
- return &allTestSpecsSingleton{}
-}
-
-type allTestSpecsSingleton struct {
- // Path where the collected metadata is stored after successful validation.
- outputPath android.OutputPath
-}
-
-func (this *allTestSpecsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
- var intermediateMetadataPaths android.Paths
-
- ctx.VisitAllModules(func(module android.Module) {
- if metadata, ok := android.OtherModuleProvider(ctx, module, TestSpecProviderKey); ok {
- intermediateMetadataPaths = append(intermediateMetadataPaths, metadata.IntermediatePath)
- }
- })
-
- rspFile := android.PathForOutput(ctx, fileContainingFilePaths)
- this.outputPath = android.PathForOutput(ctx, ownershipDirectory, allTestSpecsFile)
-
- rule := android.NewRuleBuilder(pctx, ctx)
- cmd := rule.Command().
- BuiltTool("metadata").
- FlagWithArg("-rule ", "test_spec").
- FlagWithRspFileInputList("-inputFile ", rspFile, intermediateMetadataPaths)
- cmd.FlagWithOutput("-outputFile ", this.outputPath)
- rule.Build("all_test_specs_rule", "Generate all test specifications")
- ctx.Phony("all_test_specs", this.outputPath)
-}
-
-func (this *allTestSpecsSingleton) MakeVars(ctx android.MakeVarsContext) {
- ctx.DistForGoal("test_specs", this.outputPath)
-}
diff --git a/testing/code_metadata.go b/testing/code_metadata.go
deleted file mode 100644
index 11ba430..0000000
--- a/testing/code_metadata.go
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2020 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 testing
-
-import (
- "path/filepath"
-
- "android/soong/android"
- "android/soong/testing/code_metadata_internal_proto"
- "github.com/google/blueprint"
-
- "google.golang.org/protobuf/proto"
-)
-
-func CodeMetadataFactory() android.Module {
- module := &CodeMetadataModule{}
-
- android.InitAndroidModule(module)
- android.InitDefaultableModule(module)
- module.AddProperties(&module.properties)
-
- return module
-}
-
-type CodeMetadataModule struct {
- android.ModuleBase
- android.DefaultableModuleBase
-
- // Properties for "code_metadata"
- properties struct {
- // Specifies the name of the code_config.
- Name string
- // Specifies the team ID.
- TeamId string
- // Specifies the list of modules that this code_metadata covers.
- Code []string
- // An optional field to specify if multiple ownerships for source files is allowed.
- MultiOwnership bool
- }
-}
-
-type codeDepTagType struct {
- blueprint.BaseDependencyTag
-}
-
-var codeDepTag = codeDepTagType{}
-
-func (module *CodeMetadataModule) DepsMutator(ctx android.BottomUpMutatorContext) {
- // Validate Properties
- if len(module.properties.TeamId) == 0 {
- ctx.PropertyErrorf(
- "TeamId",
- "Team Id not found in the code_metadata module. Hint: Maybe the teamId property hasn't been properly specified.",
- )
- }
- if !isInt(module.properties.TeamId) {
- ctx.PropertyErrorf(
- "TeamId", "Invalid value for Team ID. The Team ID must be an integer.",
- )
- }
- if len(module.properties.Code) == 0 {
- ctx.PropertyErrorf(
- "Code",
- "Targets to be attributed cannot be empty. Hint: Maybe the code property hasn't been properly specified.",
- )
- }
- ctx.AddDependency(ctx.Module(), codeDepTag, module.properties.Code...)
-}
-
-// Provider published by CodeMetadata
-type CodeMetadataProviderData struct {
- IntermediatePath android.WritablePath
-}
-
-var CodeMetadataProviderKey = blueprint.NewProvider[CodeMetadataProviderData]()
-
-func (module *CodeMetadataModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- metadataList := make(
- []*code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership, 0,
- len(module.properties.Code),
- )
- bpFilePath := filepath.Join(ctx.ModuleDir(), ctx.BlueprintsFile())
-
- for _, m := range ctx.GetDirectDepsWithTag(codeDepTag) {
- targetName := m.Name()
- var moduleSrcs []string
- if srcsFileInfo, ok := android.OtherModuleProvider(ctx, m, blueprint.SrcsFileProviderKey); ok {
- moduleSrcs = srcsFileInfo.SrcPaths
- }
- if module.properties.MultiOwnership {
- metadata := &code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership{
- TargetName: &targetName,
- TrendyTeamId: &module.properties.TeamId,
- Path: &bpFilePath,
- MultiOwnership: &module.properties.MultiOwnership,
- SourceFiles: moduleSrcs,
- }
- metadataList = append(metadataList, metadata)
- } else {
- metadata := &code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership{
- TargetName: &targetName,
- TrendyTeamId: &module.properties.TeamId,
- Path: &bpFilePath,
- SourceFiles: moduleSrcs,
- }
- metadataList = append(metadataList, metadata)
- }
-
- }
- codeMetadata := &code_metadata_internal_proto.CodeMetadataInternal{TargetOwnershipList: metadataList}
- protoData, err := proto.Marshal(codeMetadata)
- if err != nil {
- ctx.ModuleErrorf("Error marshaling code metadata: %s", err.Error())
- return
- }
- intermediatePath := android.PathForModuleOut(
- ctx, "intermediateCodeMetadata.pb",
- )
- android.WriteFileRuleVerbatim(ctx, intermediatePath, string(protoData))
-
- android.SetProvider(ctx,
- CodeMetadataProviderKey,
- CodeMetadataProviderData{IntermediatePath: intermediatePath},
- )
-}
diff --git a/testing/code_metadata_internal_proto/OWNERS b/testing/code_metadata_internal_proto/OWNERS
deleted file mode 100644
index 03bcdf1..0000000
--- a/testing/code_metadata_internal_proto/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-dariofreni@google.com
-joeo@google.com
-ronish@google.com
-caditya@google.com
diff --git a/testing/code_metadata_internal_proto/code_metadata_internal.pb.go b/testing/code_metadata_internal_proto/code_metadata_internal.pb.go
deleted file mode 100644
index ecb8b86..0000000
--- a/testing/code_metadata_internal_proto/code_metadata_internal.pb.go
+++ /dev/null
@@ -1,277 +0,0 @@
-// 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.
-
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.30.0
-// protoc v3.21.12
-// source: code_metadata_internal.proto
-
-package code_metadata_internal_proto
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type CodeMetadataInternal struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // List of all code targets and their metadata.
- TargetOwnershipList []*CodeMetadataInternal_TargetOwnership `protobuf:"bytes,1,rep,name=target_ownership_list,json=targetOwnershipList" json:"target_ownership_list,omitempty"`
-}
-
-func (x *CodeMetadataInternal) Reset() {
- *x = CodeMetadataInternal{}
- if protoimpl.UnsafeEnabled {
- mi := &file_code_metadata_internal_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *CodeMetadataInternal) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*CodeMetadataInternal) ProtoMessage() {}
-
-func (x *CodeMetadataInternal) ProtoReflect() protoreflect.Message {
- mi := &file_code_metadata_internal_proto_msgTypes[0]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use CodeMetadataInternal.ProtoReflect.Descriptor instead.
-func (*CodeMetadataInternal) Descriptor() ([]byte, []int) {
- return file_code_metadata_internal_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *CodeMetadataInternal) GetTargetOwnershipList() []*CodeMetadataInternal_TargetOwnership {
- if x != nil {
- return x.TargetOwnershipList
- }
- return nil
-}
-
-type CodeMetadataInternal_TargetOwnership struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // REQUIRED: Name of the build target
- TargetName *string `protobuf:"bytes,1,opt,name=target_name,json=targetName" json:"target_name,omitempty"`
- // REQUIRED: Code location of the target.
- // To be used to support legacy/backup systems that use OWNERS file and is
- // also required for our dashboard to support per code location basis UI
- Path *string `protobuf:"bytes,2,opt,name=path" json:"path,omitempty"`
- // REQUIRED: Team ID of the team that owns this target.
- TrendyTeamId *string `protobuf:"bytes,3,opt,name=trendy_team_id,json=trendyTeamId" json:"trendy_team_id,omitempty"`
- // OPTIONAL: The src files of the target.
- // To be used to determine ownership of a file for ownership
- SourceFiles []string `protobuf:"bytes,4,rep,name=source_files,json=sourceFiles" json:"source_files,omitempty"`
- // OPTIONAL: Specify if multiple ownerships of the source files are allowed.
- MultiOwnership *bool `protobuf:"varint,5,opt,name=multi_ownership,json=multiOwnership" json:"multi_ownership,omitempty"`
-}
-
-func (x *CodeMetadataInternal_TargetOwnership) Reset() {
- *x = CodeMetadataInternal_TargetOwnership{}
- if protoimpl.UnsafeEnabled {
- mi := &file_code_metadata_internal_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *CodeMetadataInternal_TargetOwnership) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*CodeMetadataInternal_TargetOwnership) ProtoMessage() {}
-
-func (x *CodeMetadataInternal_TargetOwnership) ProtoReflect() protoreflect.Message {
- mi := &file_code_metadata_internal_proto_msgTypes[1]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use CodeMetadataInternal_TargetOwnership.ProtoReflect.Descriptor instead.
-func (*CodeMetadataInternal_TargetOwnership) Descriptor() ([]byte, []int) {
- return file_code_metadata_internal_proto_rawDescGZIP(), []int{0, 0}
-}
-
-func (x *CodeMetadataInternal_TargetOwnership) GetTargetName() string {
- if x != nil && x.TargetName != nil {
- return *x.TargetName
- }
- return ""
-}
-
-func (x *CodeMetadataInternal_TargetOwnership) GetPath() string {
- if x != nil && x.Path != nil {
- return *x.Path
- }
- return ""
-}
-
-func (x *CodeMetadataInternal_TargetOwnership) GetTrendyTeamId() string {
- if x != nil && x.TrendyTeamId != nil {
- return *x.TrendyTeamId
- }
- return ""
-}
-
-func (x *CodeMetadataInternal_TargetOwnership) GetSourceFiles() []string {
- if x != nil {
- return x.SourceFiles
- }
- return nil
-}
-
-func (x *CodeMetadataInternal_TargetOwnership) GetMultiOwnership() bool {
- if x != nil && x.MultiOwnership != nil {
- return *x.MultiOwnership
- }
- return false
-}
-
-var File_code_metadata_internal_proto protoreflect.FileDescriptor
-
-var file_code_metadata_internal_proto_rawDesc = []byte{
- 0x0a, 0x1c, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f,
- 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c,
- 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x69, 0x6e,
- 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc9, 0x02, 0x0a,
- 0x14, 0x43, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x49, 0x6e, 0x74,
- 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x12, 0x76, 0x0a, 0x15, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f,
- 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01,
- 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61,
- 0x64, 0x61, 0x74, 0x61, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
- 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f,
- 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
- 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0xb8, 0x01,
- 0x0a, 0x0f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69,
- 0x70, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
- 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4e, 0x61,
- 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79,
- 0x5f, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
- 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79, 0x54, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c,
- 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03,
- 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12,
- 0x27, 0x0a, 0x0f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68,
- 0x69, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x4f,
- 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x42, 0x34, 0x5a, 0x32, 0x61, 0x6e, 0x64, 0x72,
- 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e,
- 0x67, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f,
- 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-}
-
-var (
- file_code_metadata_internal_proto_rawDescOnce sync.Once
- file_code_metadata_internal_proto_rawDescData = file_code_metadata_internal_proto_rawDesc
-)
-
-func file_code_metadata_internal_proto_rawDescGZIP() []byte {
- file_code_metadata_internal_proto_rawDescOnce.Do(func() {
- file_code_metadata_internal_proto_rawDescData = protoimpl.X.CompressGZIP(file_code_metadata_internal_proto_rawDescData)
- })
- return file_code_metadata_internal_proto_rawDescData
-}
-
-var file_code_metadata_internal_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
-var file_code_metadata_internal_proto_goTypes = []interface{}{
- (*CodeMetadataInternal)(nil), // 0: code_metadata_internal_proto.CodeMetadataInternal
- (*CodeMetadataInternal_TargetOwnership)(nil), // 1: code_metadata_internal_proto.CodeMetadataInternal.TargetOwnership
-}
-var file_code_metadata_internal_proto_depIdxs = []int32{
- 1, // 0: code_metadata_internal_proto.CodeMetadataInternal.target_ownership_list:type_name -> code_metadata_internal_proto.CodeMetadataInternal.TargetOwnership
- 1, // [1:1] is the sub-list for method output_type
- 1, // [1:1] is the sub-list for method input_type
- 1, // [1:1] is the sub-list for extension type_name
- 1, // [1:1] is the sub-list for extension extendee
- 0, // [0:1] is the sub-list for field type_name
-}
-
-func init() { file_code_metadata_internal_proto_init() }
-func file_code_metadata_internal_proto_init() {
- if File_code_metadata_internal_proto != nil {
- return
- }
- if !protoimpl.UnsafeEnabled {
- file_code_metadata_internal_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*CodeMetadataInternal); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_code_metadata_internal_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*CodeMetadataInternal_TargetOwnership); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: file_code_metadata_internal_proto_rawDesc,
- NumEnums: 0,
- NumMessages: 2,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_code_metadata_internal_proto_goTypes,
- DependencyIndexes: file_code_metadata_internal_proto_depIdxs,
- MessageInfos: file_code_metadata_internal_proto_msgTypes,
- }.Build()
- File_code_metadata_internal_proto = out.File
- file_code_metadata_internal_proto_rawDesc = nil
- file_code_metadata_internal_proto_goTypes = nil
- file_code_metadata_internal_proto_depIdxs = nil
-}
diff --git a/testing/code_metadata_internal_proto/code_metadata_internal.proto b/testing/code_metadata_internal_proto/code_metadata_internal.proto
deleted file mode 100644
index 14edc0f..0000000
--- a/testing/code_metadata_internal_proto/code_metadata_internal.proto
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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.
-
-syntax = "proto2";
-package code_metadata_internal_proto;
-option go_package = "android/soong/testing/code_metadata_internal_proto";
-
-message CodeMetadataInternal {
-
- message TargetOwnership {
- // REQUIRED: Name of the build target
- optional string target_name = 1;
-
- // REQUIRED: Code location of the target.
- // To be used to support legacy/backup systems that use OWNERS file and is
- // also required for our dashboard to support per code location basis UI
- optional string path = 2;
-
- // REQUIRED: Team ID of the team that owns this target.
- optional string trendy_team_id = 3;
-
- // OPTIONAL: The src files of the target.
- // To be used to determine ownership of a file for ownership
- repeated string source_files = 4;
-
- // OPTIONAL: Specify if multiple ownerships of the source files are allowed.
- optional bool multi_ownership = 5;
- }
-
- // List of all code targets and their metadata.
- repeated TargetOwnership target_ownership_list = 1;
-}
diff --git a/testing/code_metadata_internal_proto/regen.sh b/testing/code_metadata_internal_proto/regen.sh
deleted file mode 100644
index f101a02..0000000
--- a/testing/code_metadata_internal_proto/regen.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-aprotoc --go_out=paths=source_relative:. code_metadata_internal.proto
diff --git a/testing/code_metadata_proto/OWNERS b/testing/code_metadata_proto/OWNERS
deleted file mode 100644
index 03bcdf1..0000000
--- a/testing/code_metadata_proto/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-dariofreni@google.com
-joeo@google.com
-ronish@google.com
-caditya@google.com
diff --git a/testing/code_metadata_proto/code_metadata.pb.go b/testing/code_metadata_proto/code_metadata.pb.go
deleted file mode 100644
index 711bf7a..0000000
--- a/testing/code_metadata_proto/code_metadata.pb.go
+++ /dev/null
@@ -1,263 +0,0 @@
-// 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.
-
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.30.0
-// protoc v3.21.12
-// source: code_metadata.proto
-
-package code_metadata_proto
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type CodeMetadata struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // List of all code targets and their metadata.
- TargetOwnershipList []*CodeMetadata_TargetOwnership `protobuf:"bytes,1,rep,name=target_ownership_list,json=targetOwnershipList" json:"target_ownership_list,omitempty"`
-}
-
-func (x *CodeMetadata) Reset() {
- *x = CodeMetadata{}
- if protoimpl.UnsafeEnabled {
- mi := &file_code_metadata_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *CodeMetadata) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*CodeMetadata) ProtoMessage() {}
-
-func (x *CodeMetadata) ProtoReflect() protoreflect.Message {
- mi := &file_code_metadata_proto_msgTypes[0]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use CodeMetadata.ProtoReflect.Descriptor instead.
-func (*CodeMetadata) Descriptor() ([]byte, []int) {
- return file_code_metadata_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *CodeMetadata) GetTargetOwnershipList() []*CodeMetadata_TargetOwnership {
- if x != nil {
- return x.TargetOwnershipList
- }
- return nil
-}
-
-type CodeMetadata_TargetOwnership struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // REQUIRED: Name of the build target
- TargetName *string `protobuf:"bytes,1,opt,name=target_name,json=targetName" json:"target_name,omitempty"`
- // REQUIRED: Code location of the target.
- // To be used to support legacy/backup systems that use OWNERS file and is
- // also required for our dashboard to support per code location basis UI
- Path *string `protobuf:"bytes,2,opt,name=path" json:"path,omitempty"`
- // REQUIRED: Team ID of the team that owns this target.
- TrendyTeamId *string `protobuf:"bytes,3,opt,name=trendy_team_id,json=trendyTeamId" json:"trendy_team_id,omitempty"`
- // OPTIONAL: The src files of the target.
- // To be used to determine ownership of a file for ownership
- SourceFiles []string `protobuf:"bytes,4,rep,name=source_files,json=sourceFiles" json:"source_files,omitempty"`
-}
-
-func (x *CodeMetadata_TargetOwnership) Reset() {
- *x = CodeMetadata_TargetOwnership{}
- if protoimpl.UnsafeEnabled {
- mi := &file_code_metadata_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *CodeMetadata_TargetOwnership) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*CodeMetadata_TargetOwnership) ProtoMessage() {}
-
-func (x *CodeMetadata_TargetOwnership) ProtoReflect() protoreflect.Message {
- mi := &file_code_metadata_proto_msgTypes[1]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use CodeMetadata_TargetOwnership.ProtoReflect.Descriptor instead.
-func (*CodeMetadata_TargetOwnership) Descriptor() ([]byte, []int) {
- return file_code_metadata_proto_rawDescGZIP(), []int{0, 0}
-}
-
-func (x *CodeMetadata_TargetOwnership) GetTargetName() string {
- if x != nil && x.TargetName != nil {
- return *x.TargetName
- }
- return ""
-}
-
-func (x *CodeMetadata_TargetOwnership) GetPath() string {
- if x != nil && x.Path != nil {
- return *x.Path
- }
- return ""
-}
-
-func (x *CodeMetadata_TargetOwnership) GetTrendyTeamId() string {
- if x != nil && x.TrendyTeamId != nil {
- return *x.TrendyTeamId
- }
- return ""
-}
-
-func (x *CodeMetadata_TargetOwnership) GetSourceFiles() []string {
- if x != nil {
- return x.SourceFiles
- }
- return nil
-}
-
-var File_code_metadata_proto protoreflect.FileDescriptor
-
-var file_code_metadata_proto_rawDesc = []byte{
- 0x0a, 0x13, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61,
- 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x87, 0x02, 0x0a, 0x0c, 0x43,
- 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x65, 0x0a, 0x15, 0x74,
- 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x5f,
- 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x63, 0x6f, 0x64,
- 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
- 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61,
- 0x72, 0x67, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x13, 0x74,
- 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x4c, 0x69,
- 0x73, 0x74, 0x1a, 0x8f, 0x01, 0x0a, 0x0f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x77, 0x6e,
- 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
- 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x72,
- 0x67, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18,
- 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0e, 0x74,
- 0x72, 0x65, 0x6e, 0x64, 0x79, 0x5f, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79, 0x54, 0x65, 0x61, 0x6d, 0x49,
- 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65,
- 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46,
- 0x69, 0x6c, 0x65, 0x73, 0x42, 0x2b, 0x5a, 0x29, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f,
- 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x63, 0x6f,
- 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74,
- 0x6f,
-}
-
-var (
- file_code_metadata_proto_rawDescOnce sync.Once
- file_code_metadata_proto_rawDescData = file_code_metadata_proto_rawDesc
-)
-
-func file_code_metadata_proto_rawDescGZIP() []byte {
- file_code_metadata_proto_rawDescOnce.Do(func() {
- file_code_metadata_proto_rawDescData = protoimpl.X.CompressGZIP(file_code_metadata_proto_rawDescData)
- })
- return file_code_metadata_proto_rawDescData
-}
-
-var file_code_metadata_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
-var file_code_metadata_proto_goTypes = []interface{}{
- (*CodeMetadata)(nil), // 0: code_metadata_proto.CodeMetadata
- (*CodeMetadata_TargetOwnership)(nil), // 1: code_metadata_proto.CodeMetadata.TargetOwnership
-}
-var file_code_metadata_proto_depIdxs = []int32{
- 1, // 0: code_metadata_proto.CodeMetadata.target_ownership_list:type_name -> code_metadata_proto.CodeMetadata.TargetOwnership
- 1, // [1:1] is the sub-list for method output_type
- 1, // [1:1] is the sub-list for method input_type
- 1, // [1:1] is the sub-list for extension type_name
- 1, // [1:1] is the sub-list for extension extendee
- 0, // [0:1] is the sub-list for field type_name
-}
-
-func init() { file_code_metadata_proto_init() }
-func file_code_metadata_proto_init() {
- if File_code_metadata_proto != nil {
- return
- }
- if !protoimpl.UnsafeEnabled {
- file_code_metadata_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*CodeMetadata); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_code_metadata_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*CodeMetadata_TargetOwnership); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: file_code_metadata_proto_rawDesc,
- NumEnums: 0,
- NumMessages: 2,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_code_metadata_proto_goTypes,
- DependencyIndexes: file_code_metadata_proto_depIdxs,
- MessageInfos: file_code_metadata_proto_msgTypes,
- }.Build()
- File_code_metadata_proto = out.File
- file_code_metadata_proto_rawDesc = nil
- file_code_metadata_proto_goTypes = nil
- file_code_metadata_proto_depIdxs = nil
-}
diff --git a/testing/code_metadata_proto/code_metadata.proto b/testing/code_metadata_proto/code_metadata.proto
deleted file mode 100644
index 2548363..0000000
--- a/testing/code_metadata_proto/code_metadata.proto
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-
-syntax = "proto2";
-package code_metadata_proto;
-option go_package = "android/soong/testing/code_metadata_proto";
-
-message CodeMetadata {
-
- message TargetOwnership {
- // REQUIRED: Name of the build target
- optional string target_name = 1;
-
- // REQUIRED: Code location of the target.
- // To be used to support legacy/backup systems that use OWNERS file and is
- // also required for our dashboard to support per code location basis UI
- optional string path = 2;
-
- // REQUIRED: Team ID of the team that owns this target.
- optional string trendy_team_id = 3;
-
- // OPTIONAL: The src files of the target.
- // To be used to determine ownership of a file for ownership
- repeated string source_files = 4;
- }
-
- // List of all code targets and their metadata.
- repeated TargetOwnership target_ownership_list = 1;
-}
diff --git a/testing/code_metadata_proto/regen.sh b/testing/code_metadata_proto/regen.sh
deleted file mode 100644
index ffe06f7..0000000
--- a/testing/code_metadata_proto/regen.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-aprotoc --go_out=paths=source_relative:. code_metadata.proto
diff --git a/testing/init.go b/testing/init.go
deleted file mode 100644
index edcbf59..0000000
--- a/testing/init.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package testing
-
-import (
- "android/soong/android"
-)
-
-var (
- pctx = android.NewPackageContext("android/soong/testing")
-)
-
-func init() {
- RegisterBuildComponents(android.InitRegistrationContext)
- pctx.HostBinToolVariable("metadata", "metadata")
-}
-
-func RegisterBuildComponents(ctx android.RegistrationContext) {
- ctx.RegisterModuleType("code_metadata", CodeMetadataFactory)
- ctx.RegisterModuleType("test_spec", TestSpecFactory)
- ctx.RegisterParallelSingletonType("all_code_metadata", AllCodeMetadataFactory)
- ctx.RegisterParallelSingletonType("all_test_specs", AllTestSpecsFactory)
-}
diff --git a/testing/test.go b/testing/test.go
deleted file mode 100644
index cd97a8f..0000000
--- a/testing/test.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package testing
-
-import (
- "android/soong/android"
-)
-
-var PrepareForTestWithTestingBuildComponents = android.FixtureRegisterWithContext(RegisterBuildComponents)
diff --git a/testing/test_spec.go b/testing/test_spec.go
deleted file mode 100644
index 4d885c6..0000000
--- a/testing/test_spec.go
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2020 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 testing
-
-import (
- "path/filepath"
- "strconv"
-
- "android/soong/android"
- "android/soong/testing/test_spec_proto"
- "google.golang.org/protobuf/proto"
-
- "github.com/google/blueprint"
-)
-
-// ErrTestModuleDataNotFound is the error message for missing test module provider data.
-const ErrTestModuleDataNotFound = "The module '%s' does not provide test specification data. Hint: This issue could arise if either the module is not a valid testing module or if it lacks the required 'TestModuleProviderKey' provider.\n"
-
-func TestSpecFactory() android.Module {
- module := &TestSpecModule{}
-
- android.InitAndroidModule(module)
- android.InitDefaultableModule(module)
- module.AddProperties(&module.properties)
-
- return module
-}
-
-type TestSpecModule struct {
- android.ModuleBase
- android.DefaultableModuleBase
-
- // Properties for "test_spec"
- properties struct {
- // Specifies the name of the test config.
- Name string
- // Specifies the team ID.
- TeamId string
- // Specifies the list of tests covered under this module.
- Tests []string
- }
-}
-
-type testsDepTagType struct {
- blueprint.BaseDependencyTag
-}
-
-var testsDepTag = testsDepTagType{}
-
-func (module *TestSpecModule) DepsMutator(ctx android.BottomUpMutatorContext) {
- // Validate Properties
- if len(module.properties.TeamId) == 0 {
- ctx.PropertyErrorf("TeamId", "Team Id not found in the test_spec module. Hint: Maybe the TeamId property hasn't been properly specified.")
- }
- if !isInt(module.properties.TeamId) {
- ctx.PropertyErrorf("TeamId", "Invalid value for Team ID. The Team ID must be an integer.")
- }
- if len(module.properties.Tests) == 0 {
- ctx.PropertyErrorf("Tests", "Expected to attribute some test but none found. Hint: Maybe the test property hasn't been properly specified.")
- }
- ctx.AddDependency(ctx.Module(), testsDepTag, module.properties.Tests...)
-}
-func isInt(s string) bool {
- _, err := strconv.Atoi(s)
- return err == nil
-}
-
-// Provider published by TestSpec
-type TestSpecProviderData struct {
- IntermediatePath android.WritablePath
-}
-
-var TestSpecProviderKey = blueprint.NewProvider[TestSpecProviderData]()
-
-type TestModuleProviderData struct {
-}
-
-var TestModuleProviderKey = blueprint.NewProvider[TestModuleProviderData]()
-
-func (module *TestSpecModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- for _, m := range ctx.GetDirectDepsWithTag(testsDepTag) {
- if _, ok := android.OtherModuleProvider(ctx, m, TestModuleProviderKey); !ok {
- ctx.ModuleErrorf(ErrTestModuleDataNotFound, m.Name())
- }
- }
- bpFilePath := filepath.Join(ctx.ModuleDir(), ctx.BlueprintsFile())
- metadataList := make(
- []*test_spec_proto.TestSpec_OwnershipMetadata, 0,
- len(module.properties.Tests),
- )
- for _, test := range module.properties.Tests {
- targetName := test
- metadata := test_spec_proto.TestSpec_OwnershipMetadata{
- TrendyTeamId: &module.properties.TeamId,
- TargetName: &targetName,
- Path: &bpFilePath,
- }
- metadataList = append(metadataList, &metadata)
- }
- intermediatePath := android.PathForModuleOut(
- ctx, "intermediateTestSpecMetadata.pb",
- )
- testSpecMetadata := test_spec_proto.TestSpec{OwnershipMetadataList: metadataList}
- protoData, err := proto.Marshal(&testSpecMetadata)
- if err != nil {
- ctx.ModuleErrorf("Error: %s", err.Error())
- }
- android.WriteFileRuleVerbatim(ctx, intermediatePath, string(protoData))
-
- android.SetProvider(ctx,
- TestSpecProviderKey, TestSpecProviderData{
- IntermediatePath: intermediatePath,
- },
- )
-}
diff --git a/testing/test_spec_proto/Android.bp b/testing/test_spec_proto/Android.bp
deleted file mode 100644
index d5ad70b..0000000
--- a/testing/test_spec_proto/Android.bp
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-bootstrap_go_package {
- name: "soong-testing-test_spec_proto",
- pkgPath: "android/soong/testing/test_spec_proto",
- deps: [
- "golang-protobuf-reflect-protoreflect",
- "golang-protobuf-runtime-protoimpl",
- ],
- srcs: [
- "test_spec.pb.go",
- ],
-}
-
-python_library_host {
- name: "test-spec-proto-py",
- pkg_path: "test_spec",
- srcs: [
- "test_spec.proto",
- ],
- libs: [
- "libprotobuf-python",
- ],
- proto: {
- canonical_path_from_root: false,
- },
-}
diff --git a/testing/test_spec_proto/OWNERS b/testing/test_spec_proto/OWNERS
deleted file mode 100644
index 03bcdf1..0000000
--- a/testing/test_spec_proto/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-dariofreni@google.com
-joeo@google.com
-ronish@google.com
-caditya@google.com
diff --git a/testing/test_spec_proto/regen.sh b/testing/test_spec_proto/regen.sh
deleted file mode 100644
index 2cf8203..0000000
--- a/testing/test_spec_proto/regen.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-aprotoc --go_out=paths=source_relative:. test_spec.proto
diff --git a/testing/test_spec_proto/test_spec.pb.go b/testing/test_spec_proto/test_spec.pb.go
deleted file mode 100644
index 5cce600..0000000
--- a/testing/test_spec_proto/test_spec.pb.go
+++ /dev/null
@@ -1,244 +0,0 @@
-// 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.
-
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.30.0
-// protoc v3.21.12
-// source: test_spec.proto
-
-package test_spec_proto
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type TestSpec struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // List of all test targets and their metadata.
- OwnershipMetadataList []*TestSpec_OwnershipMetadata `protobuf:"bytes,1,rep,name=ownership_metadata_list,json=ownershipMetadataList" json:"ownership_metadata_list,omitempty"`
-}
-
-func (x *TestSpec) Reset() {
- *x = TestSpec{}
- if protoimpl.UnsafeEnabled {
- mi := &file_test_spec_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *TestSpec) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*TestSpec) ProtoMessage() {}
-
-func (x *TestSpec) ProtoReflect() protoreflect.Message {
- mi := &file_test_spec_proto_msgTypes[0]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use TestSpec.ProtoReflect.Descriptor instead.
-func (*TestSpec) Descriptor() ([]byte, []int) {
- return file_test_spec_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *TestSpec) GetOwnershipMetadataList() []*TestSpec_OwnershipMetadata {
- if x != nil {
- return x.OwnershipMetadataList
- }
- return nil
-}
-
-type TestSpec_OwnershipMetadata struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- TargetName *string `protobuf:"bytes,1,opt,name=target_name,json=targetName" json:"target_name,omitempty"`
- Path *string `protobuf:"bytes,2,opt,name=path" json:"path,omitempty"`
- TrendyTeamId *string `protobuf:"bytes,3,opt,name=trendy_team_id,json=trendyTeamId" json:"trendy_team_id,omitempty"`
-}
-
-func (x *TestSpec_OwnershipMetadata) Reset() {
- *x = TestSpec_OwnershipMetadata{}
- if protoimpl.UnsafeEnabled {
- mi := &file_test_spec_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *TestSpec_OwnershipMetadata) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*TestSpec_OwnershipMetadata) ProtoMessage() {}
-
-func (x *TestSpec_OwnershipMetadata) ProtoReflect() protoreflect.Message {
- mi := &file_test_spec_proto_msgTypes[1]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use TestSpec_OwnershipMetadata.ProtoReflect.Descriptor instead.
-func (*TestSpec_OwnershipMetadata) Descriptor() ([]byte, []int) {
- return file_test_spec_proto_rawDescGZIP(), []int{0, 0}
-}
-
-func (x *TestSpec_OwnershipMetadata) GetTargetName() string {
- if x != nil && x.TargetName != nil {
- return *x.TargetName
- }
- return ""
-}
-
-func (x *TestSpec_OwnershipMetadata) GetPath() string {
- if x != nil && x.Path != nil {
- return *x.Path
- }
- return ""
-}
-
-func (x *TestSpec_OwnershipMetadata) GetTrendyTeamId() string {
- if x != nil && x.TrendyTeamId != nil {
- return *x.TrendyTeamId
- }
- return ""
-}
-
-var File_test_spec_proto protoreflect.FileDescriptor
-
-var file_test_spec_proto_rawDesc = []byte{
- 0x0a, 0x0f, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x12, 0x0f, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x22, 0xdf, 0x01, 0x0a, 0x08, 0x54, 0x65, 0x73, 0x74, 0x53, 0x70, 0x65, 0x63, 0x12,
- 0x63, 0x0a, 0x17, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x5f, 0x6d, 0x65, 0x74,
- 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
- 0x32, 0x2b, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x53, 0x70, 0x65, 0x63, 0x2e, 0x4f, 0x77, 0x6e, 0x65,
- 0x72, 0x73, 0x68, 0x69, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x15, 0x6f,
- 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
- 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x6e, 0x0a, 0x11, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69,
- 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72,
- 0x67, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
- 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61,
- 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24,
- 0x0a, 0x0e, 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79, 0x5f, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64,
- 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79, 0x54, 0x65,
- 0x61, 0x6d, 0x49, 0x64, 0x42, 0x27, 0x5a, 0x25, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f,
- 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x74, 0x65,
- 0x73, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-}
-
-var (
- file_test_spec_proto_rawDescOnce sync.Once
- file_test_spec_proto_rawDescData = file_test_spec_proto_rawDesc
-)
-
-func file_test_spec_proto_rawDescGZIP() []byte {
- file_test_spec_proto_rawDescOnce.Do(func() {
- file_test_spec_proto_rawDescData = protoimpl.X.CompressGZIP(file_test_spec_proto_rawDescData)
- })
- return file_test_spec_proto_rawDescData
-}
-
-var file_test_spec_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
-var file_test_spec_proto_goTypes = []interface{}{
- (*TestSpec)(nil), // 0: test_spec_proto.TestSpec
- (*TestSpec_OwnershipMetadata)(nil), // 1: test_spec_proto.TestSpec.OwnershipMetadata
-}
-var file_test_spec_proto_depIdxs = []int32{
- 1, // 0: test_spec_proto.TestSpec.ownership_metadata_list:type_name -> test_spec_proto.TestSpec.OwnershipMetadata
- 1, // [1:1] is the sub-list for method output_type
- 1, // [1:1] is the sub-list for method input_type
- 1, // [1:1] is the sub-list for extension type_name
- 1, // [1:1] is the sub-list for extension extendee
- 0, // [0:1] is the sub-list for field type_name
-}
-
-func init() { file_test_spec_proto_init() }
-func file_test_spec_proto_init() {
- if File_test_spec_proto != nil {
- return
- }
- if !protoimpl.UnsafeEnabled {
- file_test_spec_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*TestSpec); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_test_spec_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*TestSpec_OwnershipMetadata); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: file_test_spec_proto_rawDesc,
- NumEnums: 0,
- NumMessages: 2,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_test_spec_proto_goTypes,
- DependencyIndexes: file_test_spec_proto_depIdxs,
- MessageInfos: file_test_spec_proto_msgTypes,
- }.Build()
- File_test_spec_proto = out.File
- file_test_spec_proto_rawDesc = nil
- file_test_spec_proto_goTypes = nil
- file_test_spec_proto_depIdxs = nil
-}
diff --git a/testing/test_spec_proto/test_spec.proto b/testing/test_spec_proto/test_spec.proto
deleted file mode 100644
index 86bc789..0000000
--- a/testing/test_spec_proto/test_spec.proto
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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.
-
-syntax = "proto2";
-package test_spec_proto;
-option go_package = "android/soong/testing/test_spec_proto";
-
-message TestSpec {
-
- message OwnershipMetadata {
- // REQUIRED: Name of the build target
- optional string target_name = 1;
-
- // REQUIRED: Code location of the target.
- // To be used to support legacy/backup systems that use OWNERS file and is
- // also required for our dashboard to support per code location basis UI
- optional string path = 2;
-
- // REQUIRED: Team ID of the team that owns this target.
- optional string trendy_team_id = 3;
- }
-
- // List of all test targets and their metadata.
- repeated OwnershipMetadata ownership_metadata_list = 1;
-}
diff --git a/tests/b_args_test.sh b/tests/b_args_test.sh
deleted file mode 100755
index 0dfbabf..0000000
--- a/tests/b_args_test.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/bin/bash -eu
-
-# This file tests the creation of bazel commands for b usage
-set -o pipefail
-source "$(dirname "$0")/../../bazel/lib.sh"
-
-BES_UUID="blank"
-OUT_DIR="arbitrary_out"
-b_args=$(formulate_b_args "build --config=nonsense foo:bar")
-
-if [[ $b_args != "build --profile=$OUT_DIR/bazel_metrics-profile --config=bp2build --invocation_id=$BES_UUID --config=metrics_data --config=nonsense foo:bar" ]]; then
- echo "b args are malformed"
- echo "Expected : build --profile=$OUT_DIR/bazel_metrics-profile --config=bp2build --invocation_id=$BES_UUID --config=metrics_data --config=nonsense foo:bar"
- echo "Actual: $b_args"
- exit 1
-fi
-
-b_args=$(formulate_b_args "build --config=nonsense --disable_bes --package_path \"my package\" foo:bar")
-
-if [[ $b_args != "build --profile=$OUT_DIR/bazel_metrics-profile --config=bp2build --invocation_id=$BES_UUID --config=nonsense --package_path \"my package\" foo:bar" ]]; then
- echo "b args are malformed"
- echo "Expected : build --profile=$OUT_DIR/bazel_metrics-profile --config=bp2build --invocation_id=$BES_UUID --config=nonsense --package_path \"my package\" foo:bar"
- echo "Actual: $b_args"
- exit 1
-fi
-
-# Test with startup option
-b_args=$(formulate_b_args "--batch build --config=nonsense --disable_bes --package_path \"my package\" foo:bar")
-if [[ $b_args != "--batch build --profile=$OUT_DIR/bazel_metrics-profile --config=bp2build --invocation_id=$BES_UUID --config=nonsense --package_path \"my package\" foo:bar" ]]; then
- echo "b args are malformed"
- echo "Expected : --batch build --profile=$OUT_DIR/bazel_metrics-profile --config=bp2build --invocation_id=$BES_UUID --config=nonsense --package_path \"my package\" foo:bar"
- echo "Actual: $b_args"
- exit 1
-fi
-
-OUT_DIR="mock_out"
-TEST_PROFILE_OUT=$(get_profile_out_dir)
-if [[ $TEST_PROFILE_OUT != "mock_out" ]]; then
- echo "Profile Out is malformed."
- echo "Expected: mock_out"
- echo "Actual: $TEST_PROFILE_OUT"
- exit 1
-fi
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index 2e40950..5a660e9 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -145,36 +145,19 @@
run_soong
local -r ninja_mtime1=$(stat -c "%y" out/soong/build."${target_product}".ninja)
- local glob_deps_file=out/soong/globs/"${target_product}"/0.d
-
run_soong
local -r ninja_mtime2=$(stat -c "%y" out/soong/build."${target_product}".ninja)
- # There is an ineffiencency in glob that requires bpglob to rerun once for each glob to update
- # the entry in the .ninja_log. It doesn't update the output file, but we can detect the rerun
- # by checking if the deps file was created.
- if [ ! -e "$glob_deps_file" ]; then
- fail "Glob deps file missing after second build"
- fi
-
- local -r glob_deps_mtime2=$(stat -c "%y" "$glob_deps_file")
-
if [[ "$ninja_mtime1" != "$ninja_mtime2" ]]; then
fail "Ninja file rewritten on null incremental build"
fi
run_soong
local -r ninja_mtime3=$(stat -c "%y" out/soong/build."${target_product}".ninja)
- local -r glob_deps_mtime3=$(stat -c "%y" "$glob_deps_file")
if [[ "$ninja_mtime2" != "$ninja_mtime3" ]]; then
fail "Ninja file rewritten on null incremental build"
fi
-
- # The bpglob commands should not rerun after the first incremental build.
- if [[ "$glob_deps_mtime2" != "$glob_deps_mtime3" ]]; then
- fail "Glob deps file rewritten on second null incremental build"
- fi
}
function test_add_file_to_glob() {
@@ -594,20 +577,6 @@
}
-function test_queryview_null_build() {
- setup
-
- run_soong queryview
- local -r output_mtime1=$(stat -c "%y" out/soong/queryview.marker)
-
- run_soong queryview
- local -r output_mtime2=$(stat -c "%y" out/soong/queryview.marker)
-
- if [[ "$output_mtime1" != "$output_mtime2" ]]; then
- fail "Queryview marker file changed on null build"
- fi
-}
-
# This test verifies that adding a new glob to a blueprint file only
# causes build."${target_product}".ninja to be regenerated on the *next* build, and *not*
# the build after. (This is a regression test for a bug where globs
diff --git a/tests/build_action_caching_test.sh b/tests/build_action_caching_test.sh
new file mode 100755
index 0000000..8ecd037
--- /dev/null
+++ b/tests/build_action_caching_test.sh
@@ -0,0 +1,190 @@
+#!/bin/bash -u
+
+set -o pipefail
+
+# Test that the mk and ninja files generated by Soong don't change if some
+# incremental modules are restored from cache.
+
+OUTPUT_DIR="$(mktemp -d tmp.XXXXXX)"
+
+echo ${OUTPUT_DIR}
+
+function cleanup {
+ rm -rf "${OUTPUT_DIR}"
+}
+trap cleanup EXIT
+
+function run_soong_build {
+ USE_RBE=false TARGET_PRODUCT=aosp_arm TARGET_RELEASE=trunk_staging TARGET_BUILD_VARIANT=userdebug build/soong/soong_ui.bash --make-mode "$@" nothing
+}
+
+function run_soong_clean {
+ build/soong/soong_ui.bash --make-mode clean
+}
+
+function assert_files_equal {
+ if [ $# -ne 2 ]; then
+ echo "Usage: assert_files_equal file1 file2"
+ exit 1
+ fi
+
+ if ! cmp -s "$1" "$2"; then
+ echo "Files are different: $1 $2"
+ exit 1
+ fi
+}
+
+function compare_mtimes() {
+ if [ $# -ne 2 ]; then
+ echo "Usage: compare_mtimes file1 file2"
+ exit 1
+ fi
+
+ file1_mtime=$(stat -c '%Y' $1)
+ file2_mtime=$(stat -c '%Y' $2)
+
+ if [ "$file1_mtime" -eq "$file2_mtime" ]; then
+ return 1
+ else
+ return 0
+ fi
+}
+
+function test_build_action_restoring() {
+ local test_dir="${OUTPUT_DIR}/test_build_action_restoring"
+ mkdir -p ${test_dir}
+ run_soong_clean
+ cat > ${test_dir}/Android.bp <<'EOF'
+python_binary_host {
+ name: "my_little_binary_host",
+ srcs: ["my_little_binary_host.py"],
+}
+EOF
+ touch ${test_dir}/my_little_binary_host.py
+ run_soong_build --incremental-build-actions
+ local dir_before="${test_dir}/before"
+ mkdir -p ${dir_before}
+ cp -pr out/soong/build_aosp_arm_ninja_incremental out/soong/*.mk out/soong/build.aosp_arm*.ninja ${test_dir}/before
+ # add a comment to the bp file, this should force a new analysis but no module
+ # should be really impacted, so all the incremental modules should be skipped.
+ cat >> ${test_dir}/Android.bp <<'EOF'
+// new comments
+EOF
+ run_soong_build --incremental-build-actions
+ local dir_after="${test_dir}/after"
+ mkdir -p ${dir_after}
+ cp -pr out/soong/build_aosp_arm_ninja_incremental out/soong/*.mk out/soong/build.aosp_arm*.ninja ${test_dir}/after
+
+ compare_incremental_files $dir_before $dir_after
+ rm -rf "$test_dir"
+ echo "test_build_action_restoring test passed"
+}
+
+function test_incremental_build_parity() {
+ local test_dir="${OUTPUT_DIR}/test_incremental_build_parity"
+ run_soong_clean
+ run_soong_build
+ local dir_before="${test_dir}/before"
+ mkdir -p ${dir_before}
+ cp -pr out/soong/*.mk out/soong/build.aosp_arm*.ninja ${test_dir}/before
+
+ # Now run clean build with incremental enabled
+ run_soong_clean
+ run_soong_build --incremental-build-actions
+ local dir_after="${test_dir}/after"
+ mkdir -p ${dir_after}
+ cp -pr out/soong/build_aosp_arm_ninja_incremental out/soong/*.mk out/soong/build.aosp_arm*.ninja ${test_dir}/after
+
+ compare_files_parity $dir_before $dir_after
+ rm -rf "$test_dir"
+ echo "test_incremental_build_parity test passed"
+}
+
+function compare_files_parity() {
+ local dir_before=$1; shift
+ local dir_after=$1; shift
+ count=0
+ for file_before in ${dir_before}/*.mk; do
+ file_after="${dir_after}/$(basename "$file_before")"
+ assert_files_equal $file_before $file_after
+ ((count++))
+ done
+ echo "Compared $count mk files"
+
+ combined_before_file="${dir_before}/combined_files.ninja"
+ count=0
+ for file in ${dir_before}/build.aosp_arm.*.ninja; do
+ cat $file >> $combined_before_file
+ ((count++))
+ done
+ echo "Combined $count ninja files from normal build"
+
+ combined_after_file="${dir_after}/combined_files.ninja"
+ count=0
+ for file in ${dir_after}/build.aosp_arm.*.ninja; do
+ cat $file >> $combined_after_file
+ ((count++))
+ done
+ echo "Combined $count ninja files from incremental build"
+
+ combined_incremental_ninjas="${dir_after}/combined_incremental_files.ninja"
+ count=0
+ for file in ${dir_after}/build_aosp_arm_ninja_incremental/*.ninja; do
+ cat $file >> $combined_incremental_ninjas
+ ((count++))
+ done
+ echo "Combined $count incremental ninja files"
+
+ cat $combined_incremental_ninjas >> $combined_after_file
+ sort $combined_after_file -o $combined_after_file
+ sort $combined_before_file -o $combined_before_file
+ assert_files_equal $combined_before_file $combined_after_file
+}
+
+function compare_incremental_files() {
+ local dir_before=$1; shift
+ local dir_after=$1; shift
+ count=0
+ for file_before in ${dir_before}/*.ninja; do
+ file_after="${dir_after}/$(basename "$file_before")"
+ assert_files_equal $file_before $file_after
+ compare_mtimes $file_before $file_after
+ if [ $? -ne 0 ]; then
+ echo "Files have identical mtime: $file_before $file_after"
+ exit 1
+ fi
+ ((count++))
+ done
+ echo "Compared $count ninja files"
+
+ count=0
+ for file_before in ${dir_before}/*.mk; do
+ file_after="${dir_after}/$(basename "$file_before")"
+ assert_files_equal $file_before $file_after
+ compare_mtimes $file_before $file_after
+ # mk files shouldn't be regenerated
+ if [ $? -ne 1 ]; then
+ echo "Files have different mtimes: $file_before $file_after"
+ exit 1
+ fi
+ ((count++))
+ done
+ echo "Compared $count mk files"
+
+ count=0
+ for file_before in ${dir_before}/build_aosp_arm_ninja_incremental/*.ninja; do
+ file_after="${dir_after}/build_aosp_arm_ninja_incremental/$(basename "$file_before")"
+ assert_files_equal $file_before $file_after
+ compare_mtimes $file_before $file_after
+ # ninja files of skipped modules shouldn't be regenerated
+ if [ $? -ne 1 ]; then
+ echo "Files have different mtimes: $file_before $file_after"
+ exit 1
+ fi
+ ((count++))
+ done
+ echo "Compared $count incremental ninja files"
+}
+
+test_incremental_build_parity
+test_build_action_restoring
diff --git a/tests/lib.sh b/tests/lib.sh
index 4c320d0..0e26de5 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -91,7 +91,6 @@
}
function create_mock_soong {
- create_mock_bazel
copy_directory build/blueprint
copy_directory build/soong
copy_directory build/make
@@ -143,41 +142,6 @@
USE_RBE=false TARGET_PRODUCT=aosp_arm TARGET_RELEASE=trunk_staging TARGET_BUILD_VARIANT=userdebug build/soong/soong_ui.bash --make-mode --skip-ninja --skip-config --soong-only --skip-soong-tests "$@"
}
-function create_mock_bazel {
- copy_directory build/bazel
- copy_directory build/bazel_common_rules
-
- # This requires pulling more tools into the mock top to build partitions
- delete_directory build/bazel/examples/partitions
-
- symlink_directory packages/modules/common/build
- symlink_directory prebuilts/bazel
- symlink_directory prebuilts/clang
- symlink_directory prebuilts/jdk
- symlink_directory external/bazel-skylib
- symlink_directory external/bazelbuild-rules_android
- symlink_directory external/bazelbuild-rules_go
- symlink_directory external/bazelbuild-rules_license
- symlink_directory external/bazelbuild-kotlin-rules
- symlink_directory external/bazelbuild-rules_cc
- symlink_directory external/bazelbuild-rules_python
- symlink_directory external/bazelbuild-rules_java
- symlink_directory external/bazelbuild-rules_rust
- symlink_directory external/bazelbuild-rules_testing
- symlink_directory external/rust/crates/tinyjson
-
- symlink_file WORKSPACE
- symlink_file BUILD
-}
-
-function run_bazel {
- # Remove the ninja_build output marker file to communicate to buildbot that this is not a regular Ninja build, and its
- # output should not be parsed as such.
- rm -rf out/ninja_build
-
- build/bazel/bin/bazel "$@"
-}
-
function run_ninja {
build/soong/soong_ui.bash --make-mode --skip-config --soong-only --skip-soong-tests "$@"
}
diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh
index 0471853..2ef9e37 100755
--- a/tests/sbom_test.sh
+++ b/tests/sbom_test.sh
@@ -83,6 +83,12 @@
dump_erofs=$out_dir/host/linux-x86/bin/dump.erofs
lz4=$out_dir/host/linux-x86/bin/lz4
+ declare -A diff_excludes
+ diff_excludes[system]="\
+ -I /etc/NOTICE.xml.gz \
+ -I /odm_dlkm/etc \
+ -I /vendor_dlkm/etc"
+
# Example output of dump.erofs is as below, and the data used in the test start
# at line 11. Column 1 is inode id, column 2 is inode type and column 3 is name.
# Each line is captured in variable "entry", awk is used to get type and name.
@@ -155,7 +161,11 @@
sort -n -o "$files_in_soong_spdx_file" "$files_in_soong_spdx_file"
echo ============ Diffing files in $f and SBOM created by Soong
- diff_files "$file_list_file" "$files_in_soong_spdx_file" "$partition_name" ""
+ exclude=
+ if [ -v 'diff_excludes[$partition_name]' ]; then
+ exclude=${diff_excludes[$partition_name]}
+ fi
+ diff_files "$file_list_file" "$files_in_soong_spdx_file" "$partition_name" "$exclude"
done
RAMDISK_IMAGES="$product_out/ramdisk.img"
@@ -230,10 +240,10 @@
exit 1
fi
- # PRODUCT and 7 prebuilt packages have "PackageLicenseDeclared: NOASSERTION"
+ # PRODUCT and 6 prebuilt packages have "PackageLicenseDeclared: NOASSERTION"
# All other packages have declared licenses
num_of_packages_with_noassertion_license=$(grep 'PackageLicenseDeclared: NOASSERTION' $sbom_file | wc -l)
- if [ $num_of_packages_with_noassertion_license = 15 ]
+ if [ $num_of_packages_with_noassertion_license = 13 ]
then
echo "Number of packages with NOASSERTION license is correct."
else
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index ddd0a80..8dd7381 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -190,22 +190,25 @@
return autogenPath
}
if len(options.OptionsForAutogenerated) > 0 {
- ctx.ModuleErrorf("Extra tradefed configurations were provided for an autogenerated xml file, but the autogenerated xml file was not used.")
+ ctx.ModuleErrorf("Extra tradefed configurations (%v) were provided for an autogenerated xml file, but the autogenerated xml file was not used.", options.OptionsForAutogenerated)
+ }
+ if len(options.TestRunnerOptions) > 0 {
+ ctx.ModuleErrorf("Extra test runner options (%v) were provided for an autogenerated xml file, but the autogenerated xml file was not used.", options.TestRunnerOptions)
}
return path
}
var autogenInstrumentationTest = pctx.StaticRule("autogenInstrumentationTest", blueprint.RuleParams{
- Command: "${AutoGenTestConfigScript} $out $in ${EmptyTestConfig} $template ${extraConfigs}",
+ Command: "${AutoGenTestConfigScript} $out $in ${EmptyTestConfig} $template ${extraConfigs} ${extraTestRunnerConfigs}",
CommandDeps: []string{
"${AutoGenTestConfigScript}",
"${EmptyTestConfig}",
"$template",
},
-}, "name", "template", "extraConfigs")
+}, "name", "template", "extraConfigs", "extraTestRunnerConfigs")
func AutoGenInstrumentationTestConfig(ctx android.ModuleContext, testConfigProp *string,
- testConfigTemplateProp *string, manifest android.Path, testSuites []string, autoGenConfig *bool, configs []Config) android.Path {
+ testConfigTemplateProp *string, manifest android.Path, testSuites []string, autoGenConfig *bool, configs []Config, testRunnerConfigs []Option) android.Path {
path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
var configStrings []string
if autogenPath != nil {
@@ -220,15 +223,26 @@
extraConfigs := strings.Join(configStrings, fmt.Sprintf("\\n%s", test_xml_indent))
extraConfigs = fmt.Sprintf("--extra-configs '%s'", extraConfigs)
+ var testRunnerConfigStrings []string
+ for _, config := range testRunnerConfigs {
+ testRunnerConfigStrings = append(testRunnerConfigStrings, config.Config())
+ }
+ extraTestRunnerConfigs := strings.Join(testRunnerConfigStrings, fmt.Sprintf("\\n%s%s", test_xml_indent, test_xml_indent))
+ if len(extraTestRunnerConfigs) > 0 {
+ extraTestRunnerConfigs += fmt.Sprintf("\\n%s%s", test_xml_indent, test_xml_indent)
+ }
+ extraTestRunnerConfigs = fmt.Sprintf("--extra-test-runner-configs '%s'", extraTestRunnerConfigs)
+
ctx.Build(pctx, android.BuildParams{
Rule: autogenInstrumentationTest,
Description: "test config",
Input: manifest,
Output: autogenPath,
Args: map[string]string{
- "name": ctx.ModuleName(),
- "template": template,
- "extraConfigs": extraConfigs,
+ "name": ctx.ModuleName(),
+ "template": template,
+ "extraConfigs": extraConfigs,
+ "extraTestRunnerConfigs": extraTestRunnerConfigs,
},
})
return autogenPath
diff --git a/tradefed/providers.go b/tradefed/providers.go
index 0abac12..0ae841d 100644
--- a/tradefed/providers.go
+++ b/tradefed/providers.go
@@ -9,8 +9,8 @@
// Data that test_module_config[_host] modules types will need from
// their dependencies to write out build rules and AndroidMkEntries.
type BaseTestProviderData struct {
- // data files and apps for android_test
- InstalledFiles android.Paths
+ // data files and apps installed for tests, relative to testcases dir.
+ TestcaseRelDataFiles []string
// apk for android_test
OutputFile android.Path
// Either handwritten or generated TF xml.
@@ -28,6 +28,12 @@
LocalCertificate string
// Indicates if the base module was a unit test.
IsUnitTest bool
+ // The .mk file is used AndroidMkEntries for base (soong_java_prebuilt, etc.)
+ MkInclude string
+ // The AppClass to use for the AndroidMkEntries for the base.
+ MkAppClass string
+ // value for LOCAL_MODULE_PATH. The directory where the module is installed.
+ InstallDir android.InstallPath
}
var BaseTestProviderKey = blueprint.NewProvider[BaseTestProviderData]()
diff --git a/tradefed_modules/Android.bp b/tradefed_modules/Android.bp
index 9969ae2..a765a05 100644
--- a/tradefed_modules/Android.bp
+++ b/tradefed_modules/Android.bp
@@ -9,13 +9,16 @@
"blueprint",
"soong-android",
"soong-java",
+ "soong-sh",
"soong-tradefed",
],
srcs: [
"test_module_config.go",
+ "test_suite.go",
],
testSrcs: [
"test_module_config_test.go",
+ "test_suite_test.go",
],
pluginFor: ["soong_build"],
}
diff --git a/tradefed_modules/test_module_config.go b/tradefed_modules/test_module_config.go
index ef18131..988352c 100644
--- a/tradefed_modules/test_module_config.go
+++ b/tradefed_modules/test_module_config.go
@@ -196,7 +196,7 @@
module := &testModuleConfigModule{}
module.AddProperties(&module.tradefedProperties)
- android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
android.InitDefaultableModule(module)
return module
@@ -216,13 +216,28 @@
// Implements android.AndroidMkEntriesProvider
var _ android.AndroidMkEntriesProvider = (*testModuleConfigModule)(nil)
+func (m *testModuleConfigModule) nativeExtraEntries(entries *android.AndroidMkEntries) {
+ // TODO(ron) provider for suffix and STEM?
+ entries.SetString("LOCAL_MODULE_SUFFIX", "")
+ // Should the stem and path use the base name or our module name?
+ entries.SetString("LOCAL_MODULE_STEM", m.provider.OutputFile.Rel())
+ entries.SetPath("LOCAL_MODULE_PATH", m.provider.InstallDir)
+}
+
+func (m *testModuleConfigModule) javaExtraEntries(entries *android.AndroidMkEntries) {
+ // The app_prebuilt_internal.mk files try create a copy of the OutputFile as an .apk.
+ // Normally, this copies the "package.apk" from the intermediate directory here.
+ // To prevent the copy of the large apk and to prevent confusion with the real .apk we
+ // link to, we set the STEM here to a bogus name and we set OutputFile to a small file (our manifest).
+ // We do this so we don't have to add more conditionals to base_rules.mk
+ // soong_java_prebult has the same issue for .jars so use this in both module types.
+ entries.SetString("LOCAL_MODULE_STEM", fmt.Sprintf("UNUSED-%s", *m.Base))
+ entries.SetString("LOCAL_MODULE_TAGS", "tests")
+}
+
func (m *testModuleConfigModule) AndroidMkEntries() []android.AndroidMkEntries {
- appClass := "APPS"
- include := "$(BUILD_SYSTEM)/soong_app_prebuilt.mk"
- if m.isHost {
- appClass = "JAVA_LIBRARIES"
- include = "$(BUILD_SYSTEM)/soong_java_prebuilt.mk"
- }
+ appClass := m.provider.MkAppClass
+ include := m.provider.MkInclude
return []android.AndroidMkEntries{{
Class: appClass,
OutputFile: android.OptionalPathForPath(m.manifest),
@@ -231,7 +246,6 @@
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetPath("LOCAL_FULL_TEST_CONFIG", m.testConfig)
- entries.SetString("LOCAL_MODULE_TAGS", "tests")
entries.SetString("LOCAL_TEST_MODULE_CONFIG_BASE", *m.Base)
if m.provider.LocalSdkVersion != "" {
entries.SetString("LOCAL_SDK_VERSION", m.provider.LocalSdkVersion)
@@ -242,14 +256,13 @@
entries.SetBoolIfTrue("LOCAL_IS_UNIT_TEST", m.provider.IsUnitTest)
entries.AddCompatibilityTestSuites(m.tradefedProperties.Test_suites...)
+ entries.AddStrings("LOCAL_HOST_REQUIRED_MODULES", m.provider.HostRequiredModuleNames...)
- // The app_prebuilt_internal.mk files try create a copy of the OutputFile as an .apk.
- // Normally, this copies the "package.apk" from the intermediate directory here.
- // To prevent the copy of the large apk and to prevent confusion with the real .apk we
- // link to, we set the STEM here to a bogus name and we set OutputFile to a small file (our manifest).
- // We do this so we don't have to add more conditionals to base_rules.mk
- // soong_java_prebult has the same issue for .jars so use this in both module types.
- entries.SetString("LOCAL_MODULE_STEM", fmt.Sprintf("UNUSED-%s", *m.Base))
+ if m.provider.MkAppClass == "NATIVE_TESTS" {
+ m.nativeExtraEntries(entries)
+ } else {
+ m.javaExtraEntries(entries)
+ }
// In normal java/app modules, the module writes LOCAL_COMPATIBILITY_SUPPORT_FILES
// and then base_rules.mk ends up copying each of those dependencies from .intermediates to the install directory.
@@ -356,16 +369,19 @@
// FrameworksServicesTests
// └── x86_64
// └── FrameworksServicesTests.apk
- symlinkName := fmt.Sprintf("%s/%s", ctx.DeviceConfig().DeviceArch(), baseApk.Base())
- // Only android_test, not java_host_test puts the output in the DeviceArch dir.
- if m.provider.IsHost || ctx.DeviceConfig().DeviceArch() == "" {
- // testcases/CtsDevicePolicyManagerTestCases
- // ├── CtsDevicePolicyManagerTestCases.jar
- symlinkName = baseApk.Base()
+ if m.provider.MkAppClass != "NATIVE_TESTS" {
+ symlinkName := fmt.Sprintf("%s/%s", ctx.DeviceConfig().DeviceArch(), baseApk.Base())
+ // Only android_test, not java_host_test puts the output in the DeviceArch dir.
+ if m.provider.IsHost || ctx.DeviceConfig().DeviceArch() == "" {
+ // testcases/CtsDevicePolicyManagerTestCases
+ // ├── CtsDevicePolicyManagerTestCases.jar
+ symlinkName = baseApk.Base()
+ }
+
+ target := installedBaseRelativeToHere(symlinkName, *m.tradefedProperties.Base)
+ installedApk := ctx.InstallAbsoluteSymlink(installDir, symlinkName, target)
+ m.supportFiles = append(m.supportFiles, installedApk)
}
- target := installedBaseRelativeToHere(symlinkName, *m.tradefedProperties.Base)
- installedApk := ctx.InstallAbsoluteSymlink(installDir, symlinkName, target)
- m.supportFiles = append(m.supportFiles, installedApk)
// 3) Symlink for all data deps
// And like this for data files and required modules
@@ -373,8 +389,7 @@
// ├── data
// │ └── broken_shortcut.xml
// ├── JobTestApp.apk
- for _, f := range m.provider.InstalledFiles {
- symlinkName := f.Rel()
+ for _, symlinkName := range m.provider.TestcaseRelDataFiles {
target := installedBaseRelativeToHere(symlinkName, *m.tradefedProperties.Base)
installedPath := ctx.InstallAbsoluteSymlink(installDir, symlinkName, target)
m.supportFiles = append(m.supportFiles, installedPath)
@@ -382,10 +397,31 @@
// 4) Module.config / AndroidTest.xml
m.testConfig = m.fixTestConfig(ctx, m.provider.TestConfig)
+
+ // 5) We provide so we can be listed in test_suites.
+ android.SetProvider(ctx, tradefed.BaseTestProviderKey, tradefed.BaseTestProviderData{
+ TestcaseRelDataFiles: testcaseRel(m.supportFiles.Paths()),
+ OutputFile: baseApk,
+ TestConfig: m.testConfig,
+ HostRequiredModuleNames: m.provider.HostRequiredModuleNames,
+ RequiredModuleNames: m.provider.RequiredModuleNames,
+ TestSuites: m.tradefedProperties.Test_suites,
+ IsHost: m.provider.IsHost,
+ LocalCertificate: m.provider.LocalCertificate,
+ IsUnitTest: m.provider.IsUnitTest,
+ })
}
var _ android.AndroidMkEntriesProvider = (*testModuleConfigHostModule)(nil)
+func testcaseRel(paths android.Paths) []string {
+ relPaths := []string{}
+ for _, p := range paths {
+ relPaths = append(relPaths, p.Rel())
+ }
+ return relPaths
+}
+
// Given a relative path to a file in the current directory or a subdirectory,
// return a relative path under our sibling directory named `base`.
// There should be one "../" for each subdir we descend plus one to backup to "base".
diff --git a/tradefed_modules/test_module_config_test.go b/tradefed_modules/test_module_config_test.go
index 1510a03..037dcea 100644
--- a/tradefed_modules/test_module_config_test.go
+++ b/tradefed_modules/test_module_config_test.go
@@ -16,6 +16,7 @@
import (
"android/soong/android"
"android/soong/java"
+ "android/soong/sh"
"fmt"
"strconv"
"strings"
@@ -40,6 +41,7 @@
name: "base",
sdk_version: "current",
data: [":HelperApp", "data/testfile"],
+ host_required: ["other-module"],
test_suites: ["general-tests"],
}
@@ -53,6 +55,8 @@
`
+const variant = "android_arm64_armv8-a"
+
// Ensure we create files needed and set the AndroidMkEntries needed
func TestModuleConfigAndroidTest(t *testing.T) {
@@ -61,7 +65,7 @@
android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
).RunTestWithBp(t, bp)
- derived := ctx.ModuleForTests("derived_test", "android_common")
+ derived := ctx.ModuleForTests("derived_test", variant)
// Assert there are rules to create these files.
derived.Output("test_module_config.manifest")
derived.Output("test_config_fixer/derived_test.config")
@@ -73,34 +77,109 @@
// Ensure some entries from base are there, specifically support files for data and helper apps.
// Do not use LOCAL_COMPATIBILITY_SUPPORT_FILES, but instead use LOCAL_SOONG_INSTALLED_COMPATIBILITY_SUPPORT_FILES
android.AssertStringPathsRelativeToTopEquals(t, "support-files", ctx.Config,
- []string{"out/soong/target/product/test_device/testcases/derived_test/arm64/base.apk",
- "out/soong/target/product/test_device/testcases/derived_test/HelperApp.apk",
- "out/soong/target/product/test_device/testcases/derived_test/data/testfile"},
+ []string{"out/target/product/test_device/testcases/derived_test/arm64/base.apk",
+ "out/target/product/test_device/testcases/derived_test/HelperApp.apk",
+ "out/target/product/test_device/testcases/derived_test/data/testfile"},
entries.EntryMap["LOCAL_SOONG_INSTALLED_COMPATIBILITY_SUPPORT_FILES"])
android.AssertArrayString(t, "", entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"], []string{})
android.AssertArrayString(t, "", entries.EntryMap["LOCAL_REQUIRED_MODULES"], []string{"base"})
+ android.AssertArrayString(t, "", entries.EntryMap["LOCAL_HOST_REQUIRED_MODULES"], []string{"other-module"})
android.AssertArrayString(t, "", entries.EntryMap["LOCAL_CERTIFICATE"], []string{"build/make/target/product/security/testkey.x509.pem"})
android.AssertStringEquals(t, "", entries.Class, "APPS")
// And some new derived entries are there.
android.AssertArrayString(t, "", entries.EntryMap["LOCAL_MODULE_TAGS"], []string{"tests"})
- android.AssertStringMatches(t, "", entries.EntryMap["LOCAL_FULL_TEST_CONFIG"][0], "derived_test/android_common/test_config_fixer/derived_test.config")
+ android.AssertStringMatches(t, "", entries.EntryMap["LOCAL_FULL_TEST_CONFIG"][0], fmt.Sprintf("derived_test/%s/test_config_fixer/derived_test.config", variant))
// Check the footer lines. Our support files should depend on base's support files.
convertedActual := make([]string, 5)
for i, e := range entries.FooterLinesForTests() {
// AssertStringPathsRelativeToTop doesn't replace both instances
- convertedActual[i] = strings.Replace(e, ctx.Config.SoongOutDir(), "", 2)
+ convertedActual[i] = strings.Replace(e, ctx.Config.OutDir(), "", 2)
}
- android.AssertArrayString(t, fmt.Sprintf("%s", ctx.Config.SoongOutDir()), convertedActual, []string{
+ android.AssertArrayString(t, fmt.Sprintf("%s", ctx.Config.OutDir()), []string{
"include $(BUILD_SYSTEM)/soong_app_prebuilt.mk",
"/target/product/test_device/testcases/derived_test/arm64/base.apk: /target/product/test_device/testcases/base/arm64/base.apk",
"/target/product/test_device/testcases/derived_test/HelperApp.apk: /target/product/test_device/testcases/base/HelperApp.apk",
"/target/product/test_device/testcases/derived_test/data/testfile: /target/product/test_device/testcases/base/data/testfile",
"",
- })
+ }, convertedActual)
+}
+
+func TestModuleConfigShTest(t *testing.T) {
+ ctx := android.GroupFixturePreparers(
+ sh.PrepareForTestWithShBuildComponents,
+ android.PrepareForTestWithAndroidBuildComponents,
+ android.FixtureMergeMockFs(android.MockFS{
+ "test.sh": nil,
+ "testdata/data1": nil,
+ "testdata/sub/data2": nil,
+ }),
+ android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
+ ).RunTestWithBp(t, `
+ sh_test {
+ name: "shell_test",
+ src: "test.sh",
+ filename: "test.sh",
+ test_suites: ["general-tests"],
+ data: [
+ "testdata/data1",
+ "testdata/sub/data2",
+ ],
+ }
+ test_module_config {
+ name: "conch",
+ base: "shell_test",
+ test_suites: ["general-tests"],
+ options: [{name: "SomeName", value: "OptionValue"}],
+ }
+ `)
+ derived := ctx.ModuleForTests("conch", variant) //
+ conch := derived.Module().(*testModuleConfigModule)
+ android.AssertArrayString(t, "TestcaseRelDataFiles", []string{"arm64/testdata/data1", "arm64/testdata/sub/data2"}, conch.provider.TestcaseRelDataFiles)
+ android.AssertStringEquals(t, "Rel OutputFile", "test.sh", conch.provider.OutputFile.Rel())
+
+ // Assert there are rules to create these files.
+ derived.Output("test_module_config.manifest")
+ derived.Output("test_config_fixer/conch.config")
+
+ // Ensure some basic rules exist.
+ entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, derived.Module())[0]
+
+ // Ensure some entries from base are there, specifically support files for data and helper apps.
+ // Do not use LOCAL_COMPATIBILITY_SUPPORT_FILES, but instead use LOCAL_SOONG_INSTALLED_COMPATIBILITY_SUPPORT_FILES
+ android.AssertStringPathsRelativeToTopEquals(t, "support-files", ctx.Config,
+ []string{"out/target/product/test_device/testcases/conch/arm64/testdata/data1",
+ "out/target/product/test_device/testcases/conch/arm64/testdata/sub/data2"},
+ entries.EntryMap["LOCAL_SOONG_INSTALLED_COMPATIBILITY_SUPPORT_FILES"])
+ android.AssertArrayString(t, "", entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"], []string{})
+
+ android.AssertStringEquals(t, "app class", "NATIVE_TESTS", entries.Class)
+ android.AssertArrayString(t, "required modules", []string{"shell_test"}, entries.EntryMap["LOCAL_REQUIRED_MODULES"])
+ android.AssertArrayString(t, "host required modules", []string{}, entries.EntryMap["LOCAL_HOST_REQUIRED_MODULES"])
+ android.AssertArrayString(t, "cert", []string{}, entries.EntryMap["LOCAL_CERTIFICATE"])
+
+ // And some new derived entries are there.
+ android.AssertArrayString(t, "tags", []string{}, entries.EntryMap["LOCAL_MODULE_TAGS"])
+
+ android.AssertStringMatches(t, "", entries.EntryMap["LOCAL_FULL_TEST_CONFIG"][0],
+ fmt.Sprintf("conch/%s/test_config_fixer/conch.config", variant))
+
+ // Check the footer lines. Our support files should depend on base's support files.
+ convertedActual := make([]string, 4)
+ for i, e := range entries.FooterLinesForTests() {
+ // AssertStringPathsRelativeToTop doesn't replace both instances
+ convertedActual[i] = strings.Replace(e, ctx.Config.OutDir(), "", 2)
+ }
+ android.AssertArrayString(t, fmt.Sprintf("%s", ctx.Config.OutDir()), []string{
+ "include $(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk",
+ "/target/product/test_device/testcases/conch/arm64/testdata/data1: /target/product/test_device/testcases/shell_test/arm64/testdata/data1",
+ "/target/product/test_device/testcases/conch/arm64/testdata/sub/data2: /target/product/test_device/testcases/shell_test/arm64/testdata/sub/data2",
+ "",
+ }, convertedActual)
+
}
// Make sure we call test-config-fixer with the right args.
@@ -112,7 +191,7 @@
).RunTestWithBp(t, bp)
// Check that we generate a rule to make a new AndroidTest.xml/Module.config file.
- derived := ctx.ModuleForTests("derived_test", "android_common")
+ derived := ctx.ModuleForTests("derived_test", variant)
rule_cmd := derived.Rule("fix_test_config").RuleParams.Command
android.AssertStringDoesContain(t, "Bad FixConfig rule inputs", rule_cmd,
`--test-runner-options='[{"Name":"exclude-filter","Key":"","Value":"android.test.example.devcodelab.DevCodelabTest#testHelloFail"},{"Name":"include-annotation","Key":"","Value":"android.platform.test.annotations.LargeTest"}]'`)
@@ -121,24 +200,24 @@
// Ensure we error for a base we don't support.
func TestModuleConfigWithHostBaseShouldFailWithExplicitMessage(t *testing.T) {
badBp := `
- java_test_host {
- name: "base",
- srcs: ["a.java"],
+ java_test {
+ name: "base",
+ srcs: ["a.java"],
}
- test_module_config {
- name: "derived_test",
- base: "base",
- exclude_filters: ["android.test.example.devcodelab.DevCodelabTest#testHelloFail"],
- include_annotations: ["android.platform.test.annotations.LargeTest"],
- test_suites: ["general-tests"],
- }`
+ test_module_config {
+ name: "derived_test",
+ base: "base",
+ exclude_filters: ["android.test.example.devcodelab.DevCodelabTest#testHelloFail"],
+ include_annotations: ["android.platform.test.annotations.LargeTest"],
+ test_suites: ["general-tests"],
+ }`
android.GroupFixturePreparers(
java.PrepareForTestWithJavaDefaultModules,
android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
).ExtendWithErrorHandler(
- android.FixtureExpectsAtLeastOneErrorMatchingPattern("'java_test_host' module used as base, but 'android_test' expected")).
+ android.FixtureExpectsAtLeastOneErrorMatchingPattern("'base' module used as base but it is not a 'android_test' module.")).
RunTestWithBp(t, badBp)
}
@@ -209,8 +288,7 @@
).ExtendWithErrorHandler(
android.FixtureExpectsAtLeastOneErrorMatchingPattern("Test options must be given")).
RunTestWithBp(t, badBp)
-
- ctx.ModuleForTests("derived_test", "android_common")
+ ctx.ModuleForTests("derived_test", variant)
}
func TestModuleConfigMultipleDerivedTestsWriteDistinctMakeEntries(t *testing.T) {
@@ -248,32 +326,33 @@
).RunTestWithBp(t, multiBp)
{
- derived := ctx.ModuleForTests("derived_test", "android_common")
+ derived := ctx.ModuleForTests("derived_test", variant)
entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, derived.Module())[0]
// All these should be the same in both derived tests
android.AssertStringPathsRelativeToTopEquals(t, "support-files", ctx.Config,
- []string{"out/soong/target/product/test_device/testcases/derived_test/arm64/base.apk",
- "out/soong/target/product/test_device/testcases/derived_test/HelperApp.apk",
- "out/soong/target/product/test_device/testcases/derived_test/data/testfile"},
+ []string{"out/target/product/test_device/testcases/derived_test/arm64/base.apk",
+ "out/target/product/test_device/testcases/derived_test/HelperApp.apk",
+ "out/target/product/test_device/testcases/derived_test/data/testfile"},
entries.EntryMap["LOCAL_SOONG_INSTALLED_COMPATIBILITY_SUPPORT_FILES"])
// Except this one, which points to the updated tradefed xml file.
- android.AssertStringMatches(t, "", entries.EntryMap["LOCAL_FULL_TEST_CONFIG"][0], "derived_test/android_common/test_config_fixer/derived_test.config")
+ android.AssertStringMatches(t, "", entries.EntryMap["LOCAL_FULL_TEST_CONFIG"][0], fmt.Sprintf("derived_test/%s/test_config_fixer/derived_test.config", variant))
// And this one, the module name.
android.AssertArrayString(t, "", entries.EntryMap["LOCAL_MODULE"], []string{"derived_test"})
}
{
- derived := ctx.ModuleForTests("another_derived_test", "android_common")
+ derived := ctx.ModuleForTests("another_derived_test", variant)
entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, derived.Module())[0]
// All these should be the same in both derived tests
android.AssertStringPathsRelativeToTopEquals(t, "support-files", ctx.Config,
- []string{"out/soong/target/product/test_device/testcases/another_derived_test/arm64/base.apk",
- "out/soong/target/product/test_device/testcases/another_derived_test/HelperApp.apk",
- "out/soong/target/product/test_device/testcases/another_derived_test/data/testfile"},
+ []string{"out/target/product/test_device/testcases/another_derived_test/arm64/base.apk",
+ "out/target/product/test_device/testcases/another_derived_test/HelperApp.apk",
+ "out/target/product/test_device/testcases/another_derived_test/data/testfile"},
entries.EntryMap["LOCAL_SOONG_INSTALLED_COMPATIBILITY_SUPPORT_FILES"])
// Except this one, which points to the updated tradefed xml file.
- android.AssertStringMatches(t, "", entries.EntryMap["LOCAL_FULL_TEST_CONFIG"][0], "another_derived_test/android_common/test_config_fixer/another_derived_test.config")
+ android.AssertStringMatches(t, "", entries.EntryMap["LOCAL_FULL_TEST_CONFIG"][0],
+ fmt.Sprintf("another_derived_test/%s/test_config_fixer/another_derived_test.config", variant))
// And this one, the module name.
android.AssertArrayString(t, "", entries.EntryMap["LOCAL_MODULE"], []string{"another_derived_test"})
}
diff --git a/tradefed_modules/test_suite.go b/tradefed_modules/test_suite.go
new file mode 100644
index 0000000..8b7babf
--- /dev/null
+++ b/tradefed_modules/test_suite.go
@@ -0,0 +1,173 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package tradefed_modules
+
+import (
+ "encoding/json"
+ "path"
+ "path/filepath"
+
+ "android/soong/android"
+ "android/soong/tradefed"
+ "github.com/google/blueprint"
+)
+
+const testSuiteModuleType = "test_suite"
+
+type testSuiteTag struct {
+ blueprint.BaseDependencyTag
+}
+
+type testSuiteManifest struct {
+ Name string `json:"name"`
+ Files []string `json:"files"`
+}
+
+func init() {
+ RegisterTestSuiteBuildComponents(android.InitRegistrationContext)
+}
+
+func RegisterTestSuiteBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType(testSuiteModuleType, TestSuiteFactory)
+}
+
+var PrepareForTestWithTestSuiteBuildComponents = android.GroupFixturePreparers(
+ android.FixtureRegisterWithContext(RegisterTestSuiteBuildComponents),
+)
+
+type testSuiteProperties struct {
+ Description string
+ Tests []string `android:"path,arch_variant"`
+}
+
+type testSuiteModule struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+ testSuiteProperties
+}
+
+func (t *testSuiteModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+ for _, test := range t.Tests {
+ if ctx.OtherModuleDependencyVariantExists(ctx.Config().BuildOSCommonTarget.Variations(), test) {
+ // Host tests.
+ ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), testSuiteTag{}, test)
+ } else {
+ // Target tests.
+ ctx.AddDependency(ctx.Module(), testSuiteTag{}, test)
+ }
+ }
+}
+
+func (t *testSuiteModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ suiteName := ctx.ModuleName()
+ modulesByName := make(map[string]android.Module)
+ ctx.WalkDeps(func(child, parent android.Module) bool {
+ // Recurse into test_suite dependencies.
+ if ctx.OtherModuleType(child) == testSuiteModuleType {
+ ctx.Phony(suiteName, android.PathForPhony(ctx, child.Name()))
+ return true
+ }
+
+ // Only write out top level test suite dependencies here.
+ if _, ok := ctx.OtherModuleDependencyTag(child).(testSuiteTag); !ok {
+ return false
+ }
+
+ if !child.InstallInTestcases() {
+ ctx.ModuleErrorf("test_suite only supports modules installed in testcases. %q is not installed in testcases.", child.Name())
+ return false
+ }
+
+ modulesByName[child.Name()] = child
+ return false
+ })
+
+ var files []string
+ for name, module := range modulesByName {
+ // Get the test provider data from the child.
+ tp, ok := android.OtherModuleProvider(ctx, module, tradefed.BaseTestProviderKey)
+ if !ok {
+ // TODO: Consider printing out a list of all module types.
+ ctx.ModuleErrorf("%q is not a test module.", name)
+ continue
+ }
+
+ files = append(files, packageModuleFiles(ctx, suiteName, module, tp)...)
+ ctx.Phony(suiteName, android.PathForPhony(ctx, name))
+ }
+
+ manifestPath := android.PathForSuiteInstall(ctx, suiteName, suiteName+".json")
+ b, err := json.Marshal(testSuiteManifest{Name: suiteName, Files: android.SortedUniqueStrings(files)})
+ if err != nil {
+ ctx.ModuleErrorf("Failed to marshal manifest: %v", err)
+ return
+ }
+ android.WriteFileRule(ctx, manifestPath, string(b))
+
+ ctx.Phony(suiteName, manifestPath)
+}
+
+func TestSuiteFactory() android.Module {
+ module := &testSuiteModule{}
+ module.AddProperties(&module.testSuiteProperties)
+
+ android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+
+ return module
+}
+
+func packageModuleFiles(ctx android.ModuleContext, suiteName string, module android.Module, tp tradefed.BaseTestProviderData) []string {
+
+ hostOrTarget := "target"
+ if tp.IsHost {
+ hostOrTarget = "host"
+ }
+
+ // suiteRoot at out/soong/packaging/<suiteName>.
+ suiteRoot := android.PathForSuiteInstall(ctx, suiteName)
+
+ var installed android.InstallPaths
+ // Install links to installed files from the module.
+ if installFilesInfo, ok := android.OtherModuleProvider(ctx, module, android.InstallFilesProvider); ok {
+ for _, f := range installFilesInfo.InstallFiles {
+ // rel is anything under .../<partition>, normally under .../testcases.
+ rel := android.Rel(ctx, f.PartitionDir(), f.String())
+
+ // Install the file under <suiteRoot>/<host|target>/<partition>.
+ installDir := suiteRoot.Join(ctx, hostOrTarget, f.Partition(), path.Dir(rel))
+ linkTo, err := filepath.Rel(installDir.String(), f.String())
+ if err != nil {
+ ctx.ModuleErrorf("Failed to get relative path from %s to %s: %v", installDir.String(), f.String(), err)
+ continue
+ }
+ installed = append(installed, ctx.InstallAbsoluteSymlink(installDir, path.Base(rel), linkTo))
+ }
+ }
+
+ // Install config file.
+ if tp.TestConfig != nil {
+ moduleRoot := suiteRoot.Join(ctx, hostOrTarget, "testcases", module.Name())
+ installed = append(installed, ctx.InstallFile(moduleRoot, module.Name()+".config", tp.TestConfig))
+ }
+
+ // Add to phony and manifest, manifestpaths are relative to suiteRoot.
+ var manifestEntries []string
+ for _, f := range installed {
+ manifestEntries = append(manifestEntries, android.Rel(ctx, suiteRoot.String(), f.String()))
+ ctx.Phony(suiteName, f)
+ }
+ return manifestEntries
+}
diff --git a/tradefed_modules/test_suite_test.go b/tradefed_modules/test_suite_test.go
new file mode 100644
index 0000000..3c0a9eb
--- /dev/null
+++ b/tradefed_modules/test_suite_test.go
@@ -0,0 +1,151 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package tradefed_modules
+
+import (
+ "android/soong/android"
+ "android/soong/java"
+ "encoding/json"
+ "slices"
+ "testing"
+)
+
+func TestTestSuites(t *testing.T) {
+ t.Parallel()
+ ctx := android.GroupFixturePreparers(
+ java.PrepareForTestWithJavaDefaultModules,
+ android.FixtureRegisterWithContext(RegisterTestSuiteBuildComponents),
+ ).RunTestWithBp(t, `
+ android_test {
+ name: "TestModule1",
+ sdk_version: "current",
+ }
+
+ android_test {
+ name: "TestModule2",
+ sdk_version: "current",
+ }
+
+ test_suite {
+ name: "my-suite",
+ description: "a test suite",
+ tests: [
+ "TestModule1",
+ "TestModule2",
+ ]
+ }
+ `)
+ manifestPath := ctx.ModuleForTests("my-suite", "android_common").Output("out/soong/test_suites/my-suite/my-suite.json")
+ var actual testSuiteManifest
+ if err := json.Unmarshal([]byte(android.ContentFromFileRuleForTests(t, ctx.TestContext, manifestPath)), &actual); err != nil {
+ t.Errorf("failed to unmarshal manifest: %v", err)
+ }
+ slices.Sort(actual.Files)
+
+ expected := testSuiteManifest{
+ Name: "my-suite",
+ Files: []string{
+ "target/testcases/TestModule1/TestModule1.config",
+ "target/testcases/TestModule1/arm64/TestModule1.apk",
+ "target/testcases/TestModule2/TestModule2.config",
+ "target/testcases/TestModule2/arm64/TestModule2.apk",
+ },
+ }
+
+ android.AssertDeepEquals(t, "manifests differ", expected, actual)
+}
+
+func TestTestSuitesWithNested(t *testing.T) {
+ t.Parallel()
+ ctx := android.GroupFixturePreparers(
+ java.PrepareForTestWithJavaDefaultModules,
+ android.FixtureRegisterWithContext(RegisterTestSuiteBuildComponents),
+ ).RunTestWithBp(t, `
+ android_test {
+ name: "TestModule1",
+ sdk_version: "current",
+ }
+
+ android_test {
+ name: "TestModule2",
+ sdk_version: "current",
+ }
+
+ android_test {
+ name: "TestModule3",
+ sdk_version: "current",
+ }
+
+ test_suite {
+ name: "my-child-suite",
+ description: "a child test suite",
+ tests: [
+ "TestModule1",
+ "TestModule2",
+ ]
+ }
+
+ test_suite {
+ name: "my-all-tests-suite",
+ description: "a parent test suite",
+ tests: [
+ "TestModule1",
+ "TestModule3",
+ "my-child-suite",
+ ]
+ }
+ `)
+ manifestPath := ctx.ModuleForTests("my-all-tests-suite", "android_common").Output("out/soong/test_suites/my-all-tests-suite/my-all-tests-suite.json")
+ var actual testSuiteManifest
+ if err := json.Unmarshal([]byte(android.ContentFromFileRuleForTests(t, ctx.TestContext, manifestPath)), &actual); err != nil {
+ t.Errorf("failed to unmarshal manifest: %v", err)
+ }
+ slices.Sort(actual.Files)
+
+ expected := testSuiteManifest{
+ Name: "my-all-tests-suite",
+ Files: []string{
+ "target/testcases/TestModule1/TestModule1.config",
+ "target/testcases/TestModule1/arm64/TestModule1.apk",
+ "target/testcases/TestModule2/TestModule2.config",
+ "target/testcases/TestModule2/arm64/TestModule2.apk",
+ "target/testcases/TestModule3/TestModule3.config",
+ "target/testcases/TestModule3/arm64/TestModule3.apk",
+ },
+ }
+
+ android.AssertDeepEquals(t, "manifests differ", expected, actual)
+}
+
+func TestTestSuitesNotInstalledInTestcases(t *testing.T) {
+ t.Parallel()
+ android.GroupFixturePreparers(
+ java.PrepareForTestWithJavaDefaultModules,
+ android.FixtureRegisterWithContext(RegisterTestSuiteBuildComponents),
+ ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern([]string{
+ `"SomeHostTest" is not installed in testcases`,
+ })).RunTestWithBp(t, `
+ java_test_host {
+ name: "SomeHostTest",
+ srcs: ["a.java"],
+ }
+ test_suite {
+ name: "my-suite",
+ description: "a test suite",
+ tests: [
+ "SomeHostTest",
+ ]
+ }
+ `)
+}
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index fcf29c5..a868d6a 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -35,12 +35,13 @@
"blueprint",
"blueprint-bootstrap",
"blueprint-microfactory",
- "soong-android",
"soong-elf",
"soong-finder",
+ "soong-finder-fs",
"soong-remoteexec",
"soong-shared",
"soong-ui-build-paths",
+ "soong-ui-execution-metrics",
"soong-ui-logger",
"soong-ui-metrics",
"soong-ui-status",
@@ -54,6 +55,7 @@
"config.go",
"context.go",
"staging_snapshot.go",
+ "source_inputs.go",
"dumpvars.go",
"environment.go",
"exec.go",
diff --git a/ui/build/androidmk_denylist.go b/ui/build/androidmk_denylist.go
index bbac2db..640a82d 100644
--- a/ui/build/androidmk_denylist.go
+++ b/ui/build/androidmk_denylist.go
@@ -25,21 +25,38 @@
"dalvik/",
"developers/",
"development/",
+ "device/common/",
+ "device/google_car/",
"device/sample/",
"frameworks/",
+ "hardware/libhardware/",
+ "hardware/libhardware_legacy/",
+ "hardware/ril/",
// Do not block other directories in kernel/, see b/319658303.
"kernel/configs/",
"kernel/prebuilts/",
"kernel/tests/",
"libcore/",
"libnativehelper/",
+ "packages/",
"pdk/",
+ "platform_testing/",
"prebuilts/",
"sdk/",
+ "system/",
"test/",
"trusty/",
// Add back toolchain/ once defensive Android.mk files are removed
//"toolchain/",
+ "vendor/google_contexthub/",
+ "vendor/google_data/",
+ "vendor/google_elmyra/",
+ "vendor/google_mhl/",
+ "vendor/google_pdk/",
+ "vendor/google_testing/",
+ "vendor/partner_testing/",
+ "vendor/partner_tools/",
+ "vendor/pdk/",
}
func blockAndroidMks(ctx Context, androidMks []string) {
@@ -52,3 +69,44 @@
}
}
}
+
+// The Android.mk files in these directories are for NDK build system.
+var external_ndk_androidmks []string = []string{
+ "external/fmtlib/",
+ "external/google-breakpad/",
+ "external/googletest/",
+ "external/libaom/",
+ "external/libusb/",
+ "external/libvpx/",
+ "external/libwebm/",
+ "external/libwebsockets/",
+ "external/vulkan-validation-layers/",
+ "external/walt/",
+ "external/webp/",
+}
+
+var art_androidmks = []string{
+ //"art/",
+}
+
+func ignoreSomeAndroidMks(androidMks []string) (filtered []string) {
+ ignore_androidmks := make([]string, 0, len(external_ndk_androidmks)+len(art_androidmks))
+ ignore_androidmks = append(ignore_androidmks, external_ndk_androidmks...)
+ ignore_androidmks = append(ignore_androidmks, art_androidmks...)
+
+ shouldKeep := func(androidmk string) bool {
+ for _, prefix := range ignore_androidmks {
+ if strings.HasPrefix(androidmk, prefix) {
+ return false
+ }
+ }
+ return true
+ }
+
+ for _, l := range androidMks {
+ if shouldKeep(l) {
+ filtered = append(filtered, l)
+ }
+ }
+ return
+}
diff --git a/ui/build/build.go b/ui/build/build.go
index 49ac791..ea86782 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -33,26 +33,13 @@
ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "CleanSpec.mk"))
ensureEmptyDirectoriesExist(ctx, config.TempDir())
- // Potentially write a marker file for whether kati is enabled. This is used by soong_build to
- // potentially run the AndroidMk singleton and postinstall commands.
- // Note that the absence of the file does not not preclude running Kati for product
- // configuration purposes.
- katiEnabledMarker := filepath.Join(config.SoongOutDir(), ".soong.kati_enabled")
- if config.SkipKatiNinja() {
- os.Remove(katiEnabledMarker)
- // Note that we can not remove the file for SkipKati builds yet -- some continuous builds
- // --skip-make builds rely on kati targets being defined.
- } else if !config.SkipKati() {
- ensureEmptyFileExists(ctx, katiEnabledMarker)
- }
-
// The ninja_build file is used by our buildbots to understand that the output
// can be parsed as ninja output.
ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "ninja_build"))
ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), ".out-dir"))
if buildDateTimeFile, ok := config.environ.Get("BUILD_DATETIME_FILE"); ok {
- err := ioutil.WriteFile(buildDateTimeFile, []byte(config.buildDateTime), 0666) // a+rw
+ err := os.WriteFile(buildDateTimeFile, []byte(config.buildDateTime), 0666) // a+rw
if err != nil {
ctx.Fatalln("Failed to write BUILD_DATETIME to file:", err)
}
@@ -80,13 +67,39 @@
if username, ok = config.environ.Get("BUILD_USERNAME"); !ok {
ctx.Fatalln("Missing BUILD_USERNAME")
}
- buildNumber = fmt.Sprintf("eng.%.6s.00000000.000000", username)
+ buildNumber = fmt.Sprintf("eng.%.6s", username)
writeValueIfChanged(ctx, config, config.OutDir(), "file_name_tag.txt", username)
}
// Write the build number to a file so it can be read back in
// without changing the command line every time. Avoids rebuilds
// when using ninja.
writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_number.txt", buildNumber)
+
+ hostname, ok := config.environ.Get("BUILD_HOSTNAME")
+ if !ok {
+ var err error
+ hostname, err = os.Hostname()
+ if err != nil {
+ ctx.Println("Failed to read hostname:", err)
+ hostname = "unknown"
+ }
+ }
+ writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_hostname.txt", hostname)
+}
+
+// SetupKatiEnabledMarker creates or delets a file that tells soong_build if we're running with
+// kati.
+func SetupKatiEnabledMarker(ctx Context, config Config) {
+ // Potentially write a marker file for whether kati is enabled. This is used by soong_build to
+ // potentially run the AndroidMk singleton and postinstall commands.
+ // Note that the absence of the file does not preclude running Kati for product
+ // configuration purposes.
+ katiEnabledMarker := filepath.Join(config.SoongOutDir(), ".soong.kati_enabled")
+ if config.SkipKati() || config.SkipKatiNinja() {
+ os.Remove(katiEnabledMarker)
+ } else {
+ ensureEmptyFileExists(ctx, katiEnabledMarker)
+ }
}
var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(`
@@ -96,8 +109,11 @@
{{end -}}
pool highmem_pool
depth = {{.HighmemParallel}}
-{{if and (not .SkipKatiNinja) .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}}
+{{if and (not .SkipKatiNinja) .HasKatiSuffix}}
+subninja {{.KatiBuildNinjaFile}}
subninja {{.KatiPackageNinjaFile}}
+{{else}}
+subninja {{.KatiSoongOnlyPackageNinjaFile}}
{{end -}}
subninja {{.SoongNinjaFile}}
`))
@@ -315,10 +331,16 @@
if what&RunProductConfig != 0 {
runMakeProductConfig(ctx, config)
+
+ // Re-evaluate what to run because there are product variables that control how
+ // soong and make are run.
+ what = evaluateWhatToRun(config, ctx.Verboseln)
}
// Everything below here depends on product config.
+ SetupKatiEnabledMarker(ctx, config)
+
if inList("installclean", config.Arguments()) ||
inList("install-clean", config.Arguments()) {
logArgsOtherThan("installclean", "install-clean")
@@ -335,25 +357,31 @@
return
}
+ // Still generate the kati suffix in soong-only builds because soong-only still uses kati for
+ // the packaging step. Also, the kati suffix is used for the combined ninja file.
+ genKatiSuffix(ctx, config)
+
if what&RunSoong != 0 {
runSoong(ctx, config)
}
if what&RunKati != 0 {
- genKatiSuffix(ctx, config)
runKatiCleanSpec(ctx, config)
runKatiBuild(ctx, config)
- runKatiPackage(ctx, config)
+ runKatiPackage(ctx, config, false)
- ioutil.WriteFile(config.LastKatiSuffixFile(), []byte(config.KatiSuffix()), 0666) // a+rw
} else if what&RunKatiNinja != 0 {
// Load last Kati Suffix if it exists
- if katiSuffix, err := ioutil.ReadFile(config.LastKatiSuffixFile()); err == nil {
+ if katiSuffix, err := os.ReadFile(config.LastKatiSuffixFile()); err == nil {
ctx.Verboseln("Loaded previous kati config:", string(katiSuffix))
config.SetKatiSuffix(string(katiSuffix))
}
+ } else if what&RunSoong != 0 {
+ runKatiPackage(ctx, config, true)
}
+ os.WriteFile(config.LastKatiSuffixFile(), []byte(config.KatiSuffix()), 0666) // a+rw
+
// Write combined ninja file
createCombinedBuildNinjaFile(ctx, config)
@@ -428,7 +456,7 @@
if !config.SoongBuildInvocationNeeded() {
// This means that the output of soong_build is not needed and thus it would
// run unnecessarily. In addition, if this code wasn't there invocations
- // with only special-cased target names like "m bp2build" would result in
+ // with only special-cased target names would result in
// passing Ninja the empty target list and it would then build the default
// targets which is not what the user asked for.
what = what &^ RunNinja
@@ -502,4 +530,5 @@
// Be careful, anything added here slows down EVERY CI build
func runDistActions(ctx Context, config Config) {
runStagingSnapshot(ctx, config)
+ runSourceInputs(ctx, config)
}
diff --git a/ui/build/config.go b/ui/build/config.go
index b8fcb6b..2a00c41 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -30,6 +30,7 @@
"syscall"
"time"
+ "android/soong/finder/fs"
"android/soong/shared"
"android/soong/ui/metrics"
@@ -41,6 +42,7 @@
const (
envConfigDir = "vendor/google/tools/soong_config"
jsonSuffix = "json"
+ abfsSrcDir = "/src"
)
var (
@@ -53,11 +55,21 @@
rbeRandPrefix = rand.Intn(1000)
}
+// Which builder are we using?
+type ninjaCommandType = int
+
+const (
+ _ = iota
+ NINJA_NINJA
+ NINJA_N2
+ NINJA_SISO
+ NINJA_NINJAGO
+)
+
type Config struct{ *configImpl }
type configImpl struct {
// Some targets that are implemented in soong_build
- // (bp2build, json-module-graph) are not here and have their own bits below.
arguments []string
goma bool
environ *Environment
@@ -66,27 +78,31 @@
logsPrefix string
// From the arguments
- parallel int
- keepGoing int
- verbose bool
- checkbuild bool
- dist bool
- jsonModuleGraph bool
- queryview bool
- reportMkMetrics bool // Collect and report mk2bp migration progress metrics.
- soongDocs bool
- skipConfig bool
- skipKati bool
- skipKatiNinja bool
- skipSoong bool
- skipNinja bool
- skipSoongTests bool
- searchApiDir bool // Scan the Android.bp files generated in out/api_surfaces
- skipMetricsUpload bool
- buildStartedTime int64 // For metrics-upload-only - manually specify a build-started time
- buildFromSourceStub bool
- incrementalBuildActions bool
- ensureAllowlistIntegrity bool // For CI builds - make sure modules are mixed-built
+ parallel int
+ keepGoing int
+ verbose bool
+ checkbuild bool
+ dist bool
+ jsonModuleGraph bool
+ reportMkMetrics bool // Collect and report mk2bp migration progress metrics.
+ soongDocs bool
+ skipConfig bool
+ // Either the user or product config requested that we skip soong (for the banner). The other
+ // skip flags tell whether *this* soong_ui invocation will skip kati - which will be true
+ // during lunch.
+ soongOnlyRequested bool
+ skipKati bool
+ skipKatiControlledByFlags bool
+ skipKatiNinja bool
+ skipSoong bool
+ skipNinja bool
+ skipSoongTests bool
+ searchApiDir bool // Scan the Android.bp files generated in out/api_surfaces
+ skipMetricsUpload bool
+ buildStartedTime int64 // For metrics-upload-only - manually specify a build-started time
+ buildFromSourceStub bool
+ incrementalBuildActions bool
+ ensureAllowlistIntegrity bool // For CI builds - make sure modules are mixed-built
// From the product config
katiArgs []string
@@ -97,7 +113,9 @@
sandboxConfig *SandboxConfig
// Autodetected
- totalRAM uint64
+ totalRAM uint64
+ systemCpuInfo *metrics.CpuInfo
+ systemMemInfo *metrics.MemInfo
brokenDupRules bool
brokenUsesNetwork bool
@@ -122,9 +140,8 @@
// could consider merging them.
moduleDebugFile string
- // Whether to use n2 instead of ninja. This is controlled with the
- // environment variable SOONG_USE_N2
- useN2 bool
+ // Which builder are we using
+ ninjaCommand ninjaCommandType
}
type NinjaWeightListSource uint
@@ -214,6 +231,10 @@
sandboxConfig: &SandboxConfig{},
ninjaWeightListSource: DEFAULT,
}
+ wd, err := os.Getwd()
+ if err != nil {
+ ctx.Fatalln("Failed to get working directory:", err)
+ }
// Skip soong tests by default on Linux
if runtime.GOOS == "linux" {
@@ -225,8 +246,29 @@
ret.keepGoing = 1
ret.totalRAM = detectTotalRAM(ctx)
+ ret.systemCpuInfo, err = metrics.NewCpuInfo(fs.OsFs)
+ if err != nil {
+ ctx.Fatalln("Failed to get cpuinfo:", err)
+ }
+ ret.systemMemInfo, err = metrics.NewMemInfo(fs.OsFs)
+ if err != nil {
+ ctx.Fatalln("Failed to get meminfo:", err)
+ }
ret.parseArgs(ctx, args)
+ if value, ok := ret.environ.Get("SOONG_ONLY"); ok && !ret.skipKatiControlledByFlags {
+ if value == "true" || value == "1" || value == "y" || value == "yes" {
+ ret.soongOnlyRequested = true
+ ret.skipKatiControlledByFlags = true
+ ret.skipKati = true
+ ret.skipKatiNinja = true
+ } else {
+ ret.skipKatiControlledByFlags = true
+ ret.skipKati = false
+ ret.skipKatiNinja = false
+ }
+ }
+
if ret.ninjaWeightListSource == HINT_FROM_SOONG {
ret.environ.Set("SOONG_GENERATES_NINJA_HINT", "always")
} else if ret.ninjaWeightListSource == DEFAULT {
@@ -245,17 +287,13 @@
// Make sure OUT_DIR is set appropriately
if outDir, ok := ret.environ.Get("OUT_DIR"); ok {
- ret.environ.Set("OUT_DIR", filepath.Clean(outDir))
+ ret.environ.Set("OUT_DIR", ret.sandboxPath(wd, filepath.Clean(outDir)))
} else {
outDir := "out"
if baseDir, ok := ret.environ.Get("OUT_DIR_COMMON_BASE"); ok {
- if wd, err := os.Getwd(); err != nil {
- ctx.Fatalln("Failed to get working directory:", err)
- } else {
- outDir = filepath.Join(baseDir, filepath.Base(wd))
- }
+ outDir = filepath.Join(baseDir, filepath.Base(wd))
}
- ret.environ.Set("OUT_DIR", outDir)
+ ret.environ.Set("OUT_DIR", ret.sandboxPath(wd, outDir))
}
// loadEnvConfig needs to know what the OUT_DIR is, so it should
@@ -287,8 +325,29 @@
ret.moduleDebugFile, _ = filepath.Abs(shared.JoinPath(ret.SoongOutDir(), "soong-debug-info.json"))
}
- if os.Getenv("SOONG_USE_N2") == "true" {
- ret.useN2 = true
+ // If SOONG_USE_PARTIAL_COMPILE is set, make it one of "true" or the empty string.
+ // This simplifies the generated Ninja rules, so that they only need to check for the empty string.
+ if value, ok := ret.environ.Get("SOONG_USE_PARTIAL_COMPILE"); ok {
+ if value == "true" || value == "1" || value == "y" || value == "yes" {
+ value = "true"
+ } else {
+ value = ""
+ }
+ ret.environ.Set("SOONG_USE_PARTIAL_COMPILE", value)
+ }
+
+ ret.ninjaCommand = NINJA_NINJA
+ switch os.Getenv("SOONG_NINJA") {
+ case "n2":
+ ret.ninjaCommand = NINJA_N2
+ case "siso":
+ ret.ninjaCommand = NINJA_SISO
+ case "ninjago":
+ ret.ninjaCommand = NINJA_NINJAGO
+ default:
+ if os.Getenv("SOONG_USE_N2") == "true" {
+ ret.ninjaCommand = NINJA_N2
+ }
}
ret.environ.Unset(
@@ -348,8 +407,12 @@
// We read it here already, don't let others share in the fun
"GENERATE_SOONG_DEBUG",
- // Use config.useN2 instead.
+ // Use config.ninjaCommand instead.
+ "SOONG_NINJA",
"SOONG_USE_N2",
+
+ // Already incorporated into the config object
+ "SOONG_ONLY",
)
if ret.UseGoma() || ret.ForceUseGoma() {
@@ -361,12 +424,12 @@
ret.environ.Set("PYTHONDONTWRITEBYTECODE", "1")
tmpDir := absPath(ctx, ret.TempDir())
- ret.environ.Set("TMPDIR", tmpDir)
+ ret.environ.Set("TMPDIR", ret.sandboxPath(wd, tmpDir))
// Always set ASAN_SYMBOLIZER_PATH so that ASAN-based tools can symbolize any crashes
symbolizerPath := filepath.Join("prebuilts/clang/host", ret.HostPrebuiltTag(),
"llvm-binutils-stable/llvm-symbolizer")
- ret.environ.Set("ASAN_SYMBOLIZER_PATH", absPath(ctx, symbolizerPath))
+ ret.environ.Set("ASAN_SYMBOLIZER_PATH", ret.sandboxPath(wd, absPath(ctx, symbolizerPath)))
// Precondition: the current directory is the top of the source tree
checkTopDir(ctx)
@@ -426,9 +489,9 @@
}
ret.environ.Unset("OVERRIDE_ANDROID_JAVA_HOME")
- ret.environ.Set("JAVA_HOME", absJavaHome)
- ret.environ.Set("ANDROID_JAVA_HOME", javaHome)
- ret.environ.Set("ANDROID_JAVA8_HOME", java8Home)
+ ret.environ.Set("JAVA_HOME", ret.sandboxPath(wd, absJavaHome))
+ ret.environ.Set("ANDROID_JAVA_HOME", ret.sandboxPath(wd, javaHome))
+ ret.environ.Set("ANDROID_JAVA8_HOME", ret.sandboxPath(wd, java8Home))
ret.environ.Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
// b/286885495, https://bugzilla.redhat.com/show_bug.cgi?id=2227130: some versions of Fedora include patches
@@ -444,7 +507,7 @@
ret.buildDateTime = strconv.FormatInt(time.Now().Unix(), 10)
}
- ret.environ.Set("BUILD_DATETIME_FILE", buildDateTimeFile)
+ ret.environ.Set("BUILD_DATETIME_FILE", ret.sandboxPath(wd, buildDateTimeFile))
if _, ok := ret.environ.Get("BUILD_USERNAME"); !ok {
username := "unknown"
@@ -455,6 +518,7 @@
}
ret.environ.Set("BUILD_USERNAME", username)
}
+ ret.environ.Set("PWD", ret.sandboxPath(wd, wd))
if ret.UseRBE() {
for k, v := range getRBEVars(ctx, Config{ret}) {
@@ -518,9 +582,23 @@
ctx.Metrics.BuildConfig(buildConfig(config))
+ cpuInfo := &smpb.SystemCpuInfo{
+ VendorId: proto.String(config.systemCpuInfo.VendorId),
+ ModelName: proto.String(config.systemCpuInfo.ModelName),
+ CpuCores: proto.Int32(config.systemCpuInfo.CpuCores),
+ Flags: proto.String(config.systemCpuInfo.Flags),
+ }
+ memInfo := &smpb.SystemMemInfo{
+ MemTotal: proto.Uint64(config.systemMemInfo.MemTotal),
+ MemFree: proto.Uint64(config.systemMemInfo.MemFree),
+ MemAvailable: proto.Uint64(config.systemMemInfo.MemAvailable),
+ }
+
s := &smpb.SystemResourceInfo{
TotalPhysicalMemory: proto.Uint64(config.TotalRAM()),
AvailableCpus: proto.Int32(int32(runtime.NumCPU())),
+ CpuInfo: cpuInfo,
+ MemInfo: memInfo,
}
ctx.Metrics.SystemResourceInfo(s)
}
@@ -541,11 +619,27 @@
}
func buildConfig(config Config) *smpb.BuildConfig {
+ var soongEnvVars *smpb.SoongEnvVars
+ ensure := func() *smpb.SoongEnvVars {
+ // Create soongEnvVars if it doesn't already exist.
+ if soongEnvVars == nil {
+ soongEnvVars = &smpb.SoongEnvVars{}
+ }
+ return soongEnvVars
+ }
+ if value, ok := config.environ.Get("SOONG_PARTIAL_COMPILE"); ok {
+ ensure().PartialCompile = proto.String(value)
+ }
+ if value, ok := config.environ.Get("SOONG_USE_PARTIAL_COMPILE"); ok {
+ ensure().UsePartialCompile = proto.String(value)
+ }
c := &smpb.BuildConfig{
ForceUseGoma: proto.Bool(config.ForceUseGoma()),
UseGoma: proto.Bool(config.UseGoma()),
UseRbe: proto.Bool(config.UseRBE()),
NinjaWeightListSource: getNinjaWeightListSourceInMetric(config.NinjaWeightListSource()),
+ SoongEnvVars: soongEnvVars,
+ SoongOnly: proto.Bool(config.soongOnlyRequested),
}
c.Targets = append(c.Targets, config.arguments...)
@@ -774,15 +868,21 @@
c.emptyNinjaFile = true
} else if arg == "--skip-ninja" {
c.skipNinja = true
- } else if arg == "--skip-make" {
- // TODO(ccross): deprecate this, it has confusing behaviors. It doesn't run kati,
- // but it does run a Kati ninja file if the .kati_enabled marker file was created
- // by a previous build.
- c.skipConfig = true
- c.skipKati = true
} else if arg == "--soong-only" {
+ if c.skipKatiControlledByFlags {
+ ctx.Fatalf("Cannot specify both --soong-only and --no-soong-only")
+ }
+ c.soongOnlyRequested = true
+ c.skipKatiControlledByFlags = true
c.skipKati = true
c.skipKatiNinja = true
+ } else if arg == "--no-soong-only" {
+ if c.skipKatiControlledByFlags {
+ ctx.Fatalf("Cannot specify both --soong-only and --no-soong-only")
+ }
+ c.skipKatiControlledByFlags = true
+ c.skipKati = false
+ c.skipKatiNinja = false
} else if arg == "--config-only" {
c.skipKati = true
c.skipKatiNinja = true
@@ -877,8 +977,6 @@
c.dist = true
} else if arg == "json-module-graph" {
c.jsonModuleGraph = true
- } else if arg == "queryview" {
- c.queryview = true
} else if arg == "soong_docs" {
c.soongDocs = true
} else {
@@ -973,7 +1071,7 @@
return true
}
- if !c.JsonModuleGraph() && !c.Queryview() && !c.SoongDocs() {
+ if !c.JsonModuleGraph() && !c.SoongDocs() {
// Command line was empty, the default Ninja target is built
return true
}
@@ -1003,7 +1101,7 @@
func (c *configImpl) NinjaArgs() []string {
if c.skipKati {
- return c.arguments
+ return append(c.arguments, c.ninjaArgs...)
}
return c.ninjaArgs
}
@@ -1035,13 +1133,9 @@
}
}
-func (c *configImpl) NamedGlobFile(name string) string {
- return shared.JoinPath(c.SoongOutDir(), "globs-"+name+".ninja")
-}
-
func (c *configImpl) UsedEnvFile(tag string) string {
if v, ok := c.environ.Get("TARGET_PRODUCT"); ok {
- return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+v+"."+tag)
+ return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+v+c.CoverageSuffix()+"."+tag)
}
return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+tag)
}
@@ -1050,10 +1144,6 @@
return shared.JoinPath(c.SoongOutDir(), "docs/soong_build.html")
}
-func (c *configImpl) QueryviewMarkerFile() string {
- return shared.JoinPath(c.SoongOutDir(), "queryview.marker")
-}
-
func (c *configImpl) ModuleGraphFile() string {
return shared.JoinPath(c.SoongOutDir(), "module-graph.json")
}
@@ -1091,10 +1181,6 @@
return c.jsonModuleGraph
}
-func (c *configImpl) Queryview() bool {
- return c.queryview
-}
-
func (c *configImpl) SoongDocs() bool {
return c.soongDocs
}
@@ -1149,6 +1235,13 @@
return "", fmt.Errorf("TARGET_PRODUCT is not defined")
}
+func (c *configImpl) CoverageSuffix() string {
+ if v := c.environ.IsEnvTrue("EMMA_INSTRUMENT"); v {
+ return ".coverage"
+ }
+ return ""
+}
+
func (c *configImpl) TargetDevice() string {
return c.targetDevice
}
@@ -1277,6 +1370,10 @@
}
func (c *configImpl) UseABFS() bool {
+ if c.ninjaCommand == NINJA_NINJAGO {
+ return true
+ }
+
if v, ok := c.environ.Get("NO_ABFS"); ok {
v = strings.ToLower(strings.TrimSpace(v))
if v == "true" || v == "1" {
@@ -1289,9 +1386,22 @@
return err == nil
}
+func (c *configImpl) sandboxPath(base, in string) string {
+ if !c.UseABFS() {
+ return in
+ }
+
+ rel, err := filepath.Rel(base, in)
+ if err != nil {
+ return in
+ }
+
+ return filepath.Join(abfsSrcDir, rel)
+}
+
func (c *configImpl) UseRBE() bool {
// These alternate modes of running Soong do not use RBE / reclient.
- if c.Queryview() || c.JsonModuleGraph() {
+ if c.JsonModuleGraph() {
return false
}
@@ -1357,8 +1467,10 @@
// Perform a log directory cleanup only when the log directory
// is auto created by the build rather than user-specified.
for _, f := range []string{"RBE_proxy_log_dir", "FLAG_output_dir"} {
- if _, ok := c.environ.Get(f); ok {
- return false
+ if v, ok := c.environ.Get(f); ok {
+ if v != c.rbeTmpDir() {
+ return false
+ }
}
}
return true
@@ -1515,12 +1627,16 @@
return filepath.Join(c.OutDir(), "build"+c.KatiSuffix()+katiPackageSuffix+".ninja")
}
+func (c *configImpl) KatiSoongOnlyPackageNinjaFile() string {
+ return filepath.Join(c.OutDir(), "build"+c.KatiSuffix()+katiSoongOnlyPackageSuffix+".ninja")
+}
+
func (c *configImpl) SoongVarsFile() string {
targetProduct, err := c.TargetProductOrErr()
if err != nil {
return filepath.Join(c.SoongOutDir(), "soong.variables")
} else {
- return filepath.Join(c.SoongOutDir(), "soong."+targetProduct+".variables")
+ return filepath.Join(c.SoongOutDir(), "soong."+targetProduct+c.CoverageSuffix()+".variables")
}
}
@@ -1529,7 +1645,7 @@
if err != nil {
return filepath.Join(c.SoongOutDir(), "soong.extra.variables")
} else {
- return filepath.Join(c.SoongOutDir(), "soong."+targetProduct+".extra.variables")
+ return filepath.Join(c.SoongOutDir(), "soong."+targetProduct+c.CoverageSuffix()+".extra.variables")
}
}
@@ -1538,7 +1654,7 @@
if err != nil {
return filepath.Join(c.SoongOutDir(), "build.ninja")
} else {
- return filepath.Join(c.SoongOutDir(), "build."+targetProduct+".ninja")
+ return filepath.Join(c.SoongOutDir(), "build."+targetProduct+c.CoverageSuffix()+".ninja")
}
}
@@ -1550,11 +1666,11 @@
}
func (c *configImpl) SoongAndroidMk() string {
- return filepath.Join(c.SoongOutDir(), "Android-"+c.TargetProduct()+".mk")
+ return filepath.Join(c.SoongOutDir(), "Android-"+c.TargetProduct()+c.CoverageSuffix()+".mk")
}
func (c *configImpl) SoongMakeVarsMk() string {
- return filepath.Join(c.SoongOutDir(), "make_vars-"+c.TargetProduct()+".mk")
+ return filepath.Join(c.SoongOutDir(), "make_vars-"+c.TargetProduct()+c.CoverageSuffix()+".mk")
}
func (c *configImpl) SoongBuildMetrics() string {
@@ -1570,7 +1686,7 @@
}
func (c *configImpl) KatiPackageMkDir() string {
- return filepath.Join(c.ProductOut(), "obj", "CONFIG", "kati_packaging")
+ return filepath.Join(c.SoongOutDir(), "kati_packaging"+c.KatiSuffix())
}
func (c *configImpl) hostOutRoot() string {
@@ -1617,13 +1733,23 @@
return c.PrebuiltBuildTool(binName)
}
+func (c *configImpl) N2Bin() string {
+ path := c.PrebuiltBuildTool("n2")
+ // Use musl instead of glibc because glibc on the build server is old and has bugs
+ return strings.ReplaceAll(path, "/linux-x86/", "/linux_musl-x86/")
+}
+
+func (c *configImpl) SisoBin() string {
+ path := c.PrebuiltBuildTool("siso")
+ // Use musl instead of glibc because glibc on the build server is old and has bugs
+ return strings.ReplaceAll(path, "/linux-x86/", "/linux_musl-x86/")
+}
+
func (c *configImpl) PrebuiltBuildTool(name string) string {
- if v, ok := c.environ.Get("SANITIZE_HOST"); ok {
- if sanitize := strings.Fields(v); inList("address", sanitize) {
- asan := filepath.Join("prebuilts/build-tools", c.HostPrebuiltTag(), "asan/bin", name)
- if _, err := os.Stat(asan); err == nil {
- return asan
- }
+ if c.environ.IsEnvTrue("SANITIZE_BUILD_TOOL_PREBUILTS") {
+ asan := filepath.Join("prebuilts/build-tools", c.HostPrebuiltTag(), "asan/bin", name)
+ if _, err := os.Stat(asan); err == nil {
+ return asan
}
}
return filepath.Join("prebuilts/build-tools", c.HostPrebuiltTag(), "bin", name)
@@ -1709,6 +1835,11 @@
}
func (c *configImpl) SkipMetricsUpload() bool {
+ // b/362625275 - Metrics upload sometimes prevents abfs unmount
+ if c.UseABFS() {
+ return true
+ }
+
return c.skipMetricsUpload
}
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index b42edb0..10de1ad 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -30,8 +30,6 @@
smpb "android/soong/ui/metrics/metrics_proto"
"android/soong/ui/status"
- "google.golang.org/protobuf/encoding/prototext"
-
"google.golang.org/protobuf/proto"
)
@@ -1006,6 +1004,12 @@
}
}
+func assertEquals[T ~bool | ~int32](t *testing.T, name string, expected, actual T) {
+ if expected != actual {
+ t.Errorf("Expected %s: %#v\nActual %s: %#v", name, expected, name, actual)
+ }
+}
+
func TestBuildConfig(t *testing.T) {
tests := []struct {
name string
@@ -1063,12 +1067,11 @@
arguments: tc.arguments,
}
config := Config{c}
- actualBuildConfig := buildConfig(config)
- if expected := tc.expectedBuildConfig; !proto.Equal(expected, actualBuildConfig) {
- t.Errorf("Build config mismatch.\n"+
- "Expected build config: %#v\n"+
- "Actual build config: %#v", prototext.Format(expected), prototext.Format(actualBuildConfig))
- }
+ actual := buildConfig(config)
+ assertEquals(t, "ForceUseGoma", *tc.expectedBuildConfig.ForceUseGoma, *actual.ForceUseGoma)
+ assertEquals(t, "UseGoma", *tc.expectedBuildConfig.UseGoma, *actual.UseGoma)
+ assertEquals(t, "UseRbe", *tc.expectedBuildConfig.UseRbe, *actual.UseRbe)
+ assertEquals(t, "NinjaWeightListSource", *tc.expectedBuildConfig.NinjaWeightListSource, *actual.NinjaWeightListSource)
})
}
}
diff --git a/ui/build/context.go b/ui/build/context.go
index fd20e26..69e5f96 100644
--- a/ui/build/context.go
+++ b/ui/build/context.go
@@ -18,6 +18,7 @@
"context"
"io"
+ "android/soong/ui/execution_metrics"
"android/soong/ui/logger"
"android/soong/ui/metrics"
soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
@@ -33,7 +34,8 @@
context.Context
logger.Logger
- Metrics *metrics.Metrics
+ Metrics *metrics.Metrics
+ ExecutionMetrics *execution_metrics.ExecutionMetrics
Writer io.Writer
Status *status.Status
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 5df3a95..16a3db8 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -137,6 +137,12 @@
}
}
if ctx.Metrics != nil {
+ // Also include TARGET_RELEASE in the metrics. Do this first
+ // so that it gets overwritten if dumpvars ever spits it out.
+ if release, found := os.LookupEnv("TARGET_RELEASE"); found {
+ ctx.Metrics.SetMetadataMetrics(
+ map[string]string{"TARGET_RELEASE": release})
+ }
ctx.Metrics.SetMetadataMetrics(ret)
}
@@ -166,7 +172,7 @@
"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE",
}
-func Banner(make_vars map[string]string) string {
+func Banner(config Config, make_vars map[string]string) string {
b := &bytes.Buffer{}
fmt.Fprintln(b, "============================================")
@@ -175,6 +181,7 @@
fmt.Fprintf(b, "%s=%s\n", name, make_vars[name])
}
}
+ fmt.Fprintf(b, "SOONG_ONLY=%t\n", config.soongOnlyRequested)
fmt.Fprint(b, "============================================")
return b.String()
@@ -240,6 +247,8 @@
// `true` will relegate missing outputs to warnings.
"BUILD_BROKEN_MISSING_OUTPUTS",
+ "PRODUCT_SOONG_ONLY",
+
// Not used, but useful to be in the soong.log
"TARGET_BUILD_TYPE",
"HOST_ARCH",
@@ -273,6 +282,7 @@
"BUILD_BROKEN_USES_BUILD_SHARED_LIBRARY",
"BUILD_BROKEN_USES_BUILD_STATIC_JAVA_LIBRARY",
"BUILD_BROKEN_USES_BUILD_STATIC_LIBRARY",
+ "RELEASE_BUILD_EXECUTION_METRICS",
}, exportEnvVars...), BannerVars...)
makeVars, err := dumpMakeVars(ctx, config, config.Arguments(), allVars, true, "")
@@ -280,13 +290,8 @@
ctx.Fatalln("Error dumping make vars:", err)
}
- env := config.Environment()
- // Print the banner like make does
- if !env.IsEnvTrue("ANDROID_QUIET_BUILD") {
- fmt.Fprintln(ctx.Writer, Banner(makeVars))
- }
-
// Populate the environment
+ env := config.Environment()
for _, name := range exportEnvVars {
if makeVars[name] == "" {
env.Unset(name)
@@ -307,4 +312,17 @@
config.SetBuildBrokenNinjaUsesEnvVars(strings.Fields(makeVars["BUILD_BROKEN_NINJA_USES_ENV_VARS"]))
config.SetSourceRootDirs(strings.Fields(makeVars["PRODUCT_SOURCE_ROOT_DIRS"]))
config.SetBuildBrokenMissingOutputs(makeVars["BUILD_BROKEN_MISSING_OUTPUTS"] == "true")
+
+ if !config.skipKatiControlledByFlags {
+ if makeVars["PRODUCT_SOONG_ONLY"] == "true" {
+ config.soongOnlyRequested = true
+ config.skipKati = true
+ config.skipKatiNinja = true
+ }
+ }
+
+ // Print the banner like make did
+ if !env.IsEnvTrue("ANDROID_QUIET_BUILD") {
+ fmt.Fprintln(ctx.Writer, Banner(config, makeVars))
+ }
}
diff --git a/ui/build/finder.go b/ui/build/finder.go
index 573df21..783b488 100644
--- a/ui/build/finder.go
+++ b/ui/build/finder.go
@@ -128,6 +128,7 @@
// Stop searching a subdirectory recursively after finding an Android.mk.
androidMks := f.FindFirstNamedAt(".", "Android.mk")
+ androidMks = ignoreSomeAndroidMks(androidMks)
blockAndroidMks(ctx, androidMks)
err := dumpListToFile(ctx, config, androidMks, filepath.Join(dumpDir, "Android.mk.list"))
if err != nil {
@@ -170,6 +171,7 @@
// Recursively look for all METADATA files.
metadataFiles := f.FindNamedAt(".", "METADATA")
+ metadataFiles = ignoreNonAndroidMetadataFiles(metadataFiles)
err = dumpListToFile(ctx, config, metadataFiles, filepath.Join(dumpDir, "METADATA.list"))
if err != nil {
ctx.Fatalf("Could not find METADATA: %v", err)
@@ -222,3 +224,16 @@
return nil
}
+
+func ignoreNonAndroidMetadataFiles(metadataFiles []string) []string {
+ result := make([]string, 0, len(metadataFiles))
+ for _, file := range metadataFiles {
+ // Ignore files like prebuilts/clang/host/linux-x86/clang-r536225/python3/lib/python3.11/site-packages/pip-23.1.2.dist-info/METADATA
+ // these METADATA files are from upstream and are not the METADATA files used in Android codebase.
+ if strings.Contains(file, "prebuilts/clang/host/") && strings.Contains(file, "/site-packages/") {
+ continue
+ }
+ result = append(result, file)
+ }
+ return result
+}
diff --git a/ui/build/kati.go b/ui/build/kati.go
index a0efd2c..6519573 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -31,6 +31,7 @@
const katiBuildSuffix = ""
const katiCleanspecSuffix = "-cleanspec"
const katiPackageSuffix = "-package"
+const katiSoongOnlyPackageSuffix = "-soong-only-package"
// genKatiSuffix creates a filename suffix for kati-generated files so that we
// can cache them based on their inputs. Such files include the generated Ninja
@@ -40,8 +41,12 @@
// Currently that includes the TARGET_PRODUCT and kati-processed command line
// arguments.
func genKatiSuffix(ctx Context, config Config) {
+ targetProduct := "unknown"
+ if p, err := config.TargetProductOrErr(); err == nil {
+ targetProduct = p
+ }
// Construct the base suffix.
- katiSuffix := "-" + config.TargetProduct()
+ katiSuffix := "-" + targetProduct + config.CoverageSuffix()
// Append kati arguments to the suffix.
if args := config.KatiArgs(); len(args) > 0 {
@@ -68,13 +73,13 @@
func writeValueIfChanged(ctx Context, config Config, dir string, filename string, value string) {
filePath := filepath.Join(dir, filename)
previousValue := ""
- rawPreviousValue, err := ioutil.ReadFile(filePath)
+ rawPreviousValue, err := os.ReadFile(filePath)
if err == nil {
previousValue = string(rawPreviousValue)
}
if previousValue != value {
- if err = ioutil.WriteFile(filePath, []byte(value), 0666); err != nil {
+ if err = os.WriteFile(filePath, []byte(value), 0666); err != nil {
ctx.Fatalf("Failed to write: %v", err)
}
}
@@ -183,18 +188,27 @@
username = usernameFromEnv
}
- hostname, ok := cmd.Environment.Get("BUILD_HOSTNAME")
+ // SOONG_USE_PARTIAL_COMPILE may be used in makefiles, but both cases must be supported.
+ //
+ // In general, the partial compile features will be implemented in Soong-based rules. We
+ // also allow them to be used in makefiles. Clear the environment variable when calling
+ // kati so that we avoid reanalysis when the user changes it. We will pass it to Ninja.
+ // As a result, rules where we want to allow the developer to toggle the feature ("use
+ // the partial compile feature" vs "legacy, aka full compile behavior") need to use this
+ // in the rule, since changing it will not cause reanalysis.
+ //
+ // Shell syntax in the rule might look something like this:
+ // if [[ -n ${SOONG_USE_PARTIAL_COMPILE} ]]; then
+ // # partial compile behavior
+ // else
+ // # legacy behavior
+ // fi
+ cmd.Environment.Unset("SOONG_USE_PARTIAL_COMPILE")
+
// Unset BUILD_HOSTNAME during kati run to avoid kati rerun, kati will use BUILD_HOSTNAME from a file.
cmd.Environment.Unset("BUILD_HOSTNAME")
- if !ok {
- hostname, err = os.Hostname()
- if err != nil {
- ctx.Println("Failed to read hostname:", err)
- hostname = "unknown"
- }
- }
- writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_hostname.txt", hostname)
- _, ok = cmd.Environment.Get("BUILD_NUMBER")
+
+ _, ok := cmd.Environment.Get("BUILD_NUMBER")
// Unset BUILD_NUMBER during kati run to avoid kati rerun, kati will use BUILD_NUMBER from a file.
cmd.Environment.Unset("BUILD_NUMBER")
if ok {
@@ -325,10 +339,19 @@
// Generate the Ninja file containing the packaging command lines for the dist
// dir.
-func runKatiPackage(ctx Context, config Config) {
+func runKatiPackage(ctx Context, config Config, soongOnly bool) {
ctx.BeginTrace(metrics.RunKati, "kati package")
defer ctx.EndTrace()
+ entryPoint := "build/make/packaging/main.mk"
+ suffix := katiPackageSuffix
+ ninjaFile := config.KatiPackageNinjaFile()
+ if soongOnly {
+ entryPoint = "build/make/packaging/main_soong_only.mk"
+ suffix = katiSoongOnlyPackageSuffix
+ ninjaFile = config.KatiSoongOnlyPackageNinjaFile()
+ }
+
args := []string{
// Mark the dist dir as writable.
"--writable", config.DistDir() + "/",
@@ -337,14 +360,14 @@
// Fail when redefining / duplicating a target.
"--werror_overriding_commands",
// Entry point.
- "-f", "build/make/packaging/main.mk",
+ "-f", entryPoint,
// Directory containing .mk files for packaging purposes, such as
// the dist.mk file, containing dist-for-goals data.
"KATI_PACKAGE_MK_DIR=" + config.KatiPackageMkDir(),
}
// Run Kati against a restricted set of environment variables.
- runKati(ctx, config, katiPackageSuffix, args, func(env *Environment) {
+ runKati(ctx, config, suffix, args, func(env *Environment) {
env.Allow([]string{
// Some generic basics
"LANG",
@@ -372,7 +395,7 @@
})
// Compress and dist the packaging Ninja file.
- distGzipFile(ctx, config, config.KatiPackageNinjaFile())
+ distGzipFile(ctx, config, ninjaFile)
}
// Run Kati on the cleanspec files to clean the build.
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 8ca62d3..1d4285f 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -17,6 +17,7 @@
import (
"fmt"
"os"
+ "os/exec"
"path/filepath"
"sort"
"strconv"
@@ -49,15 +50,11 @@
nr := status.NewNinjaReader(ctx, ctx.Status.StartTool(), fifo)
defer nr.Close()
- executable := config.NinjaBin()
- args := []string{
- "-d", "keepdepfile",
- "-d", "keeprsp",
- "-d", "stats",
- "--frontend_file", fifo,
- }
- if config.useN2 {
- executable = config.PrebuiltBuildTool("n2")
+ var executable string
+ var args []string
+ switch config.ninjaCommand {
+ case NINJA_N2:
+ executable = config.N2Bin()
args = []string{
"-d", "trace",
// TODO: implement these features, or remove them.
@@ -66,8 +63,31 @@
//"-d", "stats",
"--frontend-file", fifo,
}
+ case NINJA_SISO:
+ executable = config.SisoBin()
+ args = []string{
+ "ninja",
+ "--log_dir", config.SoongOutDir(),
+ // TODO: implement these features, or remove them.
+ //"-d", "trace",
+ //"-d", "keepdepfile",
+ //"-d", "keeprsp",
+ //"-d", "stats",
+ //"--frontend-file", fifo,
+ }
+ default:
+ // NINJA_NINJA or NINJA_NINJAGO.
+ executable = config.NinjaBin()
+ args = []string{
+ "-d", "keepdepfile",
+ "-d", "keeprsp",
+ "-d", "stats",
+ "--frontend_file", fifo,
+ "-o", "usesphonyoutputs=yes",
+ "-w", "dupbuild=err",
+ "-w", "missingdepfile=err",
+ }
}
-
args = append(args, config.NinjaArgs()...)
var parallel int
@@ -83,17 +103,10 @@
args = append(args, "-f", config.CombinedNinjaFile())
- if !config.useN2 {
- args = append(args,
- "-o", "usesphonyoutputs=yes",
- "-w", "dupbuild=err",
- "-w", "missingdepfile=err")
- }
-
if !config.BuildBrokenMissingOutputs() {
// Missing outputs will be treated as errors.
// BUILD_BROKEN_MISSING_OUTPUTS can be used to bypass this check.
- if !config.useN2 {
+ if config.ninjaCommand != NINJA_N2 {
args = append(args,
"-w", "missingoutfile=err",
)
@@ -110,21 +123,18 @@
cmd.Environment.AppendFromKati(config.KatiEnvFile())
}
- switch config.NinjaWeightListSource() {
- case NINJA_LOG:
- if !config.useN2 {
+ // TODO(b/346806126): implement this for the other ninjaCommand values.
+ if config.ninjaCommand == NINJA_NINJA {
+ switch config.NinjaWeightListSource() {
+ case NINJA_LOG:
cmd.Args = append(cmd.Args, "-o", "usesninjalogasweightlist=yes")
- }
- case EVENLY_DISTRIBUTED:
- // pass empty weight list means ninja considers every tasks's weight as 1(default value).
- if !config.useN2 {
+ case EVENLY_DISTRIBUTED:
+ // pass empty weight list means ninja considers every tasks's weight as 1(default value).
cmd.Args = append(cmd.Args, "-o", "usesweightlist=/dev/null")
- }
- case EXTERNAL_FILE:
- fallthrough
- case HINT_FROM_SOONG:
- // The weight list is already copied/generated.
- if !config.useN2 {
+ case EXTERNAL_FILE:
+ fallthrough
+ case HINT_FROM_SOONG:
+ // The weight list is already copied/generated.
ninjaWeightListPath := filepath.Join(config.OutDir(), ninjaWeightListFileName)
cmd.Args = append(cmd.Args, "-o", "usesweightlist="+ninjaWeightListPath)
}
@@ -227,18 +237,33 @@
// We don't want this build broken flag to cause reanalysis, so allow it through to the
// actions.
"BUILD_BROKEN_INCORRECT_PARTITION_IMAGES",
+ // Do not do reanalysis just because we changed ninja commands.
+ "SOONG_NINJA",
"SOONG_USE_N2",
"RUST_BACKTRACE",
"RUST_LOG",
+
+ // SOONG_USE_PARTIAL_COMPILE only determines which half of the rule we execute.
+ "SOONG_USE_PARTIAL_COMPILE",
+
+ // Directory for ExecutionMetrics
+ "SOONG_METRICS_AGGREGATION_DIR",
}, config.BuildBrokenNinjaUsesEnvVars()...)...)
}
cmd.Environment.Set("DIST_DIR", config.DistDir())
cmd.Environment.Set("SHELL", "/bin/bash")
- if config.useN2 {
+ switch config.ninjaCommand {
+ case NINJA_N2:
cmd.Environment.Set("RUST_BACKTRACE", "1")
+ default:
+ // Only set RUST_BACKTRACE for n2.
}
+ // Set up the metrics aggregation directory.
+ ctx.ExecutionMetrics.SetDir(filepath.Join(config.OutDir(), "soong", "metrics_aggregation"))
+ cmd.Environment.Set("SOONG_METRICS_AGGREGATION_DIR", ctx.ExecutionMetrics.MetricsAggregationDir)
+
// Print the environment variables that Ninja is operating in.
ctx.Verboseln("Ninja environment: ")
envVars := cmd.Environment.Environ()
@@ -283,6 +308,8 @@
}
}()
+ ctx.ExecutionMetrics.Start()
+ defer ctx.ExecutionMetrics.Finish(ctx)
ctx.Status.Status("Starting ninja...")
cmd.RunAndStreamOrFatal()
}
@@ -322,3 +349,46 @@
}
c.prevModTime = newModTime
}
+
+// Constructs and runs the Ninja command line to get the inputs of a goal.
+// For n2 and siso, this will always run ninja, because they don't have the
+// `-t inputs` command. This command will use the inputs command's -d option,
+// to use the dep file iff ninja was the executor. For other executors, the
+// results will be wrong.
+func runNinjaInputs(ctx Context, config Config, goal string) ([]string, error) {
+ var executable string
+ switch config.ninjaCommand {
+ case NINJA_N2, NINJA_SISO:
+ executable = config.PrebuiltBuildTool("ninja")
+ default:
+ executable = config.NinjaBin()
+ }
+
+ args := []string{
+ "-f",
+ config.CombinedNinjaFile(),
+ "-t",
+ "inputs",
+ }
+ // Add deps file arg for ninja
+ // TODO: Update as inputs command is implemented
+ if config.ninjaCommand == NINJA_NINJA && !config.UseABFS() {
+ args = append(args, "-d")
+ }
+ args = append(args, goal)
+
+ // This is just ninja -t inputs, so we won't bother running it in the sandbox,
+ // so use exec.Command, not soong_ui's command.
+ cmd := exec.Command(executable, args...)
+
+ cmd.Stdin = os.Stdin
+ cmd.Stderr = os.Stderr
+
+ out, err := cmd.Output()
+ if err != nil {
+ fmt.Printf("Error getting goal inputs for %s: %s\n", goal, err)
+ return nil, err
+ }
+
+ return strings.Split(strings.TrimSpace(string(out)), "\n"), nil
+}
diff --git a/ui/build/path.go b/ui/build/path.go
index 51ebff1..cc1d7e9 100644
--- a/ui/build/path.go
+++ b/ui/build/path.go
@@ -57,6 +57,22 @@
return ret
}
+func updatePathForSandbox(config Config) {
+ wd, err := os.Getwd()
+ if err != nil {
+ return
+ }
+
+ var newPath []string
+ if path, ok := config.Environment().Get("PATH"); ok && path != "" {
+ entries := strings.Split(path, string(filepath.ListSeparator))
+ for _, ent := range entries {
+ newPath = append(newPath, config.sandboxPath(wd, ent))
+ }
+ }
+ config.Environment().Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
+}
+
// SetupLitePath is the "lite" version of SetupPath used for dumpvars, or other
// places that does not need the full logging capabilities of path_interposer,
// wants the minimal performance overhead, and still get the benefits of $PATH
@@ -109,18 +125,10 @@
prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
- if value, _ := config.Environment().Get("BUILD_BROKEN_PYTHON_IS_PYTHON2"); value == "true" {
- py2Path, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86/py2")
- if info, err := os.Stat(py2Path); err == nil && info.IsDir() {
- myPath = py2Path + string(os.PathListSeparator) + myPath
- }
- } else if value != "" {
- ctx.Fatalf("BUILD_BROKEN_PYTHON_IS_PYTHON2 can only be set to 'true' or an empty string, but got %s\n", value)
- }
-
// Set $PATH to be the directories containing the host tool symlinks, and
// the prebuilts directory for the current host OS.
config.Environment().Set("PATH", myPath)
+ updatePathForSandbox(config)
config.pathReplaced = true
}
@@ -253,17 +261,9 @@
prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
- if value, _ := config.Environment().Get("BUILD_BROKEN_PYTHON_IS_PYTHON2"); value == "true" {
- py2Path, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86/py2")
- if info, err := os.Stat(py2Path); err == nil && info.IsDir() {
- myPath = py2Path + string(os.PathListSeparator) + myPath
- }
- } else if value != "" {
- ctx.Fatalf("BUILD_BROKEN_PYTHON_IS_PYTHON2 can only be set to 'true' or an empty string, but got %s\n", value)
- }
-
// Replace the $PATH variable with the path_interposer symlinks, and
// checked-in prebuilts.
config.Environment().Set("PATH", myPath)
+ updatePathForSandbox(config)
config.pathReplaced = true
}
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index 6c9a1eb..110ddee 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -42,7 +42,7 @@
}
// This tool is specifically disallowed and calling it will result in an
-// "executable no found" error.
+// "executable not found" error.
var Forbidden = PathConfig{
Symlink: false,
Log: true,
@@ -122,6 +122,10 @@
"ld.bfd": Forbidden,
"ld.gold": Forbidden,
"pkg-config": Forbidden,
+ "python": Forbidden,
+ "python2": Forbidden,
+ "python2.7": Forbidden,
+ "python3": Forbidden,
// These are toybox tools that only work on Linux.
"pgrep": LinuxOnlyPrebuilt,
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index d9ca854..95b71a7 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -50,7 +50,6 @@
const (
nsjailPath = "prebuilts/build-tools/linux-x86/bin/nsjail"
- abfsSrcDir = "/src"
)
var sandboxConfig struct {
@@ -148,20 +147,42 @@
return sandboxConfig.working
}
-func (c *Cmd) srcDirArg() string {
- if !c.config.UseABFS() {
- return sandboxConfig.srcDir
+// Assumes input path is absolute, clean, and if applicable, an evaluated
+// symlink. If path is not a subdirectory of src dir or relative path
+// cannot be determined, return the input untouched.
+func (c *Cmd) relFromSrcDir(path string) string {
+ if !strings.HasPrefix(path, sandboxConfig.srcDir) {
+ return path
}
- return sandboxConfig.srcDir + ":" + abfsSrcDir
+ rel, err := filepath.Rel(sandboxConfig.srcDir, path)
+ if err != nil {
+ return path
+ }
+
+ return rel
+}
+
+func (c *Cmd) dirArg(path string) string {
+ if !c.config.UseABFS() {
+ return path
+ }
+
+ rel := c.relFromSrcDir(path)
+
+ return path + ":" + filepath.Join(abfsSrcDir, rel)
+}
+
+func (c *Cmd) srcDirArg() string {
+ return c.dirArg(sandboxConfig.srcDir)
}
func (c *Cmd) outDirArg() string {
- if !c.config.UseABFS() {
- return sandboxConfig.outDir
- }
+ return c.dirArg(sandboxConfig.outDir)
+}
- return sandboxConfig.outDir + ":" + filepath.Join(abfsSrcDir, sandboxConfig.outDir)
+func (c *Cmd) distDirArg() string {
+ return c.dirArg(sandboxConfig.distDir)
}
// When configured to use ABFS, we need to allow the creation of the /src
@@ -187,8 +208,17 @@
return args
}
+func (c *Cmd) workDir() string {
+ if !c.config.UseABFS() {
+ wd, _ := os.Getwd()
+ return wd
+ }
+
+ return abfsSrcDir
+}
+
func (c *Cmd) wrapSandbox() {
- wd, _ := os.Getwd()
+ wd := c.workDir()
var sandboxArgs []string
sandboxArgs = append(sandboxArgs,
@@ -226,7 +256,7 @@
)
sandboxArgs = append(sandboxArgs,
- c.readMountArgs()...
+ c.readMountArgs()...,
)
sandboxArgs = append(sandboxArgs,
@@ -264,7 +294,7 @@
if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
//Mount dist dir as read-write if it already exists
- sandboxArgs = append(sandboxArgs, "-B", sandboxConfig.distDir)
+ sandboxArgs = append(sandboxArgs, "-B", c.distDirArg())
}
if c.Sandbox.AllowBuildBrokenUsesNetwork && c.config.BuildBrokenUsesNetwork() {
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 2ccdfec..58334a9 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -15,14 +15,19 @@
package build
import (
+ "encoding/json"
+ "errors"
"fmt"
"io/fs"
"os"
"path/filepath"
+ "runtime"
+ "slices"
"strconv"
"strings"
"sync"
"sync/atomic"
+ "syscall"
"time"
"android/soong/ui/tracer"
@@ -47,12 +52,11 @@
soongBuildTag = "build"
jsonModuleGraphTag = "modulegraph"
- queryviewTag = "queryview"
soongDocsTag = "soong_docs"
// bootstrapEpoch is used to determine if an incremental build is incompatible with the current
// version of bootstrap and needs cleaning before continuing the build. Increment this for
- // incompatible changes, for example when moving the location of the bpglob binary that is
+ // incompatible changes, for example when moving the location of a microfactory binary that is
// executed during bootstrap before the primary builder has had a chance to update the path.
bootstrapEpoch = 1
)
@@ -193,6 +197,8 @@
func (pb PrimaryBuilderFactory) primaryBuilderInvocation(config Config) bootstrap.PrimaryBuilderInvocation {
commonArgs := make([]string, 0, 0)
+ commonArgs = append(commonArgs, "--kati_suffix", config.KatiSuffix())
+
if !pb.config.skipSoongTests {
commonArgs = append(commonArgs, "-t")
}
@@ -226,10 +232,6 @@
var allArgs []string
allArgs = append(allArgs, pb.specificArgs...)
- globPathName := getGlobPathNameFromPrimaryBuilderFactory(config, pb)
- allArgs = append(allArgs,
- "--globListDir", globPathName,
- "--globFile", pb.config.NamedGlobFile(globPathName))
allArgs = append(allArgs, commonArgs...)
allArgs = append(allArgs, environmentArgs(pb.config, pb.name)...)
@@ -241,11 +243,8 @@
}
allArgs = append(allArgs, "Android.bp")
- globfiles := bootstrap.GlobFileListFiles(bootstrap.GlobDirectory(config.SoongOutDir(), globPathName))
-
return bootstrap.PrimaryBuilderInvocation{
- Inputs: []string{"Android.bp"},
- Implicits: globfiles,
+ Implicits: []string{pb.output + ".glob_results"},
Outputs: []string{pb.output},
Args: allArgs,
Description: pb.description,
@@ -277,28 +276,28 @@
os.Remove(file)
}
}
- for _, globFile := range bootstrapGlobFileList(config) {
- os.Remove(globFile)
- }
+ os.Remove(soongNinjaFile + ".globs")
+ os.Remove(soongNinjaFile + ".globs_time")
+ os.Remove(soongNinjaFile + ".glob_results")
// Mark the tree as up to date with the current epoch by writing the epoch marker file.
writeEmptyFile(ctx, epochPath)
}
}
-func bootstrapGlobFileList(config Config) []string {
- return []string{
- config.NamedGlobFile(getGlobPathName(config)),
- config.NamedGlobFile(jsonModuleGraphTag),
- config.NamedGlobFile(queryviewTag),
- config.NamedGlobFile(soongDocsTag),
- }
-}
-
func bootstrapBlueprint(ctx Context, config Config) {
ctx.BeginTrace(metrics.RunSoong, "blueprint bootstrap")
defer ctx.EndTrace()
+ st := ctx.Status.StartTool()
+ defer st.Finish()
+ st.SetTotalActions(1)
+ action := &status.Action{
+ Description: "bootstrap blueprint",
+ Outputs: []string{"bootstrap blueprint"},
+ }
+ st.StartAction(action)
+
// Clean up some files for incremental builds across incompatible changes.
bootstrapEpochCleanup(ctx, config)
@@ -318,8 +317,6 @@
mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--incremental-build-actions")
}
- queryviewDir := filepath.Join(config.SoongOutDir(), "queryview")
-
pbfs := []PrimaryBuilderFactory{
{
name: soongBuildTag,
@@ -339,15 +336,6 @@
),
},
{
- name: queryviewTag,
- description: fmt.Sprintf("generating the Soong module graph as a Bazel workspace at %s", queryviewDir),
- config: config,
- output: config.QueryviewMarkerFile(),
- specificArgs: append(baseArgs,
- "--bazel_queryview_dir", queryviewDir,
- ),
- },
- {
name: soongDocsTag,
description: fmt.Sprintf("generating Soong docs at %s", config.SoongDocsHtml()),
config: config,
@@ -412,37 +400,23 @@
runGoTests: !config.skipSoongTests,
// If we want to debug soong_build, we need to compile it for debugging
debugCompilation: delvePort != "",
- subninjas: bootstrapGlobFileList(config),
primaryBuilderInvocations: invocations,
}
- // The glob ninja files are generated during the main build phase. However, the
- // primary buildifer invocation depends on all of its glob files, even before
- // it's been run. Generate a "empty" glob ninja file on the first run,
- // so that the files can be there to satisfy the dependency.
- for _, pb := range pbfs {
- globPathName := getGlobPathNameFromPrimaryBuilderFactory(config, pb)
- globNinjaFile := config.NamedGlobFile(globPathName)
- if _, err := os.Stat(globNinjaFile); os.IsNotExist(err) {
- err := bootstrap.WriteBuildGlobsNinjaFile(&bootstrap.GlobSingleton{
- GlobLister: func() pathtools.MultipleGlobResults { return nil },
- GlobFile: globNinjaFile,
- GlobDir: bootstrap.GlobDirectory(config.SoongOutDir(), globPathName),
- SrcDir: ".",
- }, blueprintConfig)
- if err != nil {
- ctx.Fatal(err)
- }
- } else if err != nil {
- ctx.Fatal(err)
- }
- }
-
// since `bootstrap.ninja` is regenerated unconditionally, we ignore the deps, i.e. little
// reason to write a `bootstrap.ninja.d` file
_, err := bootstrap.RunBlueprint(blueprintArgs, bootstrap.DoEverything, blueprintCtx, blueprintConfig)
+
+ result := status.ActionResult{
+ Action: action,
+ }
if err != nil {
- ctx.Fatal(err)
+ result.Error = err
+ result.Output = err.Error()
+ }
+ st.FinishAction(result)
+ if err != nil {
+ ctx.Fatalf("bootstrap failed")
}
}
@@ -461,13 +435,13 @@
}
}
-func updateSymlinks(ctx Context, dir, prevCWD, cwd string) error {
+func updateSymlinks(ctx Context, dir, prevCWD, cwd string, updateSemaphore chan struct{}) error {
defer symlinkWg.Done()
visit := func(path string, d fs.DirEntry, err error) error {
if d.IsDir() && path != dir {
symlinkWg.Add(1)
- go updateSymlinks(ctx, path, prevCWD, cwd)
+ go updateSymlinks(ctx, path, prevCWD, cwd, updateSemaphore)
return filepath.SkipDir
}
f, err := d.Info()
@@ -498,12 +472,27 @@
return nil
}
+ <-updateSemaphore
+ defer func() { updateSemaphore <- struct{}{} }()
if err := filepath.WalkDir(dir, visit); err != nil {
return err
}
return nil
}
+// b/376466642: If the concurrency of updateSymlinks is unbounded, Go's runtime spawns a
+// theoretically unbounded number of threads to handle blocking syscalls. This causes the runtime to
+// panic due to hitting thread limits in rare cases. Limiting to GOMAXPROCS concurrent symlink
+// updates should make this a non-issue.
+func newUpdateSemaphore() chan struct{} {
+ numPermits := runtime.GOMAXPROCS(0)
+ c := make(chan struct{}, numPermits)
+ for i := 0; i < numPermits; i++ {
+ c <- struct{}{}
+ }
+ return c
+}
+
func fixOutDirSymlinks(ctx Context, config Config, outDir string) error {
cwd, err := os.Getwd()
if err != nil {
@@ -514,7 +503,7 @@
tf := filepath.Join(outDir, ".top")
defer func() {
if err := os.WriteFile(tf, []byte(cwd), 0644); err != nil {
- fmt.Fprintf(os.Stderr, fmt.Sprintf("Unable to log CWD: %v", err))
+ fmt.Fprintf(os.Stderr, "Unable to log CWD: %v", err)
}
}()
@@ -536,7 +525,7 @@
}
symlinkWg.Add(1)
- if err := updateSymlinks(ctx, outDir, prevCWD, cwd); err != nil {
+ if err := updateSymlinks(ctx, outDir, prevCWD, cwd, newUpdateSemaphore()); err != nil {
return err
}
symlinkWg.Wait()
@@ -606,18 +595,11 @@
checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(jsonModuleGraphTag))
}
- if config.Queryview() {
- checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(queryviewTag))
- }
-
if config.SoongDocs() {
checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(soongDocsTag))
}
}()
- runMicrofactory(ctx, config, "bpglob", "github.com/google/blueprint/bootstrap/bpglob",
- map[string]string{"github.com/google/blueprint": "build/blueprint"})
-
ninja := func(targets ...string) {
ctx.BeginTrace(metrics.RunSoong, "bootstrap")
defer ctx.EndTrace()
@@ -626,19 +608,11 @@
nr := status.NewNinjaReader(ctx, ctx.Status.StartTool(), fifo)
defer nr.Close()
- ninjaArgs := []string{
- "-d", "keepdepfile",
- "-d", "stats",
- "-o", "usesphonyoutputs=yes",
- "-o", "preremoveoutputs=yes",
- "-w", "dupbuild=err",
- "-w", "outputdir=err",
- "-w", "missingoutfile=err",
- "-j", strconv.Itoa(config.Parallel()),
- "--frontend_file", fifo,
- "-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"),
- }
- if config.useN2 {
+ var ninjaCmd string
+ var ninjaArgs []string
+ switch config.ninjaCommand {
+ case NINJA_N2:
+ ninjaCmd = config.N2Bin()
ninjaArgs = []string{
// TODO: implement these features, or remove them.
//"-d", "keepdepfile",
@@ -653,6 +627,39 @@
"--frontend-file", fifo,
"-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"),
}
+ case NINJA_SISO:
+ ninjaCmd = config.SisoBin()
+ ninjaArgs = []string{
+ "ninja",
+ // TODO: implement these features, or remove them.
+ //"-d", "keepdepfile",
+ //"-d", "stats",
+ //"-o", "usesphonyoutputs=yes",
+ //"-o", "preremoveoutputs=yes",
+ //"-w", "dupbuild=err",
+ //"-w", "outputdir=err",
+ //"-w", "missingoutfile=err",
+ "-v",
+ "-j", strconv.Itoa(config.Parallel()),
+ //"--frontend-file", fifo,
+ "--log_dir", config.SoongOutDir(),
+ "-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"),
+ }
+ default:
+ // NINJA_NINJA is the default.
+ ninjaCmd = config.NinjaBin()
+ ninjaArgs = []string{
+ "-d", "keepdepfile",
+ "-d", "stats",
+ "-o", "usesphonyoutputs=yes",
+ "-o", "preremoveoutputs=yes",
+ "-w", "dupbuild=err",
+ "-w", "outputdir=err",
+ "-w", "missingoutfile=err",
+ "-j", strconv.Itoa(config.Parallel()),
+ "--frontend_file", fifo,
+ "-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"),
+ }
}
if extra, ok := config.Environment().Get("SOONG_UI_NINJA_ARGS"); ok {
@@ -661,10 +668,6 @@
}
ninjaArgs = append(ninjaArgs, targets...)
- ninjaCmd := config.NinjaBin()
- if config.useN2 {
- ninjaCmd = config.PrebuiltBuildTool("n2")
- }
cmd := Command(ctx, config, "soong bootstrap",
ninjaCmd, ninjaArgs...)
@@ -686,10 +689,6 @@
targets = append(targets, config.ModuleGraphFile())
}
- if config.Queryview() {
- targets = append(targets, config.QueryviewMarkerFile())
- }
-
if config.SoongDocs() {
targets = append(targets, config.SoongDocsHtml())
}
@@ -699,6 +698,12 @@
targets = append(targets, config.SoongNinjaFile())
}
+ for _, target := range targets {
+ if err := checkGlobs(ctx, target); err != nil {
+ ctx.Fatalf("Error checking globs: %s", err.Error())
+ }
+ }
+
beforeSoongTimestamp := time.Now()
ninja(targets...)
@@ -725,6 +730,174 @@
}
}
+// checkGlobs manages the globs that cause soong to rerun.
+//
+// When soong_build runs, it will run globs. It will write all the globs
+// it ran into the "{finalOutFile}.globs" file. Then every build,
+// soong_ui will check that file, rerun the globs, and if they changed
+// from the results that soong_build got, update the ".glob_results"
+// file, causing soong_build to rerun. The ".glob_results" file will
+// be empty on the first run of soong_build, because we don't know
+// what the globs are yet, but also remain empty until the globs change
+// so that we don't run soong_build a second time unnecessarily.
+// Both soong_build and soong_ui will also update a ".globs_time" file
+// with the time that they ran at every build. When soong_ui checks
+// globs, it only reruns globs whose dependencies are newer than the
+// time in the ".globs_time" file.
+func checkGlobs(ctx Context, finalOutFile string) error {
+ ctx.BeginTrace(metrics.RunSoong, "check_globs")
+ defer ctx.EndTrace()
+ st := ctx.Status.StartTool()
+ st.Status("Running globs...")
+ defer st.Finish()
+
+ globsFile, err := os.Open(finalOutFile + ".globs")
+ if errors.Is(err, fs.ErrNotExist) {
+ // if the glob file doesn't exist, make sure the glob_results file exists and is empty.
+ if err := os.MkdirAll(filepath.Dir(finalOutFile), 0777); err != nil {
+ return err
+ }
+ f, err := os.Create(finalOutFile + ".glob_results")
+ if err != nil {
+ return err
+ }
+ return f.Close()
+ } else if err != nil {
+ return err
+ }
+ defer globsFile.Close()
+ globsFileDecoder := json.NewDecoder(globsFile)
+
+ globsTimeBytes, err := os.ReadFile(finalOutFile + ".globs_time")
+ if err != nil {
+ return err
+ }
+ globsTimeMicros, err := strconv.ParseInt(strings.TrimSpace(string(globsTimeBytes)), 10, 64)
+ if err != nil {
+ return err
+ }
+ globCheckStartTime := time.Now().UnixMicro()
+
+ globsChan := make(chan pathtools.GlobResult)
+ errorsChan := make(chan error)
+ wg := sync.WaitGroup{}
+
+ hasChangedGlobs := false
+ var changedGlobNameMutex sync.Mutex
+ var changedGlobName string
+
+ for i := 0; i < runtime.NumCPU()*2; i++ {
+ wg.Add(1)
+ go func() {
+ for cachedGlob := range globsChan {
+ // If we've already determined we have changed globs, just finish consuming
+ // the channel without doing any more checks.
+ if hasChangedGlobs {
+ continue
+ }
+ // First, check if any of the deps are newer than the last time globs were checked.
+ // If not, we don't need to rerun the glob.
+ hasNewDep := false
+ for _, dep := range cachedGlob.Deps {
+ info, err := os.Stat(dep)
+ if errors.Is(err, fs.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) {
+ hasNewDep = true
+ break
+ } else if err != nil {
+ errorsChan <- err
+ continue
+ }
+ if info.ModTime().UnixMicro() > globsTimeMicros {
+ hasNewDep = true
+ break
+ }
+ }
+ if !hasNewDep {
+ continue
+ }
+
+ // Then rerun the glob and check if we got the same result as before.
+ result, err := pathtools.Glob(cachedGlob.Pattern, cachedGlob.Excludes, pathtools.FollowSymlinks)
+ if err != nil {
+ errorsChan <- err
+ } else {
+ if !slices.Equal(result.Matches, cachedGlob.Matches) {
+ hasChangedGlobs = true
+
+ changedGlobNameMutex.Lock()
+ defer changedGlobNameMutex.Unlock()
+ changedGlobName = result.Pattern
+ if len(result.Excludes) > 2 {
+ changedGlobName += fmt.Sprintf(" (excluding %d other patterns)", len(result.Excludes))
+ } else if len(result.Excludes) > 0 {
+ changedGlobName += " (excluding " + strings.Join(result.Excludes, " and ") + ")"
+ }
+ }
+ }
+ }
+ wg.Done()
+ }()
+ }
+ go func() {
+ wg.Wait()
+ close(errorsChan)
+ }()
+
+ errorsWg := sync.WaitGroup{}
+ errorsWg.Add(1)
+ var errFromGoRoutines error
+ go func() {
+ for result := range errorsChan {
+ if errFromGoRoutines == nil {
+ errFromGoRoutines = result
+ }
+ }
+ errorsWg.Done()
+ }()
+
+ var cachedGlob pathtools.GlobResult
+ for globsFileDecoder.More() {
+ if err := globsFileDecoder.Decode(&cachedGlob); err != nil {
+ return err
+ }
+ // Need to clone the GlobResult because the json decoder will
+ // reuse the same slice allocations.
+ globsChan <- cachedGlob.Clone()
+ }
+ close(globsChan)
+ errorsWg.Wait()
+ if errFromGoRoutines != nil {
+ return errFromGoRoutines
+ }
+
+ // Update the globs_time file whether or not we found changed globs,
+ // so that we don't rerun globs in the future that we just saw didn't change.
+ err = os.WriteFile(
+ finalOutFile+".globs_time",
+ []byte(fmt.Sprintf("%d\n", globCheckStartTime)),
+ 0666,
+ )
+ if err != nil {
+ return err
+ }
+
+ if hasChangedGlobs {
+ fmt.Fprintf(os.Stdout, "Globs changed, rerunning soong...\n")
+ fmt.Fprintf(os.Stdout, "One culprit glob (may be more): %s\n", changedGlobName)
+ // Write the current time to the glob_results file. We just need
+ // some unique value to trigger a rerun, it doesn't matter what it is.
+ err = os.WriteFile(
+ finalOutFile+".glob_results",
+ []byte(fmt.Sprintf("%d\n", globCheckStartTime)),
+ 0666,
+ )
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
// loadSoongBuildMetrics reads out/soong_build_metrics.pb if it was generated by soong_build and copies the
// events stored in it into the soong_ui trace to provide introspection into how long the different phases of
// soong_build are taking.
diff --git a/ui/build/source_inputs.go b/ui/build/source_inputs.go
new file mode 100644
index 0000000..d1cc1a2
--- /dev/null
+++ b/ui/build/source_inputs.go
@@ -0,0 +1,100 @@
+package build
+
+import (
+ "compress/gzip"
+ "fmt"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+
+ "android/soong/shared"
+ "android/soong/ui/metrics"
+)
+
+func sortedStringSetKeys(m map[string]bool) []string {
+ result := make([]string, 0, len(m))
+ for key := range m {
+ result = append(result, key)
+ }
+ sort.Strings(result)
+ return result
+}
+
+func addSlash(str string) string {
+ if len(str) == 0 {
+ return ""
+ }
+ if str[len(str)-1] == '/' {
+ return str
+ }
+ return str + "/"
+}
+
+func hasPrefixStrings(str string, prefixes []string) bool {
+ for _, prefix := range prefixes {
+ if strings.HasPrefix(str, prefix) {
+ return true
+ }
+ }
+ return false
+}
+
+// Output DIST_DIR/source_inputs.txt.gz, which will contain a listing of the files
+// in the source tree (not including in the out directory) that were declared as ninja
+// inputs to the build that was just done.
+func runSourceInputs(ctx Context, config Config) {
+ ctx.BeginTrace(metrics.RunSoong, "runSourceInputs")
+ defer ctx.EndTrace()
+
+ success := false
+ outputFilename := shared.JoinPath(config.RealDistDir(), "source_inputs.txt.gz")
+
+ outputFile, err := os.Create(outputFilename)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "source_files_used: unable to open file for write: %s\n", outputFilename)
+ return
+ }
+ defer func() {
+ outputFile.Close()
+ if !success {
+ os.Remove(outputFilename)
+ }
+ }()
+
+ output := gzip.NewWriter(outputFile)
+ defer output.Close()
+
+ // Skip out dir, both absolute and relative. There are some files
+ // generated during analysis that ninja thinks are inputs not intermediates.
+ absOut, _ := filepath.Abs(config.OutDir())
+ excludes := []string{
+ addSlash(config.OutDir()),
+ addSlash(absOut),
+ }
+
+ goals := config.NinjaArgs()
+
+ result := make(map[string]bool)
+ for _, goal := range goals {
+ inputs, err := runNinjaInputs(ctx, config, goal)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "source_files_used: %v\n", err)
+ return
+ }
+
+ for _, filename := range inputs {
+ if !hasPrefixStrings(filename, excludes) {
+ result[filename] = true
+ }
+ }
+ }
+
+ for _, filename := range sortedStringSetKeys(result) {
+ output.Write([]byte(filename))
+ output.Write([]byte("\n"))
+ }
+
+ output.Flush()
+ success = true
+}
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index 3faa94d..7a2fd16 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -79,9 +79,6 @@
// out/build_date.txt is considered a "source file"
buildDatetimeFilePath := filepath.Join(outDir, "build_date.txt")
- // bpglob is built explicitly using Microfactory
- bpglob := filepath.Join(config.SoongOutDir(), "bpglob")
-
// release-config files are generated from the initial lunch or Kati phase
// before running soong and ninja.
releaseConfigDir := filepath.Join(outDir, "soong", "release-config")
@@ -105,7 +102,6 @@
line == extraVariablesFilePath ||
line == dexpreoptConfigFilePath ||
line == buildDatetimeFilePath ||
- line == bpglob ||
strings.HasPrefix(line, releaseConfigDir) ||
buildFingerPrintFilePattern.MatchString(line) {
// Leaf node is in one of Soong's bootstrap directories, which do not have
@@ -155,7 +151,7 @@
ts.FinishAction(status.ActionResult{
Action: action,
- Error: fmt.Errorf(title),
+ Error: fmt.Errorf("%s", title),
Output: sb.String(),
})
ctx.Fatal("stopping")
diff --git a/cmd/multiproduct_kati/Android.bp b/ui/execution_metrics/Android.bp
similarity index 63%
rename from cmd/multiproduct_kati/Android.bp
rename to ui/execution_metrics/Android.bp
index 20ca2a3..542e550 100644
--- a/cmd/multiproduct_kati/Android.bp
+++ b/ui/execution_metrics/Android.bp
@@ -1,4 +1,4 @@
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -16,29 +16,20 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-blueprint_go_binary {
- name: "multiproduct_kati",
+bootstrap_go_package {
+ name: "soong-ui-execution-metrics",
+ pkgPath: "android/soong/ui/execution_metrics",
deps: [
+ "golang-protobuf-proto",
+ "soong-shared",
"soong-ui-logger",
- "soong-ui-signal",
- "soong-ui-terminal",
- "soong-ui-tracer",
- "soong-zip",
+ "soong-ui-execution_metrics_proto",
+ "soong-ui-metrics_proto",
+ "soong-cmd-find_input_delta-proto",
],
srcs: [
- "main.go",
+ "execution_metrics.go",
],
testSrcs: [
- "main_test.go",
],
- linux: {
- srcs: [
- "main_linux.go",
- ],
- },
- darwin: {
- srcs: [
- "main_darwin.go",
- ],
- },
}
diff --git a/ui/execution_metrics/execution_metrics.go b/ui/execution_metrics/execution_metrics.go
new file mode 100644
index 0000000..db78449
--- /dev/null
+++ b/ui/execution_metrics/execution_metrics.go
@@ -0,0 +1,279 @@
+// 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 execution_metrics represents the metrics system for Android Platform Build Systems.
+package execution_metrics
+
+// This is the main heart of the metrics system for Android Platform Build Systems.
+// The starting of the soong_ui (cmd/soong_ui/main.go), the metrics system is
+// initialized by the invocation of New and is then stored in the context
+// (ui/build/context.go) to be used throughout the system. During the build
+// initialization phase, several functions in this file are invoked to store
+// information such as the environment, build configuration and build metadata.
+// There are several scoped code that has Begin() and defer End() functions
+// that captures the metrics and is them added as a perfInfo into the set
+// of the collected metrics. Finally, when soong_ui has finished the build,
+// the defer Dump function is invoked to store the collected metrics to the
+// raw protobuf file in the $OUT directory and this raw protobuf file will be
+// uploaded to the destination. See ui/build/upload.go for more details. The
+// filename of the raw protobuf file and the list of files to be uploaded is
+// defined in cmd/soong_ui/main.go. See ui/metrics/event.go for the explanation
+// of what an event is and how the metrics system is a stack based system.
+
+import (
+ "context"
+ "io/fs"
+ "maps"
+ "os"
+ "path/filepath"
+ "slices"
+ "sync"
+
+ "android/soong/ui/logger"
+
+ fid_proto "android/soong/cmd/find_input_delta/find_input_delta_proto"
+ "android/soong/ui/metrics"
+ soong_execution_proto "android/soong/ui/metrics/execution_metrics_proto"
+ soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
+ "google.golang.org/protobuf/encoding/protowire"
+ "google.golang.org/protobuf/proto"
+)
+
+type ExecutionMetrics struct {
+ MetricsAggregationDir string
+ ctx context.Context
+ logger logger.Logger
+ waitGroup sync.WaitGroup
+ fileList *fileList
+}
+
+type fileList struct {
+ totalChanges uint32
+ changes fileChanges
+ seenFiles map[string]bool
+}
+
+type fileChanges struct {
+ additions changeInfo
+ deletions changeInfo
+ modifications changeInfo
+}
+
+type fileChangeCounts struct {
+ additions uint32
+ deletions uint32
+ modifications uint32
+}
+
+type changeInfo struct {
+ total uint32
+ list []string
+ byExtension map[string]uint32
+}
+
+var MAXIMUM_FILES uint32 = 50
+
+// Setup the handler for SoongExecutionMetrics.
+func NewExecutionMetrics(log logger.Logger) *ExecutionMetrics {
+ return &ExecutionMetrics{
+ logger: log,
+ fileList: &fileList{seenFiles: make(map[string]bool)},
+ }
+}
+
+// Save the path for ExecutionMetrics communications.
+func (c *ExecutionMetrics) SetDir(path string) {
+ c.MetricsAggregationDir = path
+}
+
+// Start collecting SoongExecutionMetrics.
+func (c *ExecutionMetrics) Start() {
+ if c.MetricsAggregationDir == "" {
+ return
+ }
+
+ tmpDir := c.MetricsAggregationDir + ".rm"
+ if _, err := fs.Stat(os.DirFS("."), c.MetricsAggregationDir); err == nil {
+ if err = os.RemoveAll(tmpDir); err != nil {
+ c.logger.Fatalf("Failed to remove %s: %v", tmpDir, err)
+ }
+ if err = os.Rename(c.MetricsAggregationDir, tmpDir); err != nil {
+ c.logger.Fatalf("Failed to rename %s to %s: %v", c.MetricsAggregationDir, tmpDir)
+ }
+ }
+ if err := os.MkdirAll(c.MetricsAggregationDir, 0777); err != nil {
+ c.logger.Fatalf("Failed to create %s: %v", c.MetricsAggregationDir)
+ }
+
+ c.waitGroup.Add(1)
+ go func(d string) {
+ defer c.waitGroup.Done()
+ os.RemoveAll(d)
+ }(tmpDir)
+
+ c.logger.Verbosef("ExecutionMetrics running\n")
+}
+
+type hasTrace interface {
+ BeginTrace(name, desc string)
+ EndTrace()
+}
+
+// Aggregate any execution metrics.
+func (c *ExecutionMetrics) Finish(ctx hasTrace) {
+ ctx.BeginTrace(metrics.RunSoong, "execution_metrics.Finish")
+ defer ctx.EndTrace()
+ if c.MetricsAggregationDir == "" {
+ return
+ }
+ c.waitGroup.Wait()
+
+ // Find and process all of the metrics files.
+ aggFs := os.DirFS(c.MetricsAggregationDir)
+ fs.WalkDir(aggFs, ".", func(path string, d fs.DirEntry, err error) error {
+ if err != nil {
+ c.logger.Fatalf("ExecutionMetrics.Finish: Error walking %s: %v", c.MetricsAggregationDir, err)
+ }
+ if d.IsDir() {
+ return nil
+ }
+ path = filepath.Join(c.MetricsAggregationDir, path)
+ r, err := os.ReadFile(path)
+ if err != nil {
+ c.logger.Fatalf("ExecutionMetrics.Finish: Failed to read %s: %v", path, err)
+ }
+ msg := &soong_execution_proto.SoongExecutionMetrics{}
+ err = proto.Unmarshal(r, msg)
+ if err != nil {
+ c.logger.Verbosef("ExecutionMetrics.Finish: Error unmarshalling SoongExecutionMetrics message: %v\n", err)
+ return nil
+ }
+ switch {
+ case msg.GetFileList() != nil:
+ if err := c.fileList.aggregateFileList(msg.GetFileList()); err != nil {
+ c.logger.Verbosef("ExecutionMetrics.Finish: Error processing SoongExecutionMetrics message: %v\n", err)
+ }
+ // Status update for all others.
+ default:
+ tag, _ := protowire.ConsumeVarint(r)
+ id, _ := protowire.DecodeTag(tag)
+ c.logger.Verbosef("ExecutionMetrics.Finish: Unexpected SoongExecutionMetrics submessage id=%d\n", id)
+ }
+ return nil
+ })
+}
+
+func (fl *fileList) aggregateFileList(msg *fid_proto.FileList) error {
+ fl.updateChangeInfo(msg.GetAdditions(), &fl.changes.additions)
+ fl.updateChangeInfo(msg.GetDeletions(), &fl.changes.deletions)
+ fl.updateChangeInfo(msg.GetChanges(), &fl.changes.modifications)
+ return nil
+}
+
+func (fl *fileList) updateChangeInfo(list []string, info *changeInfo) {
+ for _, filename := range list {
+ if fl.seenFiles[filename] {
+ continue
+ }
+ fl.seenFiles[filename] = true
+ if info.total < MAXIMUM_FILES {
+ info.list = append(info.list, filename)
+ }
+ ext := filepath.Ext(filename)
+ if info.byExtension == nil {
+ info.byExtension = make(map[string]uint32)
+ }
+ info.byExtension[ext] += 1
+ info.total += 1
+ fl.totalChanges += 1
+ }
+}
+
+func (c *ExecutionMetrics) Dump(path string, args []string) error {
+ if c.MetricsAggregationDir == "" {
+ return nil
+ }
+ msg := c.GetMetrics(args)
+
+ if _, err := os.Stat(filepath.Dir(path)); err != nil {
+ if err = os.MkdirAll(filepath.Dir(path), 0775); err != nil {
+ return err
+ }
+ }
+ data, err := proto.Marshal(msg)
+ if err != nil {
+ return err
+ }
+ return os.WriteFile(path, data, 0644)
+}
+
+func (c *ExecutionMetrics) GetMetrics(args []string) *soong_metrics_proto.ExecutionMetrics {
+ return &soong_metrics_proto.ExecutionMetrics{
+ CommandArgs: args,
+ ChangedFiles: c.getChangedFiles(),
+ }
+}
+
+func (c *ExecutionMetrics) getChangedFiles() *soong_metrics_proto.AggregatedFileList {
+ fl := c.fileList
+ if fl == nil {
+ return nil
+ }
+ var count uint32
+ fileCounts := make(map[string]*soong_metrics_proto.FileCount)
+ ret := &soong_metrics_proto.AggregatedFileList{TotalDelta: proto.Uint32(c.fileList.totalChanges)}
+
+ // MAXIMUM_FILES is the upper bound on total file names reported.
+ if limit := min(MAXIMUM_FILES-min(MAXIMUM_FILES, count), fl.changes.additions.total); limit > 0 {
+ ret.Additions = fl.changes.additions.list[:limit]
+ count += limit
+ }
+ if limit := min(MAXIMUM_FILES-min(MAXIMUM_FILES, count), fl.changes.modifications.total); limit > 0 {
+ ret.Changes = fl.changes.modifications.list[:limit]
+ count += limit
+ }
+ if limit := min(MAXIMUM_FILES-min(MAXIMUM_FILES, count), fl.changes.deletions.total); limit > 0 {
+ ret.Deletions = fl.changes.deletions.list[:limit]
+ count += limit
+ }
+
+ addExt := func(key string) *soong_metrics_proto.FileCount {
+ // Create the fileCounts map entry if needed, and return the address to the caller.
+ if _, ok := fileCounts[key]; !ok {
+ fileCounts[key] = &soong_metrics_proto.FileCount{Extension: proto.String(key)}
+ }
+ return fileCounts[key]
+ }
+ addCount := func(loc **uint32, count uint32) {
+ if *loc == nil {
+ *loc = proto.Uint32(0)
+ }
+ **loc += count
+ }
+ for k, v := range fl.changes.additions.byExtension {
+ addCount(&addExt(k).Additions, v)
+ }
+ for k, v := range fl.changes.modifications.byExtension {
+ addCount(&addExt(k).Modifications, v)
+ }
+ for k, v := range fl.changes.deletions.byExtension {
+ addCount(&addExt(k).Deletions, v)
+ }
+
+ keys := slices.Sorted(maps.Keys(fileCounts))
+ for _, k := range keys {
+ ret.Counts = append(ret.Counts, fileCounts[k])
+ }
+ return ret
+}
diff --git a/ui/execution_metrics/execution_metrics_test.go b/ui/execution_metrics/execution_metrics_test.go
new file mode 100644
index 0000000..28fa973
--- /dev/null
+++ b/ui/execution_metrics/execution_metrics_test.go
@@ -0,0 +1,63 @@
+// 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 execution_metrics represents the metrics system for Android Platform Build Systems.
+package execution_metrics
+
+import (
+ "reflect"
+ "testing"
+
+ fid_proto "android/soong/cmd/find_input_delta/find_input_delta_proto"
+)
+
+func TestUpdateChangeInfo(t *testing.T) {
+ testCases := []struct {
+ Name string
+ Message *fid_proto.FileList
+ FileList *fileList
+ Expected *fileList
+ }{
+ {
+ Name: "various",
+ Message: &fid_proto.FileList{
+ Additions: []string{"file1", "file2", "file3", "file2"},
+ Deletions: []string{"file5.go", "file6"},
+ },
+ FileList: &fileList{seenFiles: make(map[string]bool)},
+ Expected: &fileList{
+ seenFiles: map[string]bool{"file1": true, "file2": true, "file3": true, "file5.go": true, "file6": true},
+ totalChanges: 5,
+ changes: fileChanges{
+ additions: changeInfo{
+ total: 3,
+ list: []string{"file1", "file2", "file3"},
+ byExtension: map[string]uint32{"": 3},
+ },
+ deletions: changeInfo{
+ total: 2,
+ list: []string{"file5.go", "file6"},
+ byExtension: map[string]uint32{"": 1, ".go": 1},
+ },
+ },
+ },
+ },
+ }
+ for _, tc := range testCases {
+ tc.FileList.aggregateFileList(tc.Message)
+ if !reflect.DeepEqual(tc.FileList, tc.Expected) {
+ t.Errorf("Expected: %v, Actual: %v", tc.Expected, tc.FileList)
+ }
+ }
+}
diff --git a/ui/metrics/Android.bp b/ui/metrics/Android.bp
index bd1517c..2e19f7a 100644
--- a/ui/metrics/Android.bp
+++ b/ui/metrics/Android.bp
@@ -21,20 +21,34 @@
pkgPath: "android/soong/ui/metrics",
deps: [
"golang-protobuf-proto",
- "soong-ui-bp2build_metrics_proto",
- "soong-ui-bazel_metrics_proto",
+ "soong-finder-fs",
"soong-ui-metrics_upload_proto",
"soong-ui-metrics_proto",
"soong-ui-mk_metrics_proto",
"soong-shared",
+ "soong-ui-execution_metrics_proto",
],
srcs: [
+ "hostinfo.go",
"metrics.go",
"event.go",
],
testSrcs: [
"event_test.go",
],
+ linux: {
+ srcs: [
+ "hostinfo_linux.go",
+ ],
+ testSrcs: [
+ "hostinfo_linux_test.go",
+ ],
+ },
+ darwin: {
+ srcs: [
+ "hostinfo_darwin.go",
+ ],
+ },
}
bootstrap_go_package {
@@ -50,6 +64,19 @@
}
bootstrap_go_package {
+ name: "soong-ui-execution_metrics_proto",
+ pkgPath: "android/soong/ui/metrics/execution_metrics_proto",
+ deps: [
+ "golang-protobuf-reflect-protoreflect",
+ "golang-protobuf-runtime-protoimpl",
+ "soong-cmd-find_input_delta-proto",
+ ],
+ srcs: [
+ "execution_metrics_proto/execution_metrics.pb.go",
+ ],
+}
+
+bootstrap_go_package {
name: "soong-ui-metrics_upload_proto",
pkgPath: "android/soong/ui/metrics/upload_proto",
deps: [
@@ -62,30 +89,6 @@
}
bootstrap_go_package {
- name: "soong-ui-bp2build_metrics_proto",
- pkgPath: "android/soong/ui/metrics/bp2build_metrics_proto",
- deps: [
- "golang-protobuf-reflect-protoreflect",
- "golang-protobuf-runtime-protoimpl",
- ],
- srcs: [
- "bp2build_metrics_proto/bp2build_metrics.pb.go",
- ],
-}
-
-bootstrap_go_package {
- name: "soong-ui-bazel_metrics_proto",
- pkgPath: "android/soong/ui/metrics/bazel_metrics_proto",
- deps: [
- "golang-protobuf-reflect-protoreflect",
- "golang-protobuf-runtime-protoimpl",
- ],
- srcs: [
- "bazel_metrics_proto/bazel_metrics.pb.go",
- ],
-}
-
-bootstrap_go_package {
name: "soong-ui-mk_metrics_proto",
pkgPath: "android/soong/ui/metrics/mk_metrics_proto",
deps: [
diff --git a/ui/metrics/BUILD.bazel b/ui/metrics/BUILD.bazel
deleted file mode 100644
index ca39c59..0000000
--- a/ui/metrics/BUILD.bazel
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2023 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-load("//build/bazel/rules/python:py_proto.bzl", "py_proto_library")
-
-py_proto_library(
- name = "metrics-py-proto",
- visibility = ["//build/bazel/scripts:__subpackages__"],
- deps = [":metrics-proto"],
-)
-
-proto_library(
- name = "metrics-proto",
- srcs = [
- "bazel_metrics_proto/bazel_metrics.proto",
- "bp2build_metrics_proto/bp2build_metrics.proto",
- "metrics_proto/metrics.proto",
- ],
- strip_import_prefix = "",
-)
diff --git a/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go b/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go
deleted file mode 100644
index 8b97b83..0000000
--- a/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go
+++ /dev/null
@@ -1,290 +0,0 @@
-// Copyright 2022 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.30.0
-// protoc v3.21.12
-// source: bazel_metrics.proto
-
-package bazel_metrics_proto
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type BazelMetrics struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- PhaseTimings []*PhaseTiming `protobuf:"bytes,1,rep,name=phase_timings,json=phaseTimings,proto3" json:"phase_timings,omitempty"`
- Total *int64 `protobuf:"varint,2,opt,name=total,proto3,oneof" json:"total,omitempty"`
- ExitCode *int32 `protobuf:"varint,3,opt,name=exit_code,json=exitCode,proto3,oneof" json:"exit_code,omitempty"`
- BesId *string `protobuf:"bytes,4,opt,name=bes_id,json=besId,proto3,oneof" json:"bes_id,omitempty"`
-}
-
-func (x *BazelMetrics) Reset() {
- *x = BazelMetrics{}
- if protoimpl.UnsafeEnabled {
- mi := &file_bazel_metrics_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *BazelMetrics) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*BazelMetrics) ProtoMessage() {}
-
-func (x *BazelMetrics) ProtoReflect() protoreflect.Message {
- mi := &file_bazel_metrics_proto_msgTypes[0]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use BazelMetrics.ProtoReflect.Descriptor instead.
-func (*BazelMetrics) Descriptor() ([]byte, []int) {
- return file_bazel_metrics_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *BazelMetrics) GetPhaseTimings() []*PhaseTiming {
- if x != nil {
- return x.PhaseTimings
- }
- return nil
-}
-
-func (x *BazelMetrics) GetTotal() int64 {
- if x != nil && x.Total != nil {
- return *x.Total
- }
- return 0
-}
-
-func (x *BazelMetrics) GetExitCode() int32 {
- if x != nil && x.ExitCode != nil {
- return *x.ExitCode
- }
- return 0
-}
-
-func (x *BazelMetrics) GetBesId() string {
- if x != nil && x.BesId != nil {
- return *x.BesId
- }
- return ""
-}
-
-type PhaseTiming struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // E.g. "execution", "analysis", "launch"
- PhaseName *string `protobuf:"bytes,1,opt,name=phase_name,json=phaseName,proto3,oneof" json:"phase_name,omitempty"`
- DurationNanos *int64 `protobuf:"varint,2,opt,name=duration_nanos,json=durationNanos,proto3,oneof" json:"duration_nanos,omitempty"`
- // What portion of the build time this phase took, with ten-thousandths precision.
- // E.g., 1111 = 11.11%, 111 = 1.11%
- PortionOfBuildTime *int32 `protobuf:"varint,3,opt,name=portion_of_build_time,json=portionOfBuildTime,proto3,oneof" json:"portion_of_build_time,omitempty"`
-}
-
-func (x *PhaseTiming) Reset() {
- *x = PhaseTiming{}
- if protoimpl.UnsafeEnabled {
- mi := &file_bazel_metrics_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *PhaseTiming) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*PhaseTiming) ProtoMessage() {}
-
-func (x *PhaseTiming) ProtoReflect() protoreflect.Message {
- mi := &file_bazel_metrics_proto_msgTypes[1]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use PhaseTiming.ProtoReflect.Descriptor instead.
-func (*PhaseTiming) Descriptor() ([]byte, []int) {
- return file_bazel_metrics_proto_rawDescGZIP(), []int{1}
-}
-
-func (x *PhaseTiming) GetPhaseName() string {
- if x != nil && x.PhaseName != nil {
- return *x.PhaseName
- }
- return ""
-}
-
-func (x *PhaseTiming) GetDurationNanos() int64 {
- if x != nil && x.DurationNanos != nil {
- return *x.DurationNanos
- }
- return 0
-}
-
-func (x *PhaseTiming) GetPortionOfBuildTime() int32 {
- if x != nil && x.PortionOfBuildTime != nil {
- return *x.PortionOfBuildTime
- }
- return 0
-}
-
-var File_bazel_metrics_proto protoreflect.FileDescriptor
-
-var file_bazel_metrics_proto_rawDesc = []byte{
- 0x0a, 0x13, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69,
- 0x6c, 0x64, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
- 0x22, 0xd7, 0x01, 0x0a, 0x0c, 0x42, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
- 0x73, 0x12, 0x4b, 0x0a, 0x0d, 0x70, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x69, 0x6e,
- 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67,
- 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74,
- 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67,
- 0x52, 0x0c, 0x70, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x19,
- 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52,
- 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x65, 0x78, 0x69,
- 0x74, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x48, 0x01, 0x52, 0x08,
- 0x65, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x88, 0x01, 0x01, 0x12, 0x1a, 0x0a, 0x06, 0x62,
- 0x65, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x05, 0x62,
- 0x65, 0x73, 0x49, 0x64, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x74, 0x6f, 0x74, 0x61,
- 0x6c, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x42,
- 0x09, 0x0a, 0x07, 0x5f, 0x62, 0x65, 0x73, 0x5f, 0x69, 0x64, 0x22, 0xd1, 0x01, 0x0a, 0x0b, 0x50,
- 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x12, 0x22, 0x0a, 0x0a, 0x70, 0x68,
- 0x61, 0x73, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00,
- 0x52, 0x09, 0x70, 0x68, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2a,
- 0x0a, 0x0e, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73,
- 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x0d, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x15, 0x70, 0x6f,
- 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x66, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x74,
- 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x48, 0x02, 0x52, 0x12, 0x70, 0x6f, 0x72,
- 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x66, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x88,
- 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x70, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x6e, 0x61, 0x6d,
- 0x65, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e,
- 0x61, 0x6e, 0x6f, 0x73, 0x42, 0x18, 0x0a, 0x16, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e,
- 0x5f, 0x6f, 0x66, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x42, 0x2e,
- 0x5a, 0x2c, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f,
- 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x62, 0x61, 0x7a, 0x65, 0x6c,
- 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
-}
-
-var (
- file_bazel_metrics_proto_rawDescOnce sync.Once
- file_bazel_metrics_proto_rawDescData = file_bazel_metrics_proto_rawDesc
-)
-
-func file_bazel_metrics_proto_rawDescGZIP() []byte {
- file_bazel_metrics_proto_rawDescOnce.Do(func() {
- file_bazel_metrics_proto_rawDescData = protoimpl.X.CompressGZIP(file_bazel_metrics_proto_rawDescData)
- })
- return file_bazel_metrics_proto_rawDescData
-}
-
-var file_bazel_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
-var file_bazel_metrics_proto_goTypes = []interface{}{
- (*BazelMetrics)(nil), // 0: soong_build_bazel_metrics.BazelMetrics
- (*PhaseTiming)(nil), // 1: soong_build_bazel_metrics.PhaseTiming
-}
-var file_bazel_metrics_proto_depIdxs = []int32{
- 1, // 0: soong_build_bazel_metrics.BazelMetrics.phase_timings:type_name -> soong_build_bazel_metrics.PhaseTiming
- 1, // [1:1] is the sub-list for method output_type
- 1, // [1:1] is the sub-list for method input_type
- 1, // [1:1] is the sub-list for extension type_name
- 1, // [1:1] is the sub-list for extension extendee
- 0, // [0:1] is the sub-list for field type_name
-}
-
-func init() { file_bazel_metrics_proto_init() }
-func file_bazel_metrics_proto_init() {
- if File_bazel_metrics_proto != nil {
- return
- }
- if !protoimpl.UnsafeEnabled {
- file_bazel_metrics_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*BazelMetrics); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_bazel_metrics_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*PhaseTiming); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- }
- file_bazel_metrics_proto_msgTypes[0].OneofWrappers = []interface{}{}
- file_bazel_metrics_proto_msgTypes[1].OneofWrappers = []interface{}{}
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: file_bazel_metrics_proto_rawDesc,
- NumEnums: 0,
- NumMessages: 2,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_bazel_metrics_proto_goTypes,
- DependencyIndexes: file_bazel_metrics_proto_depIdxs,
- MessageInfos: file_bazel_metrics_proto_msgTypes,
- }.Build()
- File_bazel_metrics_proto = out.File
- file_bazel_metrics_proto_rawDesc = nil
- file_bazel_metrics_proto_goTypes = nil
- file_bazel_metrics_proto_depIdxs = nil
-}
diff --git a/ui/metrics/bazel_metrics_proto/bazel_metrics.proto b/ui/metrics/bazel_metrics_proto/bazel_metrics.proto
deleted file mode 100644
index e45d2bf..0000000
--- a/ui/metrics/bazel_metrics_proto/bazel_metrics.proto
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2022 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-syntax = "proto3";
-
-package soong_build_bazel_metrics;
-option go_package = "android/soong/ui/metrics/bazel_metrics_proto";
-
-message BazelMetrics {
- repeated PhaseTiming phase_timings = 1;
- optional int64 total = 2;
- optional int32 exit_code = 3;
- optional string bes_id = 4;
-}
-
-message PhaseTiming {
- // E.g. "execution", "analysis", "launch"
- optional string phase_name = 1;
- optional int64 duration_nanos = 2;
- // What portion of the build time this phase took, with ten-thousandths precision.
- // E.g., 1111 = 11.11%, 111 = 1.11%
- optional int32 portion_of_build_time = 3;
-}
diff --git a/ui/metrics/bazel_metrics_proto/regen.sh b/ui/metrics/bazel_metrics_proto/regen.sh
deleted file mode 100755
index 2cf2bf6..0000000
--- a/ui/metrics/bazel_metrics_proto/regen.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/bash -e
-
-# Copyright 2022 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Generates the golang source file of bp2build_metrics.proto protobuf file.
-
-function die() { echo "ERROR: $1" >&2; exit 1; }
-
-readonly error_msg="Maybe you need to run 'lunch aosp_arm-eng && m aprotoc blueprint_tools'?"
-
-if ! hash aprotoc &>/dev/null; then
- die "could not find aprotoc. ${error_msg}"
-fi
-
-if ! aprotoc --go_out=paths=source_relative:. bazel_metrics.proto; then
- die "build failed. ${error_msg}"
-fi
diff --git a/ui/metrics/bp2build_metrics_proto/bp2build_metrics.pb.go b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.pb.go
deleted file mode 100644
index b34c2b6..0000000
--- a/ui/metrics/bp2build_metrics_proto/bp2build_metrics.pb.go
+++ /dev/null
@@ -1,590 +0,0 @@
-// Copyright 2021 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.30.0
-// protoc v3.21.12
-// source: bp2build_metrics.proto
-
-package bp2build_metrics_proto
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type UnconvertedReasonType int32
-
-const (
- // Bp2build does not know how to convert this specific module for some reason
- // not covered by other reason types. The reason detail should explain the
- // specific issue.
- UnconvertedReasonType_UNSUPPORTED UnconvertedReasonType = 0
- // The module was already defined in a BUILD file available in the source tree.
- UnconvertedReasonType_DEFINED_IN_BUILD_FILE UnconvertedReasonType = 1
- // The module was explicitly denylisted by name.
- UnconvertedReasonType_DENYLISTED UnconvertedReasonType = 2
- // The module's type has no bp2build implementation.
- UnconvertedReasonType_TYPE_UNSUPPORTED UnconvertedReasonType = 3
- // The module has a property not yet supported. The detail field should
- // name the unsupported property name.
- UnconvertedReasonType_PROPERTY_UNSUPPORTED UnconvertedReasonType = 4
- // The module has an unconverted dependency. The detail should consist of
- // the name of the unconverted module.
- UnconvertedReasonType_UNCONVERTED_DEP UnconvertedReasonType = 5
- // The module has a source file with the same name as the module itself.
- UnconvertedReasonType_SRC_NAME_COLLISION UnconvertedReasonType = 6
-)
-
-// Enum value maps for UnconvertedReasonType.
-var (
- UnconvertedReasonType_name = map[int32]string{
- 0: "UNSUPPORTED",
- 1: "DEFINED_IN_BUILD_FILE",
- 2: "DENYLISTED",
- 3: "TYPE_UNSUPPORTED",
- 4: "PROPERTY_UNSUPPORTED",
- 5: "UNCONVERTED_DEP",
- 6: "SRC_NAME_COLLISION",
- }
- UnconvertedReasonType_value = map[string]int32{
- "UNSUPPORTED": 0,
- "DEFINED_IN_BUILD_FILE": 1,
- "DENYLISTED": 2,
- "TYPE_UNSUPPORTED": 3,
- "PROPERTY_UNSUPPORTED": 4,
- "UNCONVERTED_DEP": 5,
- "SRC_NAME_COLLISION": 6,
- }
-)
-
-func (x UnconvertedReasonType) Enum() *UnconvertedReasonType {
- p := new(UnconvertedReasonType)
- *p = x
- return p
-}
-
-func (x UnconvertedReasonType) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (UnconvertedReasonType) Descriptor() protoreflect.EnumDescriptor {
- return file_bp2build_metrics_proto_enumTypes[0].Descriptor()
-}
-
-func (UnconvertedReasonType) Type() protoreflect.EnumType {
- return &file_bp2build_metrics_proto_enumTypes[0]
-}
-
-func (x UnconvertedReasonType) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Use UnconvertedReasonType.Descriptor instead.
-func (UnconvertedReasonType) EnumDescriptor() ([]byte, []int) {
- return file_bp2build_metrics_proto_rawDescGZIP(), []int{0}
-}
-
-type Bp2BuildMetrics struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // Total number of Soong modules converted to generated targets
- GeneratedModuleCount uint64 `protobuf:"varint,1,opt,name=generatedModuleCount,proto3" json:"generatedModuleCount,omitempty"`
- // Total number of Soong modules converted to handcrafted targets
- HandCraftedModuleCount uint64 `protobuf:"varint,2,opt,name=handCraftedModuleCount,proto3" json:"handCraftedModuleCount,omitempty"`
- // Total number of unconverted Soong modules
- UnconvertedModuleCount uint64 `protobuf:"varint,3,opt,name=unconvertedModuleCount,proto3" json:"unconvertedModuleCount,omitempty"`
- // Counts of symlinks in synthetic bazel workspace
- WorkspaceSymlinkCount uint64 `protobuf:"varint,9,opt,name=workspaceSymlinkCount,proto3" json:"workspaceSymlinkCount,omitempty"`
- // Counts of mkdir calls during creation of synthetic bazel workspace
- WorkspaceMkDirCount uint64 `protobuf:"varint,10,opt,name=workspaceMkDirCount,proto3" json:"workspaceMkDirCount,omitempty"`
- // Counts of generated Bazel targets per Bazel rule class
- RuleClassCount map[string]uint64 `protobuf:"bytes,4,rep,name=ruleClassCount,proto3" json:"ruleClassCount,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
- // List of converted modules
- ConvertedModules []string `protobuf:"bytes,5,rep,name=convertedModules,proto3" json:"convertedModules,omitempty"`
- // Unconverted modules, mapped to the reason the module was not converted.
- UnconvertedModules map[string]*UnconvertedReason `protobuf:"bytes,11,rep,name=unconvertedModules,proto3" json:"unconvertedModules,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
- // Counts of converted modules by module type.
- ConvertedModuleTypeCount map[string]uint64 `protobuf:"bytes,6,rep,name=convertedModuleTypeCount,proto3" json:"convertedModuleTypeCount,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
- // Counts of total modules by module type.
- TotalModuleTypeCount map[string]uint64 `protobuf:"bytes,7,rep,name=totalModuleTypeCount,proto3" json:"totalModuleTypeCount,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
- // List of traced runtime events of bp2build, useful for tracking bp2build
- // runtime.
- Events []*Event `protobuf:"bytes,8,rep,name=events,proto3" json:"events,omitempty"`
-}
-
-func (x *Bp2BuildMetrics) Reset() {
- *x = Bp2BuildMetrics{}
- if protoimpl.UnsafeEnabled {
- mi := &file_bp2build_metrics_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *Bp2BuildMetrics) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Bp2BuildMetrics) ProtoMessage() {}
-
-func (x *Bp2BuildMetrics) ProtoReflect() protoreflect.Message {
- mi := &file_bp2build_metrics_proto_msgTypes[0]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use Bp2BuildMetrics.ProtoReflect.Descriptor instead.
-func (*Bp2BuildMetrics) Descriptor() ([]byte, []int) {
- return file_bp2build_metrics_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *Bp2BuildMetrics) GetGeneratedModuleCount() uint64 {
- if x != nil {
- return x.GeneratedModuleCount
- }
- return 0
-}
-
-func (x *Bp2BuildMetrics) GetHandCraftedModuleCount() uint64 {
- if x != nil {
- return x.HandCraftedModuleCount
- }
- return 0
-}
-
-func (x *Bp2BuildMetrics) GetUnconvertedModuleCount() uint64 {
- if x != nil {
- return x.UnconvertedModuleCount
- }
- return 0
-}
-
-func (x *Bp2BuildMetrics) GetWorkspaceSymlinkCount() uint64 {
- if x != nil {
- return x.WorkspaceSymlinkCount
- }
- return 0
-}
-
-func (x *Bp2BuildMetrics) GetWorkspaceMkDirCount() uint64 {
- if x != nil {
- return x.WorkspaceMkDirCount
- }
- return 0
-}
-
-func (x *Bp2BuildMetrics) GetRuleClassCount() map[string]uint64 {
- if x != nil {
- return x.RuleClassCount
- }
- return nil
-}
-
-func (x *Bp2BuildMetrics) GetConvertedModules() []string {
- if x != nil {
- return x.ConvertedModules
- }
- return nil
-}
-
-func (x *Bp2BuildMetrics) GetUnconvertedModules() map[string]*UnconvertedReason {
- if x != nil {
- return x.UnconvertedModules
- }
- return nil
-}
-
-func (x *Bp2BuildMetrics) GetConvertedModuleTypeCount() map[string]uint64 {
- if x != nil {
- return x.ConvertedModuleTypeCount
- }
- return nil
-}
-
-func (x *Bp2BuildMetrics) GetTotalModuleTypeCount() map[string]uint64 {
- if x != nil {
- return x.TotalModuleTypeCount
- }
- return nil
-}
-
-func (x *Bp2BuildMetrics) GetEvents() []*Event {
- if x != nil {
- return x.Events
- }
- return nil
-}
-
-// Traced runtime event of bp2build.
-type Event struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // The event name.
- Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
- // The absolute start time of the event
- // The number of nanoseconds elapsed since January 1, 1970 UTC.
- StartTime uint64 `protobuf:"varint,2,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"`
- // The real running time.
- // The number of nanoseconds elapsed since start_time.
- RealTime uint64 `protobuf:"varint,3,opt,name=real_time,json=realTime,proto3" json:"real_time,omitempty"`
-}
-
-func (x *Event) Reset() {
- *x = Event{}
- if protoimpl.UnsafeEnabled {
- mi := &file_bp2build_metrics_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *Event) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Event) ProtoMessage() {}
-
-func (x *Event) ProtoReflect() protoreflect.Message {
- mi := &file_bp2build_metrics_proto_msgTypes[1]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use Event.ProtoReflect.Descriptor instead.
-func (*Event) Descriptor() ([]byte, []int) {
- return file_bp2build_metrics_proto_rawDescGZIP(), []int{1}
-}
-
-func (x *Event) GetName() string {
- if x != nil {
- return x.Name
- }
- return ""
-}
-
-func (x *Event) GetStartTime() uint64 {
- if x != nil {
- return x.StartTime
- }
- return 0
-}
-
-func (x *Event) GetRealTime() uint64 {
- if x != nil {
- return x.RealTime
- }
- return 0
-}
-
-type UnconvertedReason struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // The type of reason that the module could not be converted.
- Type UnconvertedReasonType `protobuf:"varint,1,opt,name=type,proto3,enum=soong_build_bp2build_metrics.UnconvertedReasonType" json:"type,omitempty"`
- // Descriptive details describing why the module could not be converted.
- // This detail should be kept very short and should be in the context of
- // the type. (Otherwise, this would significantly bloat metrics.)
- Detail string `protobuf:"bytes,2,opt,name=detail,proto3" json:"detail,omitempty"`
-}
-
-func (x *UnconvertedReason) Reset() {
- *x = UnconvertedReason{}
- if protoimpl.UnsafeEnabled {
- mi := &file_bp2build_metrics_proto_msgTypes[2]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *UnconvertedReason) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*UnconvertedReason) ProtoMessage() {}
-
-func (x *UnconvertedReason) ProtoReflect() protoreflect.Message {
- mi := &file_bp2build_metrics_proto_msgTypes[2]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use UnconvertedReason.ProtoReflect.Descriptor instead.
-func (*UnconvertedReason) Descriptor() ([]byte, []int) {
- return file_bp2build_metrics_proto_rawDescGZIP(), []int{2}
-}
-
-func (x *UnconvertedReason) GetType() UnconvertedReasonType {
- if x != nil {
- return x.Type
- }
- return UnconvertedReasonType_UNSUPPORTED
-}
-
-func (x *UnconvertedReason) GetDetail() string {
- if x != nil {
- return x.Detail
- }
- return ""
-}
-
-var File_bp2build_metrics_proto protoreflect.FileDescriptor
-
-var file_bp2build_metrics_proto_rawDesc = []byte{
- 0x0a, 0x16, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
- 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
- 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d,
- 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0xc0, 0x09, 0x0a, 0x0f, 0x42, 0x70, 0x32, 0x42, 0x75,
- 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x67, 0x65,
- 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x75,
- 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x14, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61,
- 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x36,
- 0x0a, 0x16, 0x68, 0x61, 0x6e, 0x64, 0x43, 0x72, 0x61, 0x66, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64,
- 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16,
- 0x68, 0x61, 0x6e, 0x64, 0x43, 0x72, 0x61, 0x66, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c,
- 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x36, 0x0a, 0x16, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x76,
- 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74,
- 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72,
- 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x34,
- 0x0a, 0x15, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x79, 0x6d, 0x6c, 0x69,
- 0x6e, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x77,
- 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x43,
- 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63,
- 0x65, 0x4d, 0x6b, 0x44, 0x69, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28,
- 0x04, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4d, 0x6b, 0x44, 0x69,
- 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x69, 0x0a, 0x0e, 0x72, 0x75, 0x6c, 0x65, 0x43, 0x6c,
- 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41,
- 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32,
- 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x70,
- 0x32, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x52, 0x75,
- 0x6c, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72,
- 0x79, 0x52, 0x0e, 0x72, 0x75, 0x6c, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e,
- 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f,
- 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x63, 0x6f, 0x6e,
- 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x75, 0x0a,
- 0x12, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75,
- 0x6c, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x73, 0x6f, 0x6f, 0x6e,
- 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64,
- 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x70, 0x32, 0x42, 0x75, 0x69, 0x6c,
- 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65,
- 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
- 0x52, 0x12, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64,
- 0x75, 0x6c, 0x65, 0x73, 0x12, 0x87, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74,
- 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e,
- 0x74, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x4b, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
- 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d,
- 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x70, 0x32, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d,
- 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64,
- 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45,
- 0x6e, 0x74, 0x72, 0x79, 0x52, 0x18, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d,
- 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x7b,
- 0x0a, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70,
- 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x47, 0x2e, 0x73,
- 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75,
- 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x70, 0x32, 0x42,
- 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x54, 0x6f, 0x74, 0x61,
- 0x6c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74,
- 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x75,
- 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x06, 0x65,
- 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x6f,
- 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69,
- 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74,
- 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x41, 0x0a, 0x13, 0x52, 0x75, 0x6c, 0x65,
- 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
- 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
- 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
- 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x76, 0x0a, 0x17, 0x55,
- 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
- 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x45, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
- 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
- 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d,
- 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74,
- 0x65, 0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
- 0x02, 0x38, 0x01, 0x1a, 0x4b, 0x0a, 0x1d, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64,
- 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45,
- 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
- 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
- 0x1a, 0x47, 0x0a, 0x19, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54,
- 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
- 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
- 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05,
- 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x57, 0x0a, 0x05, 0x45, 0x76, 0x65,
- 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f,
- 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72,
- 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x69,
- 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x65, 0x61, 0x6c, 0x54, 0x69,
- 0x6d, 0x65, 0x22, 0x74, 0x0a, 0x11, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65,
- 0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x33, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
- 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74,
- 0x72, 0x69, 0x63, 0x73, 0x2e, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64,
- 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
- 0x12, 0x16, 0x0a, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x2a, 0xb0, 0x01, 0x0a, 0x15, 0x55, 0x6e, 0x63,
- 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x54, 0x79,
- 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45,
- 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45, 0x44, 0x5f, 0x49,
- 0x4e, 0x5f, 0x42, 0x55, 0x49, 0x4c, 0x44, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x0e,
- 0x0a, 0x0a, 0x44, 0x45, 0x4e, 0x59, 0x4c, 0x49, 0x53, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x14,
- 0x0a, 0x10, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54,
- 0x45, 0x44, 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, 0x50, 0x52, 0x4f, 0x50, 0x45, 0x52, 0x54, 0x59,
- 0x5f, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x04, 0x12, 0x13,
- 0x0a, 0x0f, 0x55, 0x4e, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x54, 0x45, 0x44, 0x5f, 0x44, 0x45,
- 0x50, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x52, 0x43, 0x5f, 0x4e, 0x41, 0x4d, 0x45, 0x5f,
- 0x43, 0x4f, 0x4c, 0x4c, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x06, 0x42, 0x31, 0x5a, 0x2f, 0x61,
- 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f,
- 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64,
- 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
-}
-
-var (
- file_bp2build_metrics_proto_rawDescOnce sync.Once
- file_bp2build_metrics_proto_rawDescData = file_bp2build_metrics_proto_rawDesc
-)
-
-func file_bp2build_metrics_proto_rawDescGZIP() []byte {
- file_bp2build_metrics_proto_rawDescOnce.Do(func() {
- file_bp2build_metrics_proto_rawDescData = protoimpl.X.CompressGZIP(file_bp2build_metrics_proto_rawDescData)
- })
- return file_bp2build_metrics_proto_rawDescData
-}
-
-var file_bp2build_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
-var file_bp2build_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
-var file_bp2build_metrics_proto_goTypes = []interface{}{
- (UnconvertedReasonType)(0), // 0: soong_build_bp2build_metrics.UnconvertedReasonType
- (*Bp2BuildMetrics)(nil), // 1: soong_build_bp2build_metrics.Bp2BuildMetrics
- (*Event)(nil), // 2: soong_build_bp2build_metrics.Event
- (*UnconvertedReason)(nil), // 3: soong_build_bp2build_metrics.UnconvertedReason
- nil, // 4: soong_build_bp2build_metrics.Bp2BuildMetrics.RuleClassCountEntry
- nil, // 5: soong_build_bp2build_metrics.Bp2BuildMetrics.UnconvertedModulesEntry
- nil, // 6: soong_build_bp2build_metrics.Bp2BuildMetrics.ConvertedModuleTypeCountEntry
- nil, // 7: soong_build_bp2build_metrics.Bp2BuildMetrics.TotalModuleTypeCountEntry
-}
-var file_bp2build_metrics_proto_depIdxs = []int32{
- 4, // 0: soong_build_bp2build_metrics.Bp2BuildMetrics.ruleClassCount:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.RuleClassCountEntry
- 5, // 1: soong_build_bp2build_metrics.Bp2BuildMetrics.unconvertedModules:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.UnconvertedModulesEntry
- 6, // 2: soong_build_bp2build_metrics.Bp2BuildMetrics.convertedModuleTypeCount:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.ConvertedModuleTypeCountEntry
- 7, // 3: soong_build_bp2build_metrics.Bp2BuildMetrics.totalModuleTypeCount:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.TotalModuleTypeCountEntry
- 2, // 4: soong_build_bp2build_metrics.Bp2BuildMetrics.events:type_name -> soong_build_bp2build_metrics.Event
- 0, // 5: soong_build_bp2build_metrics.UnconvertedReason.type:type_name -> soong_build_bp2build_metrics.UnconvertedReasonType
- 3, // 6: soong_build_bp2build_metrics.Bp2BuildMetrics.UnconvertedModulesEntry.value:type_name -> soong_build_bp2build_metrics.UnconvertedReason
- 7, // [7:7] is the sub-list for method output_type
- 7, // [7:7] is the sub-list for method input_type
- 7, // [7:7] is the sub-list for extension type_name
- 7, // [7:7] is the sub-list for extension extendee
- 0, // [0:7] is the sub-list for field type_name
-}
-
-func init() { file_bp2build_metrics_proto_init() }
-func file_bp2build_metrics_proto_init() {
- if File_bp2build_metrics_proto != nil {
- return
- }
- if !protoimpl.UnsafeEnabled {
- file_bp2build_metrics_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*Bp2BuildMetrics); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_bp2build_metrics_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*Event); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_bp2build_metrics_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*UnconvertedReason); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: file_bp2build_metrics_proto_rawDesc,
- NumEnums: 1,
- NumMessages: 7,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_bp2build_metrics_proto_goTypes,
- DependencyIndexes: file_bp2build_metrics_proto_depIdxs,
- EnumInfos: file_bp2build_metrics_proto_enumTypes,
- MessageInfos: file_bp2build_metrics_proto_msgTypes,
- }.Build()
- File_bp2build_metrics_proto = out.File
- file_bp2build_metrics_proto_rawDesc = nil
- file_bp2build_metrics_proto_goTypes = nil
- file_bp2build_metrics_proto_depIdxs = nil
-}
diff --git a/ui/metrics/bp2build_metrics_proto/bp2build_metrics.proto b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.proto
deleted file mode 100644
index 49cb2b4..0000000
--- a/ui/metrics/bp2build_metrics_proto/bp2build_metrics.proto
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2021 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-syntax = "proto3";
-
-package soong_build_bp2build_metrics;
-option go_package = "android/soong/ui/metrics/bp2build_metrics_proto";
-
-message Bp2BuildMetrics {
- // Total number of Soong modules converted to generated targets
- uint64 generatedModuleCount = 1;
-
- // Total number of Soong modules converted to handcrafted targets
- uint64 handCraftedModuleCount = 2;
-
- // Total number of unconverted Soong modules
- uint64 unconvertedModuleCount = 3;
-
- // Counts of symlinks in synthetic bazel workspace
- uint64 workspaceSymlinkCount= 9;
-
- // Counts of mkdir calls during creation of synthetic bazel workspace
- uint64 workspaceMkDirCount= 10;
-
- // Counts of generated Bazel targets per Bazel rule class
- map<string, uint64> ruleClassCount = 4;
-
- // List of converted modules
- repeated string convertedModules = 5;
-
- // Unconverted modules, mapped to the reason the module was not converted.
- map<string, UnconvertedReason> unconvertedModules = 11;
-
- // Counts of converted modules by module type.
- map<string, uint64> convertedModuleTypeCount = 6;
-
- // Counts of total modules by module type.
- map<string, uint64> totalModuleTypeCount = 7;
-
- // List of traced runtime events of bp2build, useful for tracking bp2build
- // runtime.
- repeated Event events = 8;
-}
-
-// Traced runtime event of bp2build.
-message Event {
- // The event name.
- string name = 1;
-
- // The absolute start time of the event
- // The number of nanoseconds elapsed since January 1, 1970 UTC.
- uint64 start_time = 2;
-
- // The real running time.
- // The number of nanoseconds elapsed since start_time.
- uint64 real_time = 3;
-}
-
-message UnconvertedReason {
- // The type of reason that the module could not be converted.
- UnconvertedReasonType type = 1;
-
- // Descriptive details describing why the module could not be converted.
- // This detail should be kept very short and should be in the context of
- // the type. (Otherwise, this would significantly bloat metrics.)
- string detail = 2;
-}
-
-enum UnconvertedReasonType {
- // Bp2build does not know how to convert this specific module for some reason
- // not covered by other reason types. The reason detail should explain the
- // specific issue.
- UNSUPPORTED = 0;
-
- // The module was already defined in a BUILD file available in the source tree.
- DEFINED_IN_BUILD_FILE = 1;
-
- // The module was explicitly denylisted by name.
- DENYLISTED = 2;
-
- // The module's type has no bp2build implementation.
- TYPE_UNSUPPORTED = 3;
-
- // The module has a property not yet supported. The detail field should
- // name the unsupported property name.
- PROPERTY_UNSUPPORTED = 4;
-
- // The module has an unconverted dependency. The detail should consist of
- // the name of the unconverted module.
- UNCONVERTED_DEP = 5;
-
- // The module has a source file with the same name as the module itself.
- SRC_NAME_COLLISION = 6;
-}
\ No newline at end of file
diff --git a/ui/metrics/bp2build_metrics_proto/regen.sh b/ui/metrics/bp2build_metrics_proto/regen.sh
deleted file mode 100755
index bfe4294..0000000
--- a/ui/metrics/bp2build_metrics_proto/regen.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/bash -e
-
-# Copyright 2021 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Generates the golang source file of bp2build_metrics.proto protobuf file.
-
-function die() { echo "ERROR: $1" >&2; exit 1; }
-
-readonly error_msg="Maybe you need to run 'lunch aosp_arm-eng && m aprotoc blueprint_tools'?"
-
-if ! hash aprotoc &>/dev/null; then
- die "could not find aprotoc. ${error_msg}"
-fi
-
-if ! aprotoc --go_out=paths=source_relative:. bp2build_metrics.proto; then
- die "build failed. ${error_msg}"
-fi
diff --git a/ui/metrics/bp2build_progress_metrics_proto/BUILD.bazel b/ui/metrics/bp2build_progress_metrics_proto/BUILD.bazel
deleted file mode 100644
index f6c6df8..0000000
--- a/ui/metrics/bp2build_progress_metrics_proto/BUILD.bazel
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2022 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-load("//build/bazel/rules/python:py_proto.bzl", "py_proto_library")
-
-proto_library(
- name = "bp2build_proto",
- srcs = ["bp2build.proto"],
- strip_import_prefix = "",
-)
-
-py_proto_library(
- name = "bp2build_py_proto",
- visibility = ["//build/bazel/scripts/bp2build_progress:__pkg__"],
- deps = [":bp2build_proto"],
-)
diff --git a/ui/metrics/bp2build_progress_metrics_proto/bp2build.proto b/ui/metrics/bp2build_progress_metrics_proto/bp2build.proto
deleted file mode 100644
index 5b44002..0000000
--- a/ui/metrics/bp2build_progress_metrics_proto/bp2build.proto
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto3";
-
-package bp2build_proto;
-
-
-// Conversion progress report for root_modules .
-message Bp2buildConversionProgress {
-
- // Soong module identifying information.
- message Module {
- // Name of the Soong module.
- string name = 1;
-
- // Directory that the Soong module is in.
- string directory = 2;
-
- // Module type of this module.
- string type = 3;
-
- // All unconverted transitive dependencies.
- repeated string unconverted_deps = 4;
-
- // Total number of transitive dependencies.
- int32 num_deps = 5;
-
- // Unconverted reasons from heuristics
- repeated string unconverted_reasons_from_heuristics = 6;
- }
-
- // Modules that the transitive dependencies were identified for.
- repeated string root_modules = 1;
-
- // Names of all dependencies of the root_modules.
- int32 num_deps = 2;
-
- // Module with all its unconverted transitive dependencies.
- repeated Module unconverted = 3;
-}
diff --git a/ui/metrics/execution_metrics_proto/execution_metrics.pb.go b/ui/metrics/execution_metrics_proto/execution_metrics.pb.go
new file mode 100644
index 0000000..a065dbd
--- /dev/null
+++ b/ui/metrics/execution_metrics_proto/execution_metrics.pb.go
@@ -0,0 +1,240 @@
+// 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.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.30.0
+// protoc v3.21.12
+// source: execution_metrics.proto
+
+package execution_metrics_proto
+
+import (
+ find_input_delta_proto "android/soong/cmd/find_input_delta/find_input_delta_proto"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// These field numbers are also found in the inner message declarations.
+// We verify that the values are the same, and that every enum value is checked
+// in execution_metrics_test.go.
+// Do not change this enum without also updating:
+// - the submessage's .proto file
+// - execution_metrics_test.go
+type FieldNumbers int32
+
+const (
+ FieldNumbers_FIELD_NUMBERS_UNSPECIFIED FieldNumbers = 0
+ FieldNumbers_FIELD_NUMBERS_FILE_LIST FieldNumbers = 1
+)
+
+// Enum value maps for FieldNumbers.
+var (
+ FieldNumbers_name = map[int32]string{
+ 0: "FIELD_NUMBERS_UNSPECIFIED",
+ 1: "FIELD_NUMBERS_FILE_LIST",
+ }
+ FieldNumbers_value = map[string]int32{
+ "FIELD_NUMBERS_UNSPECIFIED": 0,
+ "FIELD_NUMBERS_FILE_LIST": 1,
+ }
+)
+
+func (x FieldNumbers) Enum() *FieldNumbers {
+ p := new(FieldNumbers)
+ *p = x
+ return p
+}
+
+func (x FieldNumbers) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (FieldNumbers) Descriptor() protoreflect.EnumDescriptor {
+ return file_execution_metrics_proto_enumTypes[0].Descriptor()
+}
+
+func (FieldNumbers) Type() protoreflect.EnumType {
+ return &file_execution_metrics_proto_enumTypes[0]
+}
+
+func (x FieldNumbers) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *FieldNumbers) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = FieldNumbers(num)
+ return nil
+}
+
+// Deprecated: Use FieldNumbers.Descriptor instead.
+func (FieldNumbers) EnumDescriptor() ([]byte, []int) {
+ return file_execution_metrics_proto_rawDescGZIP(), []int{0}
+}
+
+type SoongExecutionMetrics struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // cmd/find_input_delta/find_input_delta_proto.FileList
+ FileList *find_input_delta_proto.FileList `protobuf:"bytes,1,opt,name=file_list,json=fileList" json:"file_list,omitempty"`
+}
+
+func (x *SoongExecutionMetrics) Reset() {
+ *x = SoongExecutionMetrics{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_execution_metrics_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SoongExecutionMetrics) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SoongExecutionMetrics) ProtoMessage() {}
+
+func (x *SoongExecutionMetrics) ProtoReflect() protoreflect.Message {
+ mi := &file_execution_metrics_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SoongExecutionMetrics.ProtoReflect.Descriptor instead.
+func (*SoongExecutionMetrics) Descriptor() ([]byte, []int) {
+ return file_execution_metrics_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *SoongExecutionMetrics) GetFileList() *find_input_delta_proto.FileList {
+ if x != nil {
+ return x.FileList
+ }
+ return nil
+}
+
+var File_execution_metrics_proto protoreflect.FileDescriptor
+
+var file_execution_metrics_proto_rawDesc = []byte{
+ 0x0a, 0x17, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x72,
+ 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x73, 0x6f, 0x6f, 0x6e, 0x67,
+ 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x1a, 0x3b,
+ 0x63, 0x6d, 0x64, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64,
+ 0x65, 0x6c, 0x74, 0x61, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f,
+ 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x66, 0x69, 0x6c, 0x65,
+ 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x5e, 0x0a, 0x15, 0x53,
+ 0x6f, 0x6f, 0x6e, 0x67, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74,
+ 0x72, 0x69, 0x63, 0x73, 0x12, 0x45, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x73,
+ 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+ 0x64, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c,
+ 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73,
+ 0x74, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x2a, 0x4a, 0x0a, 0x0c, 0x46,
+ 0x69, 0x65, 0x6c, 0x64, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x19, 0x46,
+ 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x5f, 0x55, 0x4e, 0x53,
+ 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x49,
+ 0x45, 0x4c, 0x44, 0x5f, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x5f, 0x46, 0x49, 0x4c, 0x45,
+ 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x01, 0x42, 0x32, 0x5a, 0x30, 0x61, 0x6e, 0x64, 0x72, 0x6f,
+ 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72,
+ 0x69, 0x63, 0x73, 0x2f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+}
+
+var (
+ file_execution_metrics_proto_rawDescOnce sync.Once
+ file_execution_metrics_proto_rawDescData = file_execution_metrics_proto_rawDesc
+)
+
+func file_execution_metrics_proto_rawDescGZIP() []byte {
+ file_execution_metrics_proto_rawDescOnce.Do(func() {
+ file_execution_metrics_proto_rawDescData = protoimpl.X.CompressGZIP(file_execution_metrics_proto_rawDescData)
+ })
+ return file_execution_metrics_proto_rawDescData
+}
+
+var file_execution_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_execution_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_execution_metrics_proto_goTypes = []interface{}{
+ (FieldNumbers)(0), // 0: soong_build_metrics.FieldNumbers
+ (*SoongExecutionMetrics)(nil), // 1: soong_build_metrics.SoongExecutionMetrics
+ (*find_input_delta_proto.FileList)(nil), // 2: android.find_input_delta_proto.FileList
+}
+var file_execution_metrics_proto_depIdxs = []int32{
+ 2, // 0: soong_build_metrics.SoongExecutionMetrics.file_list:type_name -> android.find_input_delta_proto.FileList
+ 1, // [1:1] is the sub-list for method output_type
+ 1, // [1:1] is the sub-list for method input_type
+ 1, // [1:1] is the sub-list for extension type_name
+ 1, // [1:1] is the sub-list for extension extendee
+ 0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_execution_metrics_proto_init() }
+func file_execution_metrics_proto_init() {
+ if File_execution_metrics_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_execution_metrics_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SoongExecutionMetrics); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_execution_metrics_proto_rawDesc,
+ NumEnums: 1,
+ NumMessages: 1,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_execution_metrics_proto_goTypes,
+ DependencyIndexes: file_execution_metrics_proto_depIdxs,
+ EnumInfos: file_execution_metrics_proto_enumTypes,
+ MessageInfos: file_execution_metrics_proto_msgTypes,
+ }.Build()
+ File_execution_metrics_proto = out.File
+ file_execution_metrics_proto_rawDesc = nil
+ file_execution_metrics_proto_goTypes = nil
+ file_execution_metrics_proto_depIdxs = nil
+}
diff --git a/ui/metrics/execution_metrics_proto/execution_metrics.proto b/ui/metrics/execution_metrics_proto/execution_metrics.proto
new file mode 100644
index 0000000..381dcd1
--- /dev/null
+++ b/ui/metrics/execution_metrics_proto/execution_metrics.proto
@@ -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.
+
+syntax = "proto2";
+
+package soong_build_metrics;
+option go_package = "android/soong/ui/metrics/execution_metrics_proto";
+
+import "cmd/find_input_delta/find_input_delta_proto/file_list.proto";
+
+// These field numbers are also found in the inner message declarations.
+// We verify that the values are the same, and that every enum value is checked
+// in execution_metrics_test.go.
+// Do not change this enum without also updating:
+// - the submessage's .proto file
+// - execution_metrics_test.go
+enum FieldNumbers {
+ FIELD_NUMBERS_UNSPECIFIED = 0;
+ FIELD_NUMBERS_FILE_LIST = 1;
+}
+
+message SoongExecutionMetrics {
+ // cmd/find_input_delta/find_input_delta_proto.FileList
+ optional android.find_input_delta_proto.FileList file_list = 1;
+}
diff --git a/ui/metrics/execution_metrics_proto/execution_metrics_test.go b/ui/metrics/execution_metrics_proto/execution_metrics_test.go
new file mode 100644
index 0000000..2f71c21
--- /dev/null
+++ b/ui/metrics/execution_metrics_proto/execution_metrics_test.go
@@ -0,0 +1,33 @@
+package execution_metrics_proto
+
+import (
+ "testing"
+
+ find_input_delta_proto "android/soong/cmd/find_input_delta/find_input_delta_proto"
+)
+
+func TestExecutionMetricsMessageNums(t *testing.T) {
+ testCases := []struct {
+ Name string
+ FieldNumbers map[string]int32
+ }{
+ {
+ Name: "find_input_delta_proto",
+ FieldNumbers: find_input_delta_proto.FieldNumbers_value,
+ },
+ }
+ verifiedMap := make(map[string]bool)
+ for _, tc := range testCases {
+ for k, v := range tc.FieldNumbers {
+ if FieldNumbers_value[k] != v {
+ t.Errorf("%s: Expected FieldNumbers.%s == %v, found %v", tc.Name, k, FieldNumbers_value[k], v)
+ }
+ verifiedMap[k] = true
+ }
+ }
+ for k, v := range FieldNumbers_value {
+ if !verifiedMap[k] {
+ t.Errorf("No test case verifies FieldNumbers.%s=%v", k, v)
+ }
+ }
+}
diff --git a/ui/metrics/execution_metrics_proto/regen.sh b/ui/metrics/execution_metrics_proto/regen.sh
new file mode 100755
index 0000000..5339a9a
--- /dev/null
+++ b/ui/metrics/execution_metrics_proto/regen.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Generates the golang source file of metrics.proto protobuf file.
+
+set -e
+
+function die() { echo "ERROR: $1" >&2; exit 1; }
+
+readonly error_msg="Maybe you need to run 'lunch aosp_arm-eng && m aprotoc blueprint_tools'?"
+
+if ! hash aprotoc &>/dev/null; then
+ die "could not find aprotoc. ${error_msg}"
+fi
+
+if ! aprotoc --go_out=paths=source_relative:. -I .:../../.. execution_metrics.proto; then
+ die "build failed. ${error_msg}"
+fi
diff --git a/ui/metrics/hostinfo.go b/ui/metrics/hostinfo.go
new file mode 100644
index 0000000..f401b2a
--- /dev/null
+++ b/ui/metrics/hostinfo.go
@@ -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 metrics
+
+// The hostinfo* files contain code to extract host information from
+// /proc/cpuinfo and /proc/meminfo relevant to machine performance
+
+import (
+ "strconv"
+ "strings"
+)
+
+// CpuInfo holds information regarding the host's CPU cores.
+type CpuInfo struct {
+ // The vendor id
+ VendorId string
+
+ // The model name
+ ModelName string
+
+ // The number of CPU cores
+ CpuCores int32
+
+ // The CPU flags
+ Flags string
+}
+
+// MemInfo holds information regarding the host's memory.
+// The memory size in each of the field is in bytes.
+type MemInfo struct {
+ // The total memory.
+ MemTotal uint64
+
+ // The amount of free memory.
+ MemFree uint64
+
+ // The amount of available memory.
+ MemAvailable uint64
+}
+
+// fillCpuInfo takes the key and value, converts the value
+// to the proper size unit and is stores it in CpuInfo.
+func (c *CpuInfo) fillInfo(key, value string) {
+ switch key {
+ case "vendor_id":
+ c.VendorId = value
+ case "model name":
+ c.ModelName = value
+ case "cpu cores":
+ v, err := strconv.ParseInt(value, 10, 32)
+ if err == nil {
+ c.CpuCores = int32(v)
+ }
+ case "flags":
+ c.Flags = value
+ default:
+ // Ignore unknown keys
+ }
+}
+
+// fillCpuInfo takes the key and value, converts the value
+// to the proper size unit and is stores it in CpuInfo.
+func (m *MemInfo) fillInfo(key, value string) {
+ v := strToUint64(value)
+ switch key {
+ case "MemTotal":
+ m.MemTotal = v
+ case "MemFree":
+ m.MemFree = v
+ case "MemAvailable":
+ m.MemAvailable = v
+ default:
+ // Ignore unknown keys
+ }
+}
+
+// strToUint64 takes the string and converts to unsigned 64-bit integer.
+// If the string contains a memory unit such as kB and is converted to
+// bytes.
+func strToUint64(v string) uint64 {
+ // v could be "1024 kB" so scan for the empty space and
+ // split between the value and the unit.
+ var separatorIndex int
+ if separatorIndex = strings.IndexAny(v, " "); separatorIndex < 0 {
+ separatorIndex = len(v)
+ }
+ value, err := strconv.ParseUint(v[:separatorIndex], 10, 64)
+ if err != nil {
+ return 0
+ }
+
+ var scale uint64 = 1
+ switch strings.TrimSpace(v[separatorIndex:]) {
+ case "kB", "KB":
+ scale = 1024
+ case "mB", "MB":
+ scale = 1024 * 1024
+ }
+ return value * scale
+}
diff --git a/ui/metrics/hostinfo_darwin.go b/ui/metrics/hostinfo_darwin.go
new file mode 100644
index 0000000..6f35c7d
--- /dev/null
+++ b/ui/metrics/hostinfo_darwin.go
@@ -0,0 +1,29 @@
+// 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 metrics
+
+// This file contain code to extract host information on linux from
+// /proc/cpuinfo and /proc/meminfo relevant to machine performance
+
+import (
+ "android/soong/finder/fs"
+)
+
+func NewCpuInfo(fileSystem fs.FileSystem) (*CpuInfo, error) {
+ return &CpuInfo{}, nil
+}
+
+func NewMemInfo(fileSystem fs.FileSystem) (*MemInfo, error) {
+ return &MemInfo{}, nil
+}
diff --git a/ui/metrics/hostinfo_linux.go b/ui/metrics/hostinfo_linux.go
new file mode 100644
index 0000000..b983dbc
--- /dev/null
+++ b/ui/metrics/hostinfo_linux.go
@@ -0,0 +1,72 @@
+// 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 metrics
+
+// This file contain code to extract host information on linux from
+// /proc/cpuinfo and /proc/meminfo relevant to machine performance
+
+import (
+ "io/ioutil"
+ "strings"
+
+ "android/soong/finder/fs"
+)
+
+type fillable interface {
+ fillInfo(key, value string)
+}
+
+func NewCpuInfo(fileSystem fs.FileSystem) (*CpuInfo, error) {
+ c := &CpuInfo{}
+ if err := parseFile(c, "/proc/cpuinfo", true, fileSystem); err != nil {
+ return &CpuInfo{}, err
+ }
+ return c, nil
+}
+
+func NewMemInfo(fileSystem fs.FileSystem) (*MemInfo, error) {
+ m := &MemInfo{}
+ if err := parseFile(m, "/proc/meminfo", false, fileSystem); err != nil {
+ return &MemInfo{}, err
+ }
+ return m, nil
+}
+
+func parseFile(obj fillable, fileName string, endOnBlank bool, fileSystem fs.FileSystem) error {
+ fd, err := fileSystem.Open(fileName)
+ if err != nil {
+ return err
+ }
+ defer fd.Close()
+
+ data, err := ioutil.ReadAll(fd)
+ if err != nil {
+ return err
+ }
+
+ for _, l := range strings.Split(string(data), "\n") {
+ if !strings.Contains(l, ":") {
+ // Terminate after the first blank line.
+ if endOnBlank && strings.TrimSpace(l) == "" {
+ break
+ }
+ // If the line is not of the form "key: values", just skip it.
+ continue
+ }
+
+ kv := strings.SplitN(l, ":", 2)
+ obj.fillInfo(strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1]))
+ }
+ return nil
+}
diff --git a/ui/metrics/hostinfo_linux_test.go b/ui/metrics/hostinfo_linux_test.go
new file mode 100644
index 0000000..c44e453
--- /dev/null
+++ b/ui/metrics/hostinfo_linux_test.go
@@ -0,0 +1,118 @@
+// 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 metrics
+
+// This file contain code to extract host information on linux from
+// /proc/cpuinfo and /proc/meminfo relevant to machine performance
+
+import (
+ "reflect"
+ "testing"
+
+ "android/soong/finder/fs"
+)
+
+func TestNewCpuInfo(t *testing.T) {
+ fs := fs.NewMockFs(nil)
+
+ if err := fs.MkDirs("/proc"); err != nil {
+ t.Fatalf("failed to create /proc dir: %v", err)
+ }
+ cpuFileName := "/proc/cpuinfo"
+
+ if err := fs.WriteFile(cpuFileName, cpuData, 0644); err != nil {
+ t.Fatalf("failed to write file %s: %v", cpuFileName, err)
+ }
+
+ cpuInfo, err := NewCpuInfo(fs)
+ if err != nil {
+ t.Fatalf("got %v, want nil for error", err)
+ }
+
+ if !reflect.DeepEqual(cpuInfo, expectedCpuInfo) {
+ t.Errorf("got %v, expecting %v for CpuInfo", cpuInfo, expectedCpuInfo)
+ }
+
+}
+
+func TestNewMemInfo(t *testing.T) {
+ fs := fs.NewMockFs(nil)
+
+ if err := fs.MkDirs("/proc"); err != nil {
+ t.Fatalf("failed to create /proc dir: %v", err)
+ }
+ memFileName := "/proc/meminfo"
+
+ if err := fs.WriteFile(memFileName, memData, 0644); err != nil {
+ t.Fatalf("failed to write file %s: %v", memFileName, err)
+ }
+
+ memInfo, err := NewMemInfo(fs)
+ if err != nil {
+ t.Fatalf("got %v, want nil for error", err)
+ }
+
+ if !reflect.DeepEqual(memInfo, expectedMemInfo) {
+ t.Errorf("got %v, expecting %v for MemInfo", memInfo, expectedMemInfo)
+ }
+
+}
+
+var cpuData = []byte(`processor : 0
+vendor_id : %%VENDOR%%
+cpu family : 123
+model : 456
+model name : %%CPU MODEL NAME%%
+stepping : 0
+cpu MHz : 5555.555
+cache size : 512 KB
+physical id : 0
+siblings : 128
+core id : 0
+cpu cores : 64
+apicid : 0
+initial apicid : 0
+fpu : yes
+fpu_exception : yes
+cpuid level : 789
+wp : yes
+flags : %%cpu flags go here%%
+bugs : %%bugs go here%%
+
+processor : 1
+vendor_id : %%BADVENDOR%%
+cpu family : 234
+model : 567
+model name : %%BAD MODEL NAME%%
+flags : %%BAD cpu flags go here%%
+`)
+
+var expectedCpuInfo = &CpuInfo{
+ VendorId: "%%VENDOR%%",
+ ModelName: "%%CPU MODEL NAME%%",
+ CpuCores: 64,
+ Flags: "%%cpu flags go here%%",
+}
+
+var memData = []byte(`MemTotal: 1000 mB
+MemFree: 10240000
+MemAvailable: 3000 kB
+Buffers: 7177844 kB
+`)
+
+var expectedMemInfo = &MemInfo{
+ MemTotal: 1048576000,
+ MemFree: 10240000,
+ MemAvailable: 3072000,
+}
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index 4a275a8..8d29cfc 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -161,7 +161,7 @@
}
// SetMetadataMetrics sets information about the build such as the target
-// product, host architecture and out directory.
+// product, host architecture and out directory. May be called multiple times.
func (m *Metrics) SetMetadataMetrics(metadata map[string]string) {
for k, v := range metadata {
switch k {
@@ -171,6 +171,8 @@
m.metrics.PlatformVersionCodename = proto.String(v)
case "TARGET_PRODUCT":
m.metrics.TargetProduct = proto.String(v)
+ case "TARGET_RELEASE":
+ m.metrics.TargetRelease = proto.String(v)
case "TARGET_BUILD_VARIANT":
switch v {
case "user":
diff --git a/ui/metrics/metrics_proto/Android.bp b/ui/metrics/metrics_proto/Android.bp
new file mode 100644
index 0000000..aae5266
--- /dev/null
+++ b/ui/metrics/metrics_proto/Android.bp
@@ -0,0 +1,16 @@
+python_library_host {
+ name: "soong-metrics-proto-py",
+ srcs: [
+ "metrics.proto",
+ ],
+ visibility: [
+ "//build/make/ci",
+ ],
+ libs: [
+ "libprotobuf-python",
+ ],
+ proto: {
+ include_dirs: ["external/protobuf/src"],
+ canonical_path_from_root: false,
+ },
+}
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index b75f572..1ebe911 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -279,7 +279,7 @@
// Deprecated: Use ModuleTypeInfo_BuildSystem.Descriptor instead.
func (ModuleTypeInfo_BuildSystem) EnumDescriptor() ([]byte, []int) {
- return file_metrics_proto_rawDescGZIP(), []int{8, 0}
+ return file_metrics_proto_rawDescGZIP(), []int{11, 0}
}
type ExpConfigFetcher_ConfigStatus int32
@@ -341,7 +341,7 @@
// Deprecated: Use ExpConfigFetcher_ConfigStatus.Descriptor instead.
func (ExpConfigFetcher_ConfigStatus) EnumDescriptor() ([]byte, []int) {
- return file_metrics_proto_rawDescGZIP(), []int{12, 0}
+ return file_metrics_proto_rawDescGZIP(), []int{15, 0}
}
type MetricsBase struct {
@@ -425,6 +425,10 @@
// Note that not all changed environment variables result in analysis retriggering.
// If there was no previous build, this list will be empty.
ChangedEnvironmentVariable []string `protobuf:"bytes,34,rep,name=changed_environment_variable,json=changedEnvironmentVariable" json:"changed_environment_variable,omitempty"`
+ // Metrics related to optimized builds.
+ OptimizedBuildMetrics *OptimizedBuildMetrics `protobuf:"bytes,35,opt,name=optimized_build_metrics,json=optimizedBuildMetrics" json:"optimized_build_metrics,omitempty"`
+ // The target release information. e.g., trunk_staging.
+ TargetRelease *string `protobuf:"bytes,36,opt,name=target_release,json=targetRelease" json:"target_release,omitempty"`
}
// Default values for MetricsBase fields.
@@ -706,6 +710,20 @@
return nil
}
+func (x *MetricsBase) GetOptimizedBuildMetrics() *OptimizedBuildMetrics {
+ if x != nil {
+ return x.OptimizedBuildMetrics
+ }
+ return nil
+}
+
+func (x *MetricsBase) GetTargetRelease() string {
+ if x != nil && x.TargetRelease != nil {
+ return *x.TargetRelease
+ }
+ return ""
+}
+
type BuildConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -730,6 +748,11 @@
// EXTERNAL_FILE - ninja uses an external custom weight list
// HINT_FROM_SOONG - ninja uses a prioritized module list from Soong
NinjaWeightListSource *BuildConfig_NinjaWeightListSource `protobuf:"varint,8,opt,name=ninja_weight_list_source,json=ninjaWeightListSource,enum=soong_build_metrics.BuildConfig_NinjaWeightListSource,def=0" json:"ninja_weight_list_source,omitempty"`
+ // Values of some build-affecting environment variables.
+ SoongEnvVars *SoongEnvVars `protobuf:"bytes,9,opt,name=soong_env_vars,json=soongEnvVars" json:"soong_env_vars,omitempty"`
+ // Whether this build uses soong-only (no kati) mode (either via environment variable,
+ // command line flag or product config.
+ SoongOnly *bool `protobuf:"varint,10,opt,name=soong_only,json=soongOnly" json:"soong_only,omitempty"`
}
// Default values for BuildConfig fields.
@@ -825,6 +848,77 @@
return Default_BuildConfig_NinjaWeightListSource
}
+func (x *BuildConfig) GetSoongEnvVars() *SoongEnvVars {
+ if x != nil {
+ return x.SoongEnvVars
+ }
+ return nil
+}
+
+func (x *BuildConfig) GetSoongOnly() bool {
+ if x != nil && x.SoongOnly != nil {
+ return *x.SoongOnly
+ }
+ return false
+}
+
+type SoongEnvVars struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // SOONG_PARTIAL_COMPILE
+ PartialCompile *string `protobuf:"bytes,1,opt,name=partial_compile,json=partialCompile" json:"partial_compile,omitempty"`
+ // SOONG_USE_PARTIAL_COMPILE
+ UsePartialCompile *string `protobuf:"bytes,2,opt,name=use_partial_compile,json=usePartialCompile" json:"use_partial_compile,omitempty"`
+}
+
+func (x *SoongEnvVars) Reset() {
+ *x = SoongEnvVars{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_metrics_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SoongEnvVars) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SoongEnvVars) ProtoMessage() {}
+
+func (x *SoongEnvVars) ProtoReflect() protoreflect.Message {
+ mi := &file_metrics_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SoongEnvVars.ProtoReflect.Descriptor instead.
+func (*SoongEnvVars) Descriptor() ([]byte, []int) {
+ return file_metrics_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *SoongEnvVars) GetPartialCompile() string {
+ if x != nil && x.PartialCompile != nil {
+ return *x.PartialCompile
+ }
+ return ""
+}
+
+func (x *SoongEnvVars) GetUsePartialCompile() string {
+ if x != nil && x.UsePartialCompile != nil {
+ return *x.UsePartialCompile
+ }
+ return ""
+}
+
type SystemResourceInfo struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -834,12 +928,16 @@
TotalPhysicalMemory *uint64 `protobuf:"varint,1,opt,name=total_physical_memory,json=totalPhysicalMemory" json:"total_physical_memory,omitempty"`
// The total of available cores for building
AvailableCpus *int32 `protobuf:"varint,2,opt,name=available_cpus,json=availableCpus" json:"available_cpus,omitempty"`
+ // Information about the machine's CPU(s).
+ CpuInfo *SystemCpuInfo `protobuf:"bytes,3,opt,name=cpu_info,json=cpuInfo" json:"cpu_info,omitempty"`
+ // Information about the machine's memory.
+ MemInfo *SystemMemInfo `protobuf:"bytes,4,opt,name=mem_info,json=memInfo" json:"mem_info,omitempty"`
}
func (x *SystemResourceInfo) Reset() {
*x = SystemResourceInfo{}
if protoimpl.UnsafeEnabled {
- mi := &file_metrics_proto_msgTypes[2]
+ mi := &file_metrics_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -852,7 +950,7 @@
func (*SystemResourceInfo) ProtoMessage() {}
func (x *SystemResourceInfo) ProtoReflect() protoreflect.Message {
- mi := &file_metrics_proto_msgTypes[2]
+ mi := &file_metrics_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -865,7 +963,7 @@
// Deprecated: Use SystemResourceInfo.ProtoReflect.Descriptor instead.
func (*SystemResourceInfo) Descriptor() ([]byte, []int) {
- return file_metrics_proto_rawDescGZIP(), []int{2}
+ return file_metrics_proto_rawDescGZIP(), []int{3}
}
func (x *SystemResourceInfo) GetTotalPhysicalMemory() uint64 {
@@ -882,6 +980,161 @@
return 0
}
+func (x *SystemResourceInfo) GetCpuInfo() *SystemCpuInfo {
+ if x != nil {
+ return x.CpuInfo
+ }
+ return nil
+}
+
+func (x *SystemResourceInfo) GetMemInfo() *SystemMemInfo {
+ if x != nil {
+ return x.MemInfo
+ }
+ return nil
+}
+
+type SystemCpuInfo struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The vendor id
+ VendorId *string `protobuf:"bytes,1,opt,name=vendor_id,json=vendorId" json:"vendor_id,omitempty"`
+ // The model name
+ ModelName *string `protobuf:"bytes,2,opt,name=model_name,json=modelName" json:"model_name,omitempty"`
+ // The number of CPU cores
+ CpuCores *int32 `protobuf:"varint,3,opt,name=cpu_cores,json=cpuCores" json:"cpu_cores,omitempty"`
+ // The CPU flags
+ Flags *string `protobuf:"bytes,4,opt,name=flags" json:"flags,omitempty"`
+}
+
+func (x *SystemCpuInfo) Reset() {
+ *x = SystemCpuInfo{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_metrics_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SystemCpuInfo) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SystemCpuInfo) ProtoMessage() {}
+
+func (x *SystemCpuInfo) ProtoReflect() protoreflect.Message {
+ mi := &file_metrics_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SystemCpuInfo.ProtoReflect.Descriptor instead.
+func (*SystemCpuInfo) Descriptor() ([]byte, []int) {
+ return file_metrics_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *SystemCpuInfo) GetVendorId() string {
+ if x != nil && x.VendorId != nil {
+ return *x.VendorId
+ }
+ return ""
+}
+
+func (x *SystemCpuInfo) GetModelName() string {
+ if x != nil && x.ModelName != nil {
+ return *x.ModelName
+ }
+ return ""
+}
+
+func (x *SystemCpuInfo) GetCpuCores() int32 {
+ if x != nil && x.CpuCores != nil {
+ return *x.CpuCores
+ }
+ return 0
+}
+
+func (x *SystemCpuInfo) GetFlags() string {
+ if x != nil && x.Flags != nil {
+ return *x.Flags
+ }
+ return ""
+}
+
+type SystemMemInfo struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The total system memory
+ MemTotal *uint64 `protobuf:"varint,1,opt,name=mem_total,json=memTotal" json:"mem_total,omitempty"`
+ // The free system memory
+ MemFree *uint64 `protobuf:"varint,2,opt,name=mem_free,json=memFree" json:"mem_free,omitempty"`
+ // The available system memory
+ MemAvailable *uint64 `protobuf:"varint,3,opt,name=mem_available,json=memAvailable" json:"mem_available,omitempty"`
+}
+
+func (x *SystemMemInfo) Reset() {
+ *x = SystemMemInfo{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_metrics_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SystemMemInfo) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SystemMemInfo) ProtoMessage() {}
+
+func (x *SystemMemInfo) ProtoReflect() protoreflect.Message {
+ mi := &file_metrics_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SystemMemInfo.ProtoReflect.Descriptor instead.
+func (*SystemMemInfo) Descriptor() ([]byte, []int) {
+ return file_metrics_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *SystemMemInfo) GetMemTotal() uint64 {
+ if x != nil && x.MemTotal != nil {
+ return *x.MemTotal
+ }
+ return 0
+}
+
+func (x *SystemMemInfo) GetMemFree() uint64 {
+ if x != nil && x.MemFree != nil {
+ return *x.MemFree
+ }
+ return 0
+}
+
+func (x *SystemMemInfo) GetMemAvailable() uint64 {
+ if x != nil && x.MemAvailable != nil {
+ return *x.MemAvailable
+ }
+ return 0
+}
+
type PerfInfo struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -913,7 +1166,7 @@
func (x *PerfInfo) Reset() {
*x = PerfInfo{}
if protoimpl.UnsafeEnabled {
- mi := &file_metrics_proto_msgTypes[3]
+ mi := &file_metrics_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -926,7 +1179,7 @@
func (*PerfInfo) ProtoMessage() {}
func (x *PerfInfo) ProtoReflect() protoreflect.Message {
- mi := &file_metrics_proto_msgTypes[3]
+ mi := &file_metrics_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -939,7 +1192,7 @@
// Deprecated: Use PerfInfo.ProtoReflect.Descriptor instead.
func (*PerfInfo) Descriptor() ([]byte, []int) {
- return file_metrics_proto_rawDescGZIP(), []int{3}
+ return file_metrics_proto_rawDescGZIP(), []int{6}
}
func (x *PerfInfo) GetDescription() string {
@@ -1013,7 +1266,7 @@
func (x *PerfCounters) Reset() {
*x = PerfCounters{}
if protoimpl.UnsafeEnabled {
- mi := &file_metrics_proto_msgTypes[4]
+ mi := &file_metrics_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1026,7 +1279,7 @@
func (*PerfCounters) ProtoMessage() {}
func (x *PerfCounters) ProtoReflect() protoreflect.Message {
- mi := &file_metrics_proto_msgTypes[4]
+ mi := &file_metrics_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1039,7 +1292,7 @@
// Deprecated: Use PerfCounters.ProtoReflect.Descriptor instead.
func (*PerfCounters) Descriptor() ([]byte, []int) {
- return file_metrics_proto_rawDescGZIP(), []int{4}
+ return file_metrics_proto_rawDescGZIP(), []int{7}
}
func (x *PerfCounters) GetTime() uint64 {
@@ -1070,7 +1323,7 @@
func (x *PerfCounterGroup) Reset() {
*x = PerfCounterGroup{}
if protoimpl.UnsafeEnabled {
- mi := &file_metrics_proto_msgTypes[5]
+ mi := &file_metrics_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1083,7 +1336,7 @@
func (*PerfCounterGroup) ProtoMessage() {}
func (x *PerfCounterGroup) ProtoReflect() protoreflect.Message {
- mi := &file_metrics_proto_msgTypes[5]
+ mi := &file_metrics_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1096,7 +1349,7 @@
// Deprecated: Use PerfCounterGroup.ProtoReflect.Descriptor instead.
func (*PerfCounterGroup) Descriptor() ([]byte, []int) {
- return file_metrics_proto_rawDescGZIP(), []int{5}
+ return file_metrics_proto_rawDescGZIP(), []int{8}
}
func (x *PerfCounterGroup) GetName() string {
@@ -1127,7 +1380,7 @@
func (x *PerfCounter) Reset() {
*x = PerfCounter{}
if protoimpl.UnsafeEnabled {
- mi := &file_metrics_proto_msgTypes[6]
+ mi := &file_metrics_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1140,7 +1393,7 @@
func (*PerfCounter) ProtoMessage() {}
func (x *PerfCounter) ProtoReflect() protoreflect.Message {
- mi := &file_metrics_proto_msgTypes[6]
+ mi := &file_metrics_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1153,7 +1406,7 @@
// Deprecated: Use PerfCounter.ProtoReflect.Descriptor instead.
func (*PerfCounter) Descriptor() ([]byte, []int) {
- return file_metrics_proto_rawDescGZIP(), []int{6}
+ return file_metrics_proto_rawDescGZIP(), []int{9}
}
func (x *PerfCounter) GetName() string {
@@ -1200,7 +1453,7 @@
func (x *ProcessResourceInfo) Reset() {
*x = ProcessResourceInfo{}
if protoimpl.UnsafeEnabled {
- mi := &file_metrics_proto_msgTypes[7]
+ mi := &file_metrics_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1213,7 +1466,7 @@
func (*ProcessResourceInfo) ProtoMessage() {}
func (x *ProcessResourceInfo) ProtoReflect() protoreflect.Message {
- mi := &file_metrics_proto_msgTypes[7]
+ mi := &file_metrics_proto_msgTypes[10]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1226,7 +1479,7 @@
// Deprecated: Use ProcessResourceInfo.ProtoReflect.Descriptor instead.
func (*ProcessResourceInfo) Descriptor() ([]byte, []int) {
- return file_metrics_proto_rawDescGZIP(), []int{7}
+ return file_metrics_proto_rawDescGZIP(), []int{10}
}
func (x *ProcessResourceInfo) GetName() string {
@@ -1320,7 +1573,7 @@
func (x *ModuleTypeInfo) Reset() {
*x = ModuleTypeInfo{}
if protoimpl.UnsafeEnabled {
- mi := &file_metrics_proto_msgTypes[8]
+ mi := &file_metrics_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1333,7 +1586,7 @@
func (*ModuleTypeInfo) ProtoMessage() {}
func (x *ModuleTypeInfo) ProtoReflect() protoreflect.Message {
- mi := &file_metrics_proto_msgTypes[8]
+ mi := &file_metrics_proto_msgTypes[11]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1346,7 +1599,7 @@
// Deprecated: Use ModuleTypeInfo.ProtoReflect.Descriptor instead.
func (*ModuleTypeInfo) Descriptor() ([]byte, []int) {
- return file_metrics_proto_rawDescGZIP(), []int{8}
+ return file_metrics_proto_rawDescGZIP(), []int{11}
}
func (x *ModuleTypeInfo) GetBuildSystem() ModuleTypeInfo_BuildSystem {
@@ -1384,7 +1637,7 @@
func (x *CriticalUserJourneyMetrics) Reset() {
*x = CriticalUserJourneyMetrics{}
if protoimpl.UnsafeEnabled {
- mi := &file_metrics_proto_msgTypes[9]
+ mi := &file_metrics_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1397,7 +1650,7 @@
func (*CriticalUserJourneyMetrics) ProtoMessage() {}
func (x *CriticalUserJourneyMetrics) ProtoReflect() protoreflect.Message {
- mi := &file_metrics_proto_msgTypes[9]
+ mi := &file_metrics_proto_msgTypes[12]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1410,7 +1663,7 @@
// Deprecated: Use CriticalUserJourneyMetrics.ProtoReflect.Descriptor instead.
func (*CriticalUserJourneyMetrics) Descriptor() ([]byte, []int) {
- return file_metrics_proto_rawDescGZIP(), []int{9}
+ return file_metrics_proto_rawDescGZIP(), []int{12}
}
func (x *CriticalUserJourneyMetrics) GetName() string {
@@ -1439,7 +1692,7 @@
func (x *CriticalUserJourneysMetrics) Reset() {
*x = CriticalUserJourneysMetrics{}
if protoimpl.UnsafeEnabled {
- mi := &file_metrics_proto_msgTypes[10]
+ mi := &file_metrics_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1452,7 +1705,7 @@
func (*CriticalUserJourneysMetrics) ProtoMessage() {}
func (x *CriticalUserJourneysMetrics) ProtoReflect() protoreflect.Message {
- mi := &file_metrics_proto_msgTypes[10]
+ mi := &file_metrics_proto_msgTypes[13]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1465,7 +1718,7 @@
// Deprecated: Use CriticalUserJourneysMetrics.ProtoReflect.Descriptor instead.
func (*CriticalUserJourneysMetrics) Descriptor() ([]byte, []int) {
- return file_metrics_proto_rawDescGZIP(), []int{10}
+ return file_metrics_proto_rawDescGZIP(), []int{13}
}
func (x *CriticalUserJourneysMetrics) GetCujs() []*CriticalUserJourneyMetrics {
@@ -1501,7 +1754,7 @@
func (x *SoongBuildMetrics) Reset() {
*x = SoongBuildMetrics{}
if protoimpl.UnsafeEnabled {
- mi := &file_metrics_proto_msgTypes[11]
+ mi := &file_metrics_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1514,7 +1767,7 @@
func (*SoongBuildMetrics) ProtoMessage() {}
func (x *SoongBuildMetrics) ProtoReflect() protoreflect.Message {
- mi := &file_metrics_proto_msgTypes[11]
+ mi := &file_metrics_proto_msgTypes[14]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1527,7 +1780,7 @@
// Deprecated: Use SoongBuildMetrics.ProtoReflect.Descriptor instead.
func (*SoongBuildMetrics) Descriptor() ([]byte, []int) {
- return file_metrics_proto_rawDescGZIP(), []int{11}
+ return file_metrics_proto_rawDescGZIP(), []int{14}
}
func (x *SoongBuildMetrics) GetModules() uint32 {
@@ -1605,7 +1858,7 @@
func (x *ExpConfigFetcher) Reset() {
*x = ExpConfigFetcher{}
if protoimpl.UnsafeEnabled {
- mi := &file_metrics_proto_msgTypes[12]
+ mi := &file_metrics_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1618,7 +1871,7 @@
func (*ExpConfigFetcher) ProtoMessage() {}
func (x *ExpConfigFetcher) ProtoReflect() protoreflect.Message {
- mi := &file_metrics_proto_msgTypes[12]
+ mi := &file_metrics_proto_msgTypes[15]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1631,7 +1884,7 @@
// Deprecated: Use ExpConfigFetcher.ProtoReflect.Descriptor instead.
func (*ExpConfigFetcher) Descriptor() ([]byte, []int) {
- return file_metrics_proto_rawDescGZIP(), []int{12}
+ return file_metrics_proto_rawDescGZIP(), []int{15}
}
func (x *ExpConfigFetcher) GetStatus() ExpConfigFetcher_ConfigStatus {
@@ -1669,7 +1922,7 @@
func (x *MixedBuildsInfo) Reset() {
*x = MixedBuildsInfo{}
if protoimpl.UnsafeEnabled {
- mi := &file_metrics_proto_msgTypes[13]
+ mi := &file_metrics_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1682,7 +1935,7 @@
func (*MixedBuildsInfo) ProtoMessage() {}
func (x *MixedBuildsInfo) ProtoReflect() protoreflect.Message {
- mi := &file_metrics_proto_msgTypes[13]
+ mi := &file_metrics_proto_msgTypes[16]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1695,7 +1948,7 @@
// Deprecated: Use MixedBuildsInfo.ProtoReflect.Descriptor instead.
func (*MixedBuildsInfo) Descriptor() ([]byte, []int) {
- return file_metrics_proto_rawDescGZIP(), []int{13}
+ return file_metrics_proto_rawDescGZIP(), []int{16}
}
func (x *MixedBuildsInfo) GetMixedBuildEnabledModules() []string {
@@ -1732,7 +1985,7 @@
func (x *CriticalPathInfo) Reset() {
*x = CriticalPathInfo{}
if protoimpl.UnsafeEnabled {
- mi := &file_metrics_proto_msgTypes[14]
+ mi := &file_metrics_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1745,7 +1998,7 @@
func (*CriticalPathInfo) ProtoMessage() {}
func (x *CriticalPathInfo) ProtoReflect() protoreflect.Message {
- mi := &file_metrics_proto_msgTypes[14]
+ mi := &file_metrics_proto_msgTypes[17]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1758,7 +2011,7 @@
// Deprecated: Use CriticalPathInfo.ProtoReflect.Descriptor instead.
func (*CriticalPathInfo) Descriptor() ([]byte, []int) {
- return file_metrics_proto_rawDescGZIP(), []int{14}
+ return file_metrics_proto_rawDescGZIP(), []int{17}
}
func (x *CriticalPathInfo) GetElapsedTimeMicros() uint64 {
@@ -1803,7 +2056,7 @@
func (x *JobInfo) Reset() {
*x = JobInfo{}
if protoimpl.UnsafeEnabled {
- mi := &file_metrics_proto_msgTypes[15]
+ mi := &file_metrics_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1816,7 +2069,7 @@
func (*JobInfo) ProtoMessage() {}
func (x *JobInfo) ProtoReflect() protoreflect.Message {
- mi := &file_metrics_proto_msgTypes[15]
+ mi := &file_metrics_proto_msgTypes[18]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1829,7 +2082,7 @@
// Deprecated: Use JobInfo.ProtoReflect.Descriptor instead.
func (*JobInfo) Descriptor() ([]byte, []int) {
- return file_metrics_proto_rawDescGZIP(), []int{15}
+ return file_metrics_proto_rawDescGZIP(), []int{18}
}
func (x *JobInfo) GetElapsedTimeMicros() uint64 {
@@ -1846,12 +2099,449 @@
return ""
}
+type OptimizedBuildMetrics struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The total time spent analyzing what/how to optimize everything.
+ AnalysisPerf *PerfInfo `protobuf:"bytes,1,opt,name=analysis_perf,json=analysisPerf" json:"analysis_perf,omitempty"`
+ // The total time spent packaging artifacts.
+ PackagingPerf *PerfInfo `protobuf:"bytes,2,opt,name=packaging_perf,json=packagingPerf" json:"packaging_perf,omitempty"`
+ // Information for a single target (e.g. general-tests).
+ TargetResult []*OptimizedBuildMetrics_TargetOptimizationResult `protobuf:"bytes,3,rep,name=target_result,json=targetResult" json:"target_result,omitempty"`
+}
+
+func (x *OptimizedBuildMetrics) Reset() {
+ *x = OptimizedBuildMetrics{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_metrics_proto_msgTypes[19]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *OptimizedBuildMetrics) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OptimizedBuildMetrics) ProtoMessage() {}
+
+func (x *OptimizedBuildMetrics) ProtoReflect() protoreflect.Message {
+ mi := &file_metrics_proto_msgTypes[19]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use OptimizedBuildMetrics.ProtoReflect.Descriptor instead.
+func (*OptimizedBuildMetrics) Descriptor() ([]byte, []int) {
+ return file_metrics_proto_rawDescGZIP(), []int{19}
+}
+
+func (x *OptimizedBuildMetrics) GetAnalysisPerf() *PerfInfo {
+ if x != nil {
+ return x.AnalysisPerf
+ }
+ return nil
+}
+
+func (x *OptimizedBuildMetrics) GetPackagingPerf() *PerfInfo {
+ if x != nil {
+ return x.PackagingPerf
+ }
+ return nil
+}
+
+func (x *OptimizedBuildMetrics) GetTargetResult() []*OptimizedBuildMetrics_TargetOptimizationResult {
+ if x != nil {
+ return x.TargetResult
+ }
+ return nil
+}
+
+// This is created by soong_ui from SoongExexcutionMetrics files.
+type ExecutionMetrics struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The arguments provided on the command line.
+ CommandArgs []string `protobuf:"bytes,1,rep,name=command_args,json=commandArgs" json:"command_args,omitempty"`
+ // Changed files detected by the build.
+ ChangedFiles *AggregatedFileList `protobuf:"bytes,2,opt,name=changed_files,json=changedFiles" json:"changed_files,omitempty"`
+}
+
+func (x *ExecutionMetrics) Reset() {
+ *x = ExecutionMetrics{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_metrics_proto_msgTypes[20]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ExecutionMetrics) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ExecutionMetrics) ProtoMessage() {}
+
+func (x *ExecutionMetrics) ProtoReflect() protoreflect.Message {
+ mi := &file_metrics_proto_msgTypes[20]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ExecutionMetrics.ProtoReflect.Descriptor instead.
+func (*ExecutionMetrics) Descriptor() ([]byte, []int) {
+ return file_metrics_proto_rawDescGZIP(), []int{20}
+}
+
+func (x *ExecutionMetrics) GetCommandArgs() []string {
+ if x != nil {
+ return x.CommandArgs
+ }
+ return nil
+}
+
+func (x *ExecutionMetrics) GetChangedFiles() *AggregatedFileList {
+ if x != nil {
+ return x.ChangedFiles
+ }
+ return nil
+}
+
+// This is created by soong_ui from the various
+// android.find_input_delta_proto.FileList metrics provided to it by
+// find_input_delta.
+type AggregatedFileList struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The (possibly truncated list of) added files.
+ Additions []string `protobuf:"bytes,2,rep,name=additions" json:"additions,omitempty"`
+ // The (possibly truncated list of) changed files.
+ Changes []string `protobuf:"bytes,3,rep,name=changes" json:"changes,omitempty"`
+ // The (possibly truncated list of) deleted files.
+ Deletions []string `protobuf:"bytes,4,rep,name=deletions" json:"deletions,omitempty"`
+ // Count of files added/changed/deleted.
+ TotalDelta *uint32 `protobuf:"varint,5,opt,name=total_delta,json=totalDelta" json:"total_delta,omitempty"`
+ // Counts by extension.
+ Counts []*FileCount `protobuf:"bytes,6,rep,name=counts" json:"counts,omitempty"`
+}
+
+func (x *AggregatedFileList) Reset() {
+ *x = AggregatedFileList{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_metrics_proto_msgTypes[21]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *AggregatedFileList) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AggregatedFileList) ProtoMessage() {}
+
+func (x *AggregatedFileList) ProtoReflect() protoreflect.Message {
+ mi := &file_metrics_proto_msgTypes[21]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use AggregatedFileList.ProtoReflect.Descriptor instead.
+func (*AggregatedFileList) Descriptor() ([]byte, []int) {
+ return file_metrics_proto_rawDescGZIP(), []int{21}
+}
+
+func (x *AggregatedFileList) GetAdditions() []string {
+ if x != nil {
+ return x.Additions
+ }
+ return nil
+}
+
+func (x *AggregatedFileList) GetChanges() []string {
+ if x != nil {
+ return x.Changes
+ }
+ return nil
+}
+
+func (x *AggregatedFileList) GetDeletions() []string {
+ if x != nil {
+ return x.Deletions
+ }
+ return nil
+}
+
+func (x *AggregatedFileList) GetTotalDelta() uint32 {
+ if x != nil && x.TotalDelta != nil {
+ return *x.TotalDelta
+ }
+ return 0
+}
+
+func (x *AggregatedFileList) GetCounts() []*FileCount {
+ if x != nil {
+ return x.Counts
+ }
+ return nil
+}
+
+type FileCount struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The file extension
+ Extension *string `protobuf:"bytes,1,opt,name=extension" json:"extension,omitempty"`
+ // Number of added files with this extension.
+ Additions *uint32 `protobuf:"varint,2,opt,name=additions" json:"additions,omitempty"`
+ // Number of modified files with this extension.
+ Modifications *uint32 `protobuf:"varint,3,opt,name=modifications" json:"modifications,omitempty"`
+ // Number of deleted files with this extension.
+ Deletions *uint32 `protobuf:"varint,4,opt,name=deletions" json:"deletions,omitempty"`
+}
+
+func (x *FileCount) Reset() {
+ *x = FileCount{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_metrics_proto_msgTypes[22]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *FileCount) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FileCount) ProtoMessage() {}
+
+func (x *FileCount) ProtoReflect() protoreflect.Message {
+ mi := &file_metrics_proto_msgTypes[22]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use FileCount.ProtoReflect.Descriptor instead.
+func (*FileCount) Descriptor() ([]byte, []int) {
+ return file_metrics_proto_rawDescGZIP(), []int{22}
+}
+
+func (x *FileCount) GetExtension() string {
+ if x != nil && x.Extension != nil {
+ return *x.Extension
+ }
+ return ""
+}
+
+func (x *FileCount) GetAdditions() uint32 {
+ if x != nil && x.Additions != nil {
+ return *x.Additions
+ }
+ return 0
+}
+
+func (x *FileCount) GetModifications() uint32 {
+ if x != nil && x.Modifications != nil {
+ return *x.Modifications
+ }
+ return 0
+}
+
+func (x *FileCount) GetDeletions() uint32 {
+ if x != nil && x.Deletions != nil {
+ return *x.Deletions
+ }
+ return 0
+}
+
+type OptimizedBuildMetrics_TargetOptimizationResult struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Target name (e.g. general-tests).
+ Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+ // Whether or not this target was optimized.
+ Optimized *bool `protobuf:"varint,2,opt,name=optimized" json:"optimized,omitempty"`
+ // Reasoning for why the target wasn't optimized if it wasn't
+ OptimizationRationale *string `protobuf:"bytes,3,opt,name=optimization_rationale,json=optimizationRationale" json:"optimization_rationale,omitempty"`
+ // Time spent packaging this specific target (if it was optimized).
+ PackagingPerf *PerfInfo `protobuf:"bytes,4,opt,name=packaging_perf,json=packagingPerf" json:"packaging_perf,omitempty"`
+ // Information for each different artifact produced by this target (if it
+ // was optimized).
+ OutputArtifact []*OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact `protobuf:"bytes,5,rep,name=output_artifact,json=outputArtifact" json:"output_artifact,omitempty"`
+}
+
+func (x *OptimizedBuildMetrics_TargetOptimizationResult) Reset() {
+ *x = OptimizedBuildMetrics_TargetOptimizationResult{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_metrics_proto_msgTypes[23]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *OptimizedBuildMetrics_TargetOptimizationResult) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OptimizedBuildMetrics_TargetOptimizationResult) ProtoMessage() {}
+
+func (x *OptimizedBuildMetrics_TargetOptimizationResult) ProtoReflect() protoreflect.Message {
+ mi := &file_metrics_proto_msgTypes[23]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use OptimizedBuildMetrics_TargetOptimizationResult.ProtoReflect.Descriptor instead.
+func (*OptimizedBuildMetrics_TargetOptimizationResult) Descriptor() ([]byte, []int) {
+ return file_metrics_proto_rawDescGZIP(), []int{19, 0}
+}
+
+func (x *OptimizedBuildMetrics_TargetOptimizationResult) GetName() string {
+ if x != nil && x.Name != nil {
+ return *x.Name
+ }
+ return ""
+}
+
+func (x *OptimizedBuildMetrics_TargetOptimizationResult) GetOptimized() bool {
+ if x != nil && x.Optimized != nil {
+ return *x.Optimized
+ }
+ return false
+}
+
+func (x *OptimizedBuildMetrics_TargetOptimizationResult) GetOptimizationRationale() string {
+ if x != nil && x.OptimizationRationale != nil {
+ return *x.OptimizationRationale
+ }
+ return ""
+}
+
+func (x *OptimizedBuildMetrics_TargetOptimizationResult) GetPackagingPerf() *PerfInfo {
+ if x != nil {
+ return x.PackagingPerf
+ }
+ return nil
+}
+
+func (x *OptimizedBuildMetrics_TargetOptimizationResult) GetOutputArtifact() []*OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact {
+ if x != nil {
+ return x.OutputArtifact
+ }
+ return nil
+}
+
+type OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Artifact file name (e.g. general-tests.zip)
+ Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+ // Size of the file.
+ Size *int64 `protobuf:"varint,2,opt,name=size" json:"size,omitempty"`
+ // Lists of modules packaged into this artifact.
+ IncludedModules []string `protobuf:"bytes,3,rep,name=included_modules,json=includedModules" json:"included_modules,omitempty"`
+}
+
+func (x *OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) Reset() {
+ *x = OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_metrics_proto_msgTypes[24]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) ProtoMessage() {}
+
+func (x *OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) ProtoReflect() protoreflect.Message {
+ mi := &file_metrics_proto_msgTypes[24]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact.ProtoReflect.Descriptor instead.
+func (*OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) Descriptor() ([]byte, []int) {
+ return file_metrics_proto_rawDescGZIP(), []int{19, 0, 0}
+}
+
+func (x *OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) GetName() string {
+ if x != nil && x.Name != nil {
+ return *x.Name
+ }
+ return ""
+}
+
+func (x *OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) GetSize() int64 {
+ if x != nil && x.Size != nil {
+ return *x.Size
+ }
+ return 0
+}
+
+func (x *OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) GetIncludedModules() []string {
+ if x != nil {
+ return x.IncludedModules
+ }
+ return nil
+}
+
var File_metrics_proto protoreflect.FileDescriptor
var file_metrics_proto_rawDesc = []byte{
0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x13, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74,
- 0x72, 0x69, 0x63, 0x73, 0x22, 0xcc, 0x0f, 0x0a, 0x0b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
+ 0x72, 0x69, 0x63, 0x73, 0x22, 0xd7, 0x10, 0x0a, 0x0b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
0x42, 0x61, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x61,
0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01,
0x28, 0x03, 0x52, 0x12, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d,
@@ -1969,220 +2659,338 @@
0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c,
0x65, 0x18, 0x22, 0x20, 0x03, 0x28, 0x09, 0x52, 0x1a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64,
0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61,
- 0x62, 0x6c, 0x65, 0x22, 0x30, 0x0a, 0x0c, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x56, 0x61, 0x72, 0x69,
- 0x61, 0x6e, 0x74, 0x12, 0x08, 0x0a, 0x04, 0x55, 0x53, 0x45, 0x52, 0x10, 0x00, 0x12, 0x0d, 0x0a,
- 0x09, 0x55, 0x53, 0x45, 0x52, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03,
- 0x45, 0x4e, 0x47, 0x10, 0x02, 0x22, 0x3c, 0x0a, 0x04, 0x41, 0x72, 0x63, 0x68, 0x12, 0x0b, 0x0a,
- 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x52,
- 0x4d, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x52, 0x4d, 0x36, 0x34, 0x10, 0x02, 0x12, 0x07,
- 0x0a, 0x03, 0x58, 0x38, 0x36, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x58, 0x38, 0x36, 0x5f, 0x36,
- 0x34, 0x10, 0x04, 0x22, 0x8a, 0x04, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e,
- 0x66, 0x69, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x5f, 0x67, 0x6f, 0x6d, 0x61, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x75, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x17,
- 0x0a, 0x07, 0x75, 0x73, 0x65, 0x5f, 0x72, 0x62, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52,
- 0x06, 0x75, 0x73, 0x65, 0x52, 0x62, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x66, 0x6f, 0x72, 0x63, 0x65,
- 0x5f, 0x75, 0x73, 0x65, 0x5f, 0x67, 0x6f, 0x6d, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52,
- 0x0c, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x55, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x24, 0x0a,
- 0x0e, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x61, 0x73, 0x5f, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x18,
- 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x41, 0x73, 0x4e, 0x69,
- 0x6e, 0x6a, 0x61, 0x12, 0x2a, 0x0a, 0x11, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x69, 0x78,
- 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f,
- 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12,
- 0x18, 0x0a, 0x07, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09,
- 0x52, 0x07, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x12, 0x44, 0x0a, 0x1f, 0x66, 0x6f, 0x72,
- 0x63, 0x65, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c,
- 0x5f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x07, 0x20, 0x01,
- 0x28, 0x08, 0x52, 0x1b, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
- 0x42, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12,
- 0x79, 0x0a, 0x18, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x5f,
- 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28,
- 0x0e, 0x32, 0x36, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f,
- 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e,
- 0x66, 0x69, 0x67, 0x2e, 0x4e, 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c,
- 0x69, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3a, 0x08, 0x4e, 0x4f, 0x54, 0x5f, 0x55,
- 0x53, 0x45, 0x44, 0x52, 0x15, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74,
- 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x74, 0x0a, 0x15, 0x4e, 0x69,
- 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6f, 0x75,
- 0x72, 0x63, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x53, 0x45, 0x44, 0x10,
- 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x49, 0x4e, 0x4a, 0x41, 0x5f, 0x4c, 0x4f, 0x47, 0x10, 0x01,
- 0x12, 0x16, 0x0a, 0x12, 0x45, 0x56, 0x45, 0x4e, 0x4c, 0x59, 0x5f, 0x44, 0x49, 0x53, 0x54, 0x52,
- 0x49, 0x42, 0x55, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x45, 0x58, 0x54, 0x45,
- 0x52, 0x4e, 0x41, 0x4c, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x03, 0x12, 0x13, 0x0a, 0x0f, 0x48,
- 0x49, 0x4e, 0x54, 0x5f, 0x46, 0x52, 0x4f, 0x4d, 0x5f, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, 0x04,
- 0x22, 0x6f, 0x0a, 0x12, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
- 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x32, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f,
- 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x68, 0x79, 0x73,
- 0x69, 0x63, 0x61, 0x6c, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x76,
- 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x70, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01,
- 0x28, 0x05, 0x52, 0x0d, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x70, 0x75,
- 0x73, 0x22, 0xca, 0x02, 0x0a, 0x08, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20,
- 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
- 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
- 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69,
- 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54,
- 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65,
- 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x65, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65,
- 0x12, 0x21, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x18, 0x05,
- 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79,
- 0x55, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73,
- 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06,
- 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69,
- 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65,
- 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x15,
- 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
- 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x6f, 0x6e, 0x5f, 0x7a, 0x65, 0x72,
- 0x6f, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f,
- 0x6e, 0x5a, 0x65, 0x72, 0x6f, 0x45, 0x78, 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72,
- 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x61,
- 0x0a, 0x0c, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x12, 0x12,
- 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, 0x69,
- 0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03,
- 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
- 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75,
- 0x6e, 0x74, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70,
- 0x73, 0x22, 0x64, 0x0a, 0x10, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72,
- 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x08, 0x63, 0x6f, 0x75,
- 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f,
- 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
- 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x08, 0x63,
- 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x22, 0x37, 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x66, 0x43,
- 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
- 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
- 0x22, 0xb9, 0x03, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f,
- 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
- 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x10,
- 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73,
- 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65,
- 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d,
- 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01,
- 0x28, 0x04, 0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69,
- 0x63, 0x72, 0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f,
- 0x6b, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, 0x73,
- 0x4b, 0x62, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65,
- 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d,
- 0x69, 0x6e, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a,
- 0x0a, 0x11, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75,
- 0x6c, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, 0x72,
- 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6f,
- 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52,
- 0x09, 0x69, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6f,
- 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04,
- 0x52, 0x0a, 0x69, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, 0x1a,
- 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78,
- 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04,
- 0x52, 0x18, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65,
- 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, 0x6e,
- 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78,
- 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04,
- 0x52, 0x1a, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e,
- 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a,
- 0x0e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12,
- 0x5b, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
- 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x75,
- 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64,
- 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x52,
- 0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b,
- 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a,
- 0x0e, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18,
- 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x4d, 0x6f, 0x64, 0x75,
- 0x6c, 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74,
- 0x65, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12,
- 0x09, 0x0a, 0x05, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x41,
- 0x4b, 0x45, 0x10, 0x02, 0x22, 0x6c, 0x0a, 0x1a, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c,
- 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69,
- 0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
- 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
- 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x65,
- 0x74, 0x72, 0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69,
- 0x63, 0x73, 0x22, 0x62, 0x0a, 0x1b, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73,
- 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
- 0x73, 0x12, 0x43, 0x0a, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
- 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65,
- 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73,
- 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
- 0x52, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x22, 0x94, 0x03, 0x0a, 0x11, 0x53, 0x6f, 0x6f, 0x6e, 0x67,
- 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07,
- 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6d,
- 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e,
- 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e,
- 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f,
- 0x63, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x74,
- 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28,
- 0x0a, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x73, 0x69,
- 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41,
- 0x6c, 0x6c, 0x6f, 0x63, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f,
- 0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52,
- 0x0b, 0x6d, 0x61, 0x78, 0x48, 0x65, 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, 0x06,
- 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73,
+ 0x62, 0x6c, 0x65, 0x12, 0x62, 0x0a, 0x17, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64,
+ 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x23,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69,
+ 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6d,
+ 0x69, 0x7a, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
+ 0x52, 0x15, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64,
+ 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65,
+ 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x18, 0x24, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x22, 0x30,
+ 0x0a, 0x0c, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x56, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x12, 0x08,
+ 0x0a, 0x04, 0x55, 0x53, 0x45, 0x52, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x53, 0x45, 0x52,
+ 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x45, 0x4e, 0x47, 0x10, 0x02,
+ 0x22, 0x3c, 0x0a, 0x04, 0x41, 0x72, 0x63, 0x68, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e,
+ 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x52, 0x4d, 0x10, 0x01, 0x12, 0x09,
+ 0x0a, 0x05, 0x41, 0x52, 0x4d, 0x36, 0x34, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x58, 0x38, 0x36,
+ 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x58, 0x38, 0x36, 0x5f, 0x36, 0x34, 0x10, 0x04, 0x22, 0xf2,
+ 0x04, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x19,
+ 0x0a, 0x08, 0x75, 0x73, 0x65, 0x5f, 0x67, 0x6f, 0x6d, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x07, 0x75, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65,
+ 0x5f, 0x72, 0x62, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x75, 0x73, 0x65, 0x52,
+ 0x62, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x5f,
+ 0x67, 0x6f, 0x6d, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x66, 0x6f, 0x72, 0x63,
+ 0x65, 0x55, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x62, 0x61, 0x7a, 0x65,
+ 0x6c, 0x5f, 0x61, 0x73, 0x5f, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x0c, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x41, 0x73, 0x4e, 0x69, 0x6e, 0x6a, 0x61, 0x12, 0x2a,
+ 0x0a, 0x11, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75,
+ 0x69, 0x6c, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x62, 0x61, 0x7a, 0x65, 0x6c,
+ 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x61,
+ 0x72, 0x67, 0x65, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x74, 0x61, 0x72,
+ 0x67, 0x65, 0x74, 0x73, 0x12, 0x44, 0x0a, 0x1f, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x69,
+ 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x69, 0x78, 0x65,
+ 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x66,
+ 0x6f, 0x72, 0x63, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x61, 0x7a, 0x65, 0x6c,
+ 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x79, 0x0a, 0x18, 0x6e, 0x69,
+ 0x6e, 0x6a, 0x61, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f,
+ 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, 0x73,
0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
- 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x65, 0x76, 0x65,
- 0x6e, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x11, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69,
- 0x6c, 0x64, 0x73, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24,
- 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74,
- 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73,
- 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64,
- 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x46, 0x0a, 0x0d, 0x70, 0x65, 0x72, 0x66, 0x5f, 0x63, 0x6f,
- 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73,
- 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
- 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x52,
- 0x0c, 0x70, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x22, 0xdb, 0x01,
- 0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68,
- 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
- 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66,
- 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
- 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a,
- 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69,
- 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6d, 0x69, 0x63, 0x72,
- 0x6f, 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74,
- 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10,
- 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a,
- 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x49, 0x53, 0x53,
- 0x49, 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, 0x52, 0x54, 0x10, 0x03, 0x22, 0x91, 0x01, 0x0a, 0x0f,
- 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12,
- 0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x65,
- 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01,
- 0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64,
- 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x3f,
- 0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x69,
- 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02,
- 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64,
- 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22,
- 0x8a, 0x02, 0x0a, 0x10, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68,
- 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f,
- 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69,
- 0x63, 0x72, 0x6f, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c,
- 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f,
- 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61,
- 0x6c, 0x50, 0x61, 0x74, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12,
- 0x41, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68,
- 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62,
- 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62,
- 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61,
- 0x74, 0x68, 0x12, 0x48, 0x0a, 0x11, 0x6c, 0x6f, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6e, 0x6e, 0x69,
- 0x6e, 0x67, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e,
+ 0x63, 0x73, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x4e,
+ 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6f,
+ 0x75, 0x72, 0x63, 0x65, 0x3a, 0x08, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x53, 0x45, 0x44, 0x52, 0x15,
+ 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x53,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x47, 0x0a, 0x0e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x65,
+ 0x6e, 0x76, 0x5f, 0x76, 0x61, 0x72, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e,
0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72,
- 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6c, 0x6f, 0x6e,
- 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x62, 0x0a, 0x07,
- 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73,
- 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d,
- 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x6a, 0x6f, 0x62, 0x5f, 0x64,
- 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x0e, 0x6a, 0x6f, 0x62, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
- 0x42, 0x28, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e,
- 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74,
- 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x69, 0x63, 0x73, 0x2e, 0x53, 0x6f, 0x6f, 0x6e, 0x67, 0x45, 0x6e, 0x76, 0x56, 0x61, 0x72, 0x73,
+ 0x52, 0x0c, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x45, 0x6e, 0x76, 0x56, 0x61, 0x72, 0x73, 0x12, 0x1d,
+ 0x0a, 0x0a, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x0a, 0x20, 0x01,
+ 0x28, 0x08, 0x52, 0x09, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x74, 0x0a,
+ 0x15, 0x4e, 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x73, 0x74,
+ 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x53,
+ 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x49, 0x4e, 0x4a, 0x41, 0x5f, 0x4c, 0x4f,
+ 0x47, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x45, 0x56, 0x45, 0x4e, 0x4c, 0x59, 0x5f, 0x44, 0x49,
+ 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x45,
+ 0x58, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x03, 0x12, 0x13,
+ 0x0a, 0x0f, 0x48, 0x49, 0x4e, 0x54, 0x5f, 0x46, 0x52, 0x4f, 0x4d, 0x5f, 0x53, 0x4f, 0x4f, 0x4e,
+ 0x47, 0x10, 0x04, 0x22, 0x67, 0x0a, 0x0c, 0x53, 0x6f, 0x6f, 0x6e, 0x67, 0x45, 0x6e, 0x76, 0x56,
+ 0x61, 0x72, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x63,
+ 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x61,
+ 0x72, 0x74, 0x69, 0x61, 0x6c, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x12, 0x2e, 0x0a, 0x13,
+ 0x75, 0x73, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x6d, 0x70,
+ 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x75, 0x73, 0x65, 0x50, 0x61,
+ 0x72, 0x74, 0x69, 0x61, 0x6c, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x22, 0xed, 0x01, 0x0a,
+ 0x12, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49,
+ 0x6e, 0x66, 0x6f, 0x12, 0x32, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x68, 0x79,
+ 0x73, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x04, 0x52, 0x13, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61,
+ 0x6c, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c,
+ 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x70, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52,
+ 0x0d, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x70, 0x75, 0x73, 0x12, 0x3d,
+ 0x0a, 0x08, 0x63, 0x70, 0x75, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x22, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d,
+ 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x70, 0x75,
+ 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x63, 0x70, 0x75, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a,
+ 0x08, 0x6d, 0x65, 0x6d, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x22, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4d, 0x65, 0x6d, 0x49,
+ 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x7e, 0x0a, 0x0d,
+ 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x70, 0x75, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1b, 0x0a,
+ 0x09, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x08, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f,
+ 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
+ 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x70, 0x75,
+ 0x5f, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x63, 0x70,
+ 0x75, 0x43, 0x6f, 0x72, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18,
+ 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x22, 0x6c, 0x0a, 0x0d,
+ 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4d, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1b, 0x0a,
+ 0x09, 0x6d, 0x65, 0x6d, 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
+ 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x65,
+ 0x6d, 0x5f, 0x66, 0x72, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x6d, 0x65,
+ 0x6d, 0x46, 0x72, 0x65, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x6d, 0x5f, 0x61, 0x76, 0x61,
+ 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x65,
+ 0x6d, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x22, 0xca, 0x02, 0x0a, 0x08, 0x50,
+ 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
+ 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65,
+ 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
+ 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a,
+ 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09,
+ 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52,
+ 0x08, 0x72, 0x65, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0a, 0x6d, 0x65, 0x6d,
+ 0x6f, 0x72, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x18,
+ 0x01, 0x52, 0x09, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x17,
+ 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
+ 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e,
+ 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72,
+ 0x69, 0x63, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75,
+ 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x15, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
+ 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22,
+ 0x0a, 0x0d, 0x6e, 0x6f, 0x6e, 0x5f, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x18,
+ 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f, 0x6e, 0x5a, 0x65, 0x72, 0x6f, 0x45, 0x78,
+ 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73,
+ 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72,
+ 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x61, 0x0a, 0x0c, 0x50, 0x65, 0x72, 0x66, 0x43,
+ 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x67,
+ 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x6f,
+ 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+ 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x47, 0x72, 0x6f,
+ 0x75, 0x70, 0x52, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x22, 0x64, 0x0a, 0x10, 0x50, 0x65,
+ 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x12,
+ 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
+ 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x08, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02,
+ 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69,
+ 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43,
+ 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x08, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73,
+ 0x22, 0x37, 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12,
+ 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
+ 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xb9, 0x03, 0x0a, 0x13, 0x50, 0x72,
+ 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66,
+ 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69,
+ 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52,
+ 0x0e, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12,
+ 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d,
+ 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x73, 0x79, 0x73,
+ 0x74, 0x65, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x1c, 0x0a,
+ 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f, 0x6b, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28,
+ 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, 0x73, 0x4b, 0x62, 0x12, 0x2a, 0x0a, 0x11, 0x6d,
+ 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73,
+ 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x50, 0x61, 0x67,
+ 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x61, 0x6a, 0x6f, 0x72,
+ 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01,
+ 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75,
+ 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6f, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f,
+ 0x6b, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6f, 0x49, 0x6e, 0x70, 0x75,
+ 0x74, 0x4b, 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6f, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74,
+ 0x5f, 0x6b, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x69, 0x6f, 0x4f, 0x75, 0x74,
+ 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, 0x1a, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61,
+ 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63,
+ 0x68, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x18, 0x76, 0x6f, 0x6c, 0x75, 0x6e,
+ 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63,
+ 0x68, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61,
+ 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63,
+ 0x68, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a, 0x69, 0x6e, 0x76, 0x6f, 0x6c,
+ 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69,
+ 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a, 0x0e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
+ 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x5b, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c,
+ 0x64, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f,
+ 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74,
+ 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49,
+ 0x6e, 0x66, 0x6f, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a,
+ 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x52, 0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53,
+ 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f,
+ 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75,
+ 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66,
+ 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c,
+ 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x0b,
+ 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x55,
+ 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x4f, 0x4f, 0x4e,
+ 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x41, 0x4b, 0x45, 0x10, 0x02, 0x22, 0x6c, 0x0a,
+ 0x1a, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75,
+ 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e,
+ 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
+ 0x3a, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x20, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d,
+ 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x42, 0x61,
+ 0x73, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x62, 0x0a, 0x1b, 0x43,
+ 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e,
+ 0x65, 0x79, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x43, 0x0a, 0x04, 0x63, 0x75,
+ 0x6a, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67,
+ 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43,
+ 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e,
+ 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x22,
+ 0x94, 0x03, 0x0a, 0x11, 0x53, 0x6f, 0x6f, 0x6e, 0x67, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12,
+ 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x0d, 0x52, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x74,
+ 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c,
+ 0x6f, 0x63, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c,
+ 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
+ 0x04, 0x52, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x53, 0x69, 0x7a,
+ 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x69,
+ 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x48, 0x65, 0x61,
+ 0x70, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18,
+ 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
+ 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66,
+ 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x11,
+ 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x5f, 0x69, 0x6e, 0x66,
+ 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
+ 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x69,
+ 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6d,
+ 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x46,
+ 0x0a, 0x0d, 0x70, 0x65, 0x72, 0x66, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18,
+ 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
+ 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66,
+ 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x52, 0x0c, 0x70, 0x65, 0x72, 0x66, 0x43, 0x6f,
+ 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x22, 0xdb, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f,
+ 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73,
+ 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f,
+ 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+ 0x73, 0x2e, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68,
+ 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52,
+ 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e,
+ 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e,
+ 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20,
+ 0x01, 0x28, 0x04, 0x52, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e,
+ 0x4f, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f,
+ 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10,
+ 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45,
+ 0x52, 0x54, 0x10, 0x03, 0x22, 0x91, 0x01, 0x0a, 0x0f, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75,
+ 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65,
+ 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f,
+ 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d,
+ 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64,
+ 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64,
+ 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f,
+ 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d,
+ 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
+ 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x8a, 0x02, 0x0a, 0x10, 0x43, 0x72, 0x69,
+ 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a,
+ 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69,
+ 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70,
+ 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x39, 0x0a,
+ 0x19, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x74,
+ 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
+ 0x52, 0x16, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x54, 0x69,
+ 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x41, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x74,
+ 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
+ 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x63,
+ 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x48, 0x0a, 0x11, 0x6c,
+ 0x6f, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x6f, 0x62, 0x73,
+ 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62,
+ 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62,
+ 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6c, 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e,
+ 0x67, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x62, 0x0a, 0x07, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f,
+ 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65,
+ 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65,
+ 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73,
+ 0x12, 0x27, 0x0a, 0x0f, 0x6a, 0x6f, 0x62, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
+ 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6a, 0x6f, 0x62, 0x44, 0x65,
+ 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xb9, 0x05, 0x0a, 0x15, 0x4f, 0x70,
+ 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72,
+ 0x69, 0x63, 0x73, 0x12, 0x42, 0x0a, 0x0d, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x5f,
+ 0x70, 0x65, 0x72, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f,
+ 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
+ 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x61, 0x6e, 0x61, 0x6c, 0x79,
+ 0x73, 0x69, 0x73, 0x50, 0x65, 0x72, 0x66, 0x12, 0x44, 0x0a, 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61,
+ 0x67, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0d,
+ 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x50, 0x65, 0x72, 0x66, 0x12, 0x68, 0x0a,
+ 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03,
+ 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69,
+ 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6d,
+ 0x69, 0x7a, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
+ 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65,
+ 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0xab, 0x03, 0x0a, 0x18, 0x54, 0x61, 0x72, 0x67,
+ 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65,
+ 0x73, 0x75, 0x6c, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x70, 0x74, 0x69,
+ 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6f, 0x70, 0x74,
+ 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x35, 0x0a, 0x16, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69,
+ 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x65,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x65, 0x12, 0x44, 0x0a,
+ 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, 0x66, 0x18,
+ 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
+ 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66,
+ 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0d, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x50,
+ 0x65, 0x72, 0x66, 0x12, 0x7b, 0x0a, 0x0f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x61, 0x72,
+ 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x52, 0x2e, 0x73,
+ 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
+ 0x63, 0x73, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c,
+ 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f,
+ 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c,
+ 0x74, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74,
+ 0x52, 0x0e, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74,
+ 0x1a, 0x63, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61,
+ 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e,
+ 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x03,
+ 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x4d, 0x6f,
+ 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x83, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74,
+ 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x61, 0x72, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09,
+ 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, 0x72, 0x67, 0x73, 0x12, 0x4c, 0x0a,
+ 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69,
+ 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65,
+ 0x67, 0x61, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0c, 0x63,
+ 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x22, 0xc9, 0x01, 0x0a, 0x12,
+ 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69,
+ 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18,
+ 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x12, 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
+ 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65,
+ 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64,
+ 0x65, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61,
+ 0x6c, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74,
+ 0x6f, 0x74, 0x61, 0x6c, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x36, 0x0a, 0x06, 0x63, 0x6f, 0x75,
+ 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x6f, 0x6f, 0x6e,
+ 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e,
+ 0x46, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, 0x63, 0x6f, 0x75, 0x6e, 0x74,
+ 0x73, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x8b, 0x01, 0x0a, 0x09, 0x46, 0x69, 0x6c, 0x65,
+ 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
+ 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73,
+ 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x28, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
+ 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+ 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
}
var (
@@ -2198,64 +3006,84 @@
}
var file_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 5)
-var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 16)
+var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 25)
var file_metrics_proto_goTypes = []interface{}{
- (MetricsBase_BuildVariant)(0), // 0: soong_build_metrics.MetricsBase.BuildVariant
- (MetricsBase_Arch)(0), // 1: soong_build_metrics.MetricsBase.Arch
- (BuildConfig_NinjaWeightListSource)(0), // 2: soong_build_metrics.BuildConfig.NinjaWeightListSource
- (ModuleTypeInfo_BuildSystem)(0), // 3: soong_build_metrics.ModuleTypeInfo.BuildSystem
- (ExpConfigFetcher_ConfigStatus)(0), // 4: soong_build_metrics.ExpConfigFetcher.ConfigStatus
- (*MetricsBase)(nil), // 5: soong_build_metrics.MetricsBase
- (*BuildConfig)(nil), // 6: soong_build_metrics.BuildConfig
- (*SystemResourceInfo)(nil), // 7: soong_build_metrics.SystemResourceInfo
- (*PerfInfo)(nil), // 8: soong_build_metrics.PerfInfo
- (*PerfCounters)(nil), // 9: soong_build_metrics.PerfCounters
- (*PerfCounterGroup)(nil), // 10: soong_build_metrics.PerfCounterGroup
- (*PerfCounter)(nil), // 11: soong_build_metrics.PerfCounter
- (*ProcessResourceInfo)(nil), // 12: soong_build_metrics.ProcessResourceInfo
- (*ModuleTypeInfo)(nil), // 13: soong_build_metrics.ModuleTypeInfo
- (*CriticalUserJourneyMetrics)(nil), // 14: soong_build_metrics.CriticalUserJourneyMetrics
- (*CriticalUserJourneysMetrics)(nil), // 15: soong_build_metrics.CriticalUserJourneysMetrics
- (*SoongBuildMetrics)(nil), // 16: soong_build_metrics.SoongBuildMetrics
- (*ExpConfigFetcher)(nil), // 17: soong_build_metrics.ExpConfigFetcher
- (*MixedBuildsInfo)(nil), // 18: soong_build_metrics.MixedBuildsInfo
- (*CriticalPathInfo)(nil), // 19: soong_build_metrics.CriticalPathInfo
- (*JobInfo)(nil), // 20: soong_build_metrics.JobInfo
+ (MetricsBase_BuildVariant)(0), // 0: soong_build_metrics.MetricsBase.BuildVariant
+ (MetricsBase_Arch)(0), // 1: soong_build_metrics.MetricsBase.Arch
+ (BuildConfig_NinjaWeightListSource)(0), // 2: soong_build_metrics.BuildConfig.NinjaWeightListSource
+ (ModuleTypeInfo_BuildSystem)(0), // 3: soong_build_metrics.ModuleTypeInfo.BuildSystem
+ (ExpConfigFetcher_ConfigStatus)(0), // 4: soong_build_metrics.ExpConfigFetcher.ConfigStatus
+ (*MetricsBase)(nil), // 5: soong_build_metrics.MetricsBase
+ (*BuildConfig)(nil), // 6: soong_build_metrics.BuildConfig
+ (*SoongEnvVars)(nil), // 7: soong_build_metrics.SoongEnvVars
+ (*SystemResourceInfo)(nil), // 8: soong_build_metrics.SystemResourceInfo
+ (*SystemCpuInfo)(nil), // 9: soong_build_metrics.SystemCpuInfo
+ (*SystemMemInfo)(nil), // 10: soong_build_metrics.SystemMemInfo
+ (*PerfInfo)(nil), // 11: soong_build_metrics.PerfInfo
+ (*PerfCounters)(nil), // 12: soong_build_metrics.PerfCounters
+ (*PerfCounterGroup)(nil), // 13: soong_build_metrics.PerfCounterGroup
+ (*PerfCounter)(nil), // 14: soong_build_metrics.PerfCounter
+ (*ProcessResourceInfo)(nil), // 15: soong_build_metrics.ProcessResourceInfo
+ (*ModuleTypeInfo)(nil), // 16: soong_build_metrics.ModuleTypeInfo
+ (*CriticalUserJourneyMetrics)(nil), // 17: soong_build_metrics.CriticalUserJourneyMetrics
+ (*CriticalUserJourneysMetrics)(nil), // 18: soong_build_metrics.CriticalUserJourneysMetrics
+ (*SoongBuildMetrics)(nil), // 19: soong_build_metrics.SoongBuildMetrics
+ (*ExpConfigFetcher)(nil), // 20: soong_build_metrics.ExpConfigFetcher
+ (*MixedBuildsInfo)(nil), // 21: soong_build_metrics.MixedBuildsInfo
+ (*CriticalPathInfo)(nil), // 22: soong_build_metrics.CriticalPathInfo
+ (*JobInfo)(nil), // 23: soong_build_metrics.JobInfo
+ (*OptimizedBuildMetrics)(nil), // 24: soong_build_metrics.OptimizedBuildMetrics
+ (*ExecutionMetrics)(nil), // 25: soong_build_metrics.ExecutionMetrics
+ (*AggregatedFileList)(nil), // 26: soong_build_metrics.AggregatedFileList
+ (*FileCount)(nil), // 27: soong_build_metrics.FileCount
+ (*OptimizedBuildMetrics_TargetOptimizationResult)(nil), // 28: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult
+ (*OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact)(nil), // 29: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.OutputArtifact
}
var file_metrics_proto_depIdxs = []int32{
0, // 0: soong_build_metrics.MetricsBase.target_build_variant:type_name -> soong_build_metrics.MetricsBase.BuildVariant
1, // 1: soong_build_metrics.MetricsBase.target_arch:type_name -> soong_build_metrics.MetricsBase.Arch
1, // 2: soong_build_metrics.MetricsBase.host_arch:type_name -> soong_build_metrics.MetricsBase.Arch
1, // 3: soong_build_metrics.MetricsBase.host_2nd_arch:type_name -> soong_build_metrics.MetricsBase.Arch
- 8, // 4: soong_build_metrics.MetricsBase.setup_tools:type_name -> soong_build_metrics.PerfInfo
- 8, // 5: soong_build_metrics.MetricsBase.kati_runs:type_name -> soong_build_metrics.PerfInfo
- 8, // 6: soong_build_metrics.MetricsBase.soong_runs:type_name -> soong_build_metrics.PerfInfo
- 8, // 7: soong_build_metrics.MetricsBase.ninja_runs:type_name -> soong_build_metrics.PerfInfo
- 8, // 8: soong_build_metrics.MetricsBase.total:type_name -> soong_build_metrics.PerfInfo
- 16, // 9: soong_build_metrics.MetricsBase.soong_build_metrics:type_name -> soong_build_metrics.SoongBuildMetrics
+ 11, // 4: soong_build_metrics.MetricsBase.setup_tools:type_name -> soong_build_metrics.PerfInfo
+ 11, // 5: soong_build_metrics.MetricsBase.kati_runs:type_name -> soong_build_metrics.PerfInfo
+ 11, // 6: soong_build_metrics.MetricsBase.soong_runs:type_name -> soong_build_metrics.PerfInfo
+ 11, // 7: soong_build_metrics.MetricsBase.ninja_runs:type_name -> soong_build_metrics.PerfInfo
+ 11, // 8: soong_build_metrics.MetricsBase.total:type_name -> soong_build_metrics.PerfInfo
+ 19, // 9: soong_build_metrics.MetricsBase.soong_build_metrics:type_name -> soong_build_metrics.SoongBuildMetrics
6, // 10: soong_build_metrics.MetricsBase.build_config:type_name -> soong_build_metrics.BuildConfig
- 7, // 11: soong_build_metrics.MetricsBase.system_resource_info:type_name -> soong_build_metrics.SystemResourceInfo
- 8, // 12: soong_build_metrics.MetricsBase.bazel_runs:type_name -> soong_build_metrics.PerfInfo
- 17, // 13: soong_build_metrics.MetricsBase.exp_config_fetcher:type_name -> soong_build_metrics.ExpConfigFetcher
- 19, // 14: soong_build_metrics.MetricsBase.critical_path_info:type_name -> soong_build_metrics.CriticalPathInfo
- 2, // 15: soong_build_metrics.BuildConfig.ninja_weight_list_source:type_name -> soong_build_metrics.BuildConfig.NinjaWeightListSource
- 12, // 16: soong_build_metrics.PerfInfo.processes_resource_info:type_name -> soong_build_metrics.ProcessResourceInfo
- 10, // 17: soong_build_metrics.PerfCounters.groups:type_name -> soong_build_metrics.PerfCounterGroup
- 11, // 18: soong_build_metrics.PerfCounterGroup.counters:type_name -> soong_build_metrics.PerfCounter
- 3, // 19: soong_build_metrics.ModuleTypeInfo.build_system:type_name -> soong_build_metrics.ModuleTypeInfo.BuildSystem
- 5, // 20: soong_build_metrics.CriticalUserJourneyMetrics.metrics:type_name -> soong_build_metrics.MetricsBase
- 14, // 21: soong_build_metrics.CriticalUserJourneysMetrics.cujs:type_name -> soong_build_metrics.CriticalUserJourneyMetrics
- 8, // 22: soong_build_metrics.SoongBuildMetrics.events:type_name -> soong_build_metrics.PerfInfo
- 18, // 23: soong_build_metrics.SoongBuildMetrics.mixed_builds_info:type_name -> soong_build_metrics.MixedBuildsInfo
- 9, // 24: soong_build_metrics.SoongBuildMetrics.perf_counters:type_name -> soong_build_metrics.PerfCounters
- 4, // 25: soong_build_metrics.ExpConfigFetcher.status:type_name -> soong_build_metrics.ExpConfigFetcher.ConfigStatus
- 20, // 26: soong_build_metrics.CriticalPathInfo.critical_path:type_name -> soong_build_metrics.JobInfo
- 20, // 27: soong_build_metrics.CriticalPathInfo.long_running_jobs:type_name -> soong_build_metrics.JobInfo
- 28, // [28:28] is the sub-list for method output_type
- 28, // [28:28] is the sub-list for method input_type
- 28, // [28:28] is the sub-list for extension type_name
- 28, // [28:28] is the sub-list for extension extendee
- 0, // [0:28] is the sub-list for field type_name
+ 8, // 11: soong_build_metrics.MetricsBase.system_resource_info:type_name -> soong_build_metrics.SystemResourceInfo
+ 11, // 12: soong_build_metrics.MetricsBase.bazel_runs:type_name -> soong_build_metrics.PerfInfo
+ 20, // 13: soong_build_metrics.MetricsBase.exp_config_fetcher:type_name -> soong_build_metrics.ExpConfigFetcher
+ 22, // 14: soong_build_metrics.MetricsBase.critical_path_info:type_name -> soong_build_metrics.CriticalPathInfo
+ 24, // 15: soong_build_metrics.MetricsBase.optimized_build_metrics:type_name -> soong_build_metrics.OptimizedBuildMetrics
+ 2, // 16: soong_build_metrics.BuildConfig.ninja_weight_list_source:type_name -> soong_build_metrics.BuildConfig.NinjaWeightListSource
+ 7, // 17: soong_build_metrics.BuildConfig.soong_env_vars:type_name -> soong_build_metrics.SoongEnvVars
+ 9, // 18: soong_build_metrics.SystemResourceInfo.cpu_info:type_name -> soong_build_metrics.SystemCpuInfo
+ 10, // 19: soong_build_metrics.SystemResourceInfo.mem_info:type_name -> soong_build_metrics.SystemMemInfo
+ 15, // 20: soong_build_metrics.PerfInfo.processes_resource_info:type_name -> soong_build_metrics.ProcessResourceInfo
+ 13, // 21: soong_build_metrics.PerfCounters.groups:type_name -> soong_build_metrics.PerfCounterGroup
+ 14, // 22: soong_build_metrics.PerfCounterGroup.counters:type_name -> soong_build_metrics.PerfCounter
+ 3, // 23: soong_build_metrics.ModuleTypeInfo.build_system:type_name -> soong_build_metrics.ModuleTypeInfo.BuildSystem
+ 5, // 24: soong_build_metrics.CriticalUserJourneyMetrics.metrics:type_name -> soong_build_metrics.MetricsBase
+ 17, // 25: soong_build_metrics.CriticalUserJourneysMetrics.cujs:type_name -> soong_build_metrics.CriticalUserJourneyMetrics
+ 11, // 26: soong_build_metrics.SoongBuildMetrics.events:type_name -> soong_build_metrics.PerfInfo
+ 21, // 27: soong_build_metrics.SoongBuildMetrics.mixed_builds_info:type_name -> soong_build_metrics.MixedBuildsInfo
+ 12, // 28: soong_build_metrics.SoongBuildMetrics.perf_counters:type_name -> soong_build_metrics.PerfCounters
+ 4, // 29: soong_build_metrics.ExpConfigFetcher.status:type_name -> soong_build_metrics.ExpConfigFetcher.ConfigStatus
+ 23, // 30: soong_build_metrics.CriticalPathInfo.critical_path:type_name -> soong_build_metrics.JobInfo
+ 23, // 31: soong_build_metrics.CriticalPathInfo.long_running_jobs:type_name -> soong_build_metrics.JobInfo
+ 11, // 32: soong_build_metrics.OptimizedBuildMetrics.analysis_perf:type_name -> soong_build_metrics.PerfInfo
+ 11, // 33: soong_build_metrics.OptimizedBuildMetrics.packaging_perf:type_name -> soong_build_metrics.PerfInfo
+ 28, // 34: soong_build_metrics.OptimizedBuildMetrics.target_result:type_name -> soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult
+ 26, // 35: soong_build_metrics.ExecutionMetrics.changed_files:type_name -> soong_build_metrics.AggregatedFileList
+ 27, // 36: soong_build_metrics.AggregatedFileList.counts:type_name -> soong_build_metrics.FileCount
+ 11, // 37: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.packaging_perf:type_name -> soong_build_metrics.PerfInfo
+ 29, // 38: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.output_artifact:type_name -> soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.OutputArtifact
+ 39, // [39:39] is the sub-list for method output_type
+ 39, // [39:39] is the sub-list for method input_type
+ 39, // [39:39] is the sub-list for extension type_name
+ 39, // [39:39] is the sub-list for extension extendee
+ 0, // [0:39] is the sub-list for field type_name
}
func init() { file_metrics_proto_init() }
@@ -2289,7 +3117,7 @@
}
}
file_metrics_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*SystemResourceInfo); i {
+ switch v := v.(*SoongEnvVars); i {
case 0:
return &v.state
case 1:
@@ -2301,7 +3129,7 @@
}
}
file_metrics_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*PerfInfo); i {
+ switch v := v.(*SystemResourceInfo); i {
case 0:
return &v.state
case 1:
@@ -2313,7 +3141,7 @@
}
}
file_metrics_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*PerfCounters); i {
+ switch v := v.(*SystemCpuInfo); i {
case 0:
return &v.state
case 1:
@@ -2325,7 +3153,7 @@
}
}
file_metrics_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*PerfCounterGroup); i {
+ switch v := v.(*SystemMemInfo); i {
case 0:
return &v.state
case 1:
@@ -2337,7 +3165,7 @@
}
}
file_metrics_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*PerfCounter); i {
+ switch v := v.(*PerfInfo); i {
case 0:
return &v.state
case 1:
@@ -2349,7 +3177,7 @@
}
}
file_metrics_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*ProcessResourceInfo); i {
+ switch v := v.(*PerfCounters); i {
case 0:
return &v.state
case 1:
@@ -2361,7 +3189,7 @@
}
}
file_metrics_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*ModuleTypeInfo); i {
+ switch v := v.(*PerfCounterGroup); i {
case 0:
return &v.state
case 1:
@@ -2373,7 +3201,7 @@
}
}
file_metrics_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*CriticalUserJourneyMetrics); i {
+ switch v := v.(*PerfCounter); i {
case 0:
return &v.state
case 1:
@@ -2385,7 +3213,7 @@
}
}
file_metrics_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*CriticalUserJourneysMetrics); i {
+ switch v := v.(*ProcessResourceInfo); i {
case 0:
return &v.state
case 1:
@@ -2397,7 +3225,7 @@
}
}
file_metrics_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*SoongBuildMetrics); i {
+ switch v := v.(*ModuleTypeInfo); i {
case 0:
return &v.state
case 1:
@@ -2409,7 +3237,7 @@
}
}
file_metrics_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*ExpConfigFetcher); i {
+ switch v := v.(*CriticalUserJourneyMetrics); i {
case 0:
return &v.state
case 1:
@@ -2421,7 +3249,7 @@
}
}
file_metrics_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*MixedBuildsInfo); i {
+ switch v := v.(*CriticalUserJourneysMetrics); i {
case 0:
return &v.state
case 1:
@@ -2433,7 +3261,7 @@
}
}
file_metrics_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*CriticalPathInfo); i {
+ switch v := v.(*SoongBuildMetrics); i {
case 0:
return &v.state
case 1:
@@ -2445,6 +3273,42 @@
}
}
file_metrics_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ExpConfigFetcher); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_metrics_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*MixedBuildsInfo); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_metrics_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*CriticalPathInfo); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_metrics_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*JobInfo); i {
case 0:
return &v.state
@@ -2456,6 +3320,78 @@
return nil
}
}
+ file_metrics_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*OptimizedBuildMetrics); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_metrics_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ExecutionMetrics); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_metrics_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*AggregatedFileList); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_metrics_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*FileCount); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_metrics_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*OptimizedBuildMetrics_TargetOptimizationResult); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_metrics_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
}
type x struct{}
out := protoimpl.TypeBuilder{
@@ -2463,7 +3399,7 @@
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_metrics_proto_rawDesc,
NumEnums: 5,
- NumMessages: 16,
+ NumMessages: 25,
NumExtensions: 0,
NumServices: 0,
},
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index 11fcba7..7ff389a 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -137,6 +137,12 @@
// Note that not all changed environment variables result in analysis retriggering.
// If there was no previous build, this list will be empty.
repeated string changed_environment_variable = 34;
+
+ // Metrics related to optimized builds.
+ optional OptimizedBuildMetrics optimized_build_metrics = 35;
+
+ // The target release information. e.g., trunk_staging.
+ optional string target_release = 36;
}
message BuildConfig {
@@ -174,6 +180,21 @@
// EXTERNAL_FILE - ninja uses an external custom weight list
// HINT_FROM_SOONG - ninja uses a prioritized module list from Soong
optional NinjaWeightListSource ninja_weight_list_source = 8 [default = NOT_USED];
+
+ // Values of some build-affecting environment variables.
+ optional SoongEnvVars soong_env_vars = 9;
+
+ // Whether this build uses soong-only (no kati) mode (either via environment variable,
+ // command line flag or product config.
+ optional bool soong_only = 10;
+}
+
+message SoongEnvVars {
+ // SOONG_PARTIAL_COMPILE
+ optional string partial_compile = 1;
+
+ // SOONG_USE_PARTIAL_COMPILE
+ optional string use_partial_compile = 2;
}
message SystemResourceInfo {
@@ -182,6 +203,37 @@
// The total of available cores for building
optional int32 available_cpus = 2;
+
+ // Information about the machine's CPU(s).
+ optional SystemCpuInfo cpu_info = 3;
+
+ // Information about the machine's memory.
+ optional SystemMemInfo mem_info = 4;
+}
+
+message SystemCpuInfo {
+ // The vendor id
+ optional string vendor_id = 1;
+
+ // The model name
+ optional string model_name = 2;
+
+ // The number of CPU cores
+ optional int32 cpu_cores = 3;
+
+ // The CPU flags
+ optional string flags = 4;
+}
+
+message SystemMemInfo {
+ // The total system memory
+ optional uint64 mem_total = 1;
+
+ // The free system memory
+ optional uint64 mem_free = 2;
+
+ // The available system memory
+ optional uint64 mem_available = 3;
}
message PerfInfo {
@@ -385,3 +437,80 @@
// Description of a job
optional string job_description = 2;
}
+
+message OptimizedBuildMetrics {
+ // The total time spent analyzing what/how to optimize everything.
+ optional PerfInfo analysis_perf = 1;
+ // The total time spent packaging artifacts.
+ optional PerfInfo packaging_perf = 2;
+ // Information for a single target (e.g. general-tests).
+ repeated TargetOptimizationResult target_result = 3;
+
+ message TargetOptimizationResult {
+ // Target name (e.g. general-tests).
+ optional string name = 1;
+ // Whether or not this target was optimized.
+ optional bool optimized = 2;
+ // Reasoning for why the target wasn't optimized if it wasn't
+ optional string optimization_rationale = 3;
+ // Time spent packaging this specific target (if it was optimized).
+ optional PerfInfo packaging_perf = 4;
+ // Information for each different artifact produced by this target (if it
+ // was optimized).
+ repeated OutputArtifact output_artifact = 5;
+
+ message OutputArtifact {
+ // Artifact file name (e.g. general-tests.zip)
+ optional string name = 1;
+ // Size of the file.
+ optional int64 size = 2;
+ // Lists of modules packaged into this artifact.
+ repeated string included_modules = 3;
+ }
+ }
+}
+
+// This is created by soong_ui from SoongExexcutionMetrics files.
+message ExecutionMetrics {
+ // The arguments provided on the command line.
+ repeated string command_args = 1;
+
+ // Changed files detected by the build.
+ optional AggregatedFileList changed_files = 2;
+}
+
+// This is created by soong_ui from the various
+// android.find_input_delta_proto.FileList metrics provided to it by
+// find_input_delta.
+message AggregatedFileList {
+ // The (possibly truncated list of) added files.
+ repeated string additions = 2;
+
+ // The (possibly truncated list of) changed files.
+ repeated string changes = 3;
+
+ // The (possibly truncated list of) deleted files.
+ repeated string deletions = 4;
+
+ // Count of files added/changed/deleted.
+ optional uint32 total_delta = 5;
+
+ // Counts by extension.
+ repeated FileCount counts = 6;
+
+ reserved 1;
+}
+
+message FileCount {
+ // The file extension
+ optional string extension = 1;
+
+ // Number of added files with this extension.
+ optional uint32 additions = 2;
+
+ // Number of modified files with this extension.
+ optional uint32 modifications = 3;
+
+ // Number of deleted files with this extension.
+ optional uint32 deletions = 4;
+}
diff --git a/ui/metrics/proc/status_linux_test.go b/ui/metrics/proc/status_linux_test.go
index 6709850..0edc400 100644
--- a/ui/metrics/proc/status_linux_test.go
+++ b/ui/metrics/proc/status_linux_test.go
@@ -1,7 +1,6 @@
package proc
import (
- "fmt"
"path/filepath"
"reflect"
"strconv"
@@ -29,7 +28,6 @@
t.Fatalf("got %v, want nil for error", err)
}
- fmt.Printf("%d %d\b", status.VmPeak, expectedStatus.VmPeak)
if !reflect.DeepEqual(status, expectedStatus) {
t.Errorf("got %v, expecting %v for ProcStatus", status, expectedStatus)
}
diff --git a/ui/status/log.go b/ui/status/log.go
index 14df346..7bfd396 100644
--- a/ui/status/log.go
+++ b/ui/status/log.go
@@ -22,6 +22,8 @@
"io/ioutil"
"os"
"strings"
+ "sync"
+ "time"
"google.golang.org/protobuf/proto"
@@ -31,7 +33,10 @@
)
type verboseLog struct {
- w io.WriteCloser
+ w *gzip.Writer
+ lock *sync.Mutex
+ data chan []string
+ stop chan bool
}
func NewVerboseLog(log logger.Logger, filename string) StatusOutput {
@@ -47,9 +52,42 @@
w := gzip.NewWriter(f)
- return &verboseLog{
- w: w,
+ l := &verboseLog{
+ w: w,
+ lock: &sync.Mutex{},
+ data: make(chan []string),
+ stop: make(chan bool),
}
+ l.startWriter()
+ return l
+}
+
+func (v *verboseLog) startWriter() {
+ go func() {
+ tick := time.Tick(time.Second)
+ for {
+ select {
+ case <-v.stop:
+ close(v.data)
+ v.w.Close()
+ return
+ case <-tick:
+ v.w.Flush()
+ case dataList := <-v.data:
+ for _, data := range dataList {
+ fmt.Fprint(v.w, data)
+ }
+ }
+ }
+ }()
+}
+
+func (v *verboseLog) stopWriter() {
+ v.stop <- true
+}
+
+func (v *verboseLog) queueWrite(s ...string) {
+ v.data <- s
}
func (v *verboseLog) StartAction(action *Action, counts Counts) {}
@@ -60,27 +98,27 @@
cmd = result.Description
}
- fmt.Fprintf(v.w, "[%d/%d] %s\n", counts.FinishedActions, counts.TotalActions, cmd)
+ v.queueWrite(fmt.Sprintf("[%d/%d] ", counts.FinishedActions, counts.TotalActions), cmd, "\n")
if result.Error != nil {
- fmt.Fprintf(v.w, "FAILED: %s\n", strings.Join(result.Outputs, " "))
+ v.queueWrite("FAILED: ", strings.Join(result.Outputs, " "), "\n")
}
if result.Output != "" {
- fmt.Fprintln(v.w, result.Output)
+ v.queueWrite(result.Output, "\n")
}
}
func (v *verboseLog) Flush() {
- v.w.Close()
+ v.stopWriter()
}
func (v *verboseLog) Message(level MsgLevel, message string) {
- fmt.Fprintf(v.w, "%s%s\n", level.Prefix(), message)
+ v.queueWrite(level.Prefix(), message, "\n")
}
func (v *verboseLog) Write(p []byte) (int, error) {
- fmt.Fprint(v.w, string(p))
+ v.queueWrite(string(p))
return len(p), nil
}
diff --git a/xml/xml_test.go b/xml/xml_test.go
index a59a293..9f28315 100644
--- a/xml/xml_test.go
+++ b/xml/xml_test.go
@@ -80,5 +80,5 @@
}
m := result.ModuleForTests("foo.xml", "android_arm64_armv8-a").Module().(*prebuiltEtcXml)
- android.AssertPathRelativeToTopEquals(t, "installDir", "out/soong/target/product/test_device/system/etc", m.InstallDirPath())
+ android.AssertPathRelativeToTopEquals(t, "installDir", "out/target/product/test_device/system/etc", m.InstallDirPath())
}
diff --git a/zip/cmd/Android.bp b/zip/cmd/Android.bp
index 43bf232..16c3f69 100644
--- a/zip/cmd/Android.bp
+++ b/zip/cmd/Android.bp
@@ -24,4 +24,6 @@
srcs: [
"main.go",
],
+ // Used by genrules
+ visibility: ["//visibility:public"],
}