xref: /aosp_15_r20/build/soong/dexpreopt/dexpreopt.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2018 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Worker// The dexpreopt package converts a global dexpreopt config and a module dexpreopt config into rules to perform
16*333d2b36SAndroid Build Coastguard Worker// dexpreopting.
17*333d2b36SAndroid Build Coastguard Worker//
18*333d2b36SAndroid Build Coastguard Worker// It is used in two places; in the dexpeopt_gen binary for modules defined in Make, and directly linked into Soong.
19*333d2b36SAndroid Build Coastguard Worker//
20*333d2b36SAndroid Build Coastguard Worker// For Make modules it is built into the dexpreopt_gen binary, which is executed as a Make rule using global config and
21*333d2b36SAndroid Build Coastguard Worker// module config specified in JSON files.  The binary writes out two shell scripts, only updating them if they have
22*333d2b36SAndroid Build Coastguard Worker// changed.  One script takes an APK or JAR as an input and produces a zip file containing any outputs of preopting,
23*333d2b36SAndroid Build Coastguard Worker// in the location they should be on the device.  The Make build rules will unzip the zip file into $(PRODUCT_OUT) when
24*333d2b36SAndroid Build Coastguard Worker// installing the APK, which will install the preopt outputs into $(PRODUCT_OUT)/system or $(PRODUCT_OUT)/system_other
25*333d2b36SAndroid Build Coastguard Worker// as necessary.  The zip file may be empty if preopting was disabled for any reason.
26*333d2b36SAndroid Build Coastguard Worker//
27*333d2b36SAndroid Build Coastguard Worker// The intermediate shell scripts allow changes to this package or to the global config to regenerate the shell scripts
28*333d2b36SAndroid Build Coastguard Worker// but only require re-executing preopting if the script has changed.
29*333d2b36SAndroid Build Coastguard Worker//
30*333d2b36SAndroid Build Coastguard Worker// For Soong modules this package is linked directly into Soong and run from the java package.  It generates the same
31*333d2b36SAndroid Build Coastguard Worker// commands as for make, using athe same global config JSON file used by make, but using a module config structure
32*333d2b36SAndroid Build Coastguard Worker// provided by Soong.  The generated commands are then converted into Soong rule and written directly to the ninja file,
33*333d2b36SAndroid Build Coastguard Worker// with no extra shell scripts involved.
34*333d2b36SAndroid Build Coastguard Workerpackage dexpreopt
35*333d2b36SAndroid Build Coastguard Worker
36*333d2b36SAndroid Build Coastguard Workerimport (
37*333d2b36SAndroid Build Coastguard Worker	"fmt"
38*333d2b36SAndroid Build Coastguard Worker	"path/filepath"
39*333d2b36SAndroid Build Coastguard Worker	"runtime"
40*333d2b36SAndroid Build Coastguard Worker	"strings"
41*333d2b36SAndroid Build Coastguard Worker
42*333d2b36SAndroid Build Coastguard Worker	"android/soong/android"
43*333d2b36SAndroid Build Coastguard Worker
44*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint/pathtools"
45*333d2b36SAndroid Build Coastguard Worker)
46*333d2b36SAndroid Build Coastguard Worker
47*333d2b36SAndroid Build Coastguard Workerconst SystemPartition = "/system/"
48*333d2b36SAndroid Build Coastguard Workerconst SystemOtherPartition = "/system_other/"
49*333d2b36SAndroid Build Coastguard Worker
50*333d2b36SAndroid Build Coastguard Workervar DexpreoptRunningInSoong = false
51*333d2b36SAndroid Build Coastguard Worker
52*333d2b36SAndroid Build Coastguard Worker// GenerateDexpreoptRule generates a set of commands that will preopt a module based on a GlobalConfig and a
53*333d2b36SAndroid Build Coastguard Worker// ModuleConfig.  The produced files and their install locations will be available through rule.Installs().
54*333d2b36SAndroid Build Coastguard Workerfunc GenerateDexpreoptRule(ctx android.BuilderContext, globalSoong *GlobalSoongConfig,
55*333d2b36SAndroid Build Coastguard Worker	global *GlobalConfig, module *ModuleConfig, productPackages android.Path, copyApexSystemServerJarDex bool) (
56*333d2b36SAndroid Build Coastguard Worker	rule *android.RuleBuilder, err error) {
57*333d2b36SAndroid Build Coastguard Worker
58*333d2b36SAndroid Build Coastguard Worker	defer func() {
59*333d2b36SAndroid Build Coastguard Worker		if r := recover(); r != nil {
60*333d2b36SAndroid Build Coastguard Worker			if _, ok := r.(runtime.Error); ok {
61*333d2b36SAndroid Build Coastguard Worker				panic(r)
62*333d2b36SAndroid Build Coastguard Worker			} else if e, ok := r.(error); ok {
63*333d2b36SAndroid Build Coastguard Worker				err = e
64*333d2b36SAndroid Build Coastguard Worker				rule = nil
65*333d2b36SAndroid Build Coastguard Worker			} else {
66*333d2b36SAndroid Build Coastguard Worker				panic(r)
67*333d2b36SAndroid Build Coastguard Worker			}
68*333d2b36SAndroid Build Coastguard Worker		}
69*333d2b36SAndroid Build Coastguard Worker	}()
70*333d2b36SAndroid Build Coastguard Worker
71*333d2b36SAndroid Build Coastguard Worker	rule = android.NewRuleBuilder(pctx, ctx)
72*333d2b36SAndroid Build Coastguard Worker
73*333d2b36SAndroid Build Coastguard Worker	generateProfile := module.ProfileClassListing.Valid() && !global.DisableGenerateProfile
74*333d2b36SAndroid Build Coastguard Worker	generateBootProfile := module.ProfileBootListing.Valid() && !global.DisableGenerateProfile
75*333d2b36SAndroid Build Coastguard Worker
76*333d2b36SAndroid Build Coastguard Worker	var profile android.WritablePath
77*333d2b36SAndroid Build Coastguard Worker	if generateProfile {
78*333d2b36SAndroid Build Coastguard Worker		profile = profileCommand(ctx, globalSoong, global, module, rule)
79*333d2b36SAndroid Build Coastguard Worker	}
80*333d2b36SAndroid Build Coastguard Worker	if generateBootProfile {
81*333d2b36SAndroid Build Coastguard Worker		bootProfileCommand(ctx, globalSoong, global, module, rule)
82*333d2b36SAndroid Build Coastguard Worker	}
83*333d2b36SAndroid Build Coastguard Worker
84*333d2b36SAndroid Build Coastguard Worker	if !dexpreoptDisabled(ctx, global, module) {
85*333d2b36SAndroid Build Coastguard Worker		if valid, err := validateClassLoaderContext(module.ClassLoaderContexts); err != nil {
86*333d2b36SAndroid Build Coastguard Worker			android.ReportPathErrorf(ctx, err.Error())
87*333d2b36SAndroid Build Coastguard Worker		} else if valid {
88*333d2b36SAndroid Build Coastguard Worker			fixClassLoaderContext(module.ClassLoaderContexts)
89*333d2b36SAndroid Build Coastguard Worker
90*333d2b36SAndroid Build Coastguard Worker			appImage := (generateProfile || module.ForceCreateAppImage || global.DefaultAppImages) &&
91*333d2b36SAndroid Build Coastguard Worker				!module.NoCreateAppImage
92*333d2b36SAndroid Build Coastguard Worker
93*333d2b36SAndroid Build Coastguard Worker			generateDM := shouldGenerateDM(module, global)
94*333d2b36SAndroid Build Coastguard Worker
95*333d2b36SAndroid Build Coastguard Worker			for archIdx, _ := range module.Archs {
96*333d2b36SAndroid Build Coastguard Worker				dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage,
97*333d2b36SAndroid Build Coastguard Worker					generateDM, productPackages, copyApexSystemServerJarDex)
98*333d2b36SAndroid Build Coastguard Worker			}
99*333d2b36SAndroid Build Coastguard Worker		}
100*333d2b36SAndroid Build Coastguard Worker	}
101*333d2b36SAndroid Build Coastguard Worker
102*333d2b36SAndroid Build Coastguard Worker	return rule, nil
103*333d2b36SAndroid Build Coastguard Worker}
104*333d2b36SAndroid Build Coastguard Worker
105*333d2b36SAndroid Build Coastguard Worker// If dexpreopt is applicable to the module, returns whether dexpreopt is disabled. Otherwise, the
106*333d2b36SAndroid Build Coastguard Worker// behavior is undefined.
107*333d2b36SAndroid Build Coastguard Worker// When it returns true, dexpreopt artifacts will not be generated, but profile will still be
108*333d2b36SAndroid Build Coastguard Worker// generated if profile-guided compilation is requested.
109*333d2b36SAndroid Build Coastguard Workerfunc dexpreoptDisabled(ctx android.PathContext, global *GlobalConfig, module *ModuleConfig) bool {
110*333d2b36SAndroid Build Coastguard Worker	if ctx.Config().UnbundledBuild() {
111*333d2b36SAndroid Build Coastguard Worker		return true
112*333d2b36SAndroid Build Coastguard Worker	}
113*333d2b36SAndroid Build Coastguard Worker
114*333d2b36SAndroid Build Coastguard Worker	if global.DisablePreopt {
115*333d2b36SAndroid Build Coastguard Worker		return true
116*333d2b36SAndroid Build Coastguard Worker	}
117*333d2b36SAndroid Build Coastguard Worker
118*333d2b36SAndroid Build Coastguard Worker	if contains(global.DisablePreoptModules, module.Name) {
119*333d2b36SAndroid Build Coastguard Worker		return true
120*333d2b36SAndroid Build Coastguard Worker	}
121*333d2b36SAndroid Build Coastguard Worker
122*333d2b36SAndroid Build Coastguard Worker	// Don't preopt individual boot jars, they will be preopted together.
123*333d2b36SAndroid Build Coastguard Worker	if global.BootJars.ContainsJar(module.Name) {
124*333d2b36SAndroid Build Coastguard Worker		return true
125*333d2b36SAndroid Build Coastguard Worker	}
126*333d2b36SAndroid Build Coastguard Worker
127*333d2b36SAndroid Build Coastguard Worker	if global.OnlyPreoptArtBootImage {
128*333d2b36SAndroid Build Coastguard Worker		return true
129*333d2b36SAndroid Build Coastguard Worker	}
130*333d2b36SAndroid Build Coastguard Worker
131*333d2b36SAndroid Build Coastguard Worker	return false
132*333d2b36SAndroid Build Coastguard Worker}
133*333d2b36SAndroid Build Coastguard Worker
134*333d2b36SAndroid Build Coastguard Workerfunc profileCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
135*333d2b36SAndroid Build Coastguard Worker	module *ModuleConfig, rule *android.RuleBuilder) android.WritablePath {
136*333d2b36SAndroid Build Coastguard Worker
137*333d2b36SAndroid Build Coastguard Worker	profilePath := module.BuildPath.InSameDir(ctx, "profile.prof")
138*333d2b36SAndroid Build Coastguard Worker	profileInstalledPath := module.DexLocation + ".prof"
139*333d2b36SAndroid Build Coastguard Worker
140*333d2b36SAndroid Build Coastguard Worker	if !module.ProfileIsTextListing {
141*333d2b36SAndroid Build Coastguard Worker		rule.Command().Text("rm -f").Output(profilePath)
142*333d2b36SAndroid Build Coastguard Worker		rule.Command().Text("touch").Output(profilePath)
143*333d2b36SAndroid Build Coastguard Worker	}
144*333d2b36SAndroid Build Coastguard Worker
145*333d2b36SAndroid Build Coastguard Worker	cmd := rule.Command().
146*333d2b36SAndroid Build Coastguard Worker		Text(`ANDROID_LOG_TAGS="*:e"`).
147*333d2b36SAndroid Build Coastguard Worker		Tool(globalSoong.Profman)
148*333d2b36SAndroid Build Coastguard Worker
149*333d2b36SAndroid Build Coastguard Worker	if module.ProfileIsTextListing {
150*333d2b36SAndroid Build Coastguard Worker		// The profile is a test listing of classes (used for framework jars).
151*333d2b36SAndroid Build Coastguard Worker		// We need to generate the actual binary profile before being able to compile.
152*333d2b36SAndroid Build Coastguard Worker		cmd.FlagWithInput("--create-profile-from=", module.ProfileClassListing.Path())
153*333d2b36SAndroid Build Coastguard Worker	} else {
154*333d2b36SAndroid Build Coastguard Worker		// The profile is binary profile (used for apps). Run it through profman to
155*333d2b36SAndroid Build Coastguard Worker		// ensure the profile keys match the apk.
156*333d2b36SAndroid Build Coastguard Worker		cmd.
157*333d2b36SAndroid Build Coastguard Worker			Flag("--copy-and-update-profile-key").
158*333d2b36SAndroid Build Coastguard Worker			FlagWithInput("--profile-file=", module.ProfileClassListing.Path())
159*333d2b36SAndroid Build Coastguard Worker	}
160*333d2b36SAndroid Build Coastguard Worker
161*333d2b36SAndroid Build Coastguard Worker	cmd.
162*333d2b36SAndroid Build Coastguard Worker		Flag("--output-profile-type=app").
163*333d2b36SAndroid Build Coastguard Worker		FlagWithInput("--apk=", module.DexPath).
164*333d2b36SAndroid Build Coastguard Worker		Flag("--dex-location="+module.DexLocation).
165*333d2b36SAndroid Build Coastguard Worker		FlagWithOutput("--reference-profile-file=", profilePath)
166*333d2b36SAndroid Build Coastguard Worker
167*333d2b36SAndroid Build Coastguard Worker	if !module.ProfileIsTextListing {
168*333d2b36SAndroid Build Coastguard Worker		cmd.Text(fmt.Sprintf(`|| echo "Profile out of date for %s"`, module.DexPath))
169*333d2b36SAndroid Build Coastguard Worker	}
170*333d2b36SAndroid Build Coastguard Worker	rule.Install(profilePath, profileInstalledPath)
171*333d2b36SAndroid Build Coastguard Worker
172*333d2b36SAndroid Build Coastguard Worker	return profilePath
173*333d2b36SAndroid Build Coastguard Worker}
174*333d2b36SAndroid Build Coastguard Worker
175*333d2b36SAndroid Build Coastguard Workerfunc bootProfileCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
176*333d2b36SAndroid Build Coastguard Worker	module *ModuleConfig, rule *android.RuleBuilder) android.WritablePath {
177*333d2b36SAndroid Build Coastguard Worker
178*333d2b36SAndroid Build Coastguard Worker	profilePath := module.BuildPath.InSameDir(ctx, "profile.bprof")
179*333d2b36SAndroid Build Coastguard Worker	profileInstalledPath := module.DexLocation + ".bprof"
180*333d2b36SAndroid Build Coastguard Worker
181*333d2b36SAndroid Build Coastguard Worker	if !module.ProfileIsTextListing {
182*333d2b36SAndroid Build Coastguard Worker		rule.Command().Text("rm -f").Output(profilePath)
183*333d2b36SAndroid Build Coastguard Worker		rule.Command().Text("touch").Output(profilePath)
184*333d2b36SAndroid Build Coastguard Worker	}
185*333d2b36SAndroid Build Coastguard Worker
186*333d2b36SAndroid Build Coastguard Worker	cmd := rule.Command().
187*333d2b36SAndroid Build Coastguard Worker		Text(`ANDROID_LOG_TAGS="*:e"`).
188*333d2b36SAndroid Build Coastguard Worker		Tool(globalSoong.Profman)
189*333d2b36SAndroid Build Coastguard Worker
190*333d2b36SAndroid Build Coastguard Worker	// The profile is a test listing of methods.
191*333d2b36SAndroid Build Coastguard Worker	// We need to generate the actual binary profile.
192*333d2b36SAndroid Build Coastguard Worker	cmd.FlagWithInput("--create-profile-from=", module.ProfileBootListing.Path())
193*333d2b36SAndroid Build Coastguard Worker
194*333d2b36SAndroid Build Coastguard Worker	cmd.
195*333d2b36SAndroid Build Coastguard Worker		Flag("--output-profile-type=bprof").
196*333d2b36SAndroid Build Coastguard Worker		FlagWithInput("--apk=", module.DexPath).
197*333d2b36SAndroid Build Coastguard Worker		Flag("--dex-location="+module.DexLocation).
198*333d2b36SAndroid Build Coastguard Worker		FlagWithOutput("--reference-profile-file=", profilePath)
199*333d2b36SAndroid Build Coastguard Worker
200*333d2b36SAndroid Build Coastguard Worker	if !module.ProfileIsTextListing {
201*333d2b36SAndroid Build Coastguard Worker		cmd.Text(fmt.Sprintf(`|| echo "Profile out of date for %s"`, module.DexPath))
202*333d2b36SAndroid Build Coastguard Worker	}
203*333d2b36SAndroid Build Coastguard Worker	rule.Install(profilePath, profileInstalledPath)
204*333d2b36SAndroid Build Coastguard Worker
205*333d2b36SAndroid Build Coastguard Worker	return profilePath
206*333d2b36SAndroid Build Coastguard Worker}
207*333d2b36SAndroid Build Coastguard Worker
208*333d2b36SAndroid Build Coastguard Worker// Returns the dex location of a system server java library.
209*333d2b36SAndroid Build Coastguard Workerfunc GetSystemServerDexLocation(ctx android.PathContext, global *GlobalConfig, lib string) string {
210*333d2b36SAndroid Build Coastguard Worker	if apex := global.AllApexSystemServerJars(ctx).ApexOfJar(lib); apex != "" {
211*333d2b36SAndroid Build Coastguard Worker		return fmt.Sprintf("/apex/%s/javalib/%s.jar", apex, lib)
212*333d2b36SAndroid Build Coastguard Worker	}
213*333d2b36SAndroid Build Coastguard Worker
214*333d2b36SAndroid Build Coastguard Worker	if apex := global.AllPlatformSystemServerJars(ctx).ApexOfJar(lib); apex == "system_ext" {
215*333d2b36SAndroid Build Coastguard Worker		return fmt.Sprintf("/system_ext/framework/%s.jar", lib)
216*333d2b36SAndroid Build Coastguard Worker	}
217*333d2b36SAndroid Build Coastguard Worker
218*333d2b36SAndroid Build Coastguard Worker	return fmt.Sprintf("/system/framework/%s.jar", lib)
219*333d2b36SAndroid Build Coastguard Worker}
220*333d2b36SAndroid Build Coastguard Worker
221*333d2b36SAndroid Build Coastguard Worker// Returns the location to the odex file for the dex file at `path`.
222*333d2b36SAndroid Build Coastguard Workerfunc ToOdexPath(path string, arch android.ArchType, partition string) string {
223*333d2b36SAndroid Build Coastguard Worker	if strings.HasPrefix(path, "/apex/") {
224*333d2b36SAndroid Build Coastguard Worker		return filepath.Join(partition, "framework/oat", arch.String(),
225*333d2b36SAndroid Build Coastguard Worker			strings.ReplaceAll(path[1:], "/", "@")+"@classes.odex")
226*333d2b36SAndroid Build Coastguard Worker	}
227*333d2b36SAndroid Build Coastguard Worker
228*333d2b36SAndroid Build Coastguard Worker	return filepath.Join(filepath.Dir(path), "oat", arch.String(),
229*333d2b36SAndroid Build Coastguard Worker		pathtools.ReplaceExtension(filepath.Base(path), "odex"))
230*333d2b36SAndroid Build Coastguard Worker}
231*333d2b36SAndroid Build Coastguard Worker
232*333d2b36SAndroid Build Coastguard Workerfunc dexpreoptCommand(ctx android.BuilderContext, globalSoong *GlobalSoongConfig,
233*333d2b36SAndroid Build Coastguard Worker	global *GlobalConfig, module *ModuleConfig, rule *android.RuleBuilder, archIdx int,
234*333d2b36SAndroid Build Coastguard Worker	profile android.WritablePath, appImage bool, generateDM bool, productPackages android.Path, copyApexSystemServerJarDex bool) {
235*333d2b36SAndroid Build Coastguard Worker
236*333d2b36SAndroid Build Coastguard Worker	arch := module.Archs[archIdx]
237*333d2b36SAndroid Build Coastguard Worker
238*333d2b36SAndroid Build Coastguard Worker	// HACK: make soname in Soong-generated .odex files match Make.
239*333d2b36SAndroid Build Coastguard Worker	base := filepath.Base(module.DexLocation)
240*333d2b36SAndroid Build Coastguard Worker	if filepath.Ext(base) == ".jar" {
241*333d2b36SAndroid Build Coastguard Worker		base = "javalib.jar"
242*333d2b36SAndroid Build Coastguard Worker	} else if filepath.Ext(base) == ".apk" {
243*333d2b36SAndroid Build Coastguard Worker		base = "package.apk"
244*333d2b36SAndroid Build Coastguard Worker	}
245*333d2b36SAndroid Build Coastguard Worker
246*333d2b36SAndroid Build Coastguard Worker	odexPath := module.BuildPath.InSameDir(ctx, "oat", arch.String(), pathtools.ReplaceExtension(base, "odex"))
247*333d2b36SAndroid Build Coastguard Worker	odexSymbolsPath := odexPath.ReplaceExtension(ctx, "symbols.odex")
248*333d2b36SAndroid Build Coastguard Worker	odexInstallPath := ToOdexPath(module.DexLocation, arch, module.ApexPartition)
249*333d2b36SAndroid Build Coastguard Worker	if odexOnSystemOther(module, global) {
250*333d2b36SAndroid Build Coastguard Worker		odexInstallPath = filepath.Join(SystemOtherPartition, odexInstallPath)
251*333d2b36SAndroid Build Coastguard Worker	}
252*333d2b36SAndroid Build Coastguard Worker
253*333d2b36SAndroid Build Coastguard Worker	vdexPath := odexPath.ReplaceExtension(ctx, "vdex")
254*333d2b36SAndroid Build Coastguard Worker	vdexInstallPath := pathtools.ReplaceExtension(odexInstallPath, "vdex")
255*333d2b36SAndroid Build Coastguard Worker
256*333d2b36SAndroid Build Coastguard Worker	invocationPath := odexPath.ReplaceExtension(ctx, "invocation")
257*333d2b36SAndroid Build Coastguard Worker
258*333d2b36SAndroid Build Coastguard Worker	systemServerJars := global.AllSystemServerJars(ctx)
259*333d2b36SAndroid Build Coastguard Worker	systemServerClasspathJars := global.AllSystemServerClasspathJars(ctx)
260*333d2b36SAndroid Build Coastguard Worker
261*333d2b36SAndroid Build Coastguard Worker	rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String()))
262*333d2b36SAndroid Build Coastguard Worker	rule.Command().FlagWithOutput("rm -f ", odexPath).
263*333d2b36SAndroid Build Coastguard Worker		FlagWithArg("rm -f ", odexSymbolsPath.String())
264*333d2b36SAndroid Build Coastguard Worker
265*333d2b36SAndroid Build Coastguard Worker	if jarIndex := systemServerJars.IndexOfJar(module.Name); jarIndex >= 0 {
266*333d2b36SAndroid Build Coastguard Worker		// System server jars should be dexpreopted together: class loader context of each jar
267*333d2b36SAndroid Build Coastguard Worker		// should include all preceding jars on the system server classpath.
268*333d2b36SAndroid Build Coastguard Worker
269*333d2b36SAndroid Build Coastguard Worker		var clcHost android.Paths
270*333d2b36SAndroid Build Coastguard Worker		var clcTarget []string
271*333d2b36SAndroid Build Coastguard Worker		endIndex := systemServerClasspathJars.IndexOfJar(module.Name)
272*333d2b36SAndroid Build Coastguard Worker		if endIndex < 0 {
273*333d2b36SAndroid Build Coastguard Worker			// The jar is a standalone one. Use the full classpath as the class loader context.
274*333d2b36SAndroid Build Coastguard Worker			endIndex = systemServerClasspathJars.Len()
275*333d2b36SAndroid Build Coastguard Worker		}
276*333d2b36SAndroid Build Coastguard Worker		for i := 0; i < endIndex; i++ {
277*333d2b36SAndroid Build Coastguard Worker			lib := systemServerClasspathJars.Jar(i)
278*333d2b36SAndroid Build Coastguard Worker			clcHost = append(clcHost, SystemServerDexJarHostPath(ctx, lib))
279*333d2b36SAndroid Build Coastguard Worker			clcTarget = append(clcTarget, GetSystemServerDexLocation(ctx, global, lib))
280*333d2b36SAndroid Build Coastguard Worker		}
281*333d2b36SAndroid Build Coastguard Worker
282*333d2b36SAndroid Build Coastguard Worker		if DexpreoptRunningInSoong && copyApexSystemServerJarDex {
283*333d2b36SAndroid Build Coastguard Worker			// Copy the system server jar to a predefined location where dex2oat will find it.
284*333d2b36SAndroid Build Coastguard Worker			dexPathHost := SystemServerDexJarHostPath(ctx, module.Name)
285*333d2b36SAndroid Build Coastguard Worker			rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String()))
286*333d2b36SAndroid Build Coastguard Worker			rule.Command().Text("cp -f").Input(module.DexPath).Output(dexPathHost)
287*333d2b36SAndroid Build Coastguard Worker		} else {
288*333d2b36SAndroid Build Coastguard Worker			// For Make modules the copy rule is generated in the makefiles, not in dexpreopt.sh.
289*333d2b36SAndroid Build Coastguard Worker			// This is necessary to expose the rule to Ninja, otherwise it has rules that depend on
290*333d2b36SAndroid Build Coastguard Worker			// the jar (namely, dexpreopt commands for all subsequent system server jars that have
291*333d2b36SAndroid Build Coastguard Worker			// this one in their class loader context), but no rule that creates it (because Ninja
292*333d2b36SAndroid Build Coastguard Worker			// cannot see the rule in the generated dexpreopt.sh script).
293*333d2b36SAndroid Build Coastguard Worker		}
294*333d2b36SAndroid Build Coastguard Worker
295*333d2b36SAndroid Build Coastguard Worker		clcHostString := "PCL[" + strings.Join(clcHost.Strings(), ":") + "]"
296*333d2b36SAndroid Build Coastguard Worker		clcTargetString := "PCL[" + strings.Join(clcTarget, ":") + "]"
297*333d2b36SAndroid Build Coastguard Worker
298*333d2b36SAndroid Build Coastguard Worker		if systemServerClasspathJars.ContainsJar(module.Name) {
299*333d2b36SAndroid Build Coastguard Worker			checkSystemServerOrder(ctx, jarIndex)
300*333d2b36SAndroid Build Coastguard Worker		} else {
301*333d2b36SAndroid Build Coastguard Worker			// Standalone jars are loaded by separate class loaders with SYSTEMSERVERCLASSPATH as the
302*333d2b36SAndroid Build Coastguard Worker			// parent.
303*333d2b36SAndroid Build Coastguard Worker			clcHostString = "PCL[];" + clcHostString
304*333d2b36SAndroid Build Coastguard Worker			clcTargetString = "PCL[];" + clcTargetString
305*333d2b36SAndroid Build Coastguard Worker		}
306*333d2b36SAndroid Build Coastguard Worker
307*333d2b36SAndroid Build Coastguard Worker		rule.Command().
308*333d2b36SAndroid Build Coastguard Worker			Text(`class_loader_context_arg=--class-loader-context="` + clcHostString + `"`).
309*333d2b36SAndroid Build Coastguard Worker			Implicits(clcHost).
310*333d2b36SAndroid Build Coastguard Worker			Text(`stored_class_loader_context_arg=--stored-class-loader-context="` + clcTargetString + `"`)
311*333d2b36SAndroid Build Coastguard Worker
312*333d2b36SAndroid Build Coastguard Worker	} else {
313*333d2b36SAndroid Build Coastguard Worker		// There are three categories of Java modules handled here:
314*333d2b36SAndroid Build Coastguard Worker		//
315*333d2b36SAndroid Build Coastguard Worker		// - Modules that have passed verify_uses_libraries check. They are AOT-compiled and
316*333d2b36SAndroid Build Coastguard Worker		//   expected to be loaded on device without CLC mismatch errors.
317*333d2b36SAndroid Build Coastguard Worker		//
318*333d2b36SAndroid Build Coastguard Worker		// - Modules that have failed the check in relaxed mode, so it didn't cause a build error.
319*333d2b36SAndroid Build Coastguard Worker		//   They are dexpreopted with "verify" filter and not AOT-compiled.
320*333d2b36SAndroid Build Coastguard Worker		//   TODO(b/132357300): ensure that CLC mismatch errors are ignored with "verify" filter.
321*333d2b36SAndroid Build Coastguard Worker		//
322*333d2b36SAndroid Build Coastguard Worker		// - Modules that didn't run the check. They are AOT-compiled, but it's unknown if they
323*333d2b36SAndroid Build Coastguard Worker		//   will have CLC mismatch errors on device (the check is disabled by default).
324*333d2b36SAndroid Build Coastguard Worker		//
325*333d2b36SAndroid Build Coastguard Worker		// TODO(b/132357300): enable the check by default and eliminate the last category, so that
326*333d2b36SAndroid Build Coastguard Worker		// no time/space is wasted on AOT-compiling modules that will fail CLC check on device.
327*333d2b36SAndroid Build Coastguard Worker
328*333d2b36SAndroid Build Coastguard Worker		var manifestOrApk android.Path
329*333d2b36SAndroid Build Coastguard Worker		if module.ManifestPath.Valid() {
330*333d2b36SAndroid Build Coastguard Worker			// Ok, there is an XML manifest.
331*333d2b36SAndroid Build Coastguard Worker			manifestOrApk = module.ManifestPath.Path()
332*333d2b36SAndroid Build Coastguard Worker		} else if filepath.Ext(base) == ".apk" {
333*333d2b36SAndroid Build Coastguard Worker			// Ok, there is is an APK with the manifest inside.
334*333d2b36SAndroid Build Coastguard Worker			manifestOrApk = module.DexPath
335*333d2b36SAndroid Build Coastguard Worker		}
336*333d2b36SAndroid Build Coastguard Worker
337*333d2b36SAndroid Build Coastguard Worker		// Generate command that saves target SDK version in a shell variable.
338*333d2b36SAndroid Build Coastguard Worker		if manifestOrApk == nil {
339*333d2b36SAndroid Build Coastguard Worker			// There is neither an XML manifest nor APK => nowhere to extract targetSdkVersion from.
340*333d2b36SAndroid Build Coastguard Worker			// Set the latest ("any") version: then construct_context will not add any compatibility
341*333d2b36SAndroid Build Coastguard Worker			// libraries (if this is incorrect, there will be a CLC mismatch and dexopt on device).
342*333d2b36SAndroid Build Coastguard Worker			rule.Command().Textf(`target_sdk_version=%d`, AnySdkVersion)
343*333d2b36SAndroid Build Coastguard Worker		} else {
344*333d2b36SAndroid Build Coastguard Worker			rule.Command().Text(`target_sdk_version="$(`).
345*333d2b36SAndroid Build Coastguard Worker				Tool(globalSoong.ManifestCheck).
346*333d2b36SAndroid Build Coastguard Worker				Flag("--extract-target-sdk-version").
347*333d2b36SAndroid Build Coastguard Worker				Input(manifestOrApk).
348*333d2b36SAndroid Build Coastguard Worker				FlagWithInput("--aapt ", globalSoong.Aapt).
349*333d2b36SAndroid Build Coastguard Worker				Text(`)"`)
350*333d2b36SAndroid Build Coastguard Worker		}
351*333d2b36SAndroid Build Coastguard Worker
352*333d2b36SAndroid Build Coastguard Worker		// Generate command that saves host and target class loader context in shell variables.
353*333d2b36SAndroid Build Coastguard Worker		_, paths := ComputeClassLoaderContextDependencies(module.ClassLoaderContexts)
354*333d2b36SAndroid Build Coastguard Worker		rule.Command().
355*333d2b36SAndroid Build Coastguard Worker			Text(`eval "$(`).Tool(globalSoong.ConstructContext).
356*333d2b36SAndroid Build Coastguard Worker			Text(` --target-sdk-version ${target_sdk_version}`).
357*333d2b36SAndroid Build Coastguard Worker			FlagWithArg("--context-json=", module.ClassLoaderContexts.DumpForFlag()).
358*333d2b36SAndroid Build Coastguard Worker			FlagWithInput("--product-packages=", productPackages).
359*333d2b36SAndroid Build Coastguard Worker			Implicits(paths).
360*333d2b36SAndroid Build Coastguard Worker			Text(`)"`)
361*333d2b36SAndroid Build Coastguard Worker	}
362*333d2b36SAndroid Build Coastguard Worker
363*333d2b36SAndroid Build Coastguard Worker	// Devices that do not have a product partition use a symlink from /product to /system/product.
364*333d2b36SAndroid Build Coastguard Worker	// Because on-device dexopt will see dex locations starting with /product, we change the paths
365*333d2b36SAndroid Build Coastguard Worker	// to mimic this behavior.
366*333d2b36SAndroid Build Coastguard Worker	dexLocationArg := module.DexLocation
367*333d2b36SAndroid Build Coastguard Worker	if strings.HasPrefix(dexLocationArg, "/system/product/") {
368*333d2b36SAndroid Build Coastguard Worker		dexLocationArg = strings.TrimPrefix(dexLocationArg, "/system")
369*333d2b36SAndroid Build Coastguard Worker	}
370*333d2b36SAndroid Build Coastguard Worker
371*333d2b36SAndroid Build Coastguard Worker	cmd := rule.Command().
372*333d2b36SAndroid Build Coastguard Worker		Text(`ANDROID_LOG_TAGS="*:e"`).
373*333d2b36SAndroid Build Coastguard Worker		Tool(globalSoong.Dex2oat).
374*333d2b36SAndroid Build Coastguard Worker		Flag("--avoid-storing-invocation").
375*333d2b36SAndroid Build Coastguard Worker		FlagWithOutput("--write-invocation-to=", invocationPath).ImplicitOutput(invocationPath).
376*333d2b36SAndroid Build Coastguard Worker		Flag("--runtime-arg").FlagWithArg("-Xms", global.Dex2oatXms).
377*333d2b36SAndroid Build Coastguard Worker		Flag("--runtime-arg").FlagWithArg("-Xmx", global.Dex2oatXmx).
378*333d2b36SAndroid Build Coastguard Worker		Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", module.PreoptBootClassPathDexFiles, ":").
379*333d2b36SAndroid Build Coastguard Worker		Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", module.PreoptBootClassPathDexLocations, ":").
380*333d2b36SAndroid Build Coastguard Worker		Flag("${class_loader_context_arg}").
381*333d2b36SAndroid Build Coastguard Worker		Flag("${stored_class_loader_context_arg}").
382*333d2b36SAndroid Build Coastguard Worker		FlagWithArg("--boot-image=", strings.Join(module.DexPreoptImageLocationsOnHost, ":")).Implicits(module.DexPreoptImagesDeps[archIdx].Paths()).
383*333d2b36SAndroid Build Coastguard Worker		FlagWithInput("--dex-file=", module.DexPath).
384*333d2b36SAndroid Build Coastguard Worker		FlagWithArg("--dex-location=", dexLocationArg).
385*333d2b36SAndroid Build Coastguard Worker		FlagWithOutput("--oat-file=", odexPath).ImplicitOutput(vdexPath).
386*333d2b36SAndroid Build Coastguard Worker		// Pass an empty directory, dex2oat shouldn't be reading arbitrary files
387*333d2b36SAndroid Build Coastguard Worker		FlagWithArg("--android-root=", global.EmptyDirectory).
388*333d2b36SAndroid Build Coastguard Worker		FlagWithArg("--instruction-set=", arch.String()).
389*333d2b36SAndroid Build Coastguard Worker		FlagWithArg("--instruction-set-variant=", global.CpuVariant[arch]).
390*333d2b36SAndroid Build Coastguard Worker		FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch]).
391*333d2b36SAndroid Build Coastguard Worker		FlagWithOutput("--oat-symbols=", odexSymbolsPath).
392*333d2b36SAndroid Build Coastguard Worker		Flag("--generate-debug-info").
393*333d2b36SAndroid Build Coastguard Worker		Flag("--strip").
394*333d2b36SAndroid Build Coastguard Worker		Flag("--generate-build-id").
395*333d2b36SAndroid Build Coastguard Worker		Flag("--abort-on-hard-verifier-error").
396*333d2b36SAndroid Build Coastguard Worker		Flag("--force-determinism").
397*333d2b36SAndroid Build Coastguard Worker		FlagWithArg("--no-inline-from=", "core-oj.jar").
398*333d2b36SAndroid Build Coastguard Worker		Text("$(cat").Input(globalSoong.UffdGcFlag).Text(")")
399*333d2b36SAndroid Build Coastguard Worker
400*333d2b36SAndroid Build Coastguard Worker	var preoptFlags []string
401*333d2b36SAndroid Build Coastguard Worker	if len(module.PreoptFlags) > 0 {
402*333d2b36SAndroid Build Coastguard Worker		preoptFlags = module.PreoptFlags
403*333d2b36SAndroid Build Coastguard Worker	} else if len(global.PreoptFlags) > 0 {
404*333d2b36SAndroid Build Coastguard Worker		preoptFlags = global.PreoptFlags
405*333d2b36SAndroid Build Coastguard Worker	}
406*333d2b36SAndroid Build Coastguard Worker
407*333d2b36SAndroid Build Coastguard Worker	if len(preoptFlags) > 0 {
408*333d2b36SAndroid Build Coastguard Worker		cmd.Text(strings.Join(preoptFlags, " "))
409*333d2b36SAndroid Build Coastguard Worker	}
410*333d2b36SAndroid Build Coastguard Worker
411*333d2b36SAndroid Build Coastguard Worker	if module.UncompressedDex {
412*333d2b36SAndroid Build Coastguard Worker		cmd.FlagWithArg("--copy-dex-files=", "false")
413*333d2b36SAndroid Build Coastguard Worker	}
414*333d2b36SAndroid Build Coastguard Worker
415*333d2b36SAndroid Build Coastguard Worker	if !android.PrefixInList(preoptFlags, "--compiler-filter=") {
416*333d2b36SAndroid Build Coastguard Worker		var compilerFilter string
417*333d2b36SAndroid Build Coastguard Worker		if systemServerJars.ContainsJar(module.Name) {
418*333d2b36SAndroid Build Coastguard Worker			if global.SystemServerCompilerFilter != "" {
419*333d2b36SAndroid Build Coastguard Worker				// Use the product option if it is set.
420*333d2b36SAndroid Build Coastguard Worker				compilerFilter = global.SystemServerCompilerFilter
421*333d2b36SAndroid Build Coastguard Worker			} else if profile != nil {
422*333d2b36SAndroid Build Coastguard Worker				// Use "speed-profile" for system server jars that have a profile.
423*333d2b36SAndroid Build Coastguard Worker				compilerFilter = "speed-profile"
424*333d2b36SAndroid Build Coastguard Worker			} else {
425*333d2b36SAndroid Build Coastguard Worker				// Use "speed" for system server jars that do not have a profile.
426*333d2b36SAndroid Build Coastguard Worker				compilerFilter = "speed"
427*333d2b36SAndroid Build Coastguard Worker			}
428*333d2b36SAndroid Build Coastguard Worker		} else if contains(global.SpeedApps, module.Name) || contains(global.SystemServerApps, module.Name) {
429*333d2b36SAndroid Build Coastguard Worker			// Apps loaded into system server, and apps the product default to being compiled with the
430*333d2b36SAndroid Build Coastguard Worker			// 'speed' compiler filter.
431*333d2b36SAndroid Build Coastguard Worker			compilerFilter = "speed"
432*333d2b36SAndroid Build Coastguard Worker		} else if profile != nil {
433*333d2b36SAndroid Build Coastguard Worker			// For non system server jars, use speed-profile when we have a profile.
434*333d2b36SAndroid Build Coastguard Worker			compilerFilter = "speed-profile"
435*333d2b36SAndroid Build Coastguard Worker		} else if global.DefaultCompilerFilter != "" {
436*333d2b36SAndroid Build Coastguard Worker			compilerFilter = global.DefaultCompilerFilter
437*333d2b36SAndroid Build Coastguard Worker		} else {
438*333d2b36SAndroid Build Coastguard Worker			compilerFilter = "quicken"
439*333d2b36SAndroid Build Coastguard Worker		}
440*333d2b36SAndroid Build Coastguard Worker		if module.EnforceUsesLibraries {
441*333d2b36SAndroid Build Coastguard Worker			// If the verify_uses_libraries check failed (in this case status file contains a
442*333d2b36SAndroid Build Coastguard Worker			// non-empty error message), then use "verify" compiler filter to avoid compiling any
443*333d2b36SAndroid Build Coastguard Worker			// code (it would be rejected on device because of a class loader context mismatch).
444*333d2b36SAndroid Build Coastguard Worker			cmd.Text("--compiler-filter=$(if test -s ").
445*333d2b36SAndroid Build Coastguard Worker				Input(module.EnforceUsesLibrariesStatusFile).
446*333d2b36SAndroid Build Coastguard Worker				Text(" ; then echo verify ; else echo " + compilerFilter + " ; fi)")
447*333d2b36SAndroid Build Coastguard Worker		} else {
448*333d2b36SAndroid Build Coastguard Worker			cmd.FlagWithArg("--compiler-filter=", compilerFilter)
449*333d2b36SAndroid Build Coastguard Worker		}
450*333d2b36SAndroid Build Coastguard Worker	}
451*333d2b36SAndroid Build Coastguard Worker
452*333d2b36SAndroid Build Coastguard Worker	if generateDM {
453*333d2b36SAndroid Build Coastguard Worker		cmd.FlagWithArg("--copy-dex-files=", "false")
454*333d2b36SAndroid Build Coastguard Worker		dmPath := module.BuildPath.InSameDir(ctx, "generated.dm")
455*333d2b36SAndroid Build Coastguard Worker		dmInstalledPath := pathtools.ReplaceExtension(module.DexLocation, "dm")
456*333d2b36SAndroid Build Coastguard Worker		tmpPath := module.BuildPath.InSameDir(ctx, "primary.vdex")
457*333d2b36SAndroid Build Coastguard Worker		rule.Command().Text("cp -f").Input(vdexPath).Output(tmpPath)
458*333d2b36SAndroid Build Coastguard Worker		rule.Command().Tool(globalSoong.SoongZip).
459*333d2b36SAndroid Build Coastguard Worker			FlagWithArg("-L", "9").
460*333d2b36SAndroid Build Coastguard Worker			FlagWithOutput("-o", dmPath).
461*333d2b36SAndroid Build Coastguard Worker			Flag("-j").
462*333d2b36SAndroid Build Coastguard Worker			Input(tmpPath)
463*333d2b36SAndroid Build Coastguard Worker		rule.Install(dmPath, dmInstalledPath)
464*333d2b36SAndroid Build Coastguard Worker	}
465*333d2b36SAndroid Build Coastguard Worker
466*333d2b36SAndroid Build Coastguard Worker	// By default, emit debug info.
467*333d2b36SAndroid Build Coastguard Worker	debugInfo := true
468*333d2b36SAndroid Build Coastguard Worker	if global.NoDebugInfo {
469*333d2b36SAndroid Build Coastguard Worker		// If the global setting suppresses mini-debug-info, disable it.
470*333d2b36SAndroid Build Coastguard Worker		debugInfo = false
471*333d2b36SAndroid Build Coastguard Worker	}
472*333d2b36SAndroid Build Coastguard Worker
473*333d2b36SAndroid Build Coastguard Worker	// PRODUCT_SYSTEM_SERVER_DEBUG_INFO overrides WITH_DEXPREOPT_DEBUG_INFO.
474*333d2b36SAndroid Build Coastguard Worker	// PRODUCT_OTHER_JAVA_DEBUG_INFO overrides WITH_DEXPREOPT_DEBUG_INFO.
475*333d2b36SAndroid Build Coastguard Worker	if systemServerJars.ContainsJar(module.Name) {
476*333d2b36SAndroid Build Coastguard Worker		if global.AlwaysSystemServerDebugInfo {
477*333d2b36SAndroid Build Coastguard Worker			debugInfo = true
478*333d2b36SAndroid Build Coastguard Worker		} else if global.NeverSystemServerDebugInfo {
479*333d2b36SAndroid Build Coastguard Worker			debugInfo = false
480*333d2b36SAndroid Build Coastguard Worker		}
481*333d2b36SAndroid Build Coastguard Worker	} else {
482*333d2b36SAndroid Build Coastguard Worker		if global.AlwaysOtherDebugInfo {
483*333d2b36SAndroid Build Coastguard Worker			debugInfo = true
484*333d2b36SAndroid Build Coastguard Worker		} else if global.NeverOtherDebugInfo {
485*333d2b36SAndroid Build Coastguard Worker			debugInfo = false
486*333d2b36SAndroid Build Coastguard Worker		}
487*333d2b36SAndroid Build Coastguard Worker	}
488*333d2b36SAndroid Build Coastguard Worker
489*333d2b36SAndroid Build Coastguard Worker	if debugInfo {
490*333d2b36SAndroid Build Coastguard Worker		cmd.Flag("--generate-mini-debug-info")
491*333d2b36SAndroid Build Coastguard Worker	} else {
492*333d2b36SAndroid Build Coastguard Worker		cmd.Flag("--no-generate-mini-debug-info")
493*333d2b36SAndroid Build Coastguard Worker	}
494*333d2b36SAndroid Build Coastguard Worker
495*333d2b36SAndroid Build Coastguard Worker	// Set the compiler reason to 'prebuilt' to identify the oat files produced
496*333d2b36SAndroid Build Coastguard Worker	// during the build, as opposed to compiled on the device.
497*333d2b36SAndroid Build Coastguard Worker	cmd.FlagWithArg("--compilation-reason=", "prebuilt")
498*333d2b36SAndroid Build Coastguard Worker
499*333d2b36SAndroid Build Coastguard Worker	if appImage {
500*333d2b36SAndroid Build Coastguard Worker		appImagePath := odexPath.ReplaceExtension(ctx, "art")
501*333d2b36SAndroid Build Coastguard Worker		appImageInstallPath := pathtools.ReplaceExtension(odexInstallPath, "art")
502*333d2b36SAndroid Build Coastguard Worker		cmd.FlagWithOutput("--app-image-file=", appImagePath).
503*333d2b36SAndroid Build Coastguard Worker			FlagWithArg("--image-format=", "lz4")
504*333d2b36SAndroid Build Coastguard Worker		if !global.DontResolveStartupStrings {
505*333d2b36SAndroid Build Coastguard Worker			cmd.FlagWithArg("--resolve-startup-const-strings=", "true")
506*333d2b36SAndroid Build Coastguard Worker		}
507*333d2b36SAndroid Build Coastguard Worker		rule.Install(appImagePath, appImageInstallPath)
508*333d2b36SAndroid Build Coastguard Worker	}
509*333d2b36SAndroid Build Coastguard Worker
510*333d2b36SAndroid Build Coastguard Worker	if profile != nil {
511*333d2b36SAndroid Build Coastguard Worker		cmd.FlagWithInput("--profile-file=", profile)
512*333d2b36SAndroid Build Coastguard Worker	}
513*333d2b36SAndroid Build Coastguard Worker
514*333d2b36SAndroid Build Coastguard Worker	rule.Install(odexPath, odexInstallPath)
515*333d2b36SAndroid Build Coastguard Worker	rule.Install(vdexPath, vdexInstallPath)
516*333d2b36SAndroid Build Coastguard Worker}
517*333d2b36SAndroid Build Coastguard Worker
518*333d2b36SAndroid Build Coastguard Workerfunc shouldGenerateDM(module *ModuleConfig, global *GlobalConfig) bool {
519*333d2b36SAndroid Build Coastguard Worker	// Generating DM files only makes sense for verify, avoid doing for non verify compiler filter APKs.
520*333d2b36SAndroid Build Coastguard Worker	// No reason to use a dm file if the dex is already uncompressed.
521*333d2b36SAndroid Build Coastguard Worker	return global.GenerateDMFiles && !module.UncompressedDex &&
522*333d2b36SAndroid Build Coastguard Worker		contains(module.PreoptFlags, "--compiler-filter=verify")
523*333d2b36SAndroid Build Coastguard Worker}
524*333d2b36SAndroid Build Coastguard Worker
525*333d2b36SAndroid Build Coastguard Workerfunc OdexOnSystemOtherByName(name string, dexLocation string, global *GlobalConfig) bool {
526*333d2b36SAndroid Build Coastguard Worker	if !global.HasSystemOther {
527*333d2b36SAndroid Build Coastguard Worker		return false
528*333d2b36SAndroid Build Coastguard Worker	}
529*333d2b36SAndroid Build Coastguard Worker
530*333d2b36SAndroid Build Coastguard Worker	if global.SanitizeLite {
531*333d2b36SAndroid Build Coastguard Worker		return false
532*333d2b36SAndroid Build Coastguard Worker	}
533*333d2b36SAndroid Build Coastguard Worker
534*333d2b36SAndroid Build Coastguard Worker	if contains(global.SystemServerApps, name) {
535*333d2b36SAndroid Build Coastguard Worker		return false
536*333d2b36SAndroid Build Coastguard Worker	}
537*333d2b36SAndroid Build Coastguard Worker
538*333d2b36SAndroid Build Coastguard Worker	for _, f := range global.PatternsOnSystemOther {
539*333d2b36SAndroid Build Coastguard Worker		if makefileMatch("/"+f, dexLocation) || makefileMatch(filepath.Join(SystemPartition, f), dexLocation) {
540*333d2b36SAndroid Build Coastguard Worker			return true
541*333d2b36SAndroid Build Coastguard Worker		}
542*333d2b36SAndroid Build Coastguard Worker	}
543*333d2b36SAndroid Build Coastguard Worker
544*333d2b36SAndroid Build Coastguard Worker	return false
545*333d2b36SAndroid Build Coastguard Worker}
546*333d2b36SAndroid Build Coastguard Worker
547*333d2b36SAndroid Build Coastguard Workerfunc odexOnSystemOther(module *ModuleConfig, global *GlobalConfig) bool {
548*333d2b36SAndroid Build Coastguard Worker	return OdexOnSystemOtherByName(module.Name, module.DexLocation, global)
549*333d2b36SAndroid Build Coastguard Worker}
550*333d2b36SAndroid Build Coastguard Worker
551*333d2b36SAndroid Build Coastguard Worker// PathToLocation converts .../system/framework/arm64/boot.art to .../system/framework/boot.art
552*333d2b36SAndroid Build Coastguard Workerfunc PathToLocation(path android.Path, arch android.ArchType) string {
553*333d2b36SAndroid Build Coastguard Worker	return PathStringToLocation(path.String(), arch)
554*333d2b36SAndroid Build Coastguard Worker}
555*333d2b36SAndroid Build Coastguard Worker
556*333d2b36SAndroid Build Coastguard Worker// PathStringToLocation converts .../system/framework/arm64/boot.art to .../system/framework/boot.art
557*333d2b36SAndroid Build Coastguard Workerfunc PathStringToLocation(path string, arch android.ArchType) string {
558*333d2b36SAndroid Build Coastguard Worker	pathArch := filepath.Base(filepath.Dir(path))
559*333d2b36SAndroid Build Coastguard Worker	if pathArch != arch.String() {
560*333d2b36SAndroid Build Coastguard Worker		panic(fmt.Errorf("last directory in %q must be %q", path, arch.String()))
561*333d2b36SAndroid Build Coastguard Worker	}
562*333d2b36SAndroid Build Coastguard Worker	return filepath.Join(filepath.Dir(filepath.Dir(path)), filepath.Base(path))
563*333d2b36SAndroid Build Coastguard Worker}
564*333d2b36SAndroid Build Coastguard Worker
565*333d2b36SAndroid Build Coastguard Workerfunc makefileMatch(pattern, s string) bool {
566*333d2b36SAndroid Build Coastguard Worker	percent := strings.IndexByte(pattern, '%')
567*333d2b36SAndroid Build Coastguard Worker	switch percent {
568*333d2b36SAndroid Build Coastguard Worker	case -1:
569*333d2b36SAndroid Build Coastguard Worker		return pattern == s
570*333d2b36SAndroid Build Coastguard Worker	case len(pattern) - 1:
571*333d2b36SAndroid Build Coastguard Worker		return strings.HasPrefix(s, pattern[:len(pattern)-1])
572*333d2b36SAndroid Build Coastguard Worker	default:
573*333d2b36SAndroid Build Coastguard Worker		panic(fmt.Errorf("unsupported makefile pattern %q", pattern))
574*333d2b36SAndroid Build Coastguard Worker	}
575*333d2b36SAndroid Build Coastguard Worker}
576*333d2b36SAndroid Build Coastguard Worker
577*333d2b36SAndroid Build Coastguard Worker// A predefined location for the system server dex jars. This is needed in order to generate
578*333d2b36SAndroid Build Coastguard Worker// class loader context for dex2oat, as the path to the jar in the Soong module may be unknown
579*333d2b36SAndroid Build Coastguard Worker// at that time (Soong processes the jars in dependency order, which may be different from the
580*333d2b36SAndroid Build Coastguard Worker// the system server classpath order).
581*333d2b36SAndroid Build Coastguard Workerfunc SystemServerDexJarHostPath(ctx android.PathContext, jar string) android.OutputPath {
582*333d2b36SAndroid Build Coastguard Worker	if DexpreoptRunningInSoong {
583*333d2b36SAndroid Build Coastguard Worker		// Soong module, just use the default output directory $OUT/soong.
584*333d2b36SAndroid Build Coastguard Worker		return android.PathForOutput(ctx, "system_server_dexjars", jar+".jar")
585*333d2b36SAndroid Build Coastguard Worker	} else {
586*333d2b36SAndroid Build Coastguard Worker		// Make module, default output directory is $OUT (passed via the "null config" created
587*333d2b36SAndroid Build Coastguard Worker		// by dexpreopt_gen). Append Soong subdirectory to match Soong module paths.
588*333d2b36SAndroid Build Coastguard Worker		return android.PathForOutput(ctx, "soong", "system_server_dexjars", jar+".jar")
589*333d2b36SAndroid Build Coastguard Worker	}
590*333d2b36SAndroid Build Coastguard Worker}
591*333d2b36SAndroid Build Coastguard Worker
592*333d2b36SAndroid Build Coastguard Worker// Check the order of jars on the system server classpath and give a warning/error if a jar precedes
593*333d2b36SAndroid Build Coastguard Worker// one of its dependencies. This is not an error, but a missed optimization, as dexpreopt won't
594*333d2b36SAndroid Build Coastguard Worker// have the dependency jar in the class loader context, and it won't be able to resolve any
595*333d2b36SAndroid Build Coastguard Worker// references to its classes and methods.
596*333d2b36SAndroid Build Coastguard Workerfunc checkSystemServerOrder(ctx android.PathContext, jarIndex int) {
597*333d2b36SAndroid Build Coastguard Worker	mctx, isModule := ctx.(android.ModuleContext)
598*333d2b36SAndroid Build Coastguard Worker	if isModule {
599*333d2b36SAndroid Build Coastguard Worker		config := GetGlobalConfig(ctx)
600*333d2b36SAndroid Build Coastguard Worker		jars := config.AllSystemServerClasspathJars(ctx)
601*333d2b36SAndroid Build Coastguard Worker		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
602*333d2b36SAndroid Build Coastguard Worker			depIndex := jars.IndexOfJar(dep.Name())
603*333d2b36SAndroid Build Coastguard Worker			if jarIndex < depIndex && !config.BrokenSuboptimalOrderOfSystemServerJars {
604*333d2b36SAndroid Build Coastguard Worker				jar := jars.Jar(jarIndex)
605*333d2b36SAndroid Build Coastguard Worker				dep := jars.Jar(depIndex)
606*333d2b36SAndroid Build Coastguard Worker				mctx.ModuleErrorf("non-optimal order of jars on the system server classpath:"+
607*333d2b36SAndroid Build Coastguard Worker					" '%s' precedes its dependency '%s', so dexpreopt is unable to resolve any"+
608*333d2b36SAndroid Build Coastguard Worker					" references from '%s' to '%s'.\n", jar, dep, jar, dep)
609*333d2b36SAndroid Build Coastguard Worker			}
610*333d2b36SAndroid Build Coastguard Worker			return true
611*333d2b36SAndroid Build Coastguard Worker		})
612*333d2b36SAndroid Build Coastguard Worker	}
613*333d2b36SAndroid Build Coastguard Worker}
614*333d2b36SAndroid Build Coastguard Worker
615*333d2b36SAndroid Build Coastguard Worker// Returns path to a file containing the reult of verify_uses_libraries check (empty if the check
616*333d2b36SAndroid Build Coastguard Worker// has succeeded, or an error message if it failed).
617*333d2b36SAndroid Build Coastguard Workerfunc UsesLibrariesStatusFile(ctx android.ModuleContext) android.WritablePath {
618*333d2b36SAndroid Build Coastguard Worker	return android.PathForModuleOut(ctx, "enforce_uses_libraries.status")
619*333d2b36SAndroid Build Coastguard Worker}
620*333d2b36SAndroid Build Coastguard Worker
621*333d2b36SAndroid Build Coastguard Workerfunc contains(l []string, s string) bool {
622*333d2b36SAndroid Build Coastguard Worker	for _, e := range l {
623*333d2b36SAndroid Build Coastguard Worker		if e == s {
624*333d2b36SAndroid Build Coastguard Worker			return true
625*333d2b36SAndroid Build Coastguard Worker		}
626*333d2b36SAndroid Build Coastguard Worker	}
627*333d2b36SAndroid Build Coastguard Worker	return false
628*333d2b36SAndroid Build Coastguard Worker}
629