Merge "Reapply "Upgrade to clang-r530567"" into main
diff --git a/android/Android.bp b/android/Android.bp
index 3c38148..774d24a 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -42,6 +42,7 @@
"buildinfo_prop.go",
"compliance_metadata.go",
"config.go",
+ "container.go",
"test_config.go",
"configurable_properties.go",
"configured_jars.go",
diff --git a/android/container.go b/android/container.go
new file mode 100644
index 0000000..c4fdd9c
--- /dev/null
+++ b/android/container.go
@@ -0,0 +1,233 @@
+// 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 (
+ "reflect"
+ "slices"
+
+ "github.com/google/blueprint"
+)
+
+type StubsAvailableModule interface {
+ IsStubsModule() bool
+}
+
+// Returns true if the dependency module is a stubs module
+var depIsStubsModule = func(_ ModuleContext, _, dep Module) bool {
+ if stubsModule, ok := dep.(StubsAvailableModule); ok {
+ return stubsModule.IsStubsModule()
+ }
+ return false
+}
+
+// Labels of exception functions, which are used to determine special dependencies that allow
+// otherwise restricted inter-container dependencies
+type exceptionHandleFuncLabel int
+
+const (
+ checkStubs exceptionHandleFuncLabel = iota
+)
+
+// Functions cannot be used as a value passed in providers, because functions are not
+// hashable. As a workaround, the exceptionHandleFunc enum values are passed using providers,
+// and the corresponding functions are called from this map.
+var exceptionHandleFunctionsTable = map[exceptionHandleFuncLabel]func(ModuleContext, Module, Module) bool{
+ checkStubs: depIsStubsModule,
+}
+
+type InstallableModule interface {
+ EnforceApiContainerChecks() bool
+}
+
+type restriction struct {
+ // container of the dependency
+ dependency *container
+
+ // Error message to be emitted to the user when the dependency meets this restriction
+ errorMessage string
+
+ // List of labels of allowed exception functions that allows bypassing this restriction.
+ // If any of the functions mapped to each labels returns true, this dependency would be
+ // considered allowed and an error will not be thrown.
+ allowedExceptions []exceptionHandleFuncLabel
+}
+type container struct {
+ // The name of the container i.e. partition, api domain
+ name string
+
+ // Map of dependency restricted containers.
+ restricted []restriction
+}
+
+var (
+ VendorContainer = &container{
+ name: VendorVariation,
+ restricted: nil,
+ }
+ SystemContainer = &container{
+ name: "system",
+ restricted: []restriction{
+ {
+ dependency: VendorContainer,
+ errorMessage: "Module belonging to the system partition other than HALs is " +
+ "not allowed to depend on the vendor partition module, in order to support " +
+ "independent development/update cycles and to support the Generic System " +
+ "Image. Try depending on HALs, VNDK or AIDL instead.",
+ allowedExceptions: []exceptionHandleFuncLabel{},
+ },
+ },
+ }
+ ProductContainer = &container{
+ name: ProductVariation,
+ restricted: []restriction{
+ {
+ dependency: VendorContainer,
+ errorMessage: "Module belonging to the product partition is not allowed to " +
+ "depend on the vendor partition module, as this may lead to security " +
+ "vulnerabilities. Try depending on the HALs or utilize AIDL instead.",
+ allowedExceptions: []exceptionHandleFuncLabel{},
+ },
+ },
+ }
+ ApexContainer = initializeApexContainer()
+ CtsContainer = &container{
+ name: "cts",
+ restricted: []restriction{
+ {
+ dependency: SystemContainer,
+ errorMessage: "CTS module should not depend on the modules belonging to the " +
+ "system partition, including \"framework\". Depending on the system " +
+ "partition may lead to disclosure of implementation details and regression " +
+ "due to API changes across platform versions. Try depending on the stubs instead.",
+ allowedExceptions: []exceptionHandleFuncLabel{checkStubs},
+ },
+ },
+ }
+)
+
+func initializeApexContainer() *container {
+ apexContainer := &container{
+ name: "apex",
+ restricted: []restriction{
+ {
+ dependency: SystemContainer,
+ errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
+ "modules belonging to the system partition. Either statically depend on the " +
+ "module or convert the depending module to java_sdk_library and depend on " +
+ "the stubs.",
+ allowedExceptions: []exceptionHandleFuncLabel{checkStubs},
+ },
+ },
+ }
+
+ apexContainer.restricted = append(apexContainer.restricted, restriction{
+ dependency: apexContainer,
+ errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
+ "modules belonging to other Apex(es). Either include the depending " +
+ "module in the Apex or convert the depending module to java_sdk_library " +
+ "and depend on its stubs.",
+ allowedExceptions: []exceptionHandleFuncLabel{checkStubs},
+ })
+
+ return apexContainer
+}
+
+type ContainersInfo struct {
+ belongingContainers []*container
+
+ belongingApexes []ApexInfo
+}
+
+func (c *ContainersInfo) BelongingContainers() []*container {
+ return c.belongingContainers
+}
+
+var ContainersInfoProvider = blueprint.NewProvider[ContainersInfo]()
+
+// Determines if the module can be installed in the system partition or not.
+// Logic is identical to that of modulePartition(...) defined in paths.go
+func installInSystemPartition(ctx ModuleContext) bool {
+ module := ctx.Module()
+ return !module.InstallInTestcases() &&
+ !module.InstallInData() &&
+ !module.InstallInRamdisk() &&
+ !module.InstallInVendorRamdisk() &&
+ !module.InstallInDebugRamdisk() &&
+ !module.InstallInRecovery() &&
+ !module.InstallInVendor() &&
+ !module.InstallInOdm() &&
+ !module.InstallInProduct() &&
+ determineModuleKind(module.base(), ctx.blueprintBaseModuleContext()) == platformModule
+}
+
+func generateContainerInfo(ctx ModuleContext) ContainersInfo {
+ inSystem := installInSystemPartition(ctx)
+ inProduct := ctx.Module().InstallInProduct()
+ inVendor := ctx.Module().InstallInVendor()
+ inCts := false
+ inApex := false
+
+ if m, ok := ctx.Module().(ImageInterface); ok {
+ inProduct = inProduct || m.ProductVariantNeeded(ctx)
+ inVendor = inVendor || m.VendorVariantNeeded(ctx)
+ }
+
+ props := ctx.Module().GetProperties()
+ for _, prop := range props {
+ val := reflect.ValueOf(prop).Elem()
+ if val.Kind() == reflect.Struct {
+ testSuites := val.FieldByName("Test_suites")
+ if testSuites.IsValid() && testSuites.Kind() == reflect.Slice && slices.Contains(testSuites.Interface().([]string), "cts") {
+ inCts = true
+ }
+ }
+ }
+
+ var belongingApexes []ApexInfo
+ if apexInfo, ok := ModuleProvider(ctx, AllApexInfoProvider); ok {
+ belongingApexes = apexInfo.ApexInfos
+ inApex = true
+ }
+
+ containers := []*container{}
+ if inSystem {
+ containers = append(containers, SystemContainer)
+ }
+ if inProduct {
+ containers = append(containers, ProductContainer)
+ }
+ if inVendor {
+ containers = append(containers, VendorContainer)
+ }
+ if inCts {
+ containers = append(containers, CtsContainer)
+ }
+ if inApex {
+ containers = append(containers, ApexContainer)
+ }
+
+ return ContainersInfo{
+ belongingContainers: containers,
+ belongingApexes: belongingApexes,
+ }
+}
+
+func setContainerInfo(ctx ModuleContext) {
+ if _, ok := ctx.Module().(InstallableModule); ok {
+ containersInfo := generateContainerInfo(ctx)
+ SetProvider(ctx, ContainersInfoProvider, containersInfo)
+ }
+}
diff --git a/android/image.go b/android/image.go
index c278dcd..0f03107 100644
--- a/android/image.go
+++ b/android/image.go
@@ -22,7 +22,7 @@
// VendorVariantNeeded should return true if the module needs a vendor variant (installed on the vendor image).
VendorVariantNeeded(ctx BaseModuleContext) bool
- // ProductVariantNeeded should return true if the module needs a product variant (unstalled on the product image).
+ // ProductVariantNeeded should return true if the module needs a product variant (installed on the product image).
ProductVariantNeeded(ctx BaseModuleContext) bool
// CoreVariantNeeded should return true if the module needs a core variant (installed on the system image).
diff --git a/android/module.go b/android/module.go
index 9f7cb37..dd56031 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1207,29 +1207,7 @@
continue
}
}
-
- // if the tagged dist file cannot be obtained from OutputFilesProvider,
- // fall back to use OutputFileProducer
- // TODO: remove this part after OutputFilesProvider fully replaces OutputFileProducer
- if outputFileProducer, ok := m.module.(OutputFileProducer); ok {
- // Call the OutputFiles(tag) method to get the paths associated with the tag.
- distFilesForTag, err := outputFileProducer.OutputFiles(tag)
- // If the tag was not supported and is not DefaultDistTag then it is an error.
- // Failing to find paths for DefaultDistTag is not an error. It just means
- // that the module type requires the legacy behavior.
- if err != nil && tag != DefaultDistTag {
- ctx.PropertyErrorf("dist.tag", "%s", err.Error())
- }
- distFiles = distFiles.addPathsForTag(tag, distFilesForTag...)
- } else if tag != DefaultDistTag {
- // If the tag was specified then it is an error if the module does not
- // implement OutputFileProducer because there is no other way of accessing
- // the paths for the specified tag.
- ctx.PropertyErrorf("dist.tag",
- "tag %s not supported because the module does not implement OutputFileProducer", tag)
- }
}
-
return distFiles
}
@@ -1779,6 +1757,8 @@
variables: make(map[string]string),
}
+ setContainerInfo(ctx)
+
m.licenseMetadataFile = PathForModuleOut(ctx, "meta_lic")
dependencyInstallFiles, dependencyPackagingSpecs := m.computeInstallDeps(ctx)
@@ -2383,7 +2363,7 @@
// The name of the module.
moduleName string
- // The tag that will be passed to the module's OutputFileProducer.OutputFiles(tag) method.
+ // The tag that will be used to get the specific output file(s).
tag string
}
@@ -2437,14 +2417,7 @@
Srcs() Paths
}
-// A module that implements OutputFileProducer can be referenced from any property that is tagged with `android:"path"`
-// using the ":module" syntax or ":module{.tag}" syntax and provides a list of output files to be used as if they were
-// listed in the property.
-type OutputFileProducer interface {
- OutputFiles(tag string) (Paths, error)
-}
-
-// OutputFilesForModule returns the paths from an OutputFileProducer with the given tag. On error, including if the
+// 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 {
paths, err := outputFilesForModule(ctx, module, tag)
@@ -2455,7 +2428,7 @@
return paths
}
-// OutputFileForModule returns the path from an OutputFileProducer with the given tag. On error, including if the
+// 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 {
paths, err := outputFilesForModule(ctx, module, tag)
diff --git a/android/neverallow.go b/android/neverallow.go
index 62c5e59..ef4b8b8 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -237,6 +237,7 @@
Without("name", "init_first_stage").
Without("name", "init_first_stage.microdroid").
With("install_in_root", "true").
+ NotModuleType("prebuilt_root").
Because("install_in_root is only for init_first_stage."),
}
}
diff --git a/android/packaging.go b/android/packaging.go
index ae412e1..c247ed2 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -17,6 +17,7 @@
import (
"fmt"
"path/filepath"
+ "sort"
"strings"
"github.com/google/blueprint"
@@ -377,31 +378,59 @@
// CopySpecsToDir is a helper that will add commands to the rule builder to copy the PackagingSpec
// entries into the specified directory.
func (p *PackagingBase) CopySpecsToDir(ctx ModuleContext, builder *RuleBuilder, specs map[string]PackagingSpec, dir WritablePath) (entries []string) {
- if len(specs) == 0 {
+ dirsToSpecs := make(map[WritablePath]map[string]PackagingSpec)
+ dirsToSpecs[dir] = specs
+ return p.CopySpecsToDirs(ctx, builder, dirsToSpecs)
+}
+
+// CopySpecsToDirs is a helper that will add commands to the rule builder to copy the PackagingSpec
+// entries into corresponding directories.
+func (p *PackagingBase) CopySpecsToDirs(ctx ModuleContext, builder *RuleBuilder, dirsToSpecs map[WritablePath]map[string]PackagingSpec) (entries []string) {
+ empty := true
+ for _, specs := range dirsToSpecs {
+ if len(specs) > 0 {
+ empty = false
+ break
+ }
+ }
+ if empty {
return entries
}
+
seenDir := make(map[string]bool)
preparerPath := PathForModuleOut(ctx, "preparer.sh")
cmd := builder.Command().Tool(preparerPath)
var sb strings.Builder
sb.WriteString("set -e\n")
- for _, k := range SortedKeys(specs) {
- ps := specs[k]
- destPath := filepath.Join(dir.String(), ps.relPathInPackage)
- destDir := filepath.Dir(destPath)
- entries = append(entries, ps.relPathInPackage)
- if _, ok := seenDir[destDir]; !ok {
- seenDir[destDir] = true
- sb.WriteString(fmt.Sprintf("mkdir -p %s\n", destDir))
- }
- if ps.symlinkTarget == "" {
- cmd.Implicit(ps.srcPath)
- sb.WriteString(fmt.Sprintf("cp %s %s\n", ps.srcPath, destPath))
- } else {
- sb.WriteString(fmt.Sprintf("ln -sf %s %s\n", ps.symlinkTarget, destPath))
- }
- if ps.executable {
- sb.WriteString(fmt.Sprintf("chmod a+x %s\n", destPath))
+
+ dirs := make([]WritablePath, 0, len(dirsToSpecs))
+ for dir, _ := range dirsToSpecs {
+ dirs = append(dirs, dir)
+ }
+ sort.Slice(dirs, func(i, j int) bool {
+ return dirs[i].String() < dirs[j].String()
+ })
+
+ for _, dir := range dirs {
+ specs := dirsToSpecs[dir]
+ for _, k := range SortedKeys(specs) {
+ ps := specs[k]
+ destPath := filepath.Join(dir.String(), ps.relPathInPackage)
+ destDir := filepath.Dir(destPath)
+ entries = append(entries, ps.relPathInPackage)
+ if _, ok := seenDir[destDir]; !ok {
+ seenDir[destDir] = true
+ sb.WriteString(fmt.Sprintf("mkdir -p %s\n", destDir))
+ }
+ if ps.symlinkTarget == "" {
+ cmd.Implicit(ps.srcPath)
+ sb.WriteString(fmt.Sprintf("cp %s %s\n", ps.srcPath, destPath))
+ } else {
+ sb.WriteString(fmt.Sprintf("ln -sf %s %s\n", ps.symlinkTarget, destPath))
+ }
+ if ps.executable {
+ sb.WriteString(fmt.Sprintf("chmod a+x %s\n", destPath))
+ }
}
}
diff --git a/android/paths.go b/android/paths.go
index 03772eb..dda48dd 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -463,8 +463,8 @@
// - glob, relative to the local module directory, resolves as filepath(s), relative to the local
// source directory.
// - other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
-// or OutputFileProducer. These resolve as a filepath to an output filepath or generated source
-// filepath.
+// or set the OutputFilesProvider. These resolve as a filepath to an output filepath or generated
+// source filepath.
//
// Properties passed as the paths argument must have been annotated with struct tag
// `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
@@ -491,8 +491,8 @@
// - glob, relative to the local module directory, resolves as filepath(s), relative to the local
// source directory. Not valid in excludes.
// - other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
-// or OutputFileProducer. These resolve as a filepath to an output filepath or generated source
-// filepath.
+// or set the OutputFilesProvider. These resolve as a filepath to an output filepath or generated
+// source filepath.
//
// excluding the items (similarly resolved
// Properties passed as the paths argument must have been annotated with struct tag
@@ -620,8 +620,8 @@
// - glob, relative to the local module directory, resolves as filepath(s), relative to the local
// source directory. Not valid in excludes.
// - other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
-// or OutputFileProducer. These resolve as a filepath to an output filepath or generated source
-// filepath.
+// or set the OutputFilesProvider. These resolve as a filepath to an output filepath or generated
+// source filepath.
//
// and a list of the module names of missing module dependencies are returned as the second return.
// Properties passed as the paths argument must have been annotated with struct tag
diff --git a/android/testing.go b/android/testing.go
index 18fd3b3..e39a1a7 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -1018,31 +1018,21 @@
return normalizeStringMapRelativeToTop(m.config, m.module.VariablesForTests())
}
-// OutputFiles first checks if module base outputFiles property has any output
+// OutputFiles checks if module base outputFiles property has any output
// files can be used to return.
-// If not, it calls OutputFileProducer.OutputFiles on the
-// encapsulated module, exits the test immediately if there is an error and
+// Exits the test immediately if there is an error and
// otherwise returns the result of calling Paths.RelativeToTop
// on the returned Paths.
func (m TestingModule) OutputFiles(t *testing.T, tag string) Paths {
- // TODO: remove OutputFileProducer part
outputFiles := m.Module().base().outputFiles
if tag == "" && outputFiles.DefaultOutputFiles != nil {
return outputFiles.DefaultOutputFiles.RelativeToTop()
} else if taggedOutputFiles, hasTag := outputFiles.TaggedOutputFiles[tag]; hasTag {
- return taggedOutputFiles
+ return taggedOutputFiles.RelativeToTop()
}
- producer, ok := m.module.(OutputFileProducer)
- if !ok {
- t.Fatalf("%q must implement OutputFileProducer\n", m.module.Name())
- }
- paths, err := producer.OutputFiles(tag)
- if err != nil {
- t.Fatal(err)
- }
-
- return paths.RelativeToTop()
+ t.Fatal(fmt.Errorf("No test output file has been set for tag %q", tag))
+ return nil
}
// TestingSingleton is wrapper around an android.Singleton that provides methods to find information about individual
diff --git a/android/util.go b/android/util.go
index e21e66b..3c0af2f 100644
--- a/android/util.go
+++ b/android/util.go
@@ -201,6 +201,12 @@
return listsDiffer, diff1, diff2
}
+// Returns true if the two lists have common elements.
+func HasIntersection[T comparable](l1, l2 []T) bool {
+ _, a, b := ListSetDifference(l1, l2)
+ return len(a)+len(b) < len(setFromList(l1))+len(setFromList(l2))
+}
+
// Returns true if the given string s is prefixed with any string in the given prefix list.
func HasAnyPrefix(s string, prefixList []string) bool {
for _, prefix := range prefixList {
diff --git a/android/util_test.go b/android/util_test.go
index 8e73d83..6537d69 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -818,3 +818,52 @@
})
}
}
+
+var hasIntersectionTestCases = []struct {
+ name string
+ l1 []string
+ l2 []string
+ expected bool
+}{
+ {
+ name: "empty",
+ l1: []string{"a", "b", "c"},
+ l2: []string{},
+ expected: false,
+ },
+ {
+ name: "both empty",
+ l1: []string{},
+ l2: []string{},
+ expected: false,
+ },
+ {
+ name: "identical",
+ l1: []string{"a", "b", "c"},
+ l2: []string{"a", "b", "c"},
+ expected: true,
+ },
+ {
+ name: "duplicates",
+ l1: []string{"a", "a", "a"},
+ l2: []string{"a", "b", "c"},
+ expected: true,
+ },
+ {
+ name: "duplicates with no intersection",
+ l1: []string{"d", "d", "d", "d"},
+ l2: []string{"a", "b", "c"},
+ expected: false,
+ },
+}
+
+func TestHasIntersection(t *testing.T) {
+ for _, testCase := range hasIntersectionTestCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ hasIntersection := HasIntersection(testCase.l1, testCase.l2)
+ if !reflect.DeepEqual(hasIntersection, testCase.expected) {
+ t.Errorf("expected %#v, got %#v", testCase.expected, hasIntersection)
+ }
+ })
+ }
+}
diff --git a/android/variable.go b/android/variable.go
index d144f7d..3b02bc7 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -132,9 +132,11 @@
Keep_symbols *bool
Keep_symbols_and_debug_frame *bool
}
- Static_libs []string
- Whole_static_libs []string
- Shared_libs []string
+ Static_libs []string
+ Exclude_static_libs []string
+ Whole_static_libs []string
+ Shared_libs []string
+ Jni_libs []string
Cmdline []string
diff --git a/apex/Android.bp b/apex/Android.bp
index abae9e2..17fdfc3 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -37,6 +37,7 @@
"apex_test.go",
"bootclasspath_fragment_test.go",
"classpath_element_test.go",
+ "container_test.go",
"dexpreopt_bootjars_test.go",
"platform_bootclasspath_test.go",
"systemserver_classpath_fragment_test.go",
diff --git a/apex/apex.go b/apex/apex.go
index 10fe372..f9b30d4 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2663,12 +2663,20 @@
})
}
+// TODO (b/221087384): Remove this allowlist
+var (
+ updatableApexesWithCurrentMinSdkVersionAllowlist = []string{"com.android.profiling"}
+)
+
// checkUpdatable enforces APEX and its transitive dep properties to have desired values for updatable APEXes.
func (a *apexBundle) checkUpdatable(ctx android.ModuleContext) {
if a.Updatable() {
if a.minSdkVersionValue(ctx) == "" {
ctx.PropertyErrorf("updatable", "updatable APEXes should set min_sdk_version as well")
}
+ if a.minSdkVersion(ctx).IsCurrent() && !android.InList(ctx.ModuleName(), updatableApexesWithCurrentMinSdkVersionAllowlist) {
+ ctx.PropertyErrorf("updatable", "updatable APEXes should not set min_sdk_version to current. Please use a finalized API level or a recognized in-development codename")
+ }
if a.UsePlatformApis() {
ctx.PropertyErrorf("updatable", "updatable APEXes can't use platform APIs")
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 15c713b..a2dbbfc 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -11721,3 +11721,20 @@
java.CheckModuleHasDependency(t, res.TestContext, "myoverrideapex", "android_common_myoverrideapex_myoverrideapex", "foo")
}
+
+func TestUpdatableApexMinSdkVersionCurrent(t *testing.T) {
+ 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",
+ key: "myapex.key",
+ updatable: true,
+ min_sdk_version: "current",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `)
+}
diff --git a/apex/container_test.go b/apex/container_test.go
new file mode 100644
index 0000000..3931174
--- /dev/null
+++ b/apex/container_test.go
@@ -0,0 +1,329 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package apex
+
+import (
+ "android/soong/android"
+ "android/soong/java"
+ "fmt"
+ "testing"
+)
+
+var checkContainerMatch = func(t *testing.T, name string, container string, expected bool, actual bool) {
+ errorMessage := fmt.Sprintf("module %s container %s value differ", name, container)
+ android.AssertBoolEquals(t, errorMessage, expected, actual)
+}
+
+func TestApexDepsContainers(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForApexTest,
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithLastReleaseApis("mybootclasspathlib"),
+ ).RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ bootclasspath_fragments: [
+ "mybootclasspathfragment",
+ ],
+ updatable: true,
+ min_sdk_version: "30",
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ bootclasspath_fragment {
+ name: "mybootclasspathfragment",
+ contents: [
+ "mybootclasspathlib",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ hidden_api: {
+ split_packages: ["*"],
+ },
+ }
+ java_sdk_library {
+ name: "mybootclasspathlib",
+ srcs: [
+ "mybootclasspathlib.java",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ compile_dex: true,
+ static_libs: [
+ "foo",
+ "baz",
+ ],
+ libs: [
+ "bar",
+ ],
+ min_sdk_version: "30",
+ }
+ java_library {
+ name: "foo",
+ srcs:[
+ "A.java",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ min_sdk_version: "30",
+ }
+ java_library {
+ name: "bar",
+ srcs:[
+ "A.java",
+ ],
+ min_sdk_version: "30",
+ }
+ java_library {
+ name: "baz",
+ srcs:[
+ "A.java",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "myapex",
+ ],
+ min_sdk_version: "30",
+ }
+ `)
+ testcases := []struct {
+ moduleName string
+ variant string
+ isSystemContainer bool
+ isApexContainer bool
+ }{
+ {
+ moduleName: "mybootclasspathlib",
+ variant: "android_common_myapex",
+ isSystemContainer: true,
+ isApexContainer: true,
+ },
+ {
+ moduleName: "mybootclasspathlib.impl",
+ variant: "android_common_apex30",
+ isSystemContainer: true,
+ isApexContainer: true,
+ },
+ {
+ moduleName: "mybootclasspathlib.stubs",
+ variant: "android_common",
+ isSystemContainer: true,
+ isApexContainer: false,
+ },
+ {
+ moduleName: "foo",
+ variant: "android_common_apex30",
+ isSystemContainer: true,
+ isApexContainer: true,
+ },
+ {
+ moduleName: "bar",
+ variant: "android_common",
+ isSystemContainer: true,
+ isApexContainer: false,
+ },
+ {
+ moduleName: "baz",
+ variant: "android_common_apex30",
+ isSystemContainer: true,
+ isApexContainer: true,
+ },
+ }
+
+ for _, c := range testcases {
+ m := result.ModuleForTests(c.moduleName, c.variant)
+ containers, _ := android.OtherModuleProvider(result.TestContext.OtherModuleProviderAdaptor(), m.Module(), android.ContainersInfoProvider)
+ belongingContainers := containers.BelongingContainers()
+ checkContainerMatch(t, c.moduleName, "system", c.isSystemContainer, android.InList(android.SystemContainer, belongingContainers))
+ checkContainerMatch(t, c.moduleName, "apex", c.isApexContainer, android.InList(android.ApexContainer, belongingContainers))
+ }
+}
+
+func TestNonUpdatableApexDepsContainers(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForApexTest,
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithLastReleaseApis("mybootclasspathlib"),
+ ).RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ bootclasspath_fragments: [
+ "mybootclasspathfragment",
+ ],
+ updatable: false,
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ bootclasspath_fragment {
+ name: "mybootclasspathfragment",
+ contents: [
+ "mybootclasspathlib",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ hidden_api: {
+ split_packages: ["*"],
+ },
+ }
+ java_sdk_library {
+ name: "mybootclasspathlib",
+ srcs: [
+ "mybootclasspathlib.java",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ compile_dex: true,
+ static_libs: [
+ "foo",
+ ],
+ libs: [
+ "bar",
+ ],
+ }
+ java_library {
+ name: "foo",
+ srcs:[
+ "A.java",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ }
+ java_library {
+ name: "bar",
+ srcs:[
+ "A.java",
+ ],
+ }
+ `)
+ testcases := []struct {
+ moduleName string
+ variant string
+ isSystemContainer bool
+ isApexContainer bool
+ }{
+ {
+ moduleName: "mybootclasspathlib",
+ variant: "android_common_myapex",
+ isSystemContainer: true,
+ isApexContainer: true,
+ },
+ {
+ moduleName: "mybootclasspathlib.impl",
+ variant: "android_common_apex10000",
+ isSystemContainer: true,
+ isApexContainer: true,
+ },
+ {
+ moduleName: "mybootclasspathlib.stubs",
+ variant: "android_common",
+ isSystemContainer: true,
+ isApexContainer: false,
+ },
+ {
+ moduleName: "foo",
+ variant: "android_common_apex10000",
+ isSystemContainer: true,
+ isApexContainer: true,
+ },
+ {
+ moduleName: "bar",
+ variant: "android_common",
+ isSystemContainer: true,
+ isApexContainer: false,
+ },
+ }
+
+ for _, c := range testcases {
+ m := result.ModuleForTests(c.moduleName, c.variant)
+ containers, _ := android.OtherModuleProvider(result.TestContext.OtherModuleProviderAdaptor(), m.Module(), android.ContainersInfoProvider)
+ belongingContainers := containers.BelongingContainers()
+ checkContainerMatch(t, c.moduleName, "system", c.isSystemContainer, android.InList(android.SystemContainer, belongingContainers))
+ checkContainerMatch(t, c.moduleName, "apex", c.isApexContainer, android.InList(android.ApexContainer, belongingContainers))
+ }
+}
+
+func TestUpdatableAndNonUpdatableApexesIdenticalMinSdkVersion(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForApexTest,
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ android.FixtureMergeMockFs(android.MockFS{
+ "system/sepolicy/apex/myapex_non_updatable-file_contexts": nil,
+ "system/sepolicy/apex/myapex_updatable-file_contexts": nil,
+ }),
+ ).RunTestWithBp(t, `
+ apex {
+ name: "myapex_non_updatable",
+ key: "myapex_non_updatable.key",
+ java_libs: [
+ "foo",
+ ],
+ updatable: false,
+ min_sdk_version: "30",
+ }
+ apex_key {
+ name: "myapex_non_updatable.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ apex {
+ name: "myapex_updatable",
+ key: "myapex_updatable.key",
+ java_libs: [
+ "foo",
+ ],
+ updatable: true,
+ min_sdk_version: "30",
+ }
+ apex_key {
+ name: "myapex_updatable.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_library {
+ name: "foo",
+ srcs:[
+ "A.java",
+ ],
+ apex_available: [
+ "myapex_non_updatable",
+ "myapex_updatable",
+ ],
+ min_sdk_version: "30",
+ sdk_version: "current",
+ }
+ `)
+
+ fooApexVariant := result.ModuleForTests("foo", "android_common_apex30")
+ containers, _ := android.OtherModuleProvider(result.TestContext.OtherModuleProviderAdaptor(), fooApexVariant.Module(), android.ContainersInfoProvider)
+ belongingContainers := containers.BelongingContainers()
+ checkContainerMatch(t, "foo", "system", true, android.InList(android.SystemContainer, belongingContainers))
+ checkContainerMatch(t, "foo", "apex", true, android.InList(android.ApexContainer, belongingContainers))
+}
diff --git a/cc/cc.go b/cc/cc.go
index 740be3a..d307be6 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1867,8 +1867,10 @@
"libdl": true,
"libz": true,
// art apex
+ // TODO(b/234351700): Remove this when com.android.art.debug is gone.
"libandroidio": true,
"libdexfile": true,
+ "libdexfiled": true, // com.android.art.debug only
"libnativebridge": true,
"libnativehelper": true,
"libnativeloader": true,
diff --git a/cc/makevars.go b/cc/makevars.go
index 9d29aff..cd13965 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -138,7 +138,6 @@
ctx.Strict("CLANG_COVERAGE_HWASAN_FLAGS", strings.Join(clangCoverageHWASanFlags, " "))
ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(asanCflags, " "))
- ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS", strings.Join(asanLdflags, " "))
ctx.Strict("HWADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(hwasanCflags, " "))
ctx.Strict("HWADDRESS_SANITIZER_GLOBAL_OPTIONS", strings.Join(hwasanGlobalOptions, ","))
diff --git a/cc/sanitize.go b/cc/sanitize.go
index e6f00fa..64a313b 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -36,7 +36,6 @@
asanCflags = []string{
"-fno-omit-frame-pointer",
}
- asanLdflags = []string{"-Wl,-u,__asan_preinit"}
// DO NOT ADD MLLVM FLAGS HERE! ADD THEM BELOW TO hwasanCommonFlags.
hwasanCflags = []string{
@@ -797,16 +796,17 @@
flags.RequiredInstructionSet = "arm"
}
flags.Local.CFlags = append(flags.Local.CFlags, asanCflags...)
- flags.Local.LdFlags = append(flags.Local.LdFlags, asanLdflags...)
if Bool(sanProps.Writeonly) {
flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-asan-instrument-reads=0")
}
if ctx.Host() {
- // -nodefaultlibs (provided with libc++) prevents the driver from linking
- // libraries needed with -fsanitize=address. http://b/18650275 (WAI)
- flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--no-as-needed")
+ if !ctx.Darwin() { // ld64.lld doesn't know about '--no-as-needed'
+ // -nodefaultlibs (provided with libc++) prevents the driver from linking
+ // libraries needed with -fsanitize=address. http://b/18650275 (WAI)
+ flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--no-as-needed")
+ }
} else {
flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-asan-globals=0")
if ctx.bootstrap() {
diff --git a/cmd/release_config/release_config_lib/release_config.go b/cmd/release_config/release_config_lib/release_config.go
index 6d71d93..adf0e62 100644
--- a/cmd/release_config/release_config_lib/release_config.go
+++ b/cmd/release_config/release_config_lib/release_config.go
@@ -192,6 +192,7 @@
workflowManual := rc_proto.Workflow(rc_proto.Workflow_MANUAL)
myDirsMap := make(map[int]bool)
+ myValueDirsMap := make(map[int]bool)
if isBuildPrefix && releasePlatformVersion != nil {
if MarshalValue(releasePlatformVersion.Value) != strings.ToUpper(config.Name) {
value := FlagValue{
@@ -226,6 +227,8 @@
config.PriorStagesMap[priorStage] = true
}
myDirsMap[contrib.DeclarationIndex] = true
+ // This path *could* provide a value for this release config.
+ myValueDirsMap[contrib.DeclarationIndex] = true
if config.AconfigFlagsOnly {
// AconfigFlagsOnly allows very very few build flag values, all of them are part of aconfig flags.
allowedFlags := map[string]bool{
@@ -243,10 +246,13 @@
if !ok {
return fmt.Errorf("Setting value for undefined flag %s in %s\n", name, value.path)
}
+ // Record that flag declarations from fa.DeclarationIndex were included in this release config.
myDirsMap[fa.DeclarationIndex] = true
+ // Do not set myValueDirsMap, since it just records that we *could* provide values here.
if fa.DeclarationIndex > contrib.DeclarationIndex {
// Setting location is to the left of declaration.
- return fmt.Errorf("Setting value for flag %s not allowed in %s\n", name, value.path)
+ return fmt.Errorf("Setting value for flag %s (declared in %s) not allowed in %s\n",
+ name, filepath.Dir(configs.ReleaseConfigMaps[fa.DeclarationIndex].path), value.path)
}
if isRoot && *fa.FlagDeclaration.Workflow != workflowManual {
// The "root" release config can only contain workflow: MANUAL flags.
@@ -273,10 +279,14 @@
releaseAconfigValueSets.Value = &rc_proto.Value{Val: &rc_proto.Value_StringValue{strings.TrimSpace(strings.Join(myAconfigValueSets, " "))}}
directories := []string{}
+ valueDirectories := []string{}
for idx, confDir := range configs.configDirs {
if _, ok := myDirsMap[idx]; ok {
directories = append(directories, confDir)
}
+ if _, ok := myValueDirsMap[idx]; ok {
+ valueDirectories = append(valueDirectories, confDir)
+ }
}
// Now build the per-partition artifacts
@@ -316,6 +326,7 @@
AconfigValueSets: myAconfigValueSets,
Inherits: myInherits,
Directories: directories,
+ ValueDirectories: valueDirectories,
PriorStages: SortedMapKeys(config.PriorStagesMap),
}
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 b246eb6..c63ea26 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
@@ -223,12 +223,18 @@
// The names of the release_config_artifacts from which we inherited.
// Included for reference only.
Inherits []string `protobuf:"bytes,5,rep,name=inherits" json:"inherits,omitempty"`
- // The release config directories used for this config.
+ // The release config directories used for this config. This includes
+ // directories that provide flag declarations, but do not provide any flag
+ // values specific to this release config.
// For example, "build/release".
Directories []string `protobuf:"bytes,6,rep,name=directories" json:"directories,omitempty"`
// 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,7,rep,name=prior_stages,json=priorStages" json:"prior_stages,omitempty"`
+ // The release config directories that contribute directly to this release
+ // 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"`
}
func (x *ReleaseConfigArtifact) Reset() {
@@ -312,6 +318,13 @@
return nil
}
+func (x *ReleaseConfigArtifact) GetValueDirectories() []string {
+ if x != nil {
+ return x.ValueDirectories
+ }
+ return nil
+}
+
type ReleaseConfigsArtifact struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -412,7 +425,7 @@
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, 0xb0,
+ 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,
@@ -431,42 +444,44 @@
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, 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,
+ 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,
+ 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, 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, 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, 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, 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, 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,
+ 0x6e, 0x66, 0x69, 0x67, 0x73, 0x5f, 0x61, 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,
+ 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,
+ 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,
}
var (
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 2f1715b..4dc84e9 100644
--- a/cmd/release_config/release_config_proto/build_flags_out.proto
+++ b/cmd/release_config/release_config_proto/build_flags_out.proto
@@ -82,13 +82,20 @@
// Included for reference only.
repeated string inherits = 5;
- // The release config directories used for this config.
+ // The release config directories used for this config. This includes
+ // directories that provide flag declarations, but do not provide any flag
+ // values specific to this release config.
// For example, "build/release".
repeated string directories = 6;
// 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 = 7;
+
+ // The release config directories that contribute directly to this release
+ // config. The listed directories contain at least a `release_config` message
+ // for this release config.
+ repeated string value_directories = 8;
}
message release_configs_artifact {
diff --git a/docs/java.dot b/docs/java.dot
new file mode 100644
index 0000000..ad7628d
--- /dev/null
+++ b/docs/java.dot
@@ -0,0 +1,127 @@
+digraph java {
+ //rankdir="LR";
+ //splines="false";
+ //cluster=true;
+ //node [ ordering="in" ];
+ node [ shape="rect" style="rounded" color="blue" ];
+
+ {
+ rank="same";
+ lib_java_sources [ label="library\njava sources" group="lib" ];
+ lib2_java_sources [ label="library\njava sources" group="lib2" ];
+ app_java_sources [ label="app\njava sources" group="app" ];
+ }
+
+ node [ group="lib"];
+ {
+ rank="same";
+ lib_java_classes [ label="library java\n.class files" ];
+ lib_java_headers [ label="library java\nheader .class files" ];
+ }
+
+ node [ group="lib2"];
+ {
+ rank="same";
+ lib_spacer [ style=invis width=4 ];
+ lib2_java_classes [ label="library java\n.class files" ];
+ lib2_java_headers [ label="library java\nheader .class files" ];
+ }
+ {
+ rank="same";
+ lib2_combined_classes [ label="combined library\n.class files" ];
+ lib2_combined_headers [ label="combined library\nheader .class files" ];
+ }
+
+ node [ group="app"];
+ {
+ rank="same";
+ lib2_spacer [ style=invis width=4 ];
+ app_java_classes [ label="app java\n.class files" ];
+ }
+ {
+ rank="same";
+ app_combined_classes [ label="combined app and library\n.class files" ];
+ }
+ {
+ rank="same";
+ app_dex [ label="app classes.dex files" ];
+ }
+
+
+ node [ shape="rect" style="" color="black" ];
+ node [ group="lib"];
+ {
+ rank="same";
+ lib_turbine_action [ label="turbine" ];
+ lib_javac_action [ label="javac" ];
+ }
+
+ node [ group="lib2"];
+ {
+ rank="same";
+ lib2_turbine_action [ label="turbine" ];
+ lib2_javac_action [ label="javac" ];
+ }
+ {
+ rank="same";
+ lib2_combine_action [ label="merge_zips" ];
+ lib2_combine_headers_action [ label="merge_zips" ];
+ }
+
+ node [ group="app"];
+ {
+ rank="same";
+ app_javac_action [ label="javac" ];
+ }
+ {
+ rank="same";
+ app_combine_action [ label="merge_zips" ];
+ }
+ {
+ rank="same";
+ app_r8_action [ label="r8" ];
+ }
+
+ // library
+
+ lib_java_sources -> lib_turbine_action [ weight=100 ];
+ lib_turbine_action -> lib_java_headers [ weight=100 ];
+
+ lib_java_sources -> lib_javac_action [ weight=1000 ];
+ lib_javac_action -> lib_java_classes [ weight=100 ];
+
+ lib_java_headers -> lib_spacer [ style=invis ];
+
+ // library 2
+
+ lib_java_headers -> lib2_turbine_action [ weight=0 ];
+ lib2_java_sources -> lib2_turbine_action [ weight=100 ];
+ lib2_turbine_action -> lib2_java_headers [ weight=100 ];
+
+ lib_java_headers -> lib2_javac_action [ weight=0 ];
+ lib2_java_sources -> lib2_javac_action [ weight=1000 ];
+ lib2_javac_action ->lib2_java_classes [ weight=100 ];
+
+ lib_java_classes -> lib2_combine_action [ weight=0 ];
+ lib2_java_classes -> lib2_combine_action [ weight=100 ];
+ lib2_combine_action -> lib2_combined_classes [ weight=100 ];
+
+ lib_java_headers -> lib2_combine_headers_action [ weight=0 ];
+ lib2_java_headers -> lib2_combine_headers_action [ weight=100 ];
+ lib2_combine_headers_action -> lib2_combined_headers [ weight=100 ];
+
+ lib2_combined_headers -> lib2_spacer [ style=invis ];
+
+ // app
+
+ lib2_combined_headers -> app_javac_action [ weight=0 ];
+ app_java_sources -> app_javac_action [ weight=1000 ];
+ app_javac_action -> app_java_classes [ weight=100 ];
+
+ lib2_combined_classes -> app_combine_action [ weight=0 ];
+ app_java_classes -> app_combine_action [ weight=100 ];
+ app_combine_action -> app_combined_classes [ weight=100 ];
+
+ app_combined_classes -> app_r8_action;
+ app_r8_action -> app_dex [ weight=100 ];
+}
diff --git a/docs/kotlin.dot b/docs/kotlin.dot
new file mode 100644
index 0000000..7a23c16
--- /dev/null
+++ b/docs/kotlin.dot
@@ -0,0 +1,196 @@
+digraph java {
+ //rankdir="LR";
+ //splines="false";
+ //cluster=true;
+ ranksep="0.75 equally"
+ //node [ ordering="in" ];
+ node [ shape="rect" style="rounded" color="blue" ];
+ {
+ rank="same";
+ lib_java_sources [ label="library\njava sources" group="lib" ];
+ lib_kotlin_sources [ label="library\nkotlin sources" group="lib" ];
+ lib2_java_sources [ label="library\njava sources" group="lib2" ];
+ lib2_kotlin_sources [ label="library\nkotlin sources" group="lib2" ];
+ app_java_sources [ label="app\njava sources" group="app" ];
+ app_kotlin_sources [ label="app\nkotlin sources" group="app" ];
+ }
+
+ node [ group="lib"];
+ {
+ rank="same";
+ lib_kotlin_classes [ label="library kotlin\n.class files" ];
+ lib_kotlin_headers [ label="library kotlin\nheader .class files" ];
+ }
+ {
+ rank="same";
+ lib_java_classes [ label="library java\n.class files" ];
+ lib_java_headers [ label="library java\nheader .class files" ];
+ }
+ {
+ rank="same";
+ lib_combined_classes [ label="combined library\n.class files" ];
+ lib_combined_headers [ label="combined library\nheader .class files" ];
+ }
+
+ node [ group="lib2"];
+ {
+ rank="same";
+ lib_spacer [ style=invis width=4 ];
+ lib2_kotlin_classes [ label="library kotlin\n.class files" ];
+ lib2_kotlin_headers [ label="library kotlin\nheader .class files" ];
+ }
+ {
+ rank="same";
+ lib2_java_classes [ label="library java\n.class files" ];
+ lib2_java_headers [ label="library java\nheader .class files" ];
+ }
+ {
+ rank="same";
+ lib2_combined_classes [ label="combined library\n.class files" ];
+ lib2_combined_headers [ label="combined library\nheader .class files" ];
+ }
+
+ node [ group="app"];
+ {
+ rank="same";
+ lib2_spacer [ style=invis width=4 ];
+ app_kotlin_classes [ label="app kotlin\n.class files" ];
+ app_kotlin_headers [ label="app kotlin\nheader .class files" ] }
+ {
+ rank="same";
+ app_java_classes [ label="app java\n.class files" ];
+ }
+ {
+ rank="same";
+ app_combined_classes [ label="combined app and library\n.class files" ];
+ }
+ {
+ rank="same";
+ app_dex [ label="app classes.dex files" ];
+ }
+
+
+ node [ shape="rect" style="" color="black" ];
+ node [ group="lib"];
+ {
+ rank="same";
+ lib_kotlinc_action [ label="kotlinc" ];
+ }
+ {
+ rank="same";
+ lib_turbine_action [ label="turbine" ];
+ lib_javac_action [ label="javac" ];
+ }
+ {
+ rank="same";
+ lib_combine_action [ label="merge_zips" ];
+ lib_combine_headers_action [ label="merge_zips" ];
+ }
+
+ node [ group="lib2"];
+ {
+ rank="same";
+ lib2_kotlinc_action [ label="kotlinc" ];
+ }
+ {
+ rank="same";
+ lib2_turbine_action [ label="turbine" ];
+ lib2_javac_action [ label="javac" ];
+ }
+ {
+ rank="same";
+ lib2_combine_action [ label="merge_zips" ];
+ lib2_combine_headers_action [ label="merge_zips" ];
+ }
+
+ node [ group="app"];
+ {
+ rank="same";
+ app_kotlinc_action [ label="kotlinc" ];
+ }
+ {
+ rank="same";
+ app_javac_action [ label="javac" ];
+ }
+ {
+ rank="same";
+ app_combine_action [ label="merge_zips" ];
+ }
+ {
+ rank="same";
+ app_r8_action [ label="r8" ];
+ }
+
+ // library
+
+ lib_kotlin_sources -> lib_kotlinc_action [ weight=100 ];
+ lib_java_sources -> lib_kotlinc_action;
+ lib_kotlinc_action -> lib_kotlin_classes, lib_kotlin_headers [ weight=100 ];
+
+ lib_kotlin_headers -> lib_turbine_action [ weight=0 ];
+ lib_java_sources -> lib_turbine_action [ weight=100 ];
+ lib_turbine_action -> lib_java_headers [ weight=100 ];
+
+ lib_kotlin_headers -> lib_javac_action [ weight=0 ];
+ lib_java_sources -> lib_javac_action [ weight=1000 ];
+ lib_javac_action -> lib_java_classes [ weight=100 ];
+
+ lib_kotlin_classes -> lib_combine_action [ weight = 0 ];
+ lib_java_classes -> lib_combine_action [ weight = 100 ];
+ lib_combine_action -> lib_combined_classes [ weight=100 ];
+
+ lib_kotlin_headers -> lib_combine_headers_action [ weight = 0 ];
+ lib_java_headers -> lib_combine_headers_action [ weight = 100 ];
+ lib_combine_headers_action -> lib_combined_headers [ weight=100 ];
+
+ lib_combined_headers -> lib_spacer [ style=invis ];
+
+ // library 2
+
+ lib_combined_headers -> lib2_kotlinc_action [ weight=0 ];
+ lib2_kotlin_sources -> lib2_kotlinc_action [ weight=100 ];
+ lib2_java_sources -> lib2_kotlinc_action;
+ lib2_kotlinc_action -> lib2_kotlin_classes, lib2_kotlin_headers [ weight=100 ];
+
+ lib_combined_headers -> lib2_turbine_action [ weight=0 ];
+ lib2_kotlin_headers -> lib2_turbine_action [ weight=0 ];
+ lib2_java_sources -> lib2_turbine_action [ weight=100 ];
+ lib2_turbine_action -> lib2_java_headers [ weight=100 ];
+
+ lib_combined_headers -> lib2_javac_action [ weight=0 ];
+ lib2_kotlin_headers -> lib2_javac_action [ weight=0 ];
+ lib2_java_sources -> lib2_javac_action [ weight=1000 ];
+ lib2_javac_action ->lib2_java_classes [ weight=100 ];
+
+ lib_combined_classes -> lib2_combine_action [ weight=0 ];
+ lib2_kotlin_classes -> lib2_combine_action [ weight=0 ];
+ lib2_java_classes -> lib2_combine_action [ weight=100 ];
+ lib2_combine_action -> lib2_combined_classes [ weight=100 ];
+
+ lib_combined_headers -> lib2_combine_headers_action [ weight=0 ];
+ lib2_kotlin_headers -> lib2_combine_headers_action [ weight=0 ];
+ lib2_java_headers -> lib2_combine_headers_action [ weight=100 ];
+ lib2_combine_headers_action -> lib2_combined_headers [ weight=100 ];
+
+ lib2_combined_headers -> lib2_spacer [ style=invis ];
+
+ // app
+
+ lib2_combined_headers -> app_kotlinc_action [ weight=0 ];
+ app_kotlin_sources -> app_kotlinc_action [ weight=100 ];
+ app_java_sources -> app_kotlinc_action;
+ app_kotlinc_action -> app_kotlin_headers, app_kotlin_classes [ weight=100 ];
+
+ lib2_combined_headers -> app_javac_action [ weight=0 ];
+ app_kotlin_headers -> app_javac_action [ weight=0 ];
+ app_java_sources -> app_javac_action [ weight=1000 ];
+ app_javac_action -> app_java_classes [ weight=100 ];
+
+ lib2_combined_classes -> app_combine_action [ weight=0 ];
+ app_kotlin_classes -> app_combine_action [ weight=0 ];
+ app_java_classes -> app_combine_action [ weight=100 ];
+ app_combine_action -> app_combined_classes [ weight=100 ];
+
+ app_combined_classes -> app_r8_action;
+ app_r8_action -> app_dex [ weight=100 ];
+}
diff --git a/docs/kotlin_with_annotation_processors.dot b/docs/kotlin_with_annotation_processors.dot
new file mode 100644
index 0000000..70c9bf3
--- /dev/null
+++ b/docs/kotlin_with_annotation_processors.dot
@@ -0,0 +1,277 @@
+digraph java {
+ //rankdir="LR";
+ //splines="false";
+ //cluster=true;
+ ranksep="0.75 equally"
+ //node [ ordering="in" ];
+ node [ shape="rect" style="rounded" color="blue" ];
+ {
+ rank="same";
+ lib_java_sources [ label="library\njava sources" group="lib" ];
+ lib_kotlin_sources [ label="library\nkotlin sources" group="lib" ];
+ lib2_java_sources [ label="library\njava sources" group="lib2" ];
+ lib2_kotlin_sources [ label="library\nkotlin sources" group="lib2" ];
+ app_java_sources [ label="app\njava sources" group="app" ];
+ app_kotlin_sources [ label="app\nkotlin sources" group="app" ];
+ }
+
+ node [ group="lib"];
+ {
+ rank="same";
+ lib_kotlin_stubs [ label="library\nkotlin stubs" ];
+ }
+ {
+ rank="same";
+ lib_apt_src_jar [ label="library annotation\nprocessor sources" ];
+ }
+ {
+ rank="same";
+ lib_kotlin_classes [ label="library kotlin\n.class files" ];
+ lib_kotlin_headers [ label="library kotlin\nheader .class files" ];
+ }
+ {
+ rank="same";
+ lib_java_classes [ label="library java\n.class files" ];
+ lib_java_headers [ label="library java\nheader .class files" ];
+ }
+ {
+ rank="same";
+ lib_combined_classes [ label="combined library\n.class files" ];
+ lib_combined_headers [ label="combined library\nheader .class files" ];
+ }
+
+ node [ group="lib2"];
+ {
+ rank="same";
+ lib_spacer [ style=invis width=4 ];
+ lib2_kotlin_stubs [ label="library\nkotlin stubs" ];
+ }
+ {
+ rank="same";
+ lib2_apt_src_jar [ label="library annotation\nprocessor sources" ];
+ }
+ {
+ rank="same";
+ lib2_kotlin_classes [ label="library kotlin\n.class files" ];
+ lib2_kotlin_headers [ label="library kotlin\nheader .class files" ];
+ }
+ {
+ rank="same";
+ lib2_java_classes [ label="library java\n.class files" ];
+ lib2_java_headers [ label="library java\nheader .class files" ];
+ }
+ {
+ rank="same";
+ lib2_combined_classes [ label="combined library\n.class files" ];
+ lib2_combined_headers [ label="combined library\nheader .class files" ];
+ }
+
+ node [ group="app"];
+ {
+ rank="same";
+ lib2_spacer [ style=invis width=4 ];
+ app_kotlin_stubs [ label="app\nkotlin stubs" ];
+ }
+ {
+ rank="same";
+ app_apt_src_jar [ label="app annotation\nprocessor sources" ];
+ }
+ {
+ rank="same";
+ app_kotlin_classes [ label="app kotlin\n.class files" ];
+ app_kotlin_headers [ label="app kotlin\nheader .class files" ] }
+ {
+ rank="same";
+ app_java_classes [ label="app java\n.class files" ];
+ }
+ {
+ rank="same";
+ app_combined_classes [ label="combined app and library\n.class files" ];
+ }
+ {
+ rank="same";
+ app_dex [ label="app classes.dex files" ];
+ }
+
+
+ node [ shape="rect" style="" color="black" ];
+ node [ group="lib"];
+ {
+ rank="same";
+ lib_kapt_action [ label="kapt" ];
+ }
+ {
+ rank="same";
+ lib_turbine_apt_action [ label="turbine apt" ];
+ }
+ {
+ rank="same";
+ lib_kotlinc_action [ label="kotlinc" ];
+ }
+ {
+ rank="same";
+ lib_turbine_action [ label="turbine" ];
+ lib_javac_action [ label="javac" ];
+ }
+ {
+ rank="same";
+ lib_combine_action [ label="merge_zips" ];
+ lib_combine_headers_action [ label="merge_zips" ];
+ }
+
+ node [ group="lib2"];
+ {
+ rank="same";
+ lib2_kapt_action [ label="kapt" ];
+ }
+ {
+ rank="same";
+ lib2_turbine_apt_action [ label="turbine apt" ];
+ }
+ {
+ rank="same";
+ lib2_kotlinc_action [ label="kotlinc" ];
+ }
+ {
+ rank="same";
+ lib2_turbine_action [ label="turbine" ];
+ lib2_javac_action [ label="javac" ];
+ }
+ {
+ rank="same";
+ lib2_combine_action [ label="merge_zips" ];
+ lib2_combine_headers_action [ label="merge_zips" ];
+ }
+
+ node [ group="app"];
+ {
+ rank="same";
+ app_kapt_action [ label="kapt" ];
+ }
+ {
+ rank="same";
+ app_turbine_apt_action [ label="turbine apt" ];
+ }
+ {
+ rank="same";
+ app_kotlinc_action [ label="kotlinc" ];
+ }
+ {
+ rank="same";
+ app_javac_action [ label="javac" ];
+ }
+ {
+ rank="same";
+ app_combine_action [ label="merge_zips" ];
+ }
+ {
+ rank="same";
+ app_r8_action [ label="r8" ];
+ }
+
+ // library
+
+ lib_kotlin_sources -> lib_kapt_action [ weight=0 ];
+ lib_java_sources -> lib_kapt_action;
+ lib_kapt_action -> lib_kotlin_stubs [ weight=100 ];
+
+ lib_kotlin_stubs -> lib_turbine_apt_action [ weight=100 ];
+ lib_turbine_apt_action -> lib_apt_src_jar [ weight=100 ];
+
+ lib_apt_src_jar -> lib_kotlinc_action [ weight=0 ];
+ lib_kotlin_sources -> lib_kotlinc_action [ weight=100 ];
+ lib_java_sources -> lib_kotlinc_action;
+ lib_kotlinc_action -> lib_kotlin_classes, lib_kotlin_headers [ weight=100 ];
+
+ lib_apt_src_jar -> lib_turbine_action [ weight=0 ];
+ lib_kotlin_headers -> lib_turbine_action [ weight=0 ];
+ lib_java_sources -> lib_turbine_action [ weight=100 ];
+ lib_turbine_action -> lib_java_headers [ weight=100 ];
+
+ lib_apt_src_jar -> lib_javac_action [ weight=0 ];
+ lib_kotlin_headers -> lib_javac_action [ weight=0 ];
+ lib_java_sources -> lib_javac_action [ weight=1000 ];
+ lib_javac_action -> lib_java_classes [ weight=100 ];
+
+ lib_kotlin_classes -> lib_combine_action [ weight = 0 ];
+ lib_java_classes -> lib_combine_action [ weight = 100 ];
+ lib_combine_action -> lib_combined_classes [ weight=100 ];
+
+ lib_kotlin_headers -> lib_combine_headers_action [ weight = 0 ];
+ lib_java_headers -> lib_combine_headers_action [ weight = 100 ];
+ lib_combine_headers_action -> lib_combined_headers [ weight=100 ];
+
+ lib_combined_headers -> lib_spacer [ style=invis ];
+
+ // library 2
+
+ lib_combined_headers -> lib2_kapt_action [ weight=0 ];
+ lib2_kotlin_sources -> lib2_kapt_action [ weight=0 ];
+ lib2_java_sources -> lib2_kapt_action;
+ lib2_kapt_action -> lib2_kotlin_stubs [ weight=100 ];
+
+ lib_combined_headers -> lib2_turbine_apt_action [ weight=0 ];
+ lib2_kotlin_stubs -> lib2_turbine_apt_action [ weight=100 ];
+ lib2_turbine_apt_action -> lib2_apt_src_jar [ weight=100 ];
+
+ lib_combined_headers -> lib2_kotlinc_action [ weight=0 ];
+ lib2_apt_src_jar -> lib2_kotlinc_action [ weight=0 ];
+ lib2_kotlin_sources -> lib2_kotlinc_action [ weight=100 ];
+ lib2_java_sources -> lib2_kotlinc_action;
+ lib2_kotlinc_action -> lib2_kotlin_classes, lib2_kotlin_headers [ weight=100 ];
+
+ lib_combined_headers -> lib2_turbine_action [ weight=0 ];
+ lib2_apt_src_jar -> lib2_turbine_action [ weight=0 ];
+ lib2_kotlin_headers -> lib2_turbine_action [ weight=0 ];
+ lib2_java_sources -> lib2_turbine_action [ weight=100 ];
+ lib2_turbine_action -> lib2_java_headers [ weight=100 ];
+
+ lib_combined_headers -> lib2_javac_action [ weight=0 ];
+ lib2_apt_src_jar -> lib2_javac_action [ weight=0 ];
+ lib2_kotlin_headers -> lib2_javac_action [ weight=0 ];
+ lib2_java_sources -> lib2_javac_action [ weight=1000 ];
+ lib2_javac_action ->lib2_java_classes [ weight=100 ];
+
+ lib_combined_classes -> lib2_combine_action [ weight=0 ];
+ lib2_kotlin_classes -> lib2_combine_action [ weight=0 ];
+ lib2_java_classes -> lib2_combine_action [ weight=100 ];
+ lib2_combine_action -> lib2_combined_classes [ weight=100 ];
+
+ lib_combined_headers -> lib2_combine_headers_action [ weight=0 ];
+ lib2_kotlin_headers -> lib2_combine_headers_action [ weight=0 ];
+ lib2_java_headers -> lib2_combine_headers_action [ weight=100 ];
+ lib2_combine_headers_action -> lib2_combined_headers [ weight=100 ];
+
+ lib2_combined_headers -> lib2_spacer [ style=invis ];
+
+ // app
+
+ lib2_combined_headers -> app_kapt_action [ weight=0 ];
+ app_kotlin_sources -> app_kapt_action [ weight=0 ];
+ app_java_sources -> app_kapt_action;
+ app_kapt_action -> app_kotlin_stubs [ weight=100 ];
+
+ lib2_combined_headers -> app_turbine_apt_action [ weight=0 ];
+ app_kotlin_stubs -> app_turbine_apt_action [ weight=100 ];
+ app_turbine_apt_action -> app_apt_src_jar [ weight=100 ];
+
+ lib2_combined_headers -> app_kotlinc_action [ weight=0 ];
+ app_apt_src_jar -> app_kotlinc_action [ weight=0 ];
+ app_kotlin_sources -> app_kotlinc_action [ weight=100 ];
+ app_java_sources -> app_kotlinc_action;
+ app_kotlinc_action -> app_kotlin_headers, app_kotlin_classes [ weight=100 ];
+
+ lib2_combined_headers -> app_javac_action [ weight=0 ];
+ app_apt_src_jar -> app_javac_action [ weight=0 ];
+ app_kotlin_headers -> app_javac_action [ weight=0 ];
+ app_java_sources -> app_javac_action [ weight=1000 ];
+ app_javac_action -> app_java_classes [ weight=100 ];
+
+ lib2_combined_classes -> app_combine_action [ weight=0 ];
+ app_kotlin_classes -> app_combine_action [ weight=0 ];
+ app_java_classes -> app_combine_action [ weight=100 ];
+ app_combine_action -> app_combined_classes [ weight=100 ];
+
+ app_combined_classes -> app_r8_action;
+ app_r8_action -> app_dex [ weight=100 ];
+}
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index d04b2d1..fc6d1f7 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -126,6 +126,15 @@
Relative_install_path *string `android:"arch_variant"`
}
+type prebuiltRootProperties struct {
+ // Install this module to the root directory, without partition subdirs. When this module is
+ // added to PRODUCT_PACKAGES, this module will be installed to $PRODUCT_OUT/root, which will
+ // then be copied to the root of system.img. When this module is packaged by other modules like
+ // android_filesystem, this module will be installed to the root ("/"), unlike normal
+ // prebuilt_root modules which are installed to the partition subdir (e.g. "/system/").
+ Install_in_root *bool
+}
+
type PrebuiltEtcModule interface {
android.Module
@@ -140,7 +149,12 @@
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.
+ rootProperties prebuiltRootProperties
+
subdirProperties prebuiltSubdirProperties
sourceFilePaths android.Paths
@@ -156,9 +170,6 @@
additionalDependencies *android.Paths
usedSrcsProperty bool
- // installInRoot is used to return the value of the InstallInRoot() method. The default value is false.
- // Currently, only prebuilt_avb can be set to true.
- installInRoot bool
makeClass string
}
@@ -246,7 +257,7 @@
}
func (p *PrebuiltEtc) InstallInRoot() bool {
- return p.installInRoot
+ return proptools.Bool(p.rootProperties.Install_in_root)
}
func (p *PrebuiltEtc) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
@@ -502,21 +513,20 @@
func InitPrebuiltEtcModule(p *PrebuiltEtc, dirBase string) {
p.installDirBase = dirBase
- p.installInRoot = false
p.AddProperties(&p.properties)
p.AddProperties(&p.subdirProperties)
}
func InitPrebuiltRootModule(p *PrebuiltEtc) {
p.installDirBase = "."
- p.installInRoot = false
p.AddProperties(&p.properties)
+ p.AddProperties(&p.rootProperties)
}
func InitPrebuiltAvbModule(p *PrebuiltEtc) {
p.installDirBase = "avb"
- p.installInRoot = true
p.AddProperties(&p.properties)
+ p.rootProperties.Install_in_root = proptools.BoolPtr(true)
}
// prebuilt_etc is for a prebuilt artifact that is installed in
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 5add954..5c7ef43 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -312,6 +312,25 @@
}
}
+func (f *filesystem) copyPackagingSpecs(ctx android.ModuleContext, builder *android.RuleBuilder, specs map[string]android.PackagingSpec, rootDir, rebasedDir android.WritablePath) []string {
+ rootDirSpecs := make(map[string]android.PackagingSpec)
+ rebasedDirSpecs := make(map[string]android.PackagingSpec)
+
+ for rel, spec := range specs {
+ if spec.Partition() == "root" {
+ rootDirSpecs[rel] = spec
+ } else {
+ rebasedDirSpecs[rel] = spec
+ }
+ }
+
+ dirsToSpecs := make(map[android.WritablePath]map[string]android.PackagingSpec)
+ dirsToSpecs[rootDir] = rootDirSpecs
+ dirsToSpecs[rebasedDir] = rebasedDirSpecs
+
+ return f.CopySpecsToDirs(ctx, builder, dirsToSpecs)
+}
+
func (f *filesystem) buildImageUsingBuildImage(ctx android.ModuleContext) android.OutputPath {
rootDir := android.PathForModuleOut(ctx, "root").OutputPath
rebasedDir := rootDir
@@ -322,7 +341,7 @@
// 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.CopySpecsToDir(ctx, builder, specs, rebasedDir)
+ f.entries = f.copyPackagingSpecs(ctx, builder, specs, rootDir, rebasedDir)
f.buildNonDepsFiles(ctx, builder, rootDir)
f.addMakeBuiltFiles(ctx, builder, rootDir)
@@ -465,7 +484,7 @@
// 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.CopySpecsToDir(ctx, builder, specs, rebasedDir)
+ f.entries = f.copyPackagingSpecs(ctx, builder, specs, rootDir, rebasedDir)
f.buildNonDepsFiles(ctx, builder, rootDir)
f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir)
diff --git a/filesystem/system_image.go b/filesystem/system_image.go
index 15cacfb..69d922d 100644
--- a/filesystem/system_image.go
+++ b/filesystem/system_image.go
@@ -94,9 +94,10 @@
return output
}
-// Filter the result of GatherPackagingSpecs to discard items targeting outside "system" partition.
-// Note that "apex" module installs its contents to "apex"(fake partition) as well
+// 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"
+ return s.filesystem.filterInstallablePackagingSpec(ps) &&
+ (ps.Partition() == "system" || ps.Partition() == "root")
}
diff --git a/java/Android.bp b/java/Android.bp
index 54b36ab..a941754 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -87,6 +87,7 @@
"app_set_test.go",
"app_test.go",
"code_metadata_test.go",
+ "container_test.go",
"bootclasspath_fragment_test.go",
"device_host_converter_test.go",
"dex_test.go",
diff --git a/java/base.go b/java/base.go
index fc68d20..02dc3e3 100644
--- a/java/base.go
+++ b/java/base.go
@@ -552,6 +552,18 @@
aconfigCacheFiles android.Paths
}
+var _ android.InstallableModule = (*Module)(nil)
+
+// To satisfy the InstallableModule interface
+func (j *Module) EnforceApiContainerChecks() bool {
+ return true
+}
+
+// Overrides android.ModuleBase.InstallInProduct()
+func (j *Module) InstallInProduct() bool {
+ return j.ProductSpecific()
+}
+
func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
sdkVersion := j.SdkVersion(ctx)
if sdkVersion.Stable() {
diff --git a/java/container_test.go b/java/container_test.go
new file mode 100644
index 0000000..3441855
--- /dev/null
+++ b/java/container_test.go
@@ -0,0 +1,129 @@
+// 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 (
+ "android/soong/android"
+ "fmt"
+ "testing"
+)
+
+var checkContainerMatch = func(t *testing.T, name string, container string, expected bool, actual bool) {
+ errorMessage := fmt.Sprintf("module %s container %s value differ", name, container)
+ android.AssertBoolEquals(t, errorMessage, expected, actual)
+}
+
+func TestJavaContainersModuleProperties(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ ).RunTestWithBp(t, `
+ java_library {
+ name: "foo",
+ srcs: ["A.java"],
+ }
+ java_library {
+ name: "foo_vendor",
+ srcs: ["A.java"],
+ vendor: true,
+ sdk_version: "current",
+ }
+ java_library {
+ name: "foo_soc_specific",
+ srcs: ["A.java"],
+ soc_specific: true,
+ sdk_version: "current",
+ }
+ java_library {
+ name: "foo_product_specific",
+ srcs: ["A.java"],
+ product_specific: true,
+ sdk_version: "current",
+ }
+ java_test {
+ name: "foo_cts_test",
+ srcs: ["A.java"],
+ test_suites: [
+ "cts",
+ ],
+ }
+ java_test {
+ name: "foo_non_cts_test",
+ srcs: ["A.java"],
+ test_suites: [
+ "general-tests",
+ ],
+ }
+ `)
+
+ testcases := []struct {
+ moduleName string
+ isSystemContainer bool
+ isVendorContainer bool
+ isProductContainer bool
+ isCts bool
+ }{
+ {
+ moduleName: "foo",
+ isSystemContainer: true,
+ isVendorContainer: false,
+ isProductContainer: false,
+ isCts: false,
+ },
+ {
+ moduleName: "foo_vendor",
+ isSystemContainer: false,
+ isVendorContainer: true,
+ isProductContainer: false,
+ isCts: false,
+ },
+ {
+ moduleName: "foo_soc_specific",
+ isSystemContainer: false,
+ isVendorContainer: true,
+ isProductContainer: false,
+ isCts: false,
+ },
+ {
+ moduleName: "foo_product_specific",
+ isSystemContainer: false,
+ isVendorContainer: false,
+ isProductContainer: true,
+ isCts: false,
+ },
+ {
+ moduleName: "foo_cts_test",
+ isSystemContainer: false,
+ isVendorContainer: false,
+ isProductContainer: false,
+ isCts: true,
+ },
+ {
+ moduleName: "foo_non_cts_test",
+ isSystemContainer: false,
+ isVendorContainer: false,
+ isProductContainer: false,
+ isCts: false,
+ },
+ }
+
+ for _, c := range testcases {
+ m := result.ModuleForTests(c.moduleName, "android_common")
+ containers, _ := android.OtherModuleProvider(result.TestContext.OtherModuleProviderAdaptor(), m.Module(), android.ContainersInfoProvider)
+ belongingContainers := containers.BelongingContainers()
+ checkContainerMatch(t, c.moduleName, "system", c.isSystemContainer, android.InList(android.SystemContainer, belongingContainers))
+ checkContainerMatch(t, c.moduleName, "vendor", c.isVendorContainer, android.InList(android.VendorContainer, belongingContainers))
+ checkContainerMatch(t, c.moduleName, "product", c.isProductContainer, android.InList(android.ProductContainer, belongingContainers))
+ }
+}
diff --git a/rust/test.go b/rust/test.go
index 3087d8d..b7ddd06 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -116,7 +116,8 @@
}
func (test *testDecorator) install(ctx ModuleContext) {
- testInstallBase := "/data/local/tests/unrestricted"
+ // TODO: (b/167308193) Switch to /data/local/tests/unrestricted as the default install base.
+ testInstallBase := "/data/local/tmp"
if ctx.RustModule().InVendorOrProduct() {
testInstallBase = "/data/local/tests/vendor"
}