1// Copyright (C) 2016 The Android Open Source Project
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 art
16
17import (
18	"fmt"
19	"log"
20	"path/filepath"
21	"strings"
22	"sync"
23
24	"github.com/google/blueprint/proptools"
25
26	"android/soong/android"
27	"android/soong/apex"
28	"android/soong/cc"
29	"android/soong/cc/config"
30)
31
32var supportedArches = []string{"arm", "arm64", "x86", "x86_64"}
33
34func globalFlags(ctx android.LoadHookContext) ([]string, []string) {
35	var cflags []string
36	var asflags []string
37
38	opt := ctx.Config().GetenvWithDefault("ART_NDEBUG_OPT_FLAG", "-O3")
39	cflags = append(cflags, opt)
40
41	tlab := false
42
43	gcType := ctx.Config().GetenvWithDefault("ART_DEFAULT_GC_TYPE", "CMS")
44
45	if ctx.Config().IsEnvTrue("ART_TEST_DEBUG_GC") {
46		gcType = "SS"
47		tlab = true
48	}
49
50	cflags = append(cflags, "-DART_DEFAULT_GC_TYPE_IS_"+gcType)
51	if tlab {
52		cflags = append(cflags, "-DART_USE_TLAB=1")
53	}
54
55	if ctx.Config().IsEnvTrue("ART_HEAP_POISONING") {
56		cflags = append(cflags, "-DART_HEAP_POISONING=1")
57		asflags = append(asflags, "-DART_HEAP_POISONING=1")
58	}
59	if ctx.Config().IsEnvTrue("ART_USE_CXX_INTERPRETER") {
60		cflags = append(cflags, "-DART_USE_CXX_INTERPRETER=1")
61	}
62
63	if !ctx.Config().IsEnvFalse("ART_USE_READ_BARRIER") && ctx.Config().ArtUseReadBarrier() {
64		// Used to change the read barrier type. Valid values are BAKER, BROOKS,
65		// TABLELOOKUP. The default is BAKER.
66		barrierType := ctx.Config().GetenvWithDefault("ART_READ_BARRIER_TYPE", "BAKER")
67		cflags = append(cflags,
68			"-DART_USE_READ_BARRIER=1",
69			"-DART_READ_BARRIER_TYPE_IS_"+barrierType+"=1")
70		asflags = append(asflags,
71			"-DART_USE_READ_BARRIER=1",
72			"-DART_READ_BARRIER_TYPE_IS_"+barrierType+"=1")
73	}
74
75	if !ctx.Config().IsEnvFalse("ART_USE_GENERATIONAL_CC") {
76		cflags = append(cflags, "-DART_USE_GENERATIONAL_CC=1")
77	}
78
79	cdexLevel := ctx.Config().GetenvWithDefault("ART_DEFAULT_COMPACT_DEX_LEVEL", "fast")
80	cflags = append(cflags, "-DART_DEFAULT_COMPACT_DEX_LEVEL="+cdexLevel)
81
82	// We need larger stack overflow guards for ASAN, as the compiled code will have
83	// larger frame sizes. For simplicity, just use global not-target-specific cflags.
84	// Note: We increase this for both debug and non-debug, as the overflow gap will
85	//       be compiled into managed code. We always preopt (and build core images) with
86	//       the debug version. So make the gap consistent (and adjust for the worst).
87	if len(ctx.Config().SanitizeDevice()) > 0 || len(ctx.Config().SanitizeHost()) > 0 {
88		cflags = append(cflags,
89			"-DART_STACK_OVERFLOW_GAP_arm=8192",
90			"-DART_STACK_OVERFLOW_GAP_arm64=16384",
91			"-DART_STACK_OVERFLOW_GAP_x86=16384",
92			"-DART_STACK_OVERFLOW_GAP_x86_64=20480")
93	} else {
94		cflags = append(cflags,
95			"-DART_STACK_OVERFLOW_GAP_arm=8192",
96			"-DART_STACK_OVERFLOW_GAP_arm64=8192",
97			"-DART_STACK_OVERFLOW_GAP_x86=8192",
98			"-DART_STACK_OVERFLOW_GAP_x86_64=8192")
99	}
100
101	if ctx.Config().IsEnvTrue("ART_ENABLE_ADDRESS_SANITIZER") {
102		// Used to enable full sanitization, i.e., user poisoning, under ASAN.
103		cflags = append(cflags, "-DART_ENABLE_ADDRESS_SANITIZER=1")
104		asflags = append(asflags, "-DART_ENABLE_ADDRESS_SANITIZER=1")
105	}
106
107	if !ctx.Config().IsEnvFalse("USE_D8_DESUGAR") {
108		cflags = append(cflags, "-DUSE_D8_DESUGAR=1")
109	}
110
111	return cflags, asflags
112}
113
114func debugFlags(ctx android.LoadHookContext) []string {
115	var cflags []string
116
117	opt := ctx.Config().GetenvWithDefault("ART_DEBUG_OPT_FLAG", "-O2")
118	cflags = append(cflags, opt)
119
120	return cflags
121}
122
123func deviceFlags(ctx android.LoadHookContext) []string {
124	var cflags []string
125	deviceFrameSizeLimit := 1736
126	if len(ctx.Config().SanitizeDevice()) > 0 {
127		deviceFrameSizeLimit = 7400
128	}
129	cflags = append(cflags,
130		fmt.Sprintf("-Wframe-larger-than=%d", deviceFrameSizeLimit),
131		fmt.Sprintf("-DART_FRAME_SIZE_LIMIT=%d", deviceFrameSizeLimit),
132	)
133
134	cflags = append(cflags, "-DART_BASE_ADDRESS="+ctx.Config().LibartImgDeviceBaseAddress())
135	minDelta := ctx.Config().GetenvWithDefault("LIBART_IMG_TARGET_MIN_BASE_ADDRESS_DELTA", "-0x1000000")
136	maxDelta := ctx.Config().GetenvWithDefault("LIBART_IMG_TARGET_MAX_BASE_ADDRESS_DELTA", "0x1000000")
137	cflags = append(cflags, "-DART_BASE_ADDRESS_MIN_DELTA="+minDelta)
138	cflags = append(cflags, "-DART_BASE_ADDRESS_MAX_DELTA="+maxDelta)
139
140	return cflags
141}
142
143func hostFlags(ctx android.LoadHookContext) []string {
144	var cflags []string
145	hostFrameSizeLimit := 1736
146	if len(ctx.Config().SanitizeHost()) > 0 {
147		// art/test/137-cfi/cfi.cc
148		// error: stack frame size of 1944 bytes in function 'Java_Main_unwindInProcess'
149		hostFrameSizeLimit = 6400
150	}
151	cflags = append(cflags,
152		fmt.Sprintf("-Wframe-larger-than=%d", hostFrameSizeLimit),
153		fmt.Sprintf("-DART_FRAME_SIZE_LIMIT=%d", hostFrameSizeLimit),
154	)
155
156	cflags = append(cflags, "-DART_BASE_ADDRESS="+ctx.Config().LibartImgHostBaseAddress())
157	minDelta := ctx.Config().GetenvWithDefault("LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA", "-0x1000000")
158	maxDelta := ctx.Config().GetenvWithDefault("LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA", "0x1000000")
159	cflags = append(cflags, "-DART_BASE_ADDRESS_MIN_DELTA="+minDelta)
160	cflags = append(cflags, "-DART_BASE_ADDRESS_MAX_DELTA="+maxDelta)
161
162	if len(ctx.Config().SanitizeHost()) > 0 && !ctx.Config().IsEnvFalse("ART_ENABLE_ADDRESS_SANITIZER") {
163		// We enable full sanitization on the host by default.
164		cflags = append(cflags, "-DART_ENABLE_ADDRESS_SANITIZER=1")
165	}
166
167	clang_path := filepath.Join(config.ClangDefaultBase, ctx.Config().PrebuiltOS(), config.ClangDefaultVersion)
168	cflags = append(cflags, "-DART_CLANG_PATH=\""+clang_path+"\"")
169
170	return cflags
171}
172
173func globalDefaults(ctx android.LoadHookContext) {
174	type props struct {
175		Target struct {
176			Android struct {
177				Cflags []string
178			}
179			Host struct {
180				Cflags []string
181			}
182		}
183		Cflags   []string
184		Asflags  []string
185		Sanitize struct {
186			Recover []string
187		}
188	}
189
190	p := &props{}
191	p.Cflags, p.Asflags = globalFlags(ctx)
192	p.Target.Android.Cflags = deviceFlags(ctx)
193	p.Target.Host.Cflags = hostFlags(ctx)
194
195	if ctx.Config().IsEnvTrue("ART_DEX_FILE_ACCESS_TRACKING") {
196		p.Cflags = append(p.Cflags, "-DART_DEX_FILE_ACCESS_TRACKING")
197		p.Sanitize.Recover = []string{
198			"address",
199		}
200	}
201
202	ctx.AppendProperties(p)
203}
204
205// Hook that adds flags that are implicit for all cc_art_* modules.
206func addImplicitFlags(ctx android.LoadHookContext) {
207	type props struct {
208		Target struct {
209			Android struct {
210				Cflags []string
211			}
212		}
213	}
214
215	p := &props{}
216	if ctx.Config().IsEnvTrue("ART_TARGET_LINUX") {
217		p.Target.Android.Cflags = []string{"-DART_TARGET", "-DART_TARGET_LINUX"}
218	} else {
219		p.Target.Android.Cflags = []string{"-DART_TARGET", "-DART_TARGET_ANDROID"}
220	}
221
222	ctx.AppendProperties(p)
223}
224
225func debugDefaults(ctx android.LoadHookContext) {
226	type props struct {
227		Cflags []string
228	}
229
230	p := &props{}
231	p.Cflags = debugFlags(ctx)
232	ctx.AppendProperties(p)
233}
234
235func customLinker(ctx android.LoadHookContext) {
236	linker := ctx.Config().Getenv("CUSTOM_TARGET_LINKER")
237	type props struct {
238		DynamicLinker string
239	}
240
241	p := &props{}
242	if linker != "" {
243		p.DynamicLinker = linker
244	}
245
246	ctx.AppendProperties(p)
247}
248
249func prefer32Bit(ctx android.LoadHookContext) {
250	type props struct {
251		Target struct {
252			Host struct {
253				Compile_multilib *string
254			}
255		}
256	}
257
258	p := &props{}
259	if ctx.Config().IsEnvTrue("HOST_PREFER_32_BIT") {
260		p.Target.Host.Compile_multilib = proptools.StringPtr("prefer32")
261	}
262
263	// Prepend to make it overridable in the blueprints. Note that it doesn't work
264	// to override the property in a cc_defaults module.
265	ctx.PrependProperties(p)
266}
267
268var testMapKey = android.NewOnceKey("artTests")
269
270func testMap(config android.Config) map[string][]string {
271	return config.Once(testMapKey, func() interface{} {
272		return make(map[string][]string)
273	}).(map[string][]string)
274}
275
276func testInstall(ctx android.InstallHookContext) {
277	testMap := testMap(ctx.Config())
278
279	var name string
280	if ctx.Host() {
281		name = "host_"
282	} else {
283		name = "device_"
284	}
285	name += ctx.Arch().ArchType.String() + "_" + ctx.ModuleName()
286
287	artTestMutex.Lock()
288	defer artTestMutex.Unlock()
289
290	tests := testMap[name]
291	tests = append(tests, ctx.Path().ToMakePath().String())
292	testMap[name] = tests
293}
294
295var testcasesContentKey = android.NewOnceKey("artTestcasesContent")
296
297func testcasesContent(config android.Config) map[string]string {
298	return config.Once(testcasesContentKey, func() interface{} {
299		return make(map[string]string)
300	}).(map[string]string)
301}
302
303// Binaries and libraries also need to be copied in the testcases directory for
304// running tests on host.  This method adds module to the list of needed files.
305// The 'key' is the file in testcases and 'value' is the path to copy it from.
306// The actual copy will be done in make since soong does not do installations.
307func addTestcasesFile(ctx android.InstallHookContext) {
308	if ctx.Os() != android.BuildOs || ctx.Module().IsSkipInstall() {
309		return
310	}
311
312	testcasesContent := testcasesContent(ctx.Config())
313
314	artTestMutex.Lock()
315	defer artTestMutex.Unlock()
316
317	src := ctx.SrcPath().String()
318	path := strings.Split(ctx.Path().ToMakePath().String(), "/")
319	// Keep last two parts of the install path (e.g. bin/dex2oat).
320	dst := strings.Join(path[len(path)-2:], "/")
321	if oldSrc, ok := testcasesContent[dst]; ok {
322		ctx.ModuleErrorf("Conflicting sources for %s: %s and %s", dst, oldSrc, src)
323	}
324	testcasesContent[dst] = src
325}
326
327var artTestMutex sync.Mutex
328
329func init() {
330	artModuleTypes := []string{
331		"art_cc_library",
332		"art_cc_library_static",
333		"art_cc_binary",
334		"art_cc_test",
335		"art_cc_test_library",
336		"art_cc_defaults",
337		"libart_cc_defaults",
338		"libart_static_cc_defaults",
339		"art_global_defaults",
340		"art_debug_defaults",
341		"art_apex_test_host",
342	}
343	android.AddNeverAllowRules(
344		android.NeverAllow().
345			NotIn("art", "external/vixl").
346			ModuleType(artModuleTypes...))
347
348	android.RegisterModuleType("art_cc_library", artLibrary)
349	android.RegisterModuleType("art_cc_library_static", artStaticLibrary)
350	android.RegisterModuleType("art_cc_binary", artBinary)
351	android.RegisterModuleType("art_cc_test", artTest)
352	android.RegisterModuleType("art_cc_test_library", artTestLibrary)
353	android.RegisterModuleType("art_cc_defaults", artDefaultsFactory)
354	android.RegisterModuleType("libart_cc_defaults", libartDefaultsFactory)
355	android.RegisterModuleType("libart_static_cc_defaults", libartStaticDefaultsFactory)
356	android.RegisterModuleType("art_global_defaults", artGlobalDefaultsFactory)
357	android.RegisterModuleType("art_debug_defaults", artDebugDefaultsFactory)
358
359	// ART apex is special because it must include dexpreopt files for bootclasspath jars.
360	android.RegisterModuleType("art_apex", artApexBundleFactory)
361	android.RegisterModuleType("art_apex_test", artTestApexBundleFactory)
362
363	// TODO: This makes the module disable itself for host if HOST_PREFER_32_BIT is
364	// set. We need this because the multilib types of binaries listed in the apex
365	// rule must match the declared type. This is normally not difficult but HOST_PREFER_32_BIT
366	// changes this to 'prefer32' on all host binaries. Since HOST_PREFER_32_BIT is
367	// only used for testing we can just disable the module.
368	// See b/120617876 for more information.
369	android.RegisterModuleType("art_apex_test_host", artHostTestApexBundleFactory)
370}
371
372func artApexBundleFactory() android.Module {
373	return apex.ApexBundleFactory(false /*testApex*/, true /*artApex*/)
374}
375
376func artTestApexBundleFactory() android.Module {
377	return apex.ApexBundleFactory(true /*testApex*/, true /*artApex*/)
378}
379
380func artHostTestApexBundleFactory() android.Module {
381	module := apex.ApexBundleFactory(true /*testApex*/, true /*artApex*/)
382	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
383		if ctx.Config().IsEnvTrue("HOST_PREFER_32_BIT") {
384			type props struct {
385				Target struct {
386					Host struct {
387						Enabled *bool
388					}
389				}
390			}
391
392			p := &props{}
393			p.Target.Host.Enabled = proptools.BoolPtr(false)
394			ctx.AppendProperties(p)
395			log.Print("Disabling host build of " + ctx.ModuleName() + " for HOST_PREFER_32_BIT=true")
396		}
397	})
398
399	return module
400}
401
402func artGlobalDefaultsFactory() android.Module {
403	module := artDefaultsFactory()
404	android.AddLoadHook(module, addImplicitFlags)
405	android.AddLoadHook(module, globalDefaults)
406
407	return module
408}
409
410func artDebugDefaultsFactory() android.Module {
411	module := artDefaultsFactory()
412	android.AddLoadHook(module, debugDefaults)
413
414	return module
415}
416
417func artDefaultsFactory() android.Module {
418	c := &codegenProperties{}
419	module := cc.DefaultsFactory(c)
420	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, staticAndSharedLibrary) })
421
422	return module
423}
424
425func libartDefaultsFactory() android.Module {
426	c := &codegenProperties{}
427	module := cc.DefaultsFactory(c)
428	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, staticAndSharedLibrary) })
429
430	return module
431}
432
433func libartStaticDefaultsFactory() android.Module {
434	c := &codegenProperties{}
435	module := cc.DefaultsFactory(c)
436	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, staticLibrary) })
437
438	return module
439}
440
441func artLibrary() android.Module {
442	module := cc.LibraryFactory()
443
444	installCodegenCustomizer(module, staticAndSharedLibrary)
445
446	android.AddLoadHook(module, addImplicitFlags)
447	android.AddInstallHook(module, addTestcasesFile)
448	return module
449}
450
451func artStaticLibrary() android.Module {
452	module := cc.LibraryStaticFactory()
453
454	installCodegenCustomizer(module, staticLibrary)
455
456	android.AddLoadHook(module, addImplicitFlags)
457	return module
458}
459
460func artBinary() android.Module {
461	module := cc.BinaryFactory()
462
463	android.AddLoadHook(module, addImplicitFlags)
464	android.AddLoadHook(module, customLinker)
465	android.AddLoadHook(module, prefer32Bit)
466	android.AddInstallHook(module, addTestcasesFile)
467	return module
468}
469
470func artTest() android.Module {
471	module := cc.TestFactory()
472
473	installCodegenCustomizer(module, binary)
474
475	android.AddLoadHook(module, addImplicitFlags)
476	android.AddLoadHook(module, customLinker)
477	android.AddLoadHook(module, prefer32Bit)
478	android.AddInstallHook(module, testInstall)
479	return module
480}
481
482func artTestLibrary() android.Module {
483	module := cc.TestLibraryFactory()
484
485	installCodegenCustomizer(module, staticAndSharedLibrary)
486
487	android.AddLoadHook(module, addImplicitFlags)
488	android.AddLoadHook(module, prefer32Bit)
489	android.AddInstallHook(module, testInstall)
490	return module
491}
492