1// Copyright 2015 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
17// This file contains the module types for compiling Java for Android, and converts the properties
18// into the flags and filenames necessary to pass to the compiler.  The final creation of the rules
19// is handled in builder.go
20
21import (
22	"fmt"
23	"strings"
24
25	"github.com/google/blueprint"
26
27	"android/soong"
28	"android/soong/common"
29	"android/soong/genrule"
30)
31
32func init() {
33	soong.RegisterModuleType("java_library", JavaLibraryFactory)
34	soong.RegisterModuleType("java_library_static", JavaLibraryFactory)
35	soong.RegisterModuleType("java_library_host", JavaLibraryHostFactory)
36	soong.RegisterModuleType("java_binary", JavaBinaryFactory)
37	soong.RegisterModuleType("java_binary_host", JavaBinaryHostFactory)
38	soong.RegisterModuleType("prebuilt_java_library", JavaPrebuiltFactory)
39	soong.RegisterModuleType("prebuilt_sdk", SdkPrebuiltFactory)
40	soong.RegisterModuleType("android_app", AndroidAppFactory)
41
42	soong.RegisterSingletonType("logtags", LogtagsSingleton)
43}
44
45// TODO:
46// Autogenerated files:
47//  Proto
48//  Renderscript
49// Post-jar passes:
50//  Proguard
51//  Emma
52//  Jarjar
53//  Dex
54// Rmtypedefs
55// Jack
56// DroidDoc
57// Findbugs
58
59type javaBaseProperties struct {
60	// list of source files used to compile the Java module.  May be .java, .logtags, .proto,
61	// or .aidl files.
62	Srcs []string `android:"arch_variant"`
63
64	// list of source files that should not be used to build the Java module.
65	// This is most useful in the arch/multilib variants to remove non-common files
66	Exclude_srcs []string `android:"arch_variant"`
67
68	// list of directories containing Java resources
69	Java_resource_dirs []string `android:"arch_variant"`
70
71	// list of directories that should be excluded from java_resource_dirs
72	Exclude_java_resource_dirs []string `android:"arch_variant"`
73
74	// don't build against the default libraries (core-libart, core-junit,
75	// ext, and framework for device targets)
76	No_standard_libraries bool
77
78	// list of module-specific flags that will be used for javac compiles
79	Javacflags []string `android:"arch_variant"`
80
81	// list of module-specific flags that will be used for jack compiles
82	Jack_flags []string `android:"arch_variant"`
83
84	// list of module-specific flags that will be used for dex compiles
85	Dxflags []string `android:"arch_variant"`
86
87	// list of of java libraries that will be in the classpath
88	Java_libs []string `android:"arch_variant"`
89
90	// list of java libraries that will be compiled into the resulting jar
91	Java_static_libs []string `android:"arch_variant"`
92
93	// manifest file to be included in resulting jar
94	Manifest *string
95
96	// if not blank, set to the version of the sdk to compile against
97	Sdk_version string
98
99	// Set for device java libraries, and for host versions of device java libraries
100	// built for testing
101	Dex bool `blueprint:"mutated"`
102
103	// if not blank, run jarjar using the specified rules file
104	Jarjar_rules *string
105
106	// directories to pass to aidl tool
107	Aidl_includes []string
108
109	// directories that should be added as include directories
110	// for any aidl sources of modules that depend on this module
111	Export_aidl_include_dirs []string
112}
113
114// javaBase contains the properties and members used by all java module types, and implements
115// the blueprint.Module interface.
116type javaBase struct {
117	common.AndroidModuleBase
118	module JavaModuleType
119
120	properties javaBaseProperties
121
122	// output file suitable for inserting into the classpath of another compile
123	classpathFile common.Path
124
125	// output file suitable for installing or running
126	outputFile common.Path
127
128	// jarSpecs suitable for inserting classes from a static library into another jar
129	classJarSpecs []jarSpec
130
131	// jarSpecs suitable for inserting resources from a static library into another jar
132	resourceJarSpecs []jarSpec
133
134	exportAidlIncludeDirs common.Paths
135
136	logtagsSrcs common.Paths
137
138	// filelists of extra source files that should be included in the javac command line,
139	// for example R.java generated by aapt for android apps
140	ExtraSrcLists common.Paths
141
142	// installed file for binary dependency
143	installFile common.Path
144}
145
146type AndroidJavaModuleContext common.AndroidBaseContext
147
148type JavaModuleType interface {
149	GenerateJavaBuildActions(ctx common.AndroidModuleContext)
150	JavaDependencies(ctx AndroidJavaModuleContext) []string
151}
152
153type JavaDependency interface {
154	ClasspathFile() common.Path
155	ClassJarSpecs() []jarSpec
156	ResourceJarSpecs() []jarSpec
157	AidlIncludeDirs() common.Paths
158}
159
160func NewJavaBase(base *javaBase, module JavaModuleType, hod common.HostOrDeviceSupported,
161	props ...interface{}) (blueprint.Module, []interface{}) {
162
163	base.module = module
164
165	props = append(props, &base.properties)
166
167	return common.InitAndroidArchModule(base, hod, common.MultilibCommon, props...)
168}
169
170func (j *javaBase) BootClasspath(ctx common.AndroidBaseContext) string {
171	if ctx.Device() {
172		if j.properties.Sdk_version == "" {
173			return "core-libart"
174		} else if j.properties.Sdk_version == "current" {
175			// TODO: !TARGET_BUILD_APPS
176			// TODO: export preprocessed framework.aidl from android_stubs_current
177			return "android_stubs_current"
178		} else if j.properties.Sdk_version == "system_current" {
179			return "android_system_stubs_current"
180		} else {
181			return "sdk_v" + j.properties.Sdk_version
182		}
183	} else {
184		if j.properties.Dex {
185			return "core-libart"
186		} else {
187			return ""
188		}
189	}
190}
191
192var defaultJavaLibraries = []string{"core-libart", "core-junit", "ext", "framework"}
193
194func javaDepsMutator(ctx common.AndroidBottomUpMutatorContext) {
195	if j, ok := ctx.Module().(JavaModuleType); ok {
196		ctx.AddDependency(ctx.Module(), j.JavaDependencies(ctx)...)
197	}
198}
199
200func (j *javaBase) JavaDependencies(ctx AndroidJavaModuleContext) []string {
201	var deps []string
202
203	if !j.properties.No_standard_libraries {
204		bootClasspath := j.BootClasspath(ctx)
205		if bootClasspath != "" {
206			deps = append(deps, bootClasspath)
207		}
208		if ctx.Device() && j.properties.Sdk_version == "" {
209			deps = append(deps, defaultJavaLibraries...)
210		}
211	}
212	deps = append(deps, j.properties.Java_libs...)
213	deps = append(deps, j.properties.Java_static_libs...)
214
215	return deps
216}
217
218func (j *javaBase) aidlFlags(ctx common.AndroidModuleContext, aidlPreprocess common.OptionalPath,
219	aidlIncludeDirs common.Paths) []string {
220
221	localAidlIncludes := common.PathsForModuleSrc(ctx, j.properties.Aidl_includes)
222
223	var flags []string
224	if aidlPreprocess.Valid() {
225		flags = append(flags, "-p"+aidlPreprocess.String())
226	} else {
227		flags = append(flags, common.JoinWithPrefix(aidlIncludeDirs.Strings(), "-I"))
228	}
229
230	flags = append(flags, common.JoinWithPrefix(j.exportAidlIncludeDirs.Strings(), "-I"))
231	flags = append(flags, common.JoinWithPrefix(localAidlIncludes.Strings(), "-I"))
232	flags = append(flags, "-I"+common.PathForModuleSrc(ctx).String())
233	flags = append(flags, "-I"+common.PathForModuleSrc(ctx, "src").String())
234
235	return flags
236}
237
238func (j *javaBase) collectDeps(ctx common.AndroidModuleContext) (classpath common.Paths,
239	bootClasspath common.OptionalPath, classJarSpecs, resourceJarSpecs []jarSpec, aidlPreprocess common.OptionalPath,
240	aidlIncludeDirs common.Paths, srcFileLists common.Paths) {
241
242	ctx.VisitDirectDeps(func(module blueprint.Module) {
243		otherName := ctx.OtherModuleName(module)
244		if javaDep, ok := module.(JavaDependency); ok {
245			if otherName == j.BootClasspath(ctx) {
246				bootClasspath = common.OptionalPathForPath(javaDep.ClasspathFile())
247			} else if inList(otherName, defaultJavaLibraries) {
248				classpath = append(classpath, javaDep.ClasspathFile())
249			} else if inList(otherName, j.properties.Java_libs) {
250				classpath = append(classpath, javaDep.ClasspathFile())
251			} else if inList(otherName, j.properties.Java_static_libs) {
252				classpath = append(classpath, javaDep.ClasspathFile())
253				classJarSpecs = append(classJarSpecs, javaDep.ClassJarSpecs()...)
254				resourceJarSpecs = append(resourceJarSpecs, javaDep.ResourceJarSpecs()...)
255			} else if otherName == "framework-res" {
256				if ctx.ModuleName() == "framework" {
257					// framework.jar has a one-off dependency on the R.java and Manifest.java files
258					// generated by framework-res.apk
259					srcFileLists = append(srcFileLists, module.(*javaBase).module.(*AndroidApp).aaptJavaFileList)
260				}
261			} else {
262				panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
263			}
264			aidlIncludeDirs = append(aidlIncludeDirs, javaDep.AidlIncludeDirs()...)
265			if sdkDep, ok := module.(sdkDependency); ok {
266				if sdkDep.AidlPreprocessed().Valid() {
267					if aidlPreprocess.Valid() {
268						ctx.ModuleErrorf("multiple dependencies with preprocessed aidls:\n %q\n %q",
269							aidlPreprocess, sdkDep.AidlPreprocessed())
270					} else {
271						aidlPreprocess = sdkDep.AidlPreprocessed()
272					}
273				}
274			}
275		}
276	})
277
278	return classpath, bootClasspath, classJarSpecs, resourceJarSpecs, aidlPreprocess,
279		aidlIncludeDirs, srcFileLists
280}
281
282func (j *javaBase) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) {
283	j.module.GenerateJavaBuildActions(ctx)
284}
285
286func (j *javaBase) GenerateJavaBuildActions(ctx common.AndroidModuleContext) {
287
288	j.exportAidlIncludeDirs = common.PathsForModuleSrc(ctx, j.properties.Export_aidl_include_dirs)
289
290	classpath, bootClasspath, classJarSpecs, resourceJarSpecs, aidlPreprocess,
291		aidlIncludeDirs, srcFileLists := j.collectDeps(ctx)
292
293	var flags javaBuilderFlags
294
295	javacFlags := j.properties.Javacflags
296	if len(javacFlags) > 0 {
297		ctx.Variable(pctx, "javacFlags", strings.Join(javacFlags, " "))
298		flags.javacFlags = "$javacFlags"
299	}
300
301	aidlFlags := j.aidlFlags(ctx, aidlPreprocess, aidlIncludeDirs)
302	if len(aidlFlags) > 0 {
303		ctx.Variable(pctx, "aidlFlags", strings.Join(aidlFlags, " "))
304		flags.aidlFlags = "$aidlFlags"
305	}
306
307	var javacDeps common.Paths
308
309	if bootClasspath.Valid() {
310		flags.bootClasspath = "-bootclasspath " + bootClasspath.String()
311		javacDeps = append(javacDeps, bootClasspath.Path())
312	}
313
314	if len(classpath) > 0 {
315		flags.classpath = "-classpath " + strings.Join(classpath.Strings(), ":")
316		javacDeps = append(javacDeps, classpath...)
317	}
318
319	srcFiles := ctx.ExpandSources(j.properties.Srcs, j.properties.Exclude_srcs)
320
321	srcFiles = j.genSources(ctx, srcFiles, flags)
322
323	ctx.VisitDirectDeps(func(module blueprint.Module) {
324		if gen, ok := module.(genrule.SourceFileGenerator); ok {
325			srcFiles = append(srcFiles, gen.GeneratedSourceFiles()...)
326		}
327	})
328
329	srcFileLists = append(srcFileLists, j.ExtraSrcLists...)
330
331	if len(srcFiles) > 0 {
332		// Compile java sources into .class files
333		classes := TransformJavaToClasses(ctx, srcFiles, srcFileLists, flags, javacDeps)
334		if ctx.Failed() {
335			return
336		}
337
338		classJarSpecs = append([]jarSpec{classes}, classJarSpecs...)
339	}
340
341	resourceJarSpecs = append(ResourceDirsToJarSpecs(ctx, j.properties.Java_resource_dirs, j.properties.Exclude_java_resource_dirs),
342		resourceJarSpecs...)
343
344	manifest := common.OptionalPathForModuleSrc(ctx, j.properties.Manifest)
345
346	allJarSpecs := append([]jarSpec(nil), classJarSpecs...)
347	allJarSpecs = append(allJarSpecs, resourceJarSpecs...)
348
349	// Combine classes + resources into classes-full-debug.jar
350	outputFile := TransformClassesToJar(ctx, allJarSpecs, manifest)
351	if ctx.Failed() {
352		return
353	}
354
355	if j.properties.Jarjar_rules != nil {
356		jarjar_rules := common.PathForModuleSrc(ctx, *j.properties.Jarjar_rules)
357		// Transform classes-full-debug.jar into classes-jarjar.jar
358		outputFile = TransformJarJar(ctx, outputFile, jarjar_rules)
359		if ctx.Failed() {
360			return
361		}
362
363		classes, _ := TransformPrebuiltJarToClasses(ctx, outputFile)
364		classJarSpecs = []jarSpec{classes}
365	}
366
367	j.resourceJarSpecs = resourceJarSpecs
368	j.classJarSpecs = classJarSpecs
369	j.classpathFile = outputFile
370
371	if j.properties.Dex && len(srcFiles) > 0 {
372		dxFlags := j.properties.Dxflags
373		if false /* emma enabled */ {
374			// If you instrument class files that have local variable debug information in
375			// them emma does not correctly maintain the local variable table.
376			// This will cause an error when you try to convert the class files for Android.
377			// The workaround here is to build different dex file here based on emma switch
378			// then later copy into classes.dex. When emma is on, dx is run with --no-locals
379			// option to remove local variable information
380			dxFlags = append(dxFlags, "--no-locals")
381		}
382
383		if ctx.AConfig().Getenv("NO_OPTIMIZE_DX") != "" {
384			dxFlags = append(dxFlags, "--no-optimize")
385		}
386
387		if ctx.AConfig().Getenv("GENERATE_DEX_DEBUG") != "" {
388			dxFlags = append(dxFlags,
389				"--debug",
390				"--verbose",
391				"--dump-to="+common.PathForModuleOut(ctx, "classes.lst").String(),
392				"--dump-width=1000")
393		}
394
395		flags.dxFlags = strings.Join(dxFlags, " ")
396
397		// Compile classes.jar into classes.dex
398		dexJarSpec := TransformClassesJarToDex(ctx, outputFile, flags)
399		if ctx.Failed() {
400			return
401		}
402
403		// Combine classes.dex + resources into javalib.jar
404		outputFile = TransformDexToJavaLib(ctx, resourceJarSpecs, dexJarSpec)
405	}
406	ctx.CheckbuildFile(outputFile)
407	j.outputFile = outputFile
408}
409
410var _ JavaDependency = (*JavaLibrary)(nil)
411
412func (j *javaBase) ClasspathFile() common.Path {
413	return j.classpathFile
414}
415
416func (j *javaBase) ClassJarSpecs() []jarSpec {
417	return j.classJarSpecs
418}
419
420func (j *javaBase) ResourceJarSpecs() []jarSpec {
421	return j.resourceJarSpecs
422}
423
424func (j *javaBase) AidlIncludeDirs() common.Paths {
425	return j.exportAidlIncludeDirs
426}
427
428var _ logtagsProducer = (*javaBase)(nil)
429
430func (j *javaBase) logtags() common.Paths {
431	return j.logtagsSrcs
432}
433
434//
435// Java libraries (.jar file)
436//
437
438type JavaLibrary struct {
439	javaBase
440}
441
442func (j *JavaLibrary) GenerateJavaBuildActions(ctx common.AndroidModuleContext) {
443	j.javaBase.GenerateJavaBuildActions(ctx)
444
445	j.installFile = ctx.InstallFileName(common.PathForModuleInstall(ctx, "framework"), ctx.ModuleName()+".jar", j.outputFile)
446}
447
448func JavaLibraryFactory() (blueprint.Module, []interface{}) {
449	module := &JavaLibrary{}
450
451	module.properties.Dex = true
452
453	return NewJavaBase(&module.javaBase, module, common.HostAndDeviceSupported)
454}
455
456func JavaLibraryHostFactory() (blueprint.Module, []interface{}) {
457	module := &JavaLibrary{}
458
459	return NewJavaBase(&module.javaBase, module, common.HostSupported)
460}
461
462//
463// Java Binaries (.jar file plus wrapper script)
464//
465
466type javaBinaryProperties struct {
467	// installable script to execute the resulting jar
468	Wrapper string
469}
470
471type JavaBinary struct {
472	JavaLibrary
473
474	binaryProperties javaBinaryProperties
475}
476
477func (j *JavaBinary) GenerateJavaBuildActions(ctx common.AndroidModuleContext) {
478	j.JavaLibrary.GenerateJavaBuildActions(ctx)
479
480	// Depend on the installed jar (j.installFile) so that the wrapper doesn't get executed by
481	// another build rule before the jar has been installed.
482	ctx.InstallFile(common.PathForModuleInstall(ctx, "bin"), common.PathForModuleSrc(ctx, j.binaryProperties.Wrapper),
483		j.installFile)
484}
485
486func JavaBinaryFactory() (blueprint.Module, []interface{}) {
487	module := &JavaBinary{}
488
489	module.properties.Dex = true
490
491	return NewJavaBase(&module.javaBase, module, common.HostAndDeviceSupported, &module.binaryProperties)
492}
493
494func JavaBinaryHostFactory() (blueprint.Module, []interface{}) {
495	module := &JavaBinary{}
496
497	return NewJavaBase(&module.javaBase, module, common.HostSupported, &module.binaryProperties)
498}
499
500//
501// Java prebuilts
502//
503
504type javaPrebuiltProperties struct {
505	Srcs []string
506}
507
508type JavaPrebuilt struct {
509	common.AndroidModuleBase
510
511	properties javaPrebuiltProperties
512
513	classpathFile                   common.Path
514	classJarSpecs, resourceJarSpecs []jarSpec
515}
516
517func (j *JavaPrebuilt) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) {
518	if len(j.properties.Srcs) != 1 {
519		ctx.ModuleErrorf("expected exactly one jar in srcs")
520		return
521	}
522	prebuilt := common.PathForModuleSrc(ctx, j.properties.Srcs[0])
523
524	classJarSpec, resourceJarSpec := TransformPrebuiltJarToClasses(ctx, prebuilt)
525
526	j.classpathFile = prebuilt
527	j.classJarSpecs = []jarSpec{classJarSpec}
528	j.resourceJarSpecs = []jarSpec{resourceJarSpec}
529	ctx.InstallFileName(common.PathForModuleInstall(ctx, "framework"), ctx.ModuleName()+".jar", j.classpathFile)
530}
531
532var _ JavaDependency = (*JavaPrebuilt)(nil)
533
534func (j *JavaPrebuilt) ClasspathFile() common.Path {
535	return j.classpathFile
536}
537
538func (j *JavaPrebuilt) ClassJarSpecs() []jarSpec {
539	return j.classJarSpecs
540}
541
542func (j *JavaPrebuilt) ResourceJarSpecs() []jarSpec {
543	return j.resourceJarSpecs
544}
545
546func (j *JavaPrebuilt) AidlIncludeDirs() common.Paths {
547	return nil
548}
549
550func JavaPrebuiltFactory() (blueprint.Module, []interface{}) {
551	module := &JavaPrebuilt{}
552
553	return common.InitAndroidArchModule(module, common.HostAndDeviceSupported,
554		common.MultilibCommon, &module.properties)
555}
556
557//
558// SDK java prebuilts (.jar containing resources plus framework.aidl)
559//
560
561type sdkDependency interface {
562	JavaDependency
563	AidlPreprocessed() common.OptionalPath
564}
565
566var _ sdkDependency = (*sdkPrebuilt)(nil)
567
568type sdkPrebuiltProperties struct {
569	Aidl_preprocessed *string
570}
571
572type sdkPrebuilt struct {
573	JavaPrebuilt
574
575	sdkProperties sdkPrebuiltProperties
576
577	aidlPreprocessed common.OptionalPath
578}
579
580func (j *sdkPrebuilt) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) {
581	j.JavaPrebuilt.GenerateAndroidBuildActions(ctx)
582
583	j.aidlPreprocessed = common.OptionalPathForModuleSrc(ctx, j.sdkProperties.Aidl_preprocessed)
584}
585
586func (j *sdkPrebuilt) AidlPreprocessed() common.OptionalPath {
587	return j.aidlPreprocessed
588}
589
590func SdkPrebuiltFactory() (blueprint.Module, []interface{}) {
591	module := &sdkPrebuilt{}
592
593	return common.InitAndroidArchModule(module, common.HostAndDeviceSupported,
594		common.MultilibCommon, &module.properties, &module.sdkProperties)
595}
596
597func inList(s string, l []string) bool {
598	for _, e := range l {
599		if e == s {
600			return true
601		}
602	}
603	return false
604}
605