diff --git a/android/config.go b/android/config.go index 1f52b6c9d..8090889e8 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 48c4be6b3..73be7a03a 100644 --- a/android/variable.go +++ b/android/variable.go @@ -367,6 +367,8 @@ type productVariables struct { BoardKernelModuleInterfaceVersions []string `json:",omitempty"` BoardMoveRecoveryResourcesToVendorBoot *bool `json:",omitempty"` + + PrebuiltHiddenApiDir *string `json:",omitempty"` } func boolPtr(v bool) *bool { diff --git a/apex/apex.go b/apex/apex.go index 4a9a9a30c..bbcf5b887 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 42b24047d..aa4b9c8c6 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/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) + } +} 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) + } +} 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...)