diff --git a/android/config.go b/android/config.go index 63994e6cb..1e5a24de9 100644 --- a/android/config.go +++ b/android/config.go @@ -1087,6 +1087,10 @@ func (c *config) EnforceSystemCertificateWhitelist() []string { return c.productVariables.EnforceSystemCertificateWhitelist } +func (c *config) EnforceProductPartitionInterface() bool { + return Bool(c.productVariables.EnforceProductPartitionInterface) +} + func (c *config) ProductHiddenAPIStubs() []string { return c.productVariables.ProductHiddenAPIStubs } diff --git a/android/variable.go b/android/variable.go index abbdf21bd..25a5dc08f 100644 --- a/android/variable.go +++ b/android/variable.go @@ -309,6 +309,8 @@ type productVariables struct { TargetFSConfigGen []string `json:",omitempty"` MissingUsesLibraries []string `json:",omitempty"` + + EnforceProductPartitionInterface *bool `json:",omitempty"` } func boolPtr(v bool) *bool { diff --git a/java/aar.go b/java/aar.go index afe860c1c..d8db19251 100644 --- a/java/aar.go +++ b/java/aar.go @@ -520,7 +520,7 @@ type AARImport struct { } func (a *AARImport) sdkVersion() string { - return proptools.StringDefault(a.properties.Sdk_version, defaultSdkVersion(a)) + return String(a.properties.Sdk_version) } func (a *AARImport) systemModules() string { diff --git a/java/app.go b/java/app.go index de12b73ea..d53d62614 100644 --- a/java/app.go +++ b/java/app.go @@ -205,6 +205,7 @@ func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleCon func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.checkPlatformAPI(ctx) + a.checkSdkVersion(ctx) a.generateAndroidBuildActions(ctx) } diff --git a/java/app_test.go b/java/app_test.go index 5b6ed5422..7635f3d3b 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -666,6 +666,44 @@ func TestJNIABI(t *testing.T) { } } +func TestAppSdkVersionByPartition(t *testing.T) { + testJavaError(t, "sdk_version must have a value when the module is located at vendor or product", ` + android_app { + name: "foo", + srcs: ["a.java"], + vendor: true, + platform_apis: true, + } + `) + + testJava(t, ` + android_app { + name: "bar", + srcs: ["b.java"], + platform_apis: true, + } + `) + + for _, enforce := range []bool{true, false} { + + config := testConfig(nil) + config.TestProductVariables.EnforceProductPartitionInterface = proptools.BoolPtr(enforce) + bp := ` + android_app { + name: "foo", + srcs: ["a.java"], + product_specific: true, + platform_apis: true, + } + ` + if enforce { + testJavaErrorWithConfig(t, "sdk_version must have a value when the module is located at vendor or product", bp, config) + } else { + testJavaWithConfig(t, bp, config) + } + } +} + func TestJNIPackaging(t *testing.T) { ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` cc_library { diff --git a/java/droiddoc.go b/java/droiddoc.go index c898498a8..54f93fec2 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -404,7 +404,7 @@ func JavadocHostFactory() android.Module { var _ android.OutputFileProducer = (*Javadoc)(nil) func (j *Javadoc) sdkVersion() string { - return proptools.StringDefault(j.properties.Sdk_version, defaultSdkVersion(j)) + return String(j.properties.Sdk_version) } func (j *Javadoc) systemModules() string { diff --git a/java/java.go b/java/java.go index de2ca9ed6..9bbdff74c 100644 --- a/java/java.go +++ b/java/java.go @@ -54,6 +54,18 @@ func init() { android.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory) } +func (j *Module) checkSdkVersion(ctx android.ModuleContext) { + if j.SocSpecific() || j.DeviceSpecific() || + (j.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) { + if sc, ok := ctx.Module().(sdkContext); ok { + if sc.sdkVersion() == "" { + ctx.PropertyErrorf("sdk_version", + "sdk_version must have a value when the module is located at vendor or product(only if PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE is set).") + } + } + } +} + func (j *Module) checkPlatformAPI(ctx android.ModuleContext) { if sc, ok := ctx.Module().(sdkContext); ok { usePlatformAPI := proptools.Bool(j.deviceProperties.Platform_apis) @@ -452,18 +464,6 @@ var ( usesLibTag = dependencyTag{name: "uses-library"} ) -func defaultSdkVersion(ctx checkVendorModuleContext) string { - if ctx.SocSpecific() || ctx.DeviceSpecific() { - return "system_current" - } - return "" -} - -type checkVendorModuleContext interface { - SocSpecific() bool - DeviceSpecific() bool -} - type sdkDep struct { useModule, useFiles, useDefaultLibs, invalidVersion bool @@ -510,7 +510,7 @@ func (j *Module) shouldInstrumentStatic(ctx android.BaseModuleContext) bool { } func (j *Module) sdkVersion() string { - return proptools.StringDefault(j.deviceProperties.Sdk_version, defaultSdkVersion(j)) + return String(j.deviceProperties.Sdk_version) } func (j *Module) systemModules() string { @@ -1641,6 +1641,7 @@ func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bo } func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { + j.checkSdkVersion(ctx) j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar") j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary j.dexpreopter.isInstallable = Bool(j.properties.Installable) @@ -1984,7 +1985,7 @@ type Import struct { } func (j *Import) sdkVersion() string { - return proptools.StringDefault(j.properties.Sdk_version, defaultSdkVersion(j)) + return String(j.properties.Sdk_version) } func (j *Import) minSdkVersion() string { diff --git a/java/java_test.go b/java/java_test.go index a6ae50375..e3e45d769 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -27,6 +27,8 @@ import ( "android/soong/cc" "android/soong/dexpreopt" "android/soong/genrule" + + "github.com/google/blueprint/proptools" ) var buildDir string @@ -228,9 +230,13 @@ func run(t *testing.T, ctx *android.TestContext, config android.Config) { android.FailIfErrored(t, errs) } -func testJavaError(t *testing.T, pattern string, bp string) { +func testJavaError(t *testing.T, pattern string, bp string) (*android.TestContext, android.Config) { + t.Helper() + return testJavaErrorWithConfig(t, pattern, bp, testConfig(nil)) +} + +func testJavaErrorWithConfig(t *testing.T, pattern string, bp string, config android.Config) (*android.TestContext, android.Config) { t.Helper() - config := testConfig(nil) ctx := testContext(bp, nil) pathCtx := android.PathContextForTesting(config, nil) @@ -240,20 +246,26 @@ func testJavaError(t *testing.T, pattern string, bp string) { _, errs := ctx.ParseBlueprintsFiles("Android.bp") if len(errs) > 0 { android.FailIfNoMatchingErrors(t, pattern, errs) - return + return ctx, config } _, errs = ctx.PrepareBuildActions(config) if len(errs) > 0 { android.FailIfNoMatchingErrors(t, pattern, errs) - return + return ctx, config } t.Fatalf("missing expected error %q (0 errors are returned)", pattern) + + return ctx, config } func testJava(t *testing.T, bp string) (*android.TestContext, android.Config) { t.Helper() - config := testConfig(nil) + return testJavaWithConfig(t, bp, testConfig(nil)) +} + +func testJavaWithConfig(t *testing.T, bp string, config android.Config) (*android.TestContext, android.Config) { + t.Helper() ctx := testContext(bp, nil) run(t, ctx, config) @@ -315,29 +327,38 @@ func TestSimple(t *testing.T) { } } -func TestSdkVersion(t *testing.T) { - ctx, _ := testJava(t, ` +func TestSdkVersionByPartition(t *testing.T) { + testJavaError(t, "sdk_version must have a value when the module is located at vendor or product", ` java_library { name: "foo", srcs: ["a.java"], vendor: true, } + `) + testJava(t, ` java_library { name: "bar", srcs: ["b.java"], } `) - foo := ctx.ModuleForTests("foo", "android_common").Module().(*Library) - bar := ctx.ModuleForTests("bar", "android_common").Module().(*Library) + for _, enforce := range []bool{true, false} { - if foo.sdkVersion() != "system_current" { - t.Errorf("If sdk version of vendor module is empty, it must change to system_current.") - } - - if bar.sdkVersion() != "" { - t.Errorf("If sdk version of non-vendor module is empty, it keeps empty.") + config := testConfig(nil) + config.TestProductVariables.EnforceProductPartitionInterface = proptools.BoolPtr(enforce) + bp := ` + java_library { + name: "foo", + srcs: ["a.java"], + product_specific: true, + } + ` + if enforce { + testJavaErrorWithConfig(t, "sdk_version must have a value when the module is located at vendor or product", bp, config) + } else { + testJavaWithConfig(t, bp, config) + } } }