Merge "Add support for order-only dependencies to RuleBuilder" into rvc-dev
diff --git a/android/api_levels.go b/android/api_levels.go
index 62a5fce..b6296d8 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -74,7 +74,7 @@
"P": 28,
"Q": 29,
}
- for i, codename := range config.PlatformVersionCombinedCodenames() {
+ for i, codename := range config.PlatformVersionActiveCodenames() {
apiLevelsMap[codename] = baseApiLevel + i
}
diff --git a/android/config.go b/android/config.go
index a81b928..a0418d8 100644
--- a/android/config.go
+++ b/android/config.go
@@ -649,22 +649,6 @@
return c.productVariables.Platform_version_active_codenames
}
-// Codenames that are available in the branch but not included in the current
-// lunch target.
-func (c *config) PlatformVersionFutureCodenames() []string {
- return c.productVariables.Platform_version_future_codenames
-}
-
-// All possible codenames in the current branch. NB: Not named AllCodenames
-// because "all" has historically meant "active" in make, and still does in
-// build.prop.
-func (c *config) PlatformVersionCombinedCodenames() []string {
- combined := []string{}
- combined = append(combined, c.PlatformVersionActiveCodenames()...)
- combined = append(combined, c.PlatformVersionFutureCodenames()...)
- return combined
-}
-
func (c *config) ProductAAPTConfig() []string {
return c.productVariables.AAPTConfig
}
diff --git a/android/module.go b/android/module.go
index f668cc3..79693a1 100644
--- a/android/module.go
+++ b/android/module.go
@@ -215,6 +215,7 @@
InstallInRoot() bool
InstallBypassMake() bool
SkipInstall()
+ IsSkipInstall() bool
ExportedToMake() bool
InitRc() Paths
VintfFragments() Paths
@@ -844,7 +845,7 @@
// partition at "system/vendor/odm".
if config.OdmPath() == "odm" {
partition = "odm"
- } else if strings.HasPrefix(config.OdmPath (), "vendor/") {
+ } else if strings.HasPrefix(config.OdmPath(), "vendor/") {
partition = "vendor"
}
} else if m.ProductSpecific() {
@@ -879,6 +880,10 @@
m.commonProperties.SkipInstall = true
}
+func (m *ModuleBase) IsSkipInstall() bool {
+ return m.commonProperties.SkipInstall == true
+}
+
func (m *ModuleBase) ExportedToMake() bool {
return m.commonProperties.NamespaceExportedToMake
}
@@ -1312,16 +1317,20 @@
strictVisitDeps bool // If true, enforce that all dependencies are enabled
}
-func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string { return b.bp.OtherModuleName(m) }
-func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string { return b.bp.OtherModuleDir(m) }
+func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string {
+ return b.bp.OtherModuleName(m)
+}
+func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string { return b.bp.OtherModuleDir(m) }
func (b *baseModuleContext) OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) {
b.bp.OtherModuleErrorf(m, fmt, args...)
}
func (b *baseModuleContext) OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag {
return b.bp.OtherModuleDependencyTag(m)
}
-func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) }
-func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string { return b.bp.OtherModuleType(m) }
+func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) }
+func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string {
+ return b.bp.OtherModuleType(m)
+}
func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
return b.bp.GetDirectDepWithTag(name, tag)
diff --git a/android/rule_builder.go b/android/rule_builder.go
index b4f144a..9005f07 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -162,9 +162,10 @@
r.Command().Text("rm").Flag("-f").Outputs(temporariesList)
}
-// Inputs returns the list of paths that were passed to the RuleBuilderCommand methods that take input paths, such
-// as RuleBuilderCommand.Input, RuleBuilderComand.Implicit, or RuleBuilderCommand.FlagWithInput. Inputs to a command
-// that are also outputs of another command in the same RuleBuilder are filtered out.
+// Inputs returns the list of paths that were passed to the RuleBuilderCommand methods that take
+// input paths, such as RuleBuilderCommand.Input, RuleBuilderComand.Implicit, or
+// RuleBuilderCommand.FlagWithInput. Inputs to a command that are also outputs of another command
+// in the same RuleBuilder are filtered out. The list is sorted and duplicates removed.
func (r *RuleBuilder) Inputs() Paths {
outputs := r.outputSet()
depFiles := r.depFileSet()
@@ -193,6 +194,28 @@
return inputList
}
+// OrderOnlys returns the list of paths that were passed to the RuleBuilderCommand.OrderOnly or
+// RuleBuilderCommand.OrderOnlys. The list is sorted and duplicates removed.
+func (r *RuleBuilder) OrderOnlys() Paths {
+ orderOnlys := make(map[string]Path)
+ for _, c := range r.commands {
+ for _, orderOnly := range c.orderOnlys {
+ orderOnlys[orderOnly.String()] = orderOnly
+ }
+ }
+
+ var orderOnlyList Paths
+ for _, orderOnly := range orderOnlys {
+ orderOnlyList = append(orderOnlyList, orderOnly)
+ }
+
+ sort.Slice(orderOnlyList, func(i, j int) bool {
+ return orderOnlyList[i].String() < orderOnlyList[j].String()
+ })
+
+ return orderOnlyList
+}
+
func (r *RuleBuilder) outputSet() map[string]WritablePath {
outputs := make(map[string]WritablePath)
for _, c := range r.commands {
@@ -203,8 +226,9 @@
return outputs
}
-// Outputs returns the list of paths that were passed to the RuleBuilderCommand methods that take output paths, such
-// as RuleBuilderCommand.Output, RuleBuilderCommand.ImplicitOutput, or RuleBuilderCommand.FlagWithInput.
+// Outputs returns the list of paths that were passed to the RuleBuilderCommand methods that take
+// output paths, such as RuleBuilderCommand.Output, RuleBuilderCommand.ImplicitOutput, or
+// RuleBuilderCommand.FlagWithInput. The list is sorted and duplicates removed.
func (r *RuleBuilder) Outputs() WritablePaths {
outputs := r.outputSet()
@@ -262,7 +286,8 @@
return tools
}
-// Tools returns the list of paths that were passed to the RuleBuilderCommand.Tool method.
+// Tools returns the list of paths that were passed to the RuleBuilderCommand.Tool method. The
+// list is sorted and duplicates removed.
func (r *RuleBuilder) Tools() Paths {
toolsSet := r.toolsSet()
@@ -337,6 +362,7 @@
ctx.Build(pctx, BuildParams{
Rule: ErrorRule,
Outputs: r.Outputs(),
+ OrderOnly: r.OrderOnlys(),
Description: desc,
Args: map[string]string{
"error": "missing dependencies: " + strings.Join(r.missingDeps, ", "),
@@ -453,6 +479,7 @@
type RuleBuilderCommand struct {
buf strings.Builder
inputs Paths
+ orderOnlys Paths
outputs WritablePaths
depFiles WritablePaths
tools Paths
@@ -475,6 +502,10 @@
return path.String()
}
+func (c *RuleBuilderCommand) addOrderOnly(path Path) {
+ c.orderOnlys = append(c.orderOnlys, path)
+}
+
func (c *RuleBuilderCommand) outputStr(path Path) string {
if c.sbox {
// Errors will be handled in RuleBuilder.Build where we have a context to report them
@@ -604,6 +635,22 @@
return c
}
+// OrderOnly adds the specified input path to the dependencies returned by RuleBuilder.OrderOnlys
+// without modifying the command line.
+func (c *RuleBuilderCommand) OrderOnly(path Path) *RuleBuilderCommand {
+ c.addOrderOnly(path)
+ return c
+}
+
+// OrderOnlys adds the specified input paths to the dependencies returned by RuleBuilder.OrderOnlys
+// without modifying the command line.
+func (c *RuleBuilderCommand) OrderOnlys(paths Paths) *RuleBuilderCommand {
+ for _, path := range paths {
+ c.addOrderOnly(path)
+ }
+ return c
+}
+
// Output adds the specified output path to the command line. The path will also be added to the outputs returned by
// RuleBuilder.Outputs.
func (c *RuleBuilderCommand) Output(path WritablePath) *RuleBuilderCommand {
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index acf8127..c41b067 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -265,14 +265,16 @@
func TestRuleBuilder(t *testing.T) {
fs := map[string][]byte{
- "dep_fixer": nil,
- "input": nil,
- "Implicit": nil,
- "Input": nil,
- "Tool": nil,
- "input2": nil,
- "tool2": nil,
- "input3": nil,
+ "dep_fixer": nil,
+ "input": nil,
+ "Implicit": nil,
+ "Input": nil,
+ "OrderOnly": nil,
+ "OrderOnlys": nil,
+ "Tool": nil,
+ "input2": nil,
+ "tool2": nil,
+ "input3": nil,
}
ctx := PathContextForTesting(TestConfig("out", nil, "", fs))
@@ -290,6 +292,7 @@
ImplicitOutput(PathForOutput(ctx, "ImplicitOutput")).
Input(PathForSource(ctx, "Input")).
Output(PathForOutput(ctx, "Output")).
+ OrderOnly(PathForSource(ctx, "OrderOnly")).
Text("Text").
Tool(PathForSource(ctx, "Tool"))
@@ -298,6 +301,7 @@
DepFile(PathForOutput(ctx, "depfile2")).
Input(PathForSource(ctx, "input2")).
Output(PathForOutput(ctx, "output2")).
+ OrderOnlys(PathsForSource(ctx, []string{"OrderOnlys"})).
Tool(PathForSource(ctx, "tool2"))
// Test updates to the first command after the second command has been started
@@ -317,6 +321,7 @@
wantOutputs := PathsForOutput(ctx, []string{"ImplicitOutput", "Output", "output", "output2", "output3"})
wantDepFiles := PathsForOutput(ctx, []string{"DepFile", "depfile", "ImplicitDepFile", "depfile2"})
wantTools := PathsForSource(ctx, []string{"Tool", "tool2"})
+ wantOrderOnlys := PathsForSource(ctx, []string{"OrderOnly", "OrderOnlys"})
t.Run("normal", func(t *testing.T) {
rule := NewRuleBuilder()
@@ -346,6 +351,9 @@
if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) {
t.Errorf("\nwant rule.Tools() = %#v\n got %#v", w, g)
}
+ if g, w := rule.OrderOnlys(), wantOrderOnlys; !reflect.DeepEqual(w, g) {
+ t.Errorf("\nwant rule.OrderOnlys() = %#v\n got %#v", w, g)
+ }
if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w {
t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n got %#v", w, g)
@@ -380,6 +388,9 @@
if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) {
t.Errorf("\nwant rule.Tools() = %#v\n got %#v", w, g)
}
+ if g, w := rule.OrderOnlys(), wantOrderOnlys; !reflect.DeepEqual(w, g) {
+ t.Errorf("\nwant rule.OrderOnlys() = %#v\n got %#v", w, g)
+ }
if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w {
t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n got %#v", w, g)
diff --git a/android/variable.go b/android/variable.go
index e4dd9fc..4d1b5e4 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -148,7 +148,6 @@
Platform_sdk_codename *string `json:",omitempty"`
Platform_sdk_final *bool `json:",omitempty"`
Platform_version_active_codenames []string `json:",omitempty"`
- Platform_version_future_codenames []string `json:",omitempty"`
Platform_vndk_version *string `json:",omitempty"`
Platform_systemsdk_versions []string `json:",omitempty"`
Platform_security_patch *string `json:",omitempty"`
@@ -250,7 +249,7 @@
ClangTidy *bool `json:",omitempty"`
TidyChecks *string `json:",omitempty"`
- SamplingPGO *bool `json:",omitempty"`
+ SamplingPGO *bool `json:",omitempty"`
NativeLineCoverage *bool `json:",omitempty"`
Native_coverage *bool `json:",omitempty"`
@@ -353,7 +352,6 @@
Platform_sdk_codename: stringPtr("Q"),
Platform_sdk_final: boolPtr(false),
Platform_version_active_codenames: []string{"Q"},
- Platform_version_future_codenames: []string{"Q"},
Platform_vndk_version: stringPtr("Q"),
HostArch: stringPtr("x86_64"),
diff --git a/apex/apex.go b/apex/apex.go
index 8e3e562..3f790dc 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1005,6 +1005,12 @@
}
func init() {
+ android.AddNeverAllowRules(android.NeverAllow().
+ ModuleType("apex").
+ With("updatable", "true").
+ With("min_sdk_version", "").
+ Because("All updatable apexes should set min_sdk_version."))
+
android.RegisterModuleType("apex", BundleFactory)
android.RegisterModuleType("apex_test", testApexBundleFactory)
android.RegisterModuleType("apex_vndk", vndkApexBundleFactory)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 80d8153..4b56b6b 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -27,6 +27,7 @@
"android/soong/android"
"android/soong/cc"
+ "android/soong/dexpreopt"
"android/soong/java"
)
@@ -4089,6 +4090,175 @@
ensureContains(t, content, `"apex_config":{"apex_embedded_apk_config":[{"package_name":"com.android.foo","path":"app/AppFoo/AppFoo.apk"}]}`)
}
+func testNoUpdatableJarsInBootImage(t *testing.T, errmsg, bp string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
+ t.Helper()
+
+ bp = bp + `
+ filegroup {
+ name: "some-updatable-apex-file_contexts",
+ srcs: [
+ "system/sepolicy/apex/some-updatable-apex-file_contexts",
+ ],
+ }
+ `
+ bp += cc.GatherRequiredDepsForTest(android.Android)
+ bp += java.GatherRequiredDepsForTest()
+ bp += dexpreopt.BpToolModulesForTest()
+
+ fs := map[string][]byte{
+ "a.java": nil,
+ "a.jar": nil,
+ "build/make/target/product/security": nil,
+ "apex_manifest.json": nil,
+ "AndroidManifest.xml": nil,
+ "system/sepolicy/apex/some-updatable-apex-file_contexts": nil,
+ "system/sepolicy/apex/com.android.art.something-file_contexts": nil,
+ "framework/aidl/a.aidl": nil,
+ }
+ cc.GatherRequiredFilesForTest(fs)
+
+ ctx := android.NewTestArchContext()
+ ctx.RegisterModuleType("apex", BundleFactory)
+ ctx.RegisterModuleType("apex_key", ApexKeyFactory)
+ ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+ cc.RegisterRequiredBuildComponentsForTest(ctx)
+ java.RegisterJavaBuildComponents(ctx)
+ java.RegisterSystemModulesBuildComponents(ctx)
+ java.RegisterAppBuildComponents(ctx)
+ java.RegisterDexpreoptBootJarsComponents(ctx)
+ ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+ ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
+ ctx.PreDepsMutators(RegisterPreDepsMutators)
+ ctx.PostDepsMutators(RegisterPostDepsMutators)
+
+ config := android.TestArchConfig(buildDir, nil, bp, fs)
+ ctx.Register(config)
+
+ _ = dexpreopt.GlobalSoongConfigForTests(config)
+ dexpreopt.RegisterToolModulesForTest(ctx)
+ pathCtx := android.PathContextForTesting(config)
+ dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
+ transformDexpreoptConfig(dexpreoptConfig)
+ dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
+
+ _, errs := ctx.ParseBlueprintsFiles("Android.bp")
+ android.FailIfErrored(t, errs)
+
+ _, errs = ctx.PrepareBuildActions(config)
+ if errmsg == "" {
+ android.FailIfErrored(t, errs)
+ } else if len(errs) > 0 {
+ android.FailIfNoMatchingErrors(t, errmsg, errs)
+ return
+ } else {
+ t.Fatalf("missing expected error %q (0 errors are returned)", errmsg)
+ }
+}
+
+func TestNoUpdatableJarsInBootImage(t *testing.T) {
+ bp := `
+ java_library {
+ name: "some-updatable-apex-lib",
+ srcs: ["a.java"],
+ apex_available: [
+ "some-updatable-apex",
+ ],
+ }
+
+ java_library {
+ name: "some-platform-lib",
+ srcs: ["a.java"],
+ installable: true,
+ }
+
+ java_library {
+ name: "some-art-lib",
+ srcs: ["a.java"],
+ apex_available: [
+ "com.android.art.something",
+ ],
+ hostdex: true,
+ }
+
+ apex {
+ name: "some-updatable-apex",
+ key: "some-updatable-apex.key",
+ java_libs: ["some-updatable-apex-lib"],
+ }
+
+ apex_key {
+ name: "some-updatable-apex.key",
+ }
+
+ apex {
+ name: "com.android.art.something",
+ key: "com.android.art.something.key",
+ java_libs: ["some-art-lib"],
+ }
+
+ apex_key {
+ name: "com.android.art.something.key",
+ }
+ `
+
+ var error string
+ var transform func(*dexpreopt.GlobalConfig)
+
+ // updatable jar from ART apex in the ART boot image => ok
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = []string{"some-art-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, "", bp, transform)
+
+ // updatable jar from ART apex in the framework boot image => error
+ error = "module 'some-art-lib' from updatable apex 'com.android.art.something' is not allowed in the framework boot image"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = []string{"some-art-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+ // updatable jar from some other apex in the ART boot image => error
+ error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the ART boot image"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = []string{"some-updatable-apex-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+ // updatable jar from some other apex in the framework boot image => error
+ error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = []string{"some-updatable-apex-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+ // nonexistent jar in the ART boot image => error
+ error = "failed to find a dex jar path for module 'nonexistent'"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = []string{"nonexistent"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+ // nonexistent jar in the framework boot image => error
+ error = "failed to find a dex jar path for module 'nonexistent'"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = []string{"nonexistent"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+ // platform jar in the ART boot image => error
+ error = "module 'some-platform-lib' is part of the platform and not allowed in the ART boot image"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = []string{"some-platform-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+ // platform jar in the framework boot image => ok
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = []string{"some-platform-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, "", bp, transform)
+}
+
func TestMain(m *testing.M) {
run := func() int {
setUp()
diff --git a/cc/cc.go b/cc/cc.go
index 930c19c..cb71c3b 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1076,7 +1076,7 @@
if ctx.ctx.Device() {
if ctx.useVndk() {
vndkVer := ctx.mod.VndkVersion()
- if inList(vndkVer, ctx.ctx.Config().PlatformVersionCombinedCodenames()) {
+ if inList(vndkVer, ctx.ctx.Config().PlatformVersionActiveCodenames()) {
return "current"
}
return vndkVer
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 09050aa..7ff20f4 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -83,7 +83,7 @@
func (stub *llndkStubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
vndkVer := ctx.Module().(*Module).VndkVersion()
- if !inList(vndkVer, ctx.Config().PlatformVersionCombinedCodenames()) || vndkVer == "" {
+ if !inList(vndkVer, ctx.Config().PlatformVersionActiveCodenames()) || vndkVer == "" {
// For non-enforcing devices, vndkVer is empty. Use "current" in that case, too.
vndkVer = "current"
}
diff --git a/cc/test.go b/cc/test.go
index 05e6fe5..1085d3a 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -49,7 +49,7 @@
// list of files or filegroup modules that provide data that should be installed alongside
// the test
- Data []string `android:"path"`
+ Data []string `android:"path,arch_variant"`
// list of compatibility suites (for example "cts", "vts") that the module should be
// installed into.
diff --git a/java/app.go b/java/app.go
index f9992d8..c64f1f7 100755
--- a/java/app.go
+++ b/java/app.go
@@ -385,7 +385,18 @@
TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.useEmbeddedNativeLibs(ctx))
for _, jni := range jniLibs {
if jni.coverageFile.Valid() {
- a.jniCoverageOutputs = append(a.jniCoverageOutputs, jni.coverageFile.Path())
+ // Only collect coverage for the first target arch if this is a multilib target.
+ // TODO(jungjw): Ideally, we want to collect both reports, but that would cause coverage
+ // data file path collisions since the current coverage file path format doesn't contain
+ // arch-related strings. This is fine for now though; the code coverage team doesn't use
+ // multi-arch targets such as test_suite_* for coverage collections yet.
+ //
+ // Work with the team to come up with a new format that handles multilib modules properly
+ // and change this.
+ if len(ctx.Config().Targets[android.Android]) == 1 ||
+ ctx.Config().Targets[android.Android][0].Arch.ArchType == jni.target.Arch.ArchType {
+ a.jniCoverageOutputs = append(a.jniCoverageOutputs, jni.coverageFile.Path())
+ }
}
}
} else {
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 76b1d69..1b26667 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -26,7 +26,7 @@
)
func init() {
- android.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
+ RegisterDexpreoptBootJarsComponents(android.InitRegistrationContext)
}
// The image "location" is a symbolic path that with multiarchitecture
@@ -168,6 +168,10 @@
return &dexpreoptBootJars{}
}
+func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) {
+ ctx.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
+}
+
func skipDexpreoptBootJars(ctx android.PathContext) bool {
if dexpreopt.GetGlobalConfig(ctx).DisablePreopt {
return true
@@ -238,16 +242,66 @@
dumpOatRules(ctx, d.defaultBootImage)
}
+// Inspect this module to see if it contains a bootclasspath dex jar.
+// Note that the same jar may occur in multiple modules.
+// This logic is tested in the apex package to avoid import cycle apex <-> java.
+func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, module android.Module) (int, android.Path) {
+ // All apex Java libraries have non-installable platform variants, skip them.
+ if module.IsSkipInstall() {
+ return -1, nil
+ }
+
+ jar, hasJar := module.(interface{ DexJar() android.Path })
+ if !hasJar {
+ return -1, nil
+ }
+
+ name := ctx.ModuleName(module)
+ index := android.IndexList(name, image.modules)
+ if index == -1 {
+ return -1, nil
+ }
+
+ // Check that this module satisfies constraints for a particular boot image.
+ apex, isApexModule := module.(android.ApexModule)
+ if image.name == artBootImageName {
+ if isApexModule && strings.HasPrefix(apex.ApexName(), "com.android.art.") {
+ // ok, found the jar in the ART apex
+ } else if isApexModule && !apex.IsForPlatform() {
+ // this jar is part of an updatable apex other than ART, fail immediately
+ ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the ART boot image", name, apex.ApexName())
+ } else if isApexModule && apex.IsForPlatform() && Bool(module.(*Library).deviceProperties.Hostdex) {
+ // this is a special "hostdex" variant, skip it and resume search
+ return -1, nil
+ } else if name == "jacocoagent" && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
+ // this is Jacoco platform variant for a coverage build, skip it and resume search
+ return -1, nil
+ } else {
+ // this (installable) jar is part of the platform, fail immediately
+ ctx.Errorf("module '%s' is part of the platform and not allowed in the ART boot image", name)
+ }
+ } else if image.name == frameworkBootImageName {
+ if !isApexModule || apex.IsForPlatform() {
+ // ok, this jar is part of the platform
+ } else {
+ // this jar is part of an updatable apex, fail immediately
+ ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the framework boot image", name, apex.ApexName())
+ }
+ } else {
+ panic("unknown boot image: " + image.name)
+ }
+
+ return index, jar.DexJar()
+}
+
// buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image.
func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig {
+ // Collect dex jar paths for the boot image modules.
+ // This logic is tested in the apex package to avoid import cycle apex <-> java.
bootDexJars := make(android.Paths, len(image.modules))
ctx.VisitAllModules(func(module android.Module) {
- // Collect dex jar paths for the modules listed above.
- if j, ok := module.(interface{ DexJar() android.Path }); ok {
- name := ctx.ModuleName(module)
- if i := android.IndexList(name, image.modules); i != -1 {
- bootDexJars[i] = j.DexJar()
- }
+ if i, j := getBootImageJar(ctx, image, module); i != -1 {
+ bootDexJars[i] = j
}
})
@@ -259,7 +313,8 @@
missingDeps = append(missingDeps, image.modules[i])
bootDexJars[i] = android.PathForOutput(ctx, "missing")
} else {
- ctx.Errorf("failed to find dex jar path for module %q",
+ ctx.Errorf("failed to find a dex jar path for module '%s'"+
+ ", note that some jars may be filtered out by module constraints",
image.modules[i])
}
}
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index c3b2133..e7b3c3b 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -53,7 +53,7 @@
ctx := testContext()
- ctx.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
+ RegisterDexpreoptBootJarsComponents(ctx)
run(t, ctx, config)