Merge "Add boot_image module type"
diff --git a/apex/Android.bp b/apex/Android.bp
index 77dde72..b6fdcf4 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -25,6 +25,7 @@
     ],
     testSrcs: [
         "apex_test.go",
+        "boot_image_test.go",
         "vndk_test.go",
     ],
     pluginFor: ["soong_build"],
diff --git a/apex/boot_image_test.go b/apex/boot_image_test.go
new file mode 100644
index 0000000..07feb03
--- /dev/null
+++ b/apex/boot_image_test.go
@@ -0,0 +1,128 @@
+// Copyright (C) 2021 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 (
+	"testing"
+
+	"android/soong/android"
+	"android/soong/dexpreopt"
+	"android/soong/java"
+)
+
+// Contains tests for boot_image logic from java/boot_image.go as the ART boot image requires
+// modules from the ART apex.
+
+func TestBootImages(t *testing.T) {
+	ctx, _ := testApex(t, `
+		java_sdk_library {
+			name: "foo",
+			srcs: ["b.java"],
+			unsafe_ignore_missing_latest_api: true,
+		}
+
+		java_library {
+			name: "bar",
+			srcs: ["b.java"],
+			installable: true,
+		}
+
+		apex {
+			name: "com.android.art",
+			key: "com.android.art.key",
+ 			java_libs: [
+				"baz",
+				"quuz",
+			],
+		}
+
+		apex_key {
+			name: "com.android.art.key",
+			public_key: "com.android.art.avbpubkey",
+			private_key: "com.android.art.pem",
+		}
+
+		java_library {
+			name: "baz",
+			apex_available: [
+				"com.android.art",
+			],
+			srcs: ["b.java"],
+		}
+
+		java_library {
+			name: "quuz",
+			apex_available: [
+				"com.android.art",
+			],
+			srcs: ["b.java"],
+		}
+`,
+		// Configure some libraries in the art and framework boot images.
+		withArtBootImageJars("com.android.art:baz", "com.android.art:quuz"),
+		withFrameworkBootImageJars("platform:foo", "platform:bar"),
+		withFiles(filesForSdkLibrary),
+		// Some additional files needed for the art apex.
+		withFiles(map[string][]byte{
+			"com.android.art.avbpubkey":                          nil,
+			"com.android.art.pem":                                nil,
+			"system/sepolicy/apex/com.android.art-file_contexts": nil,
+		}),
+	)
+
+	// Make sure that the framework-boot-image is using the correct configuration.
+	checkBootImage(t, ctx, "framework-boot-image", "platform:foo,platform:bar")
+
+	// Make sure that the art-boot-image is using the correct configuration.
+	checkBootImage(t, ctx, "art-boot-image", "com.android.art:baz,com.android.art:quuz")
+}
+
+func checkBootImage(t *testing.T, ctx *android.TestContext, moduleName string, expectedConfiguredModules string) {
+	t.Helper()
+
+	bootImage := ctx.ModuleForTests(moduleName, "android_common").Module().(*java.BootImageModule)
+
+	bootImageInfo := ctx.ModuleProvider(bootImage, java.BootImageInfoProvider).(java.BootImageInfo)
+	modules := bootImageInfo.Modules()
+	if actual := modules.String(); actual != expectedConfiguredModules {
+		t.Errorf("invalid modules for %s: expected %q, actual %q", moduleName, expectedConfiguredModules, actual)
+	}
+}
+
+func modifyDexpreoptConfig(configModifier func(dexpreoptConfig *dexpreopt.GlobalConfig)) func(fs map[string][]byte, config android.Config) {
+	return func(fs map[string][]byte, config android.Config) {
+		// Initialize the dexpreopt GlobalConfig to an empty structure. This has no effect if it has
+		// already been set.
+		pathCtx := android.PathContextForTesting(config)
+		dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
+		dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
+
+		// Retrieve the existing configuration and modify it.
+		dexpreoptConfig = dexpreopt.GetGlobalConfig(pathCtx)
+		configModifier(dexpreoptConfig)
+	}
+}
+
+func withArtBootImageJars(bootJars ...string) func(fs map[string][]byte, config android.Config) {
+	return modifyDexpreoptConfig(func(dexpreoptConfig *dexpreopt.GlobalConfig) {
+		dexpreoptConfig.ArtApexJars = android.CreateTestConfiguredJarList(bootJars)
+	})
+}
+
+func withFrameworkBootImageJars(bootJars ...string) func(fs map[string][]byte, config android.Config) {
+	return modifyDexpreoptConfig(func(dexpreoptConfig *dexpreopt.GlobalConfig) {
+		dexpreoptConfig.BootJars = android.CreateTestConfiguredJarList(bootJars)
+	})
+}
diff --git a/java/Android.bp b/java/Android.bp
index 9c28968..364566a 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -24,6 +24,7 @@
         "app.go",
         "app_import.go",
         "app_set.go",
+        "boot_image.go",
         "boot_jars.go",
         "builder.go",
         "device_host_converter.go",
@@ -63,6 +64,7 @@
         "app_import_test.go",
         "app_set_test.go",
         "app_test.go",
+        "boot_image_test.go",
         "device_host_converter_test.go",
         "dexpreopt_test.go",
         "dexpreopt_bootjars_test.go",
diff --git a/java/boot_image.go b/java/boot_image.go
new file mode 100644
index 0000000..07ef0d8
--- /dev/null
+++ b/java/boot_image.go
@@ -0,0 +1,85 @@
+// Copyright (C) 2021 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 java
+
+import (
+	"strings"
+
+	"android/soong/android"
+	"github.com/google/blueprint"
+)
+
+func init() {
+	RegisterBootImageBuildComponents(android.InitRegistrationContext)
+}
+
+func RegisterBootImageBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("boot_image", bootImageFactory)
+}
+
+type bootImageProperties struct {
+	// The name of the image this represents.
+	//
+	// Must be one of "art" or "boot".
+	Image_name string
+}
+
+type BootImageModule struct {
+	android.ModuleBase
+
+	properties bootImageProperties
+}
+
+func bootImageFactory() android.Module {
+	m := &BootImageModule{}
+	m.AddProperties(&m.properties)
+	android.InitAndroidArchModule(m, android.HostAndDeviceDefault, android.MultilibCommon)
+	return m
+}
+
+var BootImageInfoProvider = blueprint.NewProvider(BootImageInfo{})
+
+type BootImageInfo struct {
+	// The image config, internal to this module (and the dex_bootjars singleton).
+	imageConfig *bootImageConfig
+}
+
+func (i BootImageInfo) Modules() android.ConfiguredJarList {
+	return i.imageConfig.modules
+}
+
+func (b *BootImageModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// Nothing to do if skipping the dexpreopt of boot image jars.
+	if SkipDexpreoptBootJars(ctx) {
+		return
+	}
+
+	// Get a map of the image configs that are supported.
+	imageConfigs := genBootImageConfigs(ctx)
+
+	// Retrieve the config for this image.
+	imageName := b.properties.Image_name
+	imageConfig := imageConfigs[imageName]
+	if imageConfig == nil {
+		ctx.PropertyErrorf("image_name", "Unknown image name %q, expected one of %s", imageName, strings.Join(android.SortedStringKeys(imageConfigs), ", "))
+		return
+	}
+
+	// Construct the boot image info from the config.
+	info := BootImageInfo{imageConfig: imageConfig}
+
+	// Make it available for other modules.
+	ctx.SetProvider(BootImageInfoProvider, info)
+}
diff --git a/java/boot_image_test.go b/java/boot_image_test.go
new file mode 100644
index 0000000..a295782
--- /dev/null
+++ b/java/boot_image_test.go
@@ -0,0 +1,31 @@
+// Copyright (C) 2021 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 java
+
+import (
+	"testing"
+)
+
+// Contains some simple tests for boot_image logic, additional tests can be found in
+// apex/boot_image_test.go as the ART boot image requires modules from the ART apex.
+
+func TestUnknownBootImage(t *testing.T) {
+	testJavaError(t, "image_name: Unknown image name \\\"unknown\\\", expected one of art, boot", `
+		boot_image {
+			name: "unknown-boot-image",
+			image_name: "unknown",
+		}
+`)
+}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 004cbbb..78d9d02 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -35,6 +35,13 @@
 //
 // Changes:
 // 1) dex_bootjars is now a singleton module and not a plain singleton.
+// 2) Boot images are now represented by the boot_image module type.
+// 3) The art boot image is called "art-boot-image", the framework boot image is called
+//    "framework-boot-image".
+// 4) They are defined in art/build/boot/Android.bp and frameworks/base/boot/Android.bp
+//    respectively.
+// 5) Each boot_image retrieves the appropriate boot image configuration from the map returned by
+//    genBootImageConfigs() using the image_name specified in the boot_image module.
 // =================================================================================================
 
 // This comment describes:
diff --git a/java/testing.go b/java/testing.go
index 0b1f2d1..31ff47f 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -107,6 +107,7 @@
 	RegisterAppBuildComponents(ctx)
 	RegisterAppImportBuildComponents(ctx)
 	RegisterAppSetBuildComponents(ctx)
+	RegisterBootImageBuildComponents(ctx)
 	RegisterDexpreoptBootJarsComponents(ctx)
 	RegisterDocsBuildComponents(ctx)
 	RegisterGenRuleBuildComponents(ctx)
@@ -218,6 +219,16 @@
 		dex_bootjars {
 			name: "dex_bootjars",
 		}
+
+		boot_image {
+			name: "art-boot-image",
+			image_name: "art",
+		}
+
+		boot_image {
+			name: "framework-boot-image",
+			image_name: "boot",
+		}
 `
 
 	return bp