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	if ctx.Config().IsEnvTrue("ART_TARGET_LINUX") {
136		cflags = append(cflags, "-DART_TARGET_LINUX")
137	} else {
138		cflags = append(cflags, "-DART_TARGET_ANDROID")
139	}
140	minDelta := ctx.Config().GetenvWithDefault("LIBART_IMG_TARGET_MIN_BASE_ADDRESS_DELTA", "-0x1000000")
141	maxDelta := ctx.Config().GetenvWithDefault("LIBART_IMG_TARGET_MAX_BASE_ADDRESS_DELTA", "0x1000000")
142	cflags = append(cflags, "-DART_BASE_ADDRESS_MIN_DELTA="+minDelta)
143	cflags = append(cflags, "-DART_BASE_ADDRESS_MAX_DELTA="+maxDelta)
144
145	return cflags
146}
147
148func hostFlags(ctx android.LoadHookContext) []string {
149	var cflags []string
150	hostFrameSizeLimit := 1736
151	if len(ctx.Config().SanitizeHost()) > 0 {
152		// art/test/137-cfi/cfi.cc
153		// error: stack frame size of 1944 bytes in function 'Java_Main_unwindInProcess'
154		hostFrameSizeLimit = 6400
155	}
156	cflags = append(cflags,
157		fmt.Sprintf("-Wframe-larger-than=%d", hostFrameSizeLimit),
158		fmt.Sprintf("-DART_FRAME_SIZE_LIMIT=%d", hostFrameSizeLimit),
159	)
160
161	cflags = append(cflags, "-DART_BASE_ADDRESS="+ctx.Config().LibartImgHostBaseAddress())
162	minDelta := ctx.Config().GetenvWithDefault("LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA", "-0x1000000")
163	maxDelta := ctx.Config().GetenvWithDefault("LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA", "0x1000000")
164	cflags = append(cflags, "-DART_BASE_ADDRESS_MIN_DELTA="+minDelta)
165	cflags = append(cflags, "-DART_BASE_ADDRESS_MAX_DELTA="+maxDelta)
166
167	if len(ctx.Config().SanitizeHost()) > 0 && !ctx.Config().IsEnvFalse("ART_ENABLE_ADDRESS_SANITIZER") {
168		// We enable full sanitization on the host by default.
169		cflags = append(cflags, "-DART_ENABLE_ADDRESS_SANITIZER=1")
170	}
171
172	clang_path := filepath.Join(config.ClangDefaultBase, ctx.Config().PrebuiltOS(), config.ClangDefaultVersion)
173	cflags = append(cflags, "-DART_CLANG_PATH=\""+clang_path+"\"")
174
175	return cflags
176}
177
178func globalDefaults(ctx android.LoadHookContext) {
179	type props struct {
180		Target struct {
181			Android struct {
182				Cflags []string
183			}
184			Host struct {
185				Cflags []string
186			}
187		}
188		Cflags   []string
189		Asflags  []string
190		Sanitize struct {
191			Recover []string
192		}
193	}
194
195	p := &props{}
196	p.Cflags, p.Asflags = globalFlags(ctx)
197	p.Target.Android.Cflags = deviceFlags(ctx)
198	p.Target.Host.Cflags = hostFlags(ctx)
199
200	if ctx.Config().IsEnvTrue("ART_DEX_FILE_ACCESS_TRACKING") {
201		p.Cflags = append(p.Cflags, "-DART_DEX_FILE_ACCESS_TRACKING")
202		p.Sanitize.Recover = []string{
203			"address",
204		}
205	}
206
207	ctx.AppendProperties(p)
208}
209
210func debugDefaults(ctx android.LoadHookContext) {
211	type props struct {
212		Cflags []string
213	}
214
215	p := &props{}
216	p.Cflags = debugFlags(ctx)
217	ctx.AppendProperties(p)
218}
219
220func customLinker(ctx android.LoadHookContext) {
221	linker := ctx.Config().Getenv("CUSTOM_TARGET_LINKER")
222	type props struct {
223		DynamicLinker string
224	}
225
226	p := &props{}
227	if linker != "" {
228		p.DynamicLinker = linker
229	}
230
231	ctx.AppendProperties(p)
232}
233
234func prefer32Bit(ctx android.LoadHookContext) {
235	type props struct {
236		Target struct {
237			Host struct {
238				Compile_multilib *string
239			}
240		}
241	}
242
243	p := &props{}
244	if ctx.Config().IsEnvTrue("HOST_PREFER_32_BIT") {
245		p.Target.Host.Compile_multilib = proptools.StringPtr("prefer32")
246	}
247
248	// Prepend to make it overridable in the blueprints. Note that it doesn't work
249	// to override the property in a cc_defaults module.
250	ctx.PrependProperties(p)
251}
252
253var testMapKey = android.NewOnceKey("artTests")
254
255func testMap(config android.Config) map[string][]string {
256	return config.Once(testMapKey, func() interface{} {
257		return make(map[string][]string)
258	}).(map[string][]string)
259}
260
261func testInstall(ctx android.InstallHookContext) {
262	testMap := testMap(ctx.Config())
263
264	var name string
265	if ctx.Host() {
266		name = "host_"
267	} else {
268		name = "device_"
269	}
270	name += ctx.Arch().ArchType.String() + "_" + ctx.ModuleName()
271
272	artTestMutex.Lock()
273	defer artTestMutex.Unlock()
274
275	tests := testMap[name]
276	tests = append(tests, ctx.Path().ToMakePath().String())
277	testMap[name] = tests
278}
279
280var testcasesContentKey = android.NewOnceKey("artTestcasesContent")
281
282func testcasesContent(config android.Config) map[string]string {
283	return config.Once(testcasesContentKey, func() interface{} {
284		return make(map[string]string)
285	}).(map[string]string)
286}
287
288// Binaries and libraries also need to be copied in the testcases directory for
289// running tests on host.  This method adds module to the list of needed files.
290// The 'key' is the file in testcases and 'value' is the path to copy it from.
291// The actual copy will be done in make since soong does not do installations.
292func addTestcasesFile(ctx android.InstallHookContext) {
293	testcasesContent := testcasesContent(ctx.Config())
294
295	artTestMutex.Lock()
296	defer artTestMutex.Unlock()
297
298	if ctx.Os().Class == android.Host {
299		src := ctx.SrcPath().String()
300		path := strings.Split(ctx.Path().ToMakePath().String(), "/")
301		// Keep last two parts of the install path (e.g. bin/dex2oat).
302		dst := strings.Join(path[len(path)-2:], "/")
303		testcasesContent[dst] = src
304	}
305}
306
307var artTestMutex sync.Mutex
308
309func init() {
310	artModuleTypes := []string{
311		"art_cc_library",
312		"art_cc_library_static",
313		"art_cc_binary",
314		"art_cc_test",
315		"art_cc_test_library",
316		"art_cc_defaults",
317		"libart_cc_defaults",
318		"libart_static_cc_defaults",
319		"art_global_defaults",
320		"art_debug_defaults",
321		"art_apex_test_host",
322	}
323	android.AddNeverAllowRules(
324		android.NeverAllow().
325			NotIn("art", "external/vixl").
326			ModuleType(artModuleTypes...))
327
328	android.RegisterModuleType("art_cc_library", artLibrary)
329	android.RegisterModuleType("art_cc_library_static", artStaticLibrary)
330	android.RegisterModuleType("art_cc_binary", artBinary)
331	android.RegisterModuleType("art_cc_test", artTest)
332	android.RegisterModuleType("art_cc_test_library", artTestLibrary)
333	android.RegisterModuleType("art_cc_defaults", artDefaultsFactory)
334	android.RegisterModuleType("libart_cc_defaults", libartDefaultsFactory)
335	android.RegisterModuleType("libart_static_cc_defaults", libartStaticDefaultsFactory)
336	android.RegisterModuleType("art_global_defaults", artGlobalDefaultsFactory)
337	android.RegisterModuleType("art_debug_defaults", artDebugDefaultsFactory)
338
339	// ART apex is special because it must include dexpreopt files for bootclasspath jars.
340	android.RegisterModuleType("art_apex", artApexBundleFactory)
341	android.RegisterModuleType("art_apex_test", artTestApexBundleFactory)
342
343	// TODO: This makes the module disable itself for host if HOST_PREFER_32_BIT is
344	// set. We need this because the multilib types of binaries listed in the apex
345	// rule must match the declared type. This is normally not difficult but HOST_PREFER_32_BIT
346	// changes this to 'prefer32' on all host binaries. Since HOST_PREFER_32_BIT is
347	// only used for testing we can just disable the module.
348	// See b/120617876 for more information.
349	android.RegisterModuleType("art_apex_test_host", artHostTestApexBundleFactory)
350}
351
352func artApexBundleFactory() android.Module {
353	return apex.ApexBundleFactory(false /*testApex*/, true /*artApex*/)
354}
355
356func artTestApexBundleFactory() android.Module {
357	return apex.ApexBundleFactory(true /*testApex*/, true /*artApex*/)
358}
359
360func artHostTestApexBundleFactory() android.Module {
361	module := apex.ApexBundleFactory(true /*testApex*/, true /*artApex*/)
362	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
363		if ctx.Config().IsEnvTrue("HOST_PREFER_32_BIT") {
364			type props struct {
365				Target struct {
366					Host struct {
367						Enabled *bool
368					}
369				}
370			}
371
372			p := &props{}
373			p.Target.Host.Enabled = proptools.BoolPtr(false)
374			ctx.AppendProperties(p)
375			log.Print("Disabling host build of " + ctx.ModuleName() + " for HOST_PREFER_32_BIT=true")
376		}
377	})
378
379	return module
380}
381
382func artGlobalDefaultsFactory() android.Module {
383	module := artDefaultsFactory()
384	android.AddLoadHook(module, globalDefaults)
385
386	return module
387}
388
389func artDebugDefaultsFactory() android.Module {
390	module := artDefaultsFactory()
391	android.AddLoadHook(module, debugDefaults)
392
393	return module
394}
395
396func artDefaultsFactory() android.Module {
397	c := &codegenProperties{}
398	module := cc.DefaultsFactory(c)
399	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, staticAndSharedLibrary) })
400
401	return module
402}
403
404func libartDefaultsFactory() android.Module {
405	c := &codegenProperties{}
406	module := cc.DefaultsFactory(c)
407	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, staticAndSharedLibrary) })
408
409	return module
410}
411
412func libartStaticDefaultsFactory() android.Module {
413	c := &codegenProperties{}
414	module := cc.DefaultsFactory(c)
415	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, staticLibrary) })
416
417	return module
418}
419
420func artLibrary() android.Module {
421	module := cc.LibraryFactory()
422
423	installCodegenCustomizer(module, staticAndSharedLibrary)
424
425	android.AddInstallHook(module, addTestcasesFile)
426	return module
427}
428
429func artStaticLibrary() android.Module {
430	module := cc.LibraryStaticFactory()
431
432	installCodegenCustomizer(module, staticLibrary)
433
434	return module
435}
436
437func artBinary() android.Module {
438	module := cc.BinaryFactory()
439
440	android.AddLoadHook(module, customLinker)
441	android.AddLoadHook(module, prefer32Bit)
442	android.AddInstallHook(module, addTestcasesFile)
443	return module
444}
445
446func artTest() android.Module {
447	module := cc.TestFactory()
448
449	installCodegenCustomizer(module, binary)
450
451	android.AddLoadHook(module, customLinker)
452	android.AddLoadHook(module, prefer32Bit)
453	android.AddInstallHook(module, testInstall)
454	return module
455}
456
457func artTestLibrary() android.Module {
458	module := cc.TestLibraryFactory()
459
460	installCodegenCustomizer(module, staticAndSharedLibrary)
461
462	android.AddLoadHook(module, prefer32Bit)
463	android.AddInstallHook(module, testInstall)
464	return module
465}
466