From 0b7089f13420061c8f1732fe6e2e56f1e9cdb21e Mon Sep 17 00:00:00 2001 From: Spandan Das Date: Tue, 23 Jan 2024 02:25:20 +0000 Subject: [PATCH] Ensure sscp jars get copied to $OUT/soong/system_server_dexjars (This was missed in aosp/2876756, which copied only the bcp jars) This hardcoded location is used by dex2oat to compile the dexpreopt artifacts. The copy rules are currently generated by java_(sdk)_library for source builds, and their prebuilt counterparts in prebuilt builds. After this change, the copy rule will be bifurcated between source and prebuilt builds 1. For source builds, it will come from java_(sdk)_library 2. For prebuilt builds, it will come from the top-level prebuilt apex. Since there can be multiple prebuilt apexes in trunk stable, HideFromMake will be used to determine which deapexed jar to copy. The bifurfaction is expected to be temporary. It is needed for now since the `apex_contributions` which will be used for source vs prebuilt selection have not been populated completely. Test: Added a unit test Test: Presubmits Test: git_master-art-host: art-gtest (https://android-build.corp.google.com/builds/abtd/run/L40800030001459791) Test: git_main:art_standalone_tests (https://android-build.corp.google.com/builds/abtd/run/L09000030001463855) Bug: 308790457 Change-Id: I3105d3b3a7e5c41cb601d07806f4ea483a61b50a --- apex/apex_test.go | 104 ++++++++++++++++++++++++++++------------- apex/prebuilt.go | 4 ++ dexpreopt/dexpreopt.go | 37 +++++++++------ java/base.go | 3 ++ java/dexpreopt.go | 4 +- 5 files changed, 105 insertions(+), 47 deletions(-) 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,