From c0eb0b1ae56b67f1a71681a4334386ca9b6b8e2a Mon Sep 17 00:00:00 2001 From: Ulya Trafimovich Date: Wed, 22 Apr 2020 18:05:58 +0100 Subject: [PATCH 1/3] Add "updatable" property to ApexModule interface. For a given variant of a module that implements ApexModule interface, the "updatable" property tests if this variant comes from an updatable apex. For platform variants it is always false. Test: lunch aosp_walleye-userdebug && m nothing Bug: 138994281 Merged-In: I2d4c54fb397e29dc9b3203be7fb17be4536529f7 Change-Id: I2d4c54fb397e29dc9b3203be7fb17be4536529f7 Exempt-From-Owner-Approval: cp from aosp (cherry picked from commit 7c140d828a0c0f6126fa60cf87381960649286ff) --- android/apex.go | 8 +++++++ apex/apex.go | 1 + apex/apex_test.go | 45 +++++++++++++++++++++++++++++++++++++- java/dexpreopt_bootjars.go | 23 +++++++++---------- 4 files changed, 65 insertions(+), 12 deletions(-) diff --git a/android/apex.go b/android/apex.go index ede096540..9056c3de7 100644 --- a/android/apex.go +++ b/android/apex.go @@ -33,6 +33,7 @@ type ApexInfo struct { ApexName string MinSdkVersion int + Updatable bool } // Extracted from ApexModule to make it easier to define custom subsets of the @@ -116,6 +117,9 @@ type ApexModule interface { // it returns 9 as string ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error) + // Tests if the module comes from an updatable APEX. + Updatable() bool + // List of APEXes that this module tests. The module has access to // the private part of the listed APEXes even when it is not included in the // APEXes. @@ -260,6 +264,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 7f153dc3b..e6b769568 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -756,6 +756,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 ad46c3098..6e58f982a 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -4342,6 +4342,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() @@ -4354,6 +4361,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, } @@ -4424,6 +4432,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"], @@ -4445,16 +4461,30 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { name: "some-updatable-apex", key: "some-updatable-apex.key", java_libs: ["some-updatable-apex-lib"], + updatable: true, + min_sdk_version: "current", + } + + 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, + min_sdk_version: "current", } apex_key { @@ -4485,6 +4515,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) { @@ -4492,6 +4529,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) { @@ -4507,7 +4550,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 1b2666708..b518e9c0d 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -264,27 +264,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 { From 93a06c10e961b69b9e8fbdf0127ce0526c3d527c Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Thu, 14 May 2020 07:44:03 +0900 Subject: [PATCH 2/3] Remove ApexBundleDepsInfo.MinSdkVersion() For java.AndroidApp app, app.MinSdkVersion() was selected from ApexBundleDepsInfo, not from java.Module. This caused app.MinSdkVersion() to return "" always. Besides, having two embeded fields and relying on depth to choose one of them makes it hard to read. Bug: 156537348 Test: m Merged-In: Ib525b2f5132c596db8e33492d0a565ea23e91d1c Change-Id: Ib525b2f5132c596db8e33492d0a565ea23e91d1c Exempt-From-Owner-Approval: cp from aosp (cherry picked from commit 98d63e1cc7057c2204ab1fdd303f70fbf45e47c4) --- android/apex.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/android/apex.go b/android/apex.go index 9056c3de7..75be15026 100644 --- a/android/apex.go +++ b/android/apex.go @@ -421,21 +421,15 @@ type ApexModuleDepInfo struct { type DepNameToDepInfoMap map[string]ApexModuleDepInfo type ApexBundleDepsInfo struct { - minSdkVersion string - flatListPath OutputPath - fullListPath OutputPath + flatListPath OutputPath + fullListPath OutputPath } type ApexDepsInfoIntf interface { - MinSdkVersion() string FlatListPath() Path FullListPath() Path } -func (d *ApexBundleDepsInfo) MinSdkVersion() string { - return d.minSdkVersion -} - func (d *ApexBundleDepsInfo) FlatListPath() Path { return d.flatListPath } @@ -450,8 +444,6 @@ var _ ApexDepsInfoIntf = (*ApexBundleDepsInfo)(nil) // 1. FullList with transitive deps and their parents in the dep graph // 2. FlatList with a flat list of transitive deps func (d *ApexBundleDepsInfo) BuildDepsInfoLists(ctx ModuleContext, minSdkVersion string, depInfos DepNameToDepInfoMap) { - d.minSdkVersion = minSdkVersion - var fullContent strings.Builder var flatContent strings.Builder From 2b4b7bbe8262c41ff47d79cc9f2964bae03a8709 Mon Sep 17 00:00:00 2001 From: Artur Satayev Date: Tue, 28 Apr 2020 14:57:42 +0100 Subject: [PATCH 3/3] Generate combined deps-info for all updatable modules. Introduce a singleton apex rule to merge contents of individual deps-info results into a single output file. Bug: 149622332 Test: m Change-Id: I4ab7e1a3527fead97a81a5a2cb0e1e93a429117c Merged-In: I4ab7e1a3527fead97a81a5a2cb0e1e93a429117c Exempt-From-Owner-Approval: cp from aosp (cherry picked from commit 849f844252872e260a35cf958cb25ab4c5ea3e7f) --- Android.bp | 1 + android/apex.go | 5 ++-- apex/apex.go | 12 ++++++-- apex/apex_singleton.go | 65 ++++++++++++++++++++++++++++++++++++++++++ java/app.go | 6 +++- 5 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 apex/apex_singleton.go diff --git a/Android.bp b/Android.bp index a81676fc2..d7c7dae52 100644 --- a/Android.bp +++ b/Android.bp @@ -489,6 +489,7 @@ bootstrap_go_package { srcs: [ "apex/androidmk.go", "apex/apex.go", + "apex/apex_singleton.go", "apex/builder.go", "apex/key.go", "apex/prebuilt.go", diff --git a/android/apex.go b/android/apex.go index 75be15026..30152db29 100644 --- a/android/apex.go +++ b/android/apex.go @@ -425,7 +425,8 @@ type ApexBundleDepsInfo struct { fullListPath OutputPath } -type ApexDepsInfoIntf interface { +type ApexBundleDepsInfoIntf interface { + Updatable() bool FlatListPath() Path FullListPath() Path } @@ -438,8 +439,6 @@ func (d *ApexBundleDepsInfo) FullListPath() Path { return d.fullListPath } -var _ ApexDepsInfoIntf = (*ApexBundleDepsInfo)(nil) - // Generate two module out files: // 1. FullList with transitive deps and their parents in the dep graph // 2. FlatList with a flat list of transitive deps diff --git a/apex/apex.go b/apex/apex.go index e6b769568..fe231f677 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -756,7 +756,7 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) { apexBundles = []android.ApexInfo{{ ApexName: mctx.ModuleName(), MinSdkVersion: a.minSdkVersion(mctx), - Updatable: proptools.Bool(a.properties.Updatable), + Updatable: a.Updatable(), }} directDep = true } else if am, ok := mctx.Module().(android.ApexModule); ok { @@ -1800,6 +1800,12 @@ func PrettyPrintTag(tag blueprint.DependencyTag) string { return tagString } +func (a *apexBundle) Updatable() bool { + return proptools.Bool(a.properties.Updatable) +} + +var _ android.ApexBundleDepsInfoIntf = (*apexBundle)(nil) + // Ensures that the dependencies are marked as available for this APEX func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { // Let's be practical. Availability for test, host, and the VNDK apex isn't important @@ -1848,7 +1854,7 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { } func (a *apexBundle) checkUpdatable(ctx android.ModuleContext) { - if proptools.Bool(a.properties.Updatable) { + if a.Updatable() { if String(a.properties.Min_sdk_version) == "" { ctx.PropertyErrorf("updatable", "updatable APEXes should set min_sdk_version as well") } @@ -2175,7 +2181,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { // We don't need the optimization for updatable APEXes, as it might give false signal // to the system health when the APEXes are still bundled (b/149805758) - if proptools.Bool(a.properties.Updatable) && a.properties.ApexType == imageApex { + if a.Updatable() && a.properties.ApexType == imageApex { a.linkToSystemLib = false } diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go new file mode 100644 index 000000000..83a56a2b5 --- /dev/null +++ b/apex/apex_singleton.go @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package apex + +import ( + "github.com/google/blueprint" + + "android/soong/android" +) + +func init() { + android.RegisterSingletonType("apex_depsinfo_singleton", apexDepsInfoSingletonFactory) +} + +type apexDepsInfoSingleton struct { + // Output file with all flatlists from updatable modules' deps-info combined + updatableFlatListsPath android.OutputPath +} + +func apexDepsInfoSingletonFactory() android.Singleton { + return &apexDepsInfoSingleton{} +} + +var combineFilesRule = pctx.AndroidStaticRule("combineFilesRule", + blueprint.RuleParams{ + Command: "cat $out.rsp | xargs cat > $out", + Rspfile: "$out.rsp", + RspfileContent: "$in", + }, +) + +func (s *apexDepsInfoSingleton) GenerateBuildActions(ctx android.SingletonContext) { + updatableFlatLists := android.Paths{} + ctx.VisitAllModules(func(module android.Module) { + if binaryInfo, ok := module.(android.ApexBundleDepsInfoIntf); ok { + if path := binaryInfo.FlatListPath(); path != nil { + if binaryInfo.Updatable() { + updatableFlatLists = append(updatableFlatLists, path) + } + } + } + }) + + s.updatableFlatListsPath = android.PathForOutput(ctx, "apex", "depsinfo", "updatable-flatlists.txt") + ctx.Build(pctx, android.BuildParams{ + Rule: combineFilesRule, + Description: "Generate " + s.updatableFlatListsPath.String(), + Inputs: updatableFlatLists, + Output: s.updatableFlatListsPath, + }) +} diff --git a/java/app.go b/java/app.go index 86cf7471d..11dc6acf8 100755 --- a/java/app.go +++ b/java/app.go @@ -414,7 +414,7 @@ func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { } func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { - if Bool(a.appProperties.Updatable) { + if a.Updatable() { if !a.sdkVersion().stable() { ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.sdkVersion()) } @@ -879,6 +879,10 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) { a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(), depsInfo) } +func (a *AndroidApp) Updatable() bool { + return Bool(a.appProperties.Updatable) || a.ApexModuleBase.Updatable() +} + func (a *AndroidApp) getCertString(ctx android.BaseModuleContext) string { certificate, overridden := ctx.DeviceConfig().OverrideCertificateFor(ctx.ModuleName()) if overridden {