1// Copyright 2019 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package java
16
17import (
18	"fmt"
19	"path/filepath"
20	"strings"
21
22	"android/soong/android"
23	"android/soong/dexpreopt"
24)
25
26// systemServerClasspath returns the on-device locations of the modules in the system server classpath.  It is computed
27// once the first time it is called for any ctx.Config(), and returns the same slice for all future calls with the same
28// ctx.Config().
29func systemServerClasspath(ctx android.MakeVarsContext) []string {
30	return ctx.Config().OnceStringSlice(systemServerClasspathKey, func() []string {
31		global := dexpreopt.GetGlobalConfig(ctx)
32		var systemServerClasspathLocations []string
33		nonUpdatable := dexpreopt.NonUpdatableSystemServerJars(ctx, global)
34		// 1) Non-updatable jars.
35		for _, m := range nonUpdatable {
36			systemServerClasspathLocations = append(systemServerClasspathLocations,
37				filepath.Join("/system/framework", m+".jar"))
38		}
39		// 2) The jars that are from an updatable apex.
40		for _, m := range global.UpdatableSystemServerJars {
41			systemServerClasspathLocations = append(systemServerClasspathLocations,
42				dexpreopt.GetJarLocationFromApexJarPair(ctx, m))
43		}
44		if len(systemServerClasspathLocations) != len(global.SystemServerJars)+len(global.UpdatableSystemServerJars) {
45			panic(fmt.Errorf("Wrong number of system server jars, got %d, expected %d",
46				len(systemServerClasspathLocations),
47				len(global.SystemServerJars)+len(global.UpdatableSystemServerJars)))
48		}
49		return systemServerClasspathLocations
50	})
51}
52
53var systemServerClasspathKey = android.NewOnceKey("systemServerClasspath")
54
55// dexpreoptTargets returns the list of targets that are relevant to dexpreopting, which excludes architectures
56// supported through native bridge.
57func dexpreoptTargets(ctx android.PathContext) []android.Target {
58	var targets []android.Target
59	for _, target := range ctx.Config().Targets[android.Android] {
60		if target.NativeBridge == android.NativeBridgeDisabled {
61			targets = append(targets, target)
62		}
63	}
64	// We may also need the images on host in order to run host-based tests.
65	for _, target := range ctx.Config().Targets[android.BuildOs] {
66		targets = append(targets, target)
67	}
68
69	return targets
70}
71
72func stemOf(moduleName string) string {
73	// b/139391334: the stem of framework-minus-apex is framework
74	// This is hard coded here until we find a good way to query the stem
75	// of a module before any other mutators are run
76	if moduleName == "framework-minus-apex" {
77		return "framework"
78	}
79	return moduleName
80}
81
82func getDexLocation(ctx android.PathContext, target android.Target, module string) string {
83	apex, jar := android.SplitApexJarPair(ctx, module)
84
85	name := stemOf(jar) + ".jar"
86
87	var subdir string
88	if apex == "platform" {
89		// Special apex name "platform" denotes jars do not come from an apex, but are part
90		// of the platform. Such jars are installed on the /system partition on device.
91		subdir = "system/framework"
92	} else if apex == "system_ext" {
93		subdir = "system_ext/framework"
94	} else {
95		subdir = filepath.Join("apex", apex, "javalib")
96	}
97
98	if target.Os.Class == android.Host {
99		return filepath.Join(ctx.Config().Getenv("OUT_DIR"), "host", ctx.Config().PrebuiltOS(), subdir, name)
100	} else {
101		return filepath.Join("/", subdir, name)
102	}
103}
104
105var (
106	bootImageConfigKey     = android.NewOnceKey("bootImageConfig")
107	artBootImageName       = "art"
108	frameworkBootImageName = "boot"
109)
110
111// Construct the global boot image configs.
112func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
113	return ctx.Config().Once(bootImageConfigKey, func() interface{} {
114
115		global := dexpreopt.GetGlobalConfig(ctx)
116		targets := dexpreoptTargets(ctx)
117		deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName())
118
119		artModules := global.ArtApexJars
120		// With EMMA_INSTRUMENT_FRAMEWORK=true the Core libraries depend on jacoco.
121		if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
122			artModules = append(artModules, "com.android.art:jacocoagent")
123		}
124		frameworkModules := android.RemoveListFromList(global.BootJars, artModules)
125
126		artSubdir := "apex/com.android.art/javalib"
127		frameworkSubdir := "system/framework"
128
129		// ART config for the primary boot image in the ART apex.
130		// It includes the Core Libraries.
131		artCfg := bootImageConfig{
132			name:          artBootImageName,
133			stem:          "boot",
134			installSubdir: artSubdir,
135			modules:       artModules,
136		}
137
138		// Framework config for the boot image extension.
139		// It includes framework libraries and depends on the ART config.
140		frameworkCfg := bootImageConfig{
141			extends:       &artCfg,
142			name:          frameworkBootImageName,
143			stem:          "boot",
144			installSubdir: frameworkSubdir,
145			modules:       frameworkModules,
146		}
147
148		configs := map[string]*bootImageConfig{
149			artBootImageName:       &artCfg,
150			frameworkBootImageName: &frameworkCfg,
151		}
152
153		// common to all configs
154		for _, c := range configs {
155			c.dir = deviceDir.Join(ctx, "dex_"+c.name+"jars")
156			c.symbolsDir = deviceDir.Join(ctx, "dex_"+c.name+"jars_unstripped")
157
158			// expands to <stem>.art for primary image and <stem>-<1st module>.art for extension
159			imageName := c.firstModuleNameOrStem(ctx) + ".art"
160
161			// The path to bootclasspath dex files needs to be known at module
162			// GenerateAndroidBuildAction time, before the bootclasspath modules have been compiled.
163			// Set up known paths for them, the singleton rules will copy them there.
164			// TODO(b/143682396): use module dependencies instead
165			inputDir := deviceDir.Join(ctx, "dex_"+c.name+"jars_input")
166			for _, m := range c.modules {
167				_, jar := android.SplitApexJarPair(ctx, m)
168				c.dexPaths = append(c.dexPaths, inputDir.Join(ctx, stemOf(jar)+".jar"))
169			}
170			c.dexPathsDeps = c.dexPaths
171
172			// Create target-specific variants.
173			for _, target := range targets {
174				arch := target.Arch.ArchType
175				imageDir := c.dir.Join(ctx, target.Os.String(), c.installSubdir, arch.String())
176				variant := &bootImageVariant{
177					bootImageConfig: c,
178					target:          target,
179					images:          imageDir.Join(ctx, imageName),
180					imagesDeps:      c.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex"),
181				}
182				for _, m := range c.modules {
183					variant.dexLocations = append(variant.dexLocations, getDexLocation(ctx, target, m))
184				}
185				variant.dexLocationsDeps = variant.dexLocations
186				c.variants = append(c.variants, variant)
187			}
188
189			c.zip = c.dir.Join(ctx, c.name+".zip")
190		}
191
192		// specific to the framework config
193		frameworkCfg.dexPathsDeps = append(artCfg.dexPathsDeps, frameworkCfg.dexPathsDeps...)
194		for i := range targets {
195			frameworkCfg.variants[i].primaryImages = artCfg.variants[i].images
196			frameworkCfg.variants[i].dexLocationsDeps = append(artCfg.variants[i].dexLocations, frameworkCfg.variants[i].dexLocationsDeps...)
197		}
198
199		return configs
200	}).(map[string]*bootImageConfig)
201}
202
203func artBootImageConfig(ctx android.PathContext) *bootImageConfig {
204	return genBootImageConfigs(ctx)[artBootImageName]
205}
206
207func defaultBootImageConfig(ctx android.PathContext) *bootImageConfig {
208	return genBootImageConfigs(ctx)[frameworkBootImageName]
209}
210
211func defaultBootclasspath(ctx android.PathContext) []string {
212	return ctx.Config().OnceStringSlice(defaultBootclasspathKey, func() []string {
213		global := dexpreopt.GetGlobalConfig(ctx)
214		image := defaultBootImageConfig(ctx)
215
216		updatableBootclasspath := make([]string, len(global.UpdatableBootJars))
217		for i, p := range global.UpdatableBootJars {
218			updatableBootclasspath[i] = dexpreopt.GetJarLocationFromApexJarPair(ctx, p)
219		}
220
221		bootclasspath := append(copyOf(image.getAnyAndroidVariant().dexLocationsDeps), updatableBootclasspath...)
222		return bootclasspath
223	})
224}
225
226var defaultBootclasspathKey = android.NewOnceKey("defaultBootclasspath")
227
228var copyOf = android.CopyOf
229
230func init() {
231	android.RegisterMakeVarsProvider(pctx, dexpreoptConfigMakevars)
232}
233
234func dexpreoptConfigMakevars(ctx android.MakeVarsContext) {
235	ctx.Strict("PRODUCT_BOOTCLASSPATH", strings.Join(defaultBootclasspath(ctx), ":"))
236	ctx.Strict("PRODUCT_DEX2OAT_BOOTCLASSPATH", strings.Join(defaultBootImageConfig(ctx).getAnyAndroidVariant().dexLocationsDeps, ":"))
237	ctx.Strict("PRODUCT_SYSTEM_SERVER_CLASSPATH", strings.Join(systemServerClasspath(ctx), ":"))
238
239	ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules, ":"))
240}
241