From bae4749de28b89a5702ed8cdeda1a390ad112e50 Mon Sep 17 00:00:00 2001 From: Bill Peckham Date: Fri, 8 Jan 2021 09:34:44 -0800 Subject: [PATCH 1/3] Enable prebuilt hiddenapi CSV files. By enabling these hiddenapi CSV files to be prebuilt, it becomes possible to create a split build that supports the hiddenapi encode dex step, but doesn't contain all of the java sources needed to generate the CSV files. Bug: 175048716 Test: m nothing Test: new TestHiddenAPISingletonWithPrebuiltCsvFile Test: local build without prebuilt hiddenapi Test: local build with prebuilt hiddenapi Change-Id: I805ea3ec05860d2df211a3985ec025bf36f0d775 --- android/config.go | 4 +++ android/variable.go | 2 ++ java/hiddenapi_singleton.go | 40 +++++++++++++++++++++ java/hiddenapi_singleton_test.go | 60 ++++++++++++++++++++++++++++---- 4 files changed, 99 insertions(+), 7 deletions(-) diff --git a/android/config.go b/android/config.go index a7e0b6711..ee86d17a4 100644 --- a/android/config.go +++ b/android/config.go @@ -1026,6 +1026,10 @@ func (c *config) HasMultilibConflict(arch ArchType) bool { return c.multilibConflicts[arch] } +func (c *config) PrebuiltHiddenApiDir(ctx PathContext) string { + return String(c.productVariables.PrebuiltHiddenApiDir) +} + func (c *deviceConfig) Arches() []Arch { var arches []Arch for _, target := range c.config.Targets[Android] { diff --git a/android/variable.go b/android/variable.go index 41cd3371e..6d8cd35d9 100644 --- a/android/variable.go +++ b/android/variable.go @@ -364,6 +364,8 @@ type productVariables struct { BoardKernelModuleInterfaceVersions []string `json:",omitempty"` BoardMoveRecoveryResourcesToVendorBoot *bool `json:",omitempty"` + + PrebuiltHiddenApiDir *string `json:",omitempty"` } func boolPtr(v bool) *bool { diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index d3025247b..4bd255cbf 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -67,6 +67,19 @@ func (h *hiddenAPISingleton) GenerateBuildActions(ctx android.SingletonContext) stubFlagsRule(ctx) + // If there is a prebuilt hiddenapi dir, generate rules to use the + // files within. Generally, we build the hiddenapi files from source + // during the build, ensuring consistency. It's possible, in a split + // build (framework and vendor) scenario, for the vendor build to use + // prebuilt hiddenapi files from the framework build. In this scenario, + // the framework and vendor builds must use the same source to ensure + // consistency. + + if ctx.Config().PrebuiltHiddenApiDir(ctx) != "" { + h.flags = prebuiltFlagsRule(ctx) + return + } + // These rules depend on files located in frameworks/base, skip them if running in a tree that doesn't have them. if ctx.Config().FrameworksBaseDirExists(ctx) { h.flags = flagsRule(ctx) @@ -212,6 +225,19 @@ func stubFlagsRule(ctx android.SingletonContext) { rule.Build("hiddenAPIStubFlagsFile", "hiddenapi stub flags") } +func prebuiltFlagsRule(ctx android.SingletonContext) android.Path { + outputPath := hiddenAPISingletonPaths(ctx).flags + inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-flags.csv") + + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Output: outputPath, + Input: inputPath, + }) + + return outputPath +} + // flagsRule creates a rule to build hiddenapi-flags.csv out of flags.csv files generated for boot image modules and // the unsupported API. func flagsRule(ctx android.SingletonContext) android.Path { @@ -391,6 +417,20 @@ func (h *hiddenAPIIndexSingleton) GenerateBuildActions(ctx android.SingletonCont return } + if ctx.Config().PrebuiltHiddenApiDir(ctx) != "" { + outputPath := hiddenAPISingletonPaths(ctx).index + inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-index.csv") + + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Output: outputPath, + Input: inputPath, + }) + + h.index = outputPath + return + } + indexes := android.Paths{} ctx.VisitAllModules(func(module android.Module) { if h, ok := module.(hiddenAPIIntf); ok { diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go index 955c73932..0f9ef5841 100644 --- a/java/hiddenapi_singleton_test.go +++ b/java/hiddenapi_singleton_test.go @@ -23,9 +23,10 @@ import ( "github.com/google/blueprint/proptools" ) -func testConfigWithBootJars(bp string, bootJars []string) android.Config { +func testConfigWithBootJars(bp string, bootJars []string, prebuiltHiddenApiDir *string) android.Config { config := testConfig(nil, bp, nil) config.TestProductVariables.BootJars = android.CreateTestConfiguredJarList(bootJars) + config.TestProductVariables.PrebuiltHiddenApiDir = prebuiltHiddenApiDir return config } @@ -44,8 +45,8 @@ func testHiddenAPIWithConfig(t *testing.T, config android.Config) *android.TestC return ctx } -func testHiddenAPIBootJars(t *testing.T, bp string, bootJars []string) (*android.TestContext, android.Config) { - config := testConfigWithBootJars(bp, bootJars) +func testHiddenAPIBootJars(t *testing.T, bp string, bootJars []string, prebuiltHiddenApiDir *string) (*android.TestContext, android.Config) { + config := testConfigWithBootJars(bp, bootJars, prebuiltHiddenApiDir) return testHiddenAPIWithConfig(t, config), config } @@ -64,7 +65,7 @@ func TestHiddenAPISingleton(t *testing.T) { srcs: ["a.java"], compile_dex: true, } - `, []string{":foo"}) + `, []string{":foo"}, nil) hiddenAPI := ctx.SingletonForTests("hiddenapi") hiddenapiRule := hiddenAPI.Rule("hiddenapi") @@ -81,7 +82,7 @@ func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { jars: ["a.jar"], compile_dex: true, } - `, []string{":foo"}) + `, []string{":foo"}, nil) hiddenAPI := ctx.SingletonForTests("hiddenapi") hiddenapiRule := hiddenAPI.Rule("hiddenapi") @@ -105,7 +106,7 @@ func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { compile_dex: true, prefer: false, } - `, []string{":foo"}) + `, []string{":foo"}, nil) hiddenAPI := ctx.SingletonForTests("hiddenapi") hiddenapiRule := hiddenAPI.Rule("hiddenapi") @@ -134,7 +135,7 @@ func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) { compile_dex: true, prefer: true, } - `, []string{":foo"}) + `, []string{":foo"}, nil) hiddenAPI := ctx.SingletonForTests("hiddenapi") hiddenapiRule := hiddenAPI.Rule("hiddenapi") @@ -217,3 +218,48 @@ func generateSdkDexPath(module string, unbundled bool) string { } return generateDexPath(module) } + +func TestHiddenAPISingletonWithPrebuiltCsvFile(t *testing.T) { + + // The idea behind this test is to ensure that when the build is + // confugured with a PrebuiltHiddenApiDir that the rules for the + // hiddenapi singleton copy the prebuilts to the typical output + // location, and then use that output location for the hiddenapi encode + // dex step. + + // Where to find the prebuilt hiddenapi files: + prebuiltHiddenApiDir := "path/to/prebuilt/hiddenapi" + + ctx, _ := testHiddenAPIBootJars(t, ` + java_import { + name: "foo", + jars: ["a.jar"], + compile_dex: true, + } + `, []string{":foo"}, &prebuiltHiddenApiDir) + + expectedCpInput := prebuiltHiddenApiDir + "/hiddenapi-flags.csv" + expectedCpOutput := buildDir + "/hiddenapi/hiddenapi-flags.csv" + expectedFlagsCsv := buildDir + "/hiddenapi/hiddenapi-flags.csv" + + foo := ctx.ModuleForTests("foo", "android_common") + + hiddenAPI := ctx.SingletonForTests("hiddenapi") + cpRule := hiddenAPI.Rule("Cp") + actualCpInput := cpRule.BuildParams.Input + actualCpOutput := cpRule.BuildParams.Output + encodeDexRule := foo.Rule("hiddenAPIEncodeDex") + actualFlagsCsv := encodeDexRule.BuildParams.Args["flagsCsv"] + + if actualCpInput.String() != expectedCpInput { + t.Errorf("Prebuilt hiddenapi cp rule input mismatch, actual: %s, expected: %s", actualCpInput, expectedCpInput) + } + + if actualCpOutput.String() != expectedCpOutput { + t.Errorf("Prebuilt hiddenapi cp rule output mismatch, actual: %s, expected: %s", actualCpOutput, expectedCpOutput) + } + + if actualFlagsCsv != expectedFlagsCsv { + t.Errorf("Prebuilt hiddenapi encode dex rule flags csv mismatch, actual: %s, expected: %s", actualFlagsCsv, expectedFlagsCsv) + } +} From a41a6963b4a8636a6b5de9b0d4aa746c9a6e99ac Mon Sep 17 00:00:00 2001 From: Bill Peckham Date: Mon, 11 Jan 2021 10:58:54 -0800 Subject: [PATCH 2/3] Enable an apex to include a java_import. With the addition of the compile_dex property to the java_import module it becomes possible to include a java_import module in an apex. This change allows the dependency and adds a test. Bug: 177228901 Test: m nothing Test: new TestApexWithJavaImport Change-Id: I9336dade1857109e2fd21f7d57e1dc4abc4a402c --- apex/apex.go | 3 ++- apex/apex_test.go | 28 ++++++++++++++++++++++++++++ java/java.go | 4 ++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/apex/apex.go b/apex/apex.go index 376811af2..6538032ec 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -1428,6 +1428,7 @@ type javaModule interface { } var _ javaModule = (*java.Library)(nil) +var _ javaModule = (*java.Import)(nil) var _ javaModule = (*java.SdkLibrary)(nil) var _ javaModule = (*java.DexImport)(nil) var _ javaModule = (*java.SdkLibraryImport)(nil) @@ -1629,7 +1630,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { } case javaLibTag: switch child.(type) { - case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport: + case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport, *java.Import: af := apexFileForJavaModule(ctx, child.(javaModule)) if !af.ok() { ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName) diff --git a/apex/apex_test.go b/apex/apex_test.go index 58739b0d6..3c7e0194b 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -4515,6 +4515,34 @@ func TestErrorsIfDepsAreNotEnabled(t *testing.T) { `) } +func TestApexWithJavaImport(t *testing.T) { + ctx, _ := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + java_libs: ["myjavaimport"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + java_import { + name: "myjavaimport", + apex_available: ["myapex"], + jars: ["my.jar"], + compile_dex: true, + } + `) + + module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + apexRule := module.Rule("apexRule") + copyCmds := apexRule.Args["copy_commands"] + ensureContains(t, copyCmds, "image.apex/javalib/myjavaimport.jar") +} + func TestApexWithApps(t *testing.T) { ctx, _ := testApex(t, ` apex { diff --git a/java/java.go b/java/java.go index 3c6146b76..59ec94d5b 100644 --- a/java/java.go +++ b/java/java.go @@ -2831,6 +2831,10 @@ func (a *Import) JacocoReportClassesFile() android.Path { return nil } +func (j *Import) LintDepSets() LintDepSets { + return LintDepSets{} +} + func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...) From fb04df4d57e52b38e6ebfec9cfcc2bb76968b2ce Mon Sep 17 00:00:00 2001 From: Bill Peckham Date: Mon, 11 Jan 2021 12:27:24 -0800 Subject: [PATCH 3/3] Supply LOCAL_SOONG_DEX_JAR for java_import with compile_dex. Without LOCAL_SOONG_DEX_JAR, ninja fails with a missing dependency error. Test: m nothing Test: new TestImportSoongDexJar Bug: 173705556 Change-Id: I54a4c6ea93877667a3fb97f8b2621c42e431f577 --- java/androidmk.go | 3 +++ java/androidmk_test.go | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/java/androidmk.go b/java/androidmk.go index aaad44f72..cc454b03d 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -196,6 +196,9 @@ func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries { ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(entries *android.AndroidMkEntries) { entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !Bool(prebuilt.properties.Installable)) + if prebuilt.dexJarFile != nil { + entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile) + } entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile) entries.SetString("LOCAL_SDK_VERSION", prebuilt.makeSdkVersion()) diff --git a/java/androidmk_test.go b/java/androidmk_test.go index 233e9d5c5..e2647cf0f 100644 --- a/java/androidmk_test.go +++ b/java/androidmk_test.go @@ -166,3 +166,25 @@ func TestJavaSdkLibrary_RequireXmlPermissionFile(t *testing.T) { } } } + +func TestImportSoongDexJar(t *testing.T) { + ctx, config := testJava(t, ` + java_import { + name: "my-java-import", + jars: ["a.jar"], + prefer: true, + compile_dex: true, + } + `) + + mod := ctx.ModuleForTests("my-java-import", "android_common").Module() + entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0] + expectedSoongDexJar := buildDir + "/.intermediates/my-java-import/android_common/dex/my-java-import.jar" + actualSoongDexJar := entries.EntryMap["LOCAL_SOONG_DEX_JAR"] + + if len(actualSoongDexJar) != 1 { + t.Errorf("LOCAL_SOONG_DEX_JAR incorrect len %d", len(actualSoongDexJar)) + } else if actualSoongDexJar[0] != expectedSoongDexJar { + t.Errorf("LOCAL_SOONG_DEX_JAR mismatch, actual: %s, expected: %s", actualSoongDexJar[0], expectedSoongDexJar) + } +}