diff --git a/apex/apex_test.go b/apex/apex_test.go index 7e67c0f9d..b58441afa 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -11537,6 +11537,17 @@ func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) { android.AssertStringMatches(t, "Could not find the correct boot dex jar in monolithic hiddenapi flags generation command", monolithicHiddenapiFlagsCmd, "--boot-dex="+expectedBootJar) } + // Check that system server jars is copied to out/soong/system_server_dexjars. This hardcoded location is used by dexpreopt + checkSystemServerJarOnHost := func(t *testing.T, ctx *android.TestContext, m, libName, expectedSystemServerJarPath string) { + variation := "android_common_com.android.foo" + if m == "com.android.foo" { + m = libName // for source builds, the cp rule is still generated by the java_library module + variation = "android_common_apex10000" + } + output := ctx.ModuleForTests(m, variation).MaybeOutput("system_server_dexjars/" + libName + ".jar") + android.AssertStringListContains(t, libName+" is expected to be copied to out/soong/system_server_dexjars/ from ", output.Implicits.Strings(), expectedSystemServerJarPath) + } + bp := ` // Source APEX. @@ -11560,6 +11571,24 @@ func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) { }, } + java_library { + name: "service-foo", + srcs: ["foo.java"], + installable: true, + apex_available: [ + "com.android.foo", + ], + } + + systemserverclasspath_fragment { + name: "foo-systemserverclasspath-fragment", + contents: ["service-foo"], + apex_available: [ + "com.android.foo", + ], + } + + apex_key { name: "com.android.foo.key", public_key: "com.android.foo.avbpubkey", @@ -11570,18 +11599,16 @@ func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) { name: "com.android.foo", key: "com.android.foo.key", bootclasspath_fragments: ["foo-bootclasspath-fragment"], + systemserverclasspath_fragments: ["foo-systemserverclasspath-fragment"], updatable: false, } // Prebuilt APEX. - java_sdk_library_import { + java_import { name: "framework-foo", - public: { - jars: ["foo.jar"], - }, + jars: ["foo.jar"], apex_available: ["com.android.foo"], - shared_library: false, } prebuilt_bootclasspath_fragment { @@ -11599,11 +11626,27 @@ func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) { ], } + java_import { + name: "service-foo", + jars: ["foo.jar"], + apex_available: ["com.android.foo"], + } + + prebuilt_systemserverclasspath_fragment { + name: "foo-systemserverclasspath-fragment", + contents: ["service-foo"], + apex_available: [ + "com.android.foo", + ], + } + + prebuilt_apex { name: "com.android.foo", apex_name: "com.android.foo", src: "com.android.foo-arm.apex", exported_bootclasspath_fragments: ["foo-bootclasspath-fragment"], + exported_systemserverclasspath_fragments: ["foo-systemserverclasspath-fragment"], } // Another Prebuilt ART APEX @@ -11612,48 +11655,41 @@ func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) { apex_name: "com.android.foo", // Used to determine the API domain src: "com.android.foo-arm.apex", exported_bootclasspath_fragments: ["foo-bootclasspath-fragment"], + exported_systemserverclasspath_fragments: ["foo-systemserverclasspath-fragment"], } // APEX contribution modules apex_contributions { - name: "foo.source.contributions", + name: "foo.contributions", api_domain: "com.android.foo", - contents: ["com.android.foo"], - } - - apex_contributions { - name: "foo.prebuilt.contributions", - api_domain: "com.android.foo", - contents: ["prebuilt_com.android.foo"], - } - - apex_contributions { - name: "foo.prebuilt.v2.contributions", - api_domain: "com.android.foo", - contents: ["com.android.foo.v2"], // prebuilt_ prefix is missing because of prebuilt_rename mutator + contents: ["%v"], } ` testCases := []struct { - desc string - selectedApexContributions string - expectedBootJar string + desc string + selectedApex string + expectedBootJar string + expectedSystemServerJar string }{ { - desc: "Source apex com.android.foo is selected, bootjar should come from source java library", - selectedApexContributions: "foo.source.contributions", - expectedBootJar: "out/soong/.intermediates/foo-bootclasspath-fragment/android_common_apex10000/hiddenapi-modular/encoded/framework-foo.jar", + desc: "Source apex com.android.foo is selected, bootjar should come from source java library", + selectedApex: "com.android.foo", + expectedBootJar: "out/soong/.intermediates/foo-bootclasspath-fragment/android_common_apex10000/hiddenapi-modular/encoded/framework-foo.jar", + expectedSystemServerJar: "out/soong/.intermediates/service-foo/android_common_apex10000/aligned/service-foo.jar", }, { - desc: "Prebuilt apex prebuilt_com.android.foo is selected, profile should come from .prof deapexed from the prebuilt", - selectedApexContributions: "foo.prebuilt.contributions", - expectedBootJar: "out/soong/.intermediates/prebuilt_com.android.foo.deapexer/android_common/deapexer/javalib/framework-foo.jar", + desc: "Prebuilt apex prebuilt_com.android.foo is selected, profile should come from .prof deapexed from the prebuilt", + selectedApex: "prebuilt_com.android.foo", + expectedBootJar: "out/soong/.intermediates/prebuilt_com.android.foo.deapexer/android_common/deapexer/javalib/framework-foo.jar", + expectedSystemServerJar: "out/soong/.intermediates/prebuilt_com.android.foo.deapexer/android_common/deapexer/javalib/service-foo.jar", }, { - desc: "Prebuilt apex prebuilt_com.android.foo.v2 is selected, profile should come from .prof deapexed from the prebuilt", - selectedApexContributions: "foo.prebuilt.v2.contributions", - expectedBootJar: "out/soong/.intermediates/prebuilt_com.android.foo.v2.deapexer/android_common/deapexer/javalib/framework-foo.jar", + desc: "Prebuilt apex prebuilt_com.android.foo.v2 is selected, profile should come from .prof deapexed from the prebuilt", + selectedApex: "com.android.foo.v2", + expectedBootJar: "out/soong/.intermediates/prebuilt_com.android.foo.v2.deapexer/android_common/deapexer/javalib/framework-foo.jar", + expectedSystemServerJar: "out/soong/.intermediates/prebuilt_com.android.foo.v2.deapexer/android_common/deapexer/javalib/service-foo.jar", }, } @@ -11665,19 +11701,21 @@ func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) { for _, tc := range testCases { preparer := android.GroupFixturePreparers( java.FixtureConfigureApexBootJars("com.android.foo:framework-foo"), + dexpreopt.FixtureSetApexSystemServerJars("com.android.foo:service-foo"), android.FixtureMergeMockFs(map[string][]byte{ "system/sepolicy/apex/com.android.foo-file_contexts": nil, }), android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.BuildFlags = map[string]string{ - "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": tc.selectedApexContributions, + "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "foo.contributions", } }), ) - ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment) + ctx := testDexpreoptWithApexes(t, fmt.Sprintf(bp, tc.selectedApex), "", preparer, fragment) checkBootDexJarPath(t, ctx, "framework-foo", tc.expectedBootJar) checkBootJarsPackageCheck(t, ctx, tc.expectedBootJar) checkBootJarsForMonolithicHiddenapi(t, ctx, tc.expectedBootJar) + checkSystemServerJarOnHost(t, ctx, tc.selectedApex, "service-foo", tc.expectedSystemServerJar) } } diff --git a/apex/prebuilt.go b/apex/prebuilt.go index 1ec38eb94..dcf0fe2f8 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -201,6 +201,10 @@ func (p *prebuiltCommon) dexpreoptSystemServerJars(ctx android.ModuleContext) { if !p.hasExportedDeps() { return } + // If this prebuilt apex has not been selected, return + if p.IsHideFromMake() { + return + } // Use apex_name to determine the api domain of this prebuilt apex apexName := p.ApexVariationName() di, err := android.FindDeapexerProviderForModule(ctx) diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go index 94707bafa..37b7f3446 100644 --- a/dexpreopt/dexpreopt.go +++ b/dexpreopt/dexpreopt.go @@ -229,6 +229,30 @@ func ToOdexPath(path string, arch android.ArchType) string { pathtools.ReplaceExtension(filepath.Base(path), "odex")) } +// Copy the dex'd system server to a predefined location in out/soong/system_server_dexjars +// dex2oat will use this predefined location to generate the dexpreopt artifacts. +func CopySystemServerJarsToPredefinedLocations(ctx android.BuilderContext, libName string, libDexPath android.Path) { + allSystemServerJars := GetGlobalConfig(ctx).AllSystemServerJars(ctx) + if !allSystemServerJars.ContainsJar(libName) { + // This is not a system server jar + return + } + if DexpreoptRunningInSoong { + // Copy the system server jar to a predefined location where dex2oat will find it. + rule := android.NewRuleBuilder(pctx, ctx) + dexPathHost := SystemServerDexJarHostPath(ctx, libName) + rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String())) + rule.Command().Text("cp -f").Input(libDexPath).Output(dexPathHost) + rule.Build("copy "+libName+" to soong/system_server_dexjars/", "system_server_dexjars") + } else { + // For Make modules the copy rule is generated in the makefiles, not in dexpreopt.sh. + // This is necessary to expose the rule to Ninja, otherwise it has rules that depend on + // the jar (namely, dexpreopt commands for all subsequent system server jars that have + // this one in their class loader context), but no rule that creates it (because Ninja + // cannot see the rule in the generated dexpreopt.sh script). + } +} + func dexpreoptCommand(ctx android.BuilderContext, globalSoong *GlobalSoongConfig, global *GlobalConfig, module *ModuleConfig, rule *android.RuleBuilder, archIdx int, profile android.WritablePath, appImage bool, generateDM bool, productPackages android.Path) { @@ -277,19 +301,6 @@ func dexpreoptCommand(ctx android.BuilderContext, globalSoong *GlobalSoongConfig clcTarget = append(clcTarget, GetSystemServerDexLocation(ctx, global, lib)) } - if DexpreoptRunningInSoong { - // Copy the system server jar to a predefined location where dex2oat will find it. - dexPathHost := SystemServerDexJarHostPath(ctx, module.Name) - rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String())) - rule.Command().Text("cp -f").Input(module.DexPath).Output(dexPathHost) - } else { - // For Make modules the copy rule is generated in the makefiles, not in dexpreopt.sh. - // This is necessary to expose the rule to Ninja, otherwise it has rules that depend on - // the jar (namely, dexpreopt commands for all subsequent system server jars that have - // this one in their class loader context), but no rule that creates it (because Ninja - // cannot see the rule in the generated dexpreopt.sh script). - } - clcHostString := "PCL[" + strings.Join(clcHost.Strings(), ":") + "]" clcTargetString := "PCL[" + strings.Join(clcTarget, ":") + "]" diff --git a/java/base.go b/java/base.go index 1ac3d30a6..71c02d208 100644 --- a/java/base.go +++ b/java/base.go @@ -1627,6 +1627,9 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath // Dexpreopting j.dexpreopt(ctx, dexOutputFile) + if !j.IsHideFromMake() { + dexpreopt.CopySystemServerJarsToPredefinedLocations(ctx, j.Name(), dexOutputFile) + } outputFile = dexOutputFile } else { diff --git a/java/dexpreopt.go b/java/dexpreopt.go index bd3cce412..fe573cc85 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -274,6 +274,8 @@ func (d *Dexpreopter) DexpreoptPrebuiltApexSystemServerJars(ctx android.ModuleCo // generate the rules for creating the .odex and .vdex files for this system server jar dexJarFile := di.PrebuiltExportPath(ApexRootRelativePathToJavaLib(libraryName)) d.dexpreopt(ctx, dexJarFile) + + dexpreopt.CopySystemServerJarsToPredefinedLocations(ctx, libraryName, dexJarFile) } func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.WritablePath) { @@ -370,7 +372,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr // Full dexpreopt config, used to create dexpreopt build rules. dexpreoptConfig := &dexpreopt.ModuleConfig{ - Name: moduleName(ctx), + Name: dexJarStem, // use dexJarStem as the name of the library so that this function can be called from an apex. DexLocation: dexLocation, BuildPath: android.PathForModuleOut(ctx, "dexpreopt", dexJarStem, moduleName(ctx)+".jar").OutputPath, DexPath: dexJarFile,