diff --git a/android/apex.go b/android/apex.go index 9bf6fc717..839a03af0 100644 --- a/android/apex.go +++ b/android/apex.go @@ -32,6 +32,7 @@ type ApexInfo struct { ApexName string MinSdkVersion int + Updatable bool } // Extracted from ApexModule to make it easier to define custom subsets of the @@ -104,6 +105,9 @@ type ApexModule interface { // For example, with maxSdkVersion is 10 and versionList is [9,11] // it returns 9 as string ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error) + + // Tests if the module comes from an updatable APEX. + Updatable() bool } type ApexProperties struct { @@ -229,6 +233,10 @@ func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) { } } +func (m *ApexModuleBase) Updatable() bool { + return m.ApexProperties.Info.Updatable +} + type byApexName []ApexInfo func (a byApexName) Len() int { return len(a) } diff --git a/apex/apex.go b/apex/apex.go index 1a7276908..3b1788699 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -844,6 +844,7 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) { apexBundles = []android.ApexInfo{{ ApexName: mctx.ModuleName(), MinSdkVersion: a.minSdkVersion(mctx), + Updatable: proptools.Bool(a.properties.Updatable), }} directDep = true } else if am, ok := mctx.Module().(android.ApexModule); ok { diff --git a/apex/apex_test.go b/apex/apex_test.go index 9f55728f2..6dcff3fcc 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -4276,6 +4276,13 @@ func testNoUpdatableJarsInBootImage(t *testing.T, errmsg, bp string, transformDe "system/sepolicy/apex/some-updatable-apex-file_contexts", ], } + + filegroup { + name: "some-non-updatable-apex-file_contexts", + srcs: [ + "system/sepolicy/apex/some-non-updatable-apex-file_contexts", + ], + } ` bp += cc.GatherRequiredDepsForTest(android.Android) bp += java.GatherRequiredDepsForTest() @@ -4288,6 +4295,7 @@ func testNoUpdatableJarsInBootImage(t *testing.T, errmsg, bp string, transformDe "apex_manifest.json": nil, "AndroidManifest.xml": nil, "system/sepolicy/apex/some-updatable-apex-file_contexts": nil, + "system/sepolicy/apex/some-non-updatable-apex-file_contexts": nil, "system/sepolicy/apex/com.android.art.something-file_contexts": nil, "framework/aidl/a.aidl": nil, } @@ -4341,6 +4349,14 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { ], } + java_library { + name: "some-non-updatable-apex-lib", + srcs: ["a.java"], + apex_available: [ + "some-non-updatable-apex", + ], + } + java_library { name: "some-platform-lib", srcs: ["a.java"], @@ -4360,16 +4376,28 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { name: "some-updatable-apex", key: "some-updatable-apex.key", java_libs: ["some-updatable-apex-lib"], + updatable: true, + } + + apex { + name: "some-non-updatable-apex", + key: "some-non-updatable-apex.key", + java_libs: ["some-non-updatable-apex-lib"], } apex_key { name: "some-updatable-apex.key", } + apex_key { + name: "some-non-updatable-apex.key", + } + apex { name: "com.android.art.something", key: "com.android.art.something.key", java_libs: ["some-art-lib"], + updatable: true, } apex_key { @@ -4400,6 +4428,13 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { } testNoUpdatableJarsInBootImage(t, error, bp, transform) + // non-updatable jar from some other apex in the ART boot image => error + error = "module 'some-non-updatable-apex-lib' is not allowed in the ART boot image" + transform = func(config *dexpreopt.GlobalConfig) { + config.ArtApexJars = []string{"some-non-updatable-apex-lib"} + } + testNoUpdatableJarsInBootImage(t, error, bp, transform) + // updatable jar from some other apex in the framework boot image => error error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image" transform = func(config *dexpreopt.GlobalConfig) { @@ -4407,6 +4442,12 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { } testNoUpdatableJarsInBootImage(t, error, bp, transform) + // non-updatable jar from some other apex in the framework boot image => ok + transform = func(config *dexpreopt.GlobalConfig) { + config.BootJars = []string{"some-non-updatable-apex-lib"} + } + testNoUpdatableJarsInBootImage(t, "", bp, transform) + // nonexistent jar in the ART boot image => error error = "failed to find a dex jar path for module 'nonexistent'" transform = func(config *dexpreopt.GlobalConfig) { @@ -4422,7 +4463,7 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { testNoUpdatableJarsInBootImage(t, error, bp, transform) // platform jar in the ART boot image => error - error = "module 'some-platform-lib' is part of the platform and not allowed in the ART boot image" + error = "module 'some-platform-lib' is not allowed in the ART boot image" transform = func(config *dexpreopt.GlobalConfig) { config.ArtApexJars = []string{"some-platform-lib"} } diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 543b2333c..c3825cbc3 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -268,27 +268,28 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul // Check that this module satisfies constraints for a particular boot image. apex, isApexModule := module.(android.ApexModule) + fromUpdatableApex := isApexModule && apex.Updatable() if image.name == artBootImageName { if isApexModule && strings.HasPrefix(apex.ApexName(), "com.android.art.") { - // ok, found the jar in the ART apex - } else if isApexModule && !apex.IsForPlatform() { - // this jar is part of an updatable apex other than ART, fail immediately - ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the ART boot image", name, apex.ApexName()) + // ok: found the jar in the ART apex } else if isApexModule && apex.IsForPlatform() && Bool(module.(*Library).deviceProperties.Hostdex) { - // this is a special "hostdex" variant, skip it and resume search + // exception (skip and continue): special "hostdex" platform variant return -1, nil } else if name == "jacocoagent" && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") { - // this is Jacoco platform variant for a coverage build, skip it and resume search + // exception (skip and continue): Jacoco platform variant for a coverage build return -1, nil + } else if fromUpdatableApex { + // error: this jar is part of an updatable apex other than ART + ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the ART boot image", name, apex.ApexName()) } else { - // this (installable) jar is part of the platform, fail immediately - ctx.Errorf("module '%s' is part of the platform and not allowed in the ART boot image", name) + // error: this jar is part of the platform or a non-updatable apex + ctx.Errorf("module '%s' is not allowed in the ART boot image", name) } } else if image.name == frameworkBootImageName { - if !isApexModule || apex.IsForPlatform() { - // ok, this jar is part of the platform + if !fromUpdatableApex { + // ok: this jar is part of the platform or a non-updatable apex } else { - // this jar is part of an updatable apex, fail immediately + // error: this jar is part of an updatable apex ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the framework boot image", name, apex.ApexName()) } } else {