From f15716ffab01cb1d1fcd9710c21243e56acf151a Mon Sep 17 00:00:00 2001 From: Sam Delmerico Date: Wed, 7 Sep 2022 12:07:07 -0400 Subject: [PATCH] add jacocoagent by default to Java modules On coverage builds, R8 will fail to properly optimize and fail the build if ignore_warnings: false, because jacoco injects dependencies on jacocoagent classes, but the jacocoagent library is not part of the classpath libraries passed in to R8 in its arguments. Instead we can add jacocoagent as a libs dependency for these modules so that it will get pulled into the r8 flags. Bug: 243903417 Test: cherry-pick ag/19866767 && make SKIP_ABI_CHECKS=true PRODUCT=cf_x86_phone-userdebug EMMA_INSTRUMENT=true EMMA_INSTRUMENT_FRAMEWORK=true CLANG_COVERAGE=true COVERAGE_PATHS="" TARGET_USERDATAIMAGE_PARTITION_SIZE=17179869184 SKIP_BOOT_JARS_CHECK=true service-uwb Change-Id: Icc24cc260b896fc800125a0318308d823ccf7a83 (cherry picked from commit 1e3f78f866504a99ecf30fd7dc81d2d374c544cf) Merged-In: Icc24cc260b896fc800125a0318308d823ccf7a83 --- apex/apex_test.go | 14 +--------- java/base.go | 11 +++----- java/bootclasspath_fragment_test.go | 19 +------------ java/jacoco.go | 28 +++++++++++++++++++ java/java.go | 2 ++ java/testing.go | 42 ++++++++++++++++++++++++----- 6 files changed, 71 insertions(+), 45 deletions(-) diff --git a/apex/apex_test.go b/apex/apex_test.go index c425e9c04..96e2f4c6c 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -8842,19 +8842,7 @@ func TestApexJavaCoverage(t *testing.T) { android.FixtureWithRootAndroidBp(bp), dexpreopt.FixtureSetApexBootJars("myapex:mybootclasspathlib"), dexpreopt.FixtureSetApexSystemServerJars("myapex:mysystemserverclasspathlib"), - android.FixtureMergeEnv(map[string]string{ - "EMMA_INSTRUMENT": "true", - }), - // need to mock jacocoagent here to satisfy dependency added for - // instrumented libraries at build time - android.FixtureAddFile("jacocoagent/Android.bp", []byte(` - java_library { - name: "jacocoagent", - srcs: ["Test.java"], - system_modules: "none", - sdk_version: "none", - } - `)), + java.PrepareForTestWithJacocoInstrumentation, ).RunTest(t) // Make sure jacoco ran on both mylib and mybootclasspathlib diff --git a/java/base.go b/java/base.go index 58c16492d..89776d8a5 100644 --- a/java/base.go +++ b/java/base.go @@ -649,6 +649,10 @@ func (j *Module) shouldInstrumentInApex(ctx android.BaseModuleContext) bool { return false } +func (j *Module) setInstrument(value bool) { + j.properties.Instrument = value +} + func (j *Module) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { return android.SdkSpecFrom(ctx, String(j.deviceProperties.Sdk_version)) } @@ -783,9 +787,6 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { } else if j.shouldInstrumentStatic(ctx) { ctx.AddVariationDependencies(nil, staticLibTag, "jacocoagent") } - if j.shouldInstrument(ctx) { - ctx.AddVariationDependencies(nil, libTag, "jacocoagent") - } if j.useCompose() { ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), kotlinPluginTag, @@ -1414,10 +1415,6 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { j.headerJarFile = j.implementationJarFile } - if j.shouldInstrumentInApex(ctx) { - j.properties.Instrument = true - } - // enforce syntax check to jacoco filters for any build (http://b/183622051) specs := j.jacocoModuleToZipCommand(ctx) if ctx.Failed() { diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go index 2bfb255af..c63df599a 100644 --- a/java/bootclasspath_fragment_test.go +++ b/java/bootclasspath_fragment_test.go @@ -96,23 +96,6 @@ func TestBootclasspathFragmentInconsistentArtConfiguration_ApexMixture(t *testin } func TestBootclasspathFragment_Coverage(t *testing.T) { - prepareForTestWithFrameworkCoverage := android.GroupFixturePreparers( - android.FixtureMergeEnv(map[string]string{ - "EMMA_INSTRUMENT": "true", - "EMMA_INSTRUMENT_FRAMEWORK": "true", - }), - // need to mock jacocoagent here to satisfy dependency added for - // instrumented libraries at build time - android.FixtureAddFile("jacocoagent/Android.bp", []byte(` - java_library { - name: "jacocoagent", - srcs: ["Test.java"], - system_modules: "none", - sdk_version: "none", - } - `)), - ) - prepareWithBp := android.FixtureWithRootAndroidBp(` bootclasspath_fragment { name: "myfragment", @@ -191,7 +174,7 @@ func TestBootclasspathFragment_Coverage(t *testing.T) { t.Run("with coverage", func(t *testing.T) { result := android.GroupFixturePreparers( - prepareForTestWithFrameworkCoverage, + prepareForTestWithFrameworkJacocoInstrumentation, preparer, ).RunTest(t) checkContents(t, result, "mybootlib", "coveragelib") diff --git a/java/jacoco.go b/java/jacoco.go index e11c2ce69..f8012b852 100644 --- a/java/jacoco.go +++ b/java/jacoco.go @@ -47,6 +47,34 @@ var ( "strippedJar", "stripSpec", "tmpDir", "tmpJar") ) +func jacocoDepsMutator(ctx android.BottomUpMutatorContext) { + type instrumentable interface { + shouldInstrument(ctx android.BaseModuleContext) bool + shouldInstrumentInApex(ctx android.BaseModuleContext) bool + setInstrument(value bool) + } + + j, ok := ctx.Module().(instrumentable) + if !ctx.Module().Enabled() || !ok { + return + } + + if j.shouldInstrumentInApex(ctx) { + j.setInstrument(true) + } + + if j.shouldInstrument(ctx) && ctx.ModuleName() != "jacocoagent" { + // We can use AddFarVariationDependencies here because, since this dep + // is added as libs only (i.e. a compiletime CLASSPATH entry only), + // the first variant of jacocoagent is sufficient to prevent + // compile time errors. + // At this stage in the build, AddVariationDependencies is not always + // able to procure a variant of jacocoagent that matches the calling + // module. + ctx.AddFarVariationDependencies(ctx.Module().Target().Variations(), libTag, "jacocoagent") + } +} + // Instruments a jar using the Jacoco command line interface. Uses stripSpec to extract a subset // of the classes in inputJar into strippedJar, instruments strippedJar into tmpJar, and then // combines the classes in tmpJar with inputJar (preferring the instrumented classes in tmpJar) diff --git a/java/java.go b/java/java.go index f98f1e88c..e46712349 100644 --- a/java/java.go +++ b/java/java.go @@ -65,6 +65,8 @@ func registerJavaBuildComponents(ctx android.RegistrationContext) { // to support the checks in dexpreoptDisabled(). ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("dexpreopt_tool_deps", dexpreoptToolDepsMutator).Parallel() + // needs access to ApexInfoProvider which is available after variant creation + ctx.BottomUp("jacoco_deps", jacocoDepsMutator).Parallel() }) ctx.RegisterSingletonType("logtags", LogtagsSingleton) diff --git a/java/testing.go b/java/testing.go index 511cc5ddb..1f411913b 100644 --- a/java/testing.go +++ b/java/testing.go @@ -59,11 +59,9 @@ var PrepareForTestWithJavaBuildComponents = android.GroupFixturePreparers( }.AddToFixture(), ) -// Test fixture preparer that will define all default java modules except the -// fake_tool_binary for dex2oatd. -var PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd = android.GroupFixturePreparers( - // Make sure that all the module types used in the defaults are registered. - PrepareForTestWithJavaBuildComponents, +var prepareForTestWithFrameworkDeps = android.GroupFixturePreparers( + // The java default module definitions. + android.FixtureAddTextFile(defaultJavaDir+"/Android.bp", gatherRequiredDepsForTest()), // Additional files needed when test disallows non-existent source. android.MockFS{ // Needed for framework-res @@ -77,8 +75,14 @@ var PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd = android.GroupFixtu "build/make/core/proguard.flags": nil, "build/make/core/proguard_basic_keeps.flags": nil, }.AddToFixture(), - // The java default module definitions. - android.FixtureAddTextFile(defaultJavaDir+"/Android.bp", gatherRequiredDepsForTest()), +) + +// Test fixture preparer that will define all default java modules except the +// fake_tool_binary for dex2oatd. +var PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd = android.GroupFixturePreparers( + // Make sure that all the module types used in the defaults are registered. + PrepareForTestWithJavaBuildComponents, + prepareForTestWithFrameworkDeps, // Add dexpreopt compat libs (android.test.base, etc.) and a fake dex2oatd module. dexpreopt.PrepareForTestWithDexpreoptCompatLibs, ) @@ -141,6 +145,30 @@ var PrepareForTestWithPrebuiltsOfCurrentApi = FixtureWithPrebuiltApis(map[string "30": {}, }) +var prepareForTestWithFrameworkJacocoInstrumentation = android.GroupFixturePreparers( + android.FixtureMergeEnv(map[string]string{ + "EMMA_INSTRUMENT_FRAMEWORK": "true", + }), + PrepareForTestWithJacocoInstrumentation, +) + +// PrepareForTestWithJacocoInstrumentation creates a mock jacocoagent library that can be +// depended on as part of the build process for instrumented Java modules. +var PrepareForTestWithJacocoInstrumentation = android.GroupFixturePreparers( + android.FixtureMergeEnv(map[string]string{ + "EMMA_INSTRUMENT": "true", + }), + android.FixtureAddFile("jacocoagent/Test.java", nil), + android.FixtureAddFile("jacocoagent/Android.bp", []byte(` + java_library { + name: "jacocoagent", + host_supported: true, + srcs: ["Test.java"], + sdk_version: "current", + } + `)), +) + // FixtureWithPrebuiltApis creates a preparer that will define prebuilt api modules for the // specified releases and modules. //