3576e769a4
Every module belonging to a single mainline module family will be hidden from make, except the one which has been flagged using apex_contributions Details - Introduce a new `source_apex_name` property to prebuilt_apex and override_apex. This property will be used to identify the source equivalent of a prebuilt soong apex module. - Create an N-ary tree from source to prebuilt(s). The tree wil be rooted at the source module. - In a subsequent mutator, visit every node in the tree(s). Query apex_contributions and store the handle of the node which is "active" (if any) - In the same mutator, do another pass over the tree. Invoke `HideFromMake` on every node which is not "active". The two-pass approach is needed PrebuiltSelectionInfoProvider does not know about the inter source-prebuilt dependency, this dependency can only be known by doing a graph walk of the N-ary tree. Some tangential implementation details - Each prebuilt apex has an internal deapxer module that is responsible for generating the deapex ninja rules. The name of this internal module uses the BaseModuleName (without the prebuilt_ prefix). Since we can have multiple prebuilt soong modules in trunk stable, change this to follow the name of the prebuilt module in order to avoid name collisions. Update existing unit tests accordingly Bug: 316179314 Test: go test ./apex -run TestInstallationRulesForMultipleApexPrebuilts Test: m nothing --no-skip-soong-tests Test: presubmits Change-Id: I58aa99d5e6a9859954614e6db9a8e9e2e581642d
413 lines
14 KiB
Go
413 lines
14 KiB
Go
// Copyright 2019 Google Inc. All rights reserved.
|
|
//
|
|
// 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 (
|
|
"fmt"
|
|
"path/filepath"
|
|
"sort"
|
|
"testing"
|
|
|
|
"android/soong/android"
|
|
"android/soong/java"
|
|
)
|
|
|
|
func testDexpreoptBoot(t *testing.T, ruleFile string, expectedInputs, expectedOutputs []string, preferPrebuilt bool) {
|
|
bp := `
|
|
// Platform.
|
|
|
|
java_sdk_library {
|
|
name: "foo",
|
|
srcs: ["a.java"],
|
|
api_packages: ["foo"],
|
|
}
|
|
|
|
java_library {
|
|
name: "bar",
|
|
srcs: ["b.java"],
|
|
installable: true,
|
|
system_ext_specific: true,
|
|
}
|
|
|
|
dex_import {
|
|
name: "baz",
|
|
jars: ["a.jar"],
|
|
}
|
|
|
|
platform_bootclasspath {
|
|
name: "platform-bootclasspath",
|
|
fragments: [
|
|
{
|
|
apex: "com.android.art",
|
|
module: "art-bootclasspath-fragment",
|
|
},
|
|
],
|
|
}
|
|
|
|
// Source ART APEX.
|
|
|
|
java_library {
|
|
name: "core-oj",
|
|
srcs: ["core-oj.java"],
|
|
installable: true,
|
|
apex_available: [
|
|
"com.android.art",
|
|
],
|
|
}
|
|
|
|
bootclasspath_fragment {
|
|
name: "art-bootclasspath-fragment",
|
|
image_name: "art",
|
|
contents: ["core-oj"],
|
|
apex_available: [
|
|
"com.android.art",
|
|
],
|
|
hidden_api: {
|
|
split_packages: ["*"],
|
|
},
|
|
}
|
|
|
|
apex_key {
|
|
name: "com.android.art.key",
|
|
public_key: "com.android.art.avbpubkey",
|
|
private_key: "com.android.art.pem",
|
|
}
|
|
|
|
apex {
|
|
name: "com.android.art",
|
|
key: "com.android.art.key",
|
|
bootclasspath_fragments: ["art-bootclasspath-fragment"],
|
|
updatable: false,
|
|
}
|
|
|
|
// Prebuilt ART APEX.
|
|
|
|
java_import {
|
|
name: "core-oj",
|
|
prefer: %[1]t,
|
|
jars: ["core-oj.jar"],
|
|
apex_available: [
|
|
"com.android.art",
|
|
],
|
|
}
|
|
|
|
prebuilt_bootclasspath_fragment {
|
|
name: "art-bootclasspath-fragment",
|
|
prefer: %[1]t,
|
|
image_name: "art",
|
|
contents: ["core-oj"],
|
|
hidden_api: {
|
|
annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
|
|
metadata: "my-bootclasspath-fragment/metadata.csv",
|
|
index: "my-bootclasspath-fragment/index.csv",
|
|
stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
|
|
all_flags: "my-bootclasspath-fragment/all-flags.csv",
|
|
},
|
|
apex_available: [
|
|
"com.android.art",
|
|
],
|
|
}
|
|
|
|
prebuilt_apex {
|
|
name: "com.android.art",
|
|
prefer: %[1]t,
|
|
apex_name: "com.android.art",
|
|
src: "com.android.art-arm.apex",
|
|
exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
|
|
}
|
|
`
|
|
|
|
result := android.GroupFixturePreparers(
|
|
java.PrepareForTestWithDexpreopt,
|
|
java.PrepareForTestWithJavaSdkLibraryFiles,
|
|
java.FixtureWithLastReleaseApis("foo"),
|
|
java.FixtureConfigureBootJars("com.android.art:core-oj", "platform:foo", "system_ext:bar", "platform:baz"),
|
|
PrepareForTestWithApexBuildComponents,
|
|
prepareForTestWithArtApex,
|
|
).RunTestWithBp(t, fmt.Sprintf(bp, preferPrebuilt))
|
|
|
|
dexBootJars := result.ModuleForTests("dex_bootjars", "android_common")
|
|
rule := dexBootJars.Output(ruleFile)
|
|
|
|
inputs := rule.Implicits.Strings()
|
|
sort.Strings(inputs)
|
|
sort.Strings(expectedInputs)
|
|
|
|
outputs := append(android.WritablePaths{rule.Output}, rule.ImplicitOutputs...).Strings()
|
|
sort.Strings(outputs)
|
|
sort.Strings(expectedOutputs)
|
|
|
|
android.AssertStringPathsRelativeToTopEquals(t, "inputs", result.Config, expectedInputs, inputs)
|
|
|
|
android.AssertStringPathsRelativeToTopEquals(t, "outputs", result.Config, expectedOutputs, outputs)
|
|
}
|
|
|
|
func TestDexpreoptBootJarsWithSourceArtApex(t *testing.T) {
|
|
ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art"
|
|
|
|
expectedInputs := []string{
|
|
"out/soong/dexpreopt_arm64/dex_bootjars_input/core-oj.jar",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars_input/foo.jar",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars_input/bar.jar",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar",
|
|
"out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/art-bootclasspath-fragment/boot.prof",
|
|
"out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof",
|
|
}
|
|
|
|
expectedOutputs := []string{
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.invocation",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-foo.art",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-bar.art",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-baz.art",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.oat",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-foo.oat",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-bar.oat",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-baz.oat",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.vdex",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-foo.vdex",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-bar.vdex",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-baz.vdex",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot.oat",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot-foo.oat",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot-bar.oat",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot-baz.oat",
|
|
}
|
|
|
|
testDexpreoptBoot(t, ruleFile, expectedInputs, expectedOutputs, false)
|
|
}
|
|
|
|
// The only difference is that the ART profile should be deapexed from the prebuilt APEX. Other
|
|
// inputs and outputs should be the same as above.
|
|
func TestDexpreoptBootJarsWithPrebuiltArtApex(t *testing.T) {
|
|
ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art"
|
|
|
|
expectedInputs := []string{
|
|
"out/soong/dexpreopt_arm64/dex_bootjars_input/core-oj.jar",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars_input/foo.jar",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars_input/bar.jar",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar",
|
|
"out/soong/.intermediates/prebuilt_com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof",
|
|
"out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof",
|
|
}
|
|
|
|
expectedOutputs := []string{
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.invocation",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-foo.art",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-bar.art",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-baz.art",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.oat",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-foo.oat",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-bar.oat",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-baz.oat",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.vdex",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-foo.vdex",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-bar.vdex",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-baz.vdex",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot.oat",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot-foo.oat",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot-bar.oat",
|
|
"out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot-baz.oat",
|
|
}
|
|
|
|
testDexpreoptBoot(t, ruleFile, expectedInputs, expectedOutputs, true)
|
|
}
|
|
|
|
// Changes to the boot.zip structure may break the ART APK scanner.
|
|
func TestDexpreoptBootZip(t *testing.T) {
|
|
ruleFile := "boot.zip"
|
|
|
|
ctx := android.PathContextForTesting(android.TestArchConfig("", nil, "", nil))
|
|
expectedInputs := []string{}
|
|
for _, target := range ctx.Config().Targets[android.Android] {
|
|
for _, ext := range []string{".art", ".oat", ".vdex"} {
|
|
for _, suffix := range []string{"", "-foo", "-bar", "-baz"} {
|
|
expectedInputs = append(expectedInputs,
|
|
filepath.Join(
|
|
"out/soong/dexpreopt_arm64/dex_bootjars",
|
|
target.Os.String(),
|
|
"system/framework",
|
|
target.Arch.ArchType.String(),
|
|
"boot"+suffix+ext))
|
|
}
|
|
}
|
|
}
|
|
|
|
expectedOutputs := []string{
|
|
"out/soong/dexpreopt_arm64/dex_bootjars/boot.zip",
|
|
}
|
|
|
|
testDexpreoptBoot(t, ruleFile, expectedInputs, expectedOutputs, false)
|
|
}
|
|
|
|
// Multiple ART apexes might exist in the tree.
|
|
// The profile should correspond to the apex selected using release build flags
|
|
func TestDexpreoptProfileWithMultiplePrebuiltArtApexes(t *testing.T) {
|
|
ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art"
|
|
bp := `
|
|
// Platform.
|
|
|
|
platform_bootclasspath {
|
|
name: "platform-bootclasspath",
|
|
fragments: [
|
|
{
|
|
apex: "com.android.art",
|
|
module: "art-bootclasspath-fragment",
|
|
},
|
|
],
|
|
}
|
|
|
|
// Source ART APEX.
|
|
|
|
java_library {
|
|
name: "core-oj",
|
|
srcs: ["core-oj.java"],
|
|
installable: true,
|
|
apex_available: [
|
|
"com.android.art",
|
|
],
|
|
}
|
|
|
|
bootclasspath_fragment {
|
|
name: "art-bootclasspath-fragment",
|
|
image_name: "art",
|
|
contents: ["core-oj"],
|
|
apex_available: [
|
|
"com.android.art",
|
|
],
|
|
hidden_api: {
|
|
split_packages: ["*"],
|
|
},
|
|
}
|
|
|
|
apex_key {
|
|
name: "com.android.art.key",
|
|
public_key: "com.android.art.avbpubkey",
|
|
private_key: "com.android.art.pem",
|
|
}
|
|
|
|
apex {
|
|
name: "com.android.art",
|
|
key: "com.android.art.key",
|
|
bootclasspath_fragments: ["art-bootclasspath-fragment"],
|
|
updatable: false,
|
|
}
|
|
|
|
// Prebuilt ART APEX.
|
|
|
|
java_import {
|
|
name: "core-oj",
|
|
jars: ["core-oj.jar"],
|
|
apex_available: [
|
|
"com.android.art",
|
|
],
|
|
}
|
|
|
|
prebuilt_bootclasspath_fragment {
|
|
name: "art-bootclasspath-fragment",
|
|
image_name: "art",
|
|
contents: ["core-oj"],
|
|
hidden_api: {
|
|
annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
|
|
metadata: "my-bootclasspath-fragment/metadata.csv",
|
|
index: "my-bootclasspath-fragment/index.csv",
|
|
stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
|
|
all_flags: "my-bootclasspath-fragment/all-flags.csv",
|
|
},
|
|
apex_available: [
|
|
"com.android.art",
|
|
],
|
|
}
|
|
|
|
prebuilt_apex {
|
|
name: "com.android.art",
|
|
apex_name: "com.android.art",
|
|
src: "com.android.art-arm.apex",
|
|
exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
|
|
}
|
|
|
|
// Another Prebuilt ART APEX
|
|
prebuilt_apex {
|
|
name: "com.android.art.v2",
|
|
apex_name: "com.android.art", // Used to determine the API domain
|
|
src: "com.android.art-arm.apex",
|
|
exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
|
|
}
|
|
|
|
// APEX contribution modules
|
|
|
|
apex_contributions {
|
|
name: "art.source.contributions",
|
|
api_domain: "com.android.art",
|
|
contents: ["com.android.art"],
|
|
}
|
|
|
|
apex_contributions {
|
|
name: "art.prebuilt.contributions",
|
|
api_domain: "com.android.art",
|
|
contents: ["prebuilt_com.android.art"],
|
|
}
|
|
|
|
apex_contributions {
|
|
name: "art.prebuilt.v2.contributions",
|
|
api_domain: "com.android.art",
|
|
contents: ["com.android.art.v2"], // prebuilt_ prefix is missing because of prebuilt_rename mutator
|
|
}
|
|
|
|
`
|
|
|
|
testCases := []struct {
|
|
desc string
|
|
selectedArtApexContributions string
|
|
expectedProfile string
|
|
}{
|
|
{
|
|
desc: "Source apex com.android.art is selected, profile should come from source java library",
|
|
selectedArtApexContributions: "art.source.contributions",
|
|
expectedProfile: "out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/art-bootclasspath-fragment/boot.prof",
|
|
},
|
|
{
|
|
desc: "Prebuilt apex prebuilt_com.android.art is selected, profile should come from .prof deapexed from the prebuilt",
|
|
selectedArtApexContributions: "art.prebuilt.contributions",
|
|
expectedProfile: "out/soong/.intermediates/prebuilt_com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof",
|
|
},
|
|
{
|
|
desc: "Prebuilt apex prebuilt_com.android.art.v2 is selected, profile should come from .prof deapexed from the prebuilt",
|
|
selectedArtApexContributions: "art.prebuilt.v2.contributions",
|
|
expectedProfile: "out/soong/.intermediates/prebuilt_com.android.art.v2.deapexer/android_common/deapexer/etc/boot-image.prof",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
result := android.GroupFixturePreparers(
|
|
java.PrepareForTestWithDexpreopt,
|
|
java.PrepareForTestWithJavaSdkLibraryFiles,
|
|
java.FixtureConfigureBootJars("com.android.art:core-oj"),
|
|
PrepareForTestWithApexBuildComponents,
|
|
prepareForTestWithArtApex,
|
|
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
|
|
variables.BuildFlags = map[string]string{
|
|
"RELEASE_APEX_CONTRIBUTIONS_ART": tc.selectedArtApexContributions,
|
|
}
|
|
}),
|
|
).RunTestWithBp(t, bp)
|
|
|
|
dexBootJars := result.ModuleForTests("dex_bootjars", "android_common")
|
|
rule := dexBootJars.Output(ruleFile)
|
|
|
|
inputs := rule.Implicits.Strings()
|
|
android.AssertStringListContains(t, tc.desc, inputs, tc.expectedProfile)
|
|
}
|
|
}
|