• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2018 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package java
16
17import (
18	"android/soong/android"
19	"android/soong/java/config"
20	"fmt"
21	"path/filepath"
22	"runtime"
23	"strings"
24
25	"github.com/google/blueprint"
26)
27
28var (
29	javadoc = pctx.AndroidStaticRule("javadoc",
30		blueprint.RuleParams{
31			Command: `rm -rf "$outDir" "$srcJarDir" "$stubsDir" && mkdir -p "$outDir" "$srcJarDir" "$stubsDir" && ` +
32				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
33				`${config.SoongJavacWrapper} ${config.JavadocCmd} -encoding UTF-8 @$out.rsp @$srcJarDir/list ` +
34				`$opts $bootclasspathArgs $classpathArgs $sourcepathArgs ` +
35				`-d $outDir -quiet  && ` +
36				`${config.SoongZipCmd} -write_if_changed -d -o $docZip -C $outDir -D $outDir && ` +
37				`${config.SoongZipCmd} -write_if_changed -jar -o $out -C $stubsDir -D $stubsDir $postDoclavaCmds && ` +
38				`rm -rf "$srcJarDir"`,
39
40			CommandDeps: []string{
41				"${config.ZipSyncCmd}",
42				"${config.JavadocCmd}",
43				"${config.SoongZipCmd}",
44			},
45			CommandOrderOnly: []string{"${config.SoongJavacWrapper}"},
46			Rspfile:          "$out.rsp",
47			RspfileContent:   "$in",
48			Restat:           true,
49		},
50		"outDir", "srcJarDir", "stubsDir", "srcJars", "opts",
51		"bootclasspathArgs", "classpathArgs", "sourcepathArgs", "docZip", "postDoclavaCmds")
52
53	apiCheck = pctx.AndroidStaticRule("apiCheck",
54		blueprint.RuleParams{
55			Command: `( ${config.ApiCheckCmd} -JXmx1024m -J"classpath $classpath" $opts ` +
56				`$apiFile $apiFileToCheck $removedApiFile $removedApiFileToCheck ` +
57				`&& touch $out ) || (echo -e "$msg" ; exit 38)`,
58			CommandDeps: []string{
59				"${config.ApiCheckCmd}",
60			},
61		},
62		"classpath", "opts", "apiFile", "apiFileToCheck", "removedApiFile", "removedApiFileToCheck", "msg")
63
64	updateApi = pctx.AndroidStaticRule("updateApi",
65		blueprint.RuleParams{
66			Command: `( ( cp -f $srcApiFile $destApiFile && cp -f $srcRemovedApiFile $destRemovedApiFile ) ` +
67				`&& touch $out ) || (echo failed to update public API ; exit 38)`,
68		},
69		"srcApiFile", "destApiFile", "srcRemovedApiFile", "destRemovedApiFile")
70
71	metalava = pctx.AndroidStaticRule("metalava",
72		blueprint.RuleParams{
73			Command: `rm -rf "$outDir" "$srcJarDir" "$stubsDir" && ` +
74				`mkdir -p "$outDir" "$srcJarDir" "$stubsDir" && ` +
75				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
76				`${config.JavaCmd} -jar ${config.MetalavaJar} -encoding UTF-8 -source $javaVersion @$out.rsp @$srcJarDir/list ` +
77				`$bootclasspathArgs $classpathArgs $sourcepathArgs --no-banner --color --quiet --format=v2 ` +
78				`$opts && ` +
79				`${config.SoongZipCmd} -write_if_changed -jar -o $out -C $stubsDir -D $stubsDir && ` +
80				`rm -rf "$srcJarDir"`,
81			CommandDeps: []string{
82				"${config.ZipSyncCmd}",
83				"${config.JavaCmd}",
84				"${config.MetalavaJar}",
85				"${config.SoongZipCmd}",
86			},
87			Rspfile:        "$out.rsp",
88			RspfileContent: "$in",
89			Restat:         true,
90		},
91		"outDir", "srcJarDir", "stubsDir", "srcJars", "javaVersion", "bootclasspathArgs",
92		"classpathArgs", "sourcepathArgs", "opts")
93
94	metalavaApiCheck = pctx.AndroidStaticRule("metalavaApiCheck",
95		blueprint.RuleParams{
96			Command: `( rm -rf "$srcJarDir" && mkdir -p "$srcJarDir" && ` +
97				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
98				`${config.JavaCmd} -jar ${config.MetalavaJar} -encoding UTF-8 -source $javaVersion @$out.rsp @$srcJarDir/list ` +
99				`$bootclasspathArgs $classpathArgs $sourcepathArgs --no-banner --color --quiet --format=v2 ` +
100				`$opts && touch $out && rm -rf "$srcJarDir") || ` +
101				`( echo -e "$msg" ; exit 38 )`,
102			CommandDeps: []string{
103				"${config.ZipSyncCmd}",
104				"${config.JavaCmd}",
105				"${config.MetalavaJar}",
106			},
107			Rspfile:        "$out.rsp",
108			RspfileContent: "$in",
109		},
110		"srcJarDir", "srcJars", "javaVersion", "bootclasspathArgs", "classpathArgs", "sourcepathArgs", "opts", "msg")
111
112	nullabilityWarningsCheck = pctx.AndroidStaticRule("nullabilityWarningsCheck",
113		blueprint.RuleParams{
114			Command: `( diff $expected $actual && touch $out ) || ( echo -e "$msg" ; exit 38 )`,
115		},
116		"expected", "actual", "msg")
117
118	dokka = pctx.AndroidStaticRule("dokka",
119		blueprint.RuleParams{
120			Command: `rm -rf "$outDir" "$srcJarDir" "$stubsDir" && ` +
121				`mkdir -p "$outDir" "$srcJarDir" "$stubsDir" && ` +
122				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
123				`${config.JavaCmd} -jar ${config.DokkaJar} $srcJarDir ` +
124				`$classpathArgs -format dac -dacRoot /reference/kotlin -output $outDir $opts && ` +
125				`${config.SoongZipCmd} -write_if_changed -d -o $docZip -C $outDir -D $outDir && ` +
126				`${config.SoongZipCmd} -write_if_changed -jar -o $out -C $stubsDir -D $stubsDir && ` +
127				`rm -rf "$srcJarDir"`,
128			CommandDeps: []string{
129				"${config.ZipSyncCmd}",
130				"${config.DokkaJar}",
131				"${config.MetalavaJar}",
132				"${config.SoongZipCmd}",
133			},
134			Restat: true,
135		},
136		"outDir", "srcJarDir", "stubsDir", "srcJars", "classpathArgs", "opts", "docZip")
137)
138
139func init() {
140	android.RegisterModuleType("doc_defaults", DocDefaultsFactory)
141	android.RegisterModuleType("stubs_defaults", StubsDefaultsFactory)
142
143	android.RegisterModuleType("droiddoc", DroiddocFactory)
144	android.RegisterModuleType("droiddoc_host", DroiddocHostFactory)
145	android.RegisterModuleType("droiddoc_exported_dir", ExportedDroiddocDirFactory)
146	android.RegisterModuleType("javadoc", JavadocFactory)
147	android.RegisterModuleType("javadoc_host", JavadocHostFactory)
148
149	android.RegisterModuleType("droidstubs", DroidstubsFactory)
150	android.RegisterModuleType("droidstubs_host", DroidstubsHostFactory)
151}
152
153var (
154	srcsLibTag = dependencyTag{name: "sources from javalib"}
155)
156
157type JavadocProperties struct {
158	// list of source files used to compile the Java module.  May be .java, .logtags, .proto,
159	// or .aidl files.
160	Srcs []string `android:"path,arch_variant"`
161
162	// list of directories rooted at the Android.bp file that will
163	// be added to the search paths for finding source files when passing package names.
164	Local_sourcepaths []string
165
166	// list of source files that should not be used to build the Java module.
167	// This is most useful in the arch/multilib variants to remove non-common files
168	// filegroup or genrule can be included within this property.
169	Exclude_srcs []string `android:"path,arch_variant"`
170
171	// list of java libraries that will be in the classpath.
172	Libs []string `android:"arch_variant"`
173
174	// don't build against the default libraries (bootclasspath, ext, and framework for device
175	// targets)
176	No_standard_libs *bool
177
178	// don't build against the framework libraries (ext, and framework for device targets)
179	No_framework_libs *bool
180
181	// the java library (in classpath) for documentation that provides java srcs and srcjars.
182	Srcs_lib *string
183
184	// the base dirs under srcs_lib will be scanned for java srcs.
185	Srcs_lib_whitelist_dirs []string
186
187	// the sub dirs under srcs_lib_whitelist_dirs will be scanned for java srcs.
188	Srcs_lib_whitelist_pkgs []string
189
190	// If set to false, don't allow this module(-docs.zip) to be exported. Defaults to true.
191	Installable *bool
192
193	// if not blank, set to the version of the sdk to compile against
194	Sdk_version *string `android:"arch_variant"`
195
196	Aidl struct {
197		// Top level directories to pass to aidl tool
198		Include_dirs []string
199
200		// Directories rooted at the Android.bp file to pass to aidl tool
201		Local_include_dirs []string
202	}
203
204	// If not blank, set the java version passed to javadoc as -source
205	Java_version *string
206
207	// local files that are used within user customized droiddoc options.
208	Arg_files []string `android:"path"`
209
210	// user customized droiddoc args.
211	// Available variables for substitution:
212	//
213	//  $(location <label>): the path to the arg_files with name <label>
214	Args *string
215
216	// names of the output files used in args that will be generated
217	Out []string
218}
219
220type ApiToCheck struct {
221	// path to the API txt file that the new API extracted from source code is checked
222	// against. The path can be local to the module or from other module (via :module syntax).
223	Api_file *string `android:"path"`
224
225	// path to the API txt file that the new @removed API extractd from source code is
226	// checked against. The path can be local to the module or from other module (via
227	// :module syntax).
228	Removed_api_file *string `android:"path"`
229
230	// Arguments to the apicheck tool.
231	Args *string
232}
233
234type DroiddocProperties struct {
235	// directory relative to top of the source tree that contains doc templates files.
236	Custom_template *string
237
238	// directories under current module source which contains html/jd files.
239	Html_dirs []string
240
241	// set a value in the Clearsilver hdf namespace.
242	Hdf []string
243
244	// proofread file contains all of the text content of the javadocs concatenated into one file,
245	// suitable for spell-checking and other goodness.
246	Proofread_file *string `android:"path"`
247
248	// a todo file lists the program elements that are missing documentation.
249	// At some point, this might be improved to show more warnings.
250	Todo_file *string `android:"path"`
251
252	// directory under current module source that provide additional resources (images).
253	Resourcesdir *string
254
255	// resources output directory under out/soong/.intermediates.
256	Resourcesoutdir *string
257
258	// if set to true, collect the values used by the Dev tools and
259	// write them in files packaged with the SDK. Defaults to false.
260	Write_sdk_values *bool
261
262	// index.html under current module will be copied to docs out dir, if not null.
263	Static_doc_index_redirect *string `android:"path"`
264
265	// source.properties under current module will be copied to docs out dir, if not null.
266	Static_doc_properties *string `android:"path"`
267
268	// a list of files under current module source dir which contains known tags in Java sources.
269	// filegroup or genrule can be included within this property.
270	Knowntags []string `android:"path"`
271
272	// the tag name used to distinguish if the API files belong to public/system/test.
273	Api_tag_name *string
274
275	// the generated public API filename by Doclava.
276	Api_filename *string
277
278	// the generated public Dex API filename by Doclava.
279	Dex_api_filename *string
280
281	// the generated private API filename by Doclava.
282	Private_api_filename *string
283
284	// the generated private Dex API filename by Doclava.
285	Private_dex_api_filename *string
286
287	// the generated removed API filename by Doclava.
288	Removed_api_filename *string
289
290	// the generated removed Dex API filename by Doclava.
291	Removed_dex_api_filename *string
292
293	// mapping of dex signatures to source file and line number. This is a temporary property and
294	// will be deleted; you probably shouldn't be using it.
295	Dex_mapping_filename *string
296
297	// the generated exact API filename by Doclava.
298	Exact_api_filename *string
299
300	// the generated proguard filename by Doclava.
301	Proguard_filename *string
302
303	// if set to false, don't allow droiddoc to generate stubs source files. Defaults to true.
304	Create_stubs *bool
305
306	Check_api struct {
307		Last_released ApiToCheck
308
309		Current ApiToCheck
310
311		// do not perform API check against Last_released, in the case that both two specified API
312		// files by Last_released are modules which don't exist.
313		Ignore_missing_latest_api *bool `blueprint:"mutated"`
314	}
315
316	// if set to true, generate docs through Dokka instead of Doclava.
317	Dokka_enabled *bool
318}
319
320type DroidstubsProperties struct {
321	// the tag name used to distinguish if the API files belong to public/system/test.
322	Api_tag_name *string
323
324	// the generated public API filename by Metalava.
325	Api_filename *string
326
327	// the generated public Dex API filename by Metalava.
328	Dex_api_filename *string
329
330	// the generated private API filename by Metalava.
331	Private_api_filename *string
332
333	// the generated private Dex API filename by Metalava.
334	Private_dex_api_filename *string
335
336	// the generated removed API filename by Metalava.
337	Removed_api_filename *string
338
339	// the generated removed Dex API filename by Metalava.
340	Removed_dex_api_filename *string
341
342	// mapping of dex signatures to source file and line number. This is a temporary property and
343	// will be deleted; you probably shouldn't be using it.
344	Dex_mapping_filename *string
345
346	// the generated exact API filename by Metalava.
347	Exact_api_filename *string
348
349	// the generated proguard filename by Metalava.
350	Proguard_filename *string
351
352	Check_api struct {
353		Last_released ApiToCheck
354
355		Current ApiToCheck
356
357		// do not perform API check against Last_released, in the case that both two specified API
358		// files by Last_released are modules which don't exist.
359		Ignore_missing_latest_api *bool `blueprint:"mutated"`
360	}
361
362	// user can specify the version of previous released API file in order to do compatibility check.
363	Previous_api *string `android:"path"`
364
365	// is set to true, Metalava will allow framework SDK to contain annotations.
366	Annotations_enabled *bool
367
368	// a list of top-level directories containing files to merge qualifier annotations (i.e. those intended to be included in the stubs written) from.
369	Merge_annotations_dirs []string
370
371	// a list of top-level directories containing Java stub files to merge show/hide annotations from.
372	Merge_inclusion_annotations_dirs []string
373
374	// a file containing a list of classes to do nullability validation for.
375	Validate_nullability_from_list *string
376
377	// a file containing expected warnings produced by validation of nullability annotations.
378	Check_nullability_warnings *string
379
380	// if set to true, allow Metalava to generate doc_stubs source files. Defaults to false.
381	Create_doc_stubs *bool
382
383	// is set to true, Metalava will allow framework SDK to contain API levels annotations.
384	Api_levels_annotations_enabled *bool
385
386	// the dirs which Metalava extracts API levels annotations from.
387	Api_levels_annotations_dirs []string
388
389	// if set to true, collect the values used by the Dev tools and
390	// write them in files packaged with the SDK. Defaults to false.
391	Write_sdk_values *bool
392
393	// If set to true, .xml based public API file will be also generated, and
394	// JDiff tool will be invoked to genreate javadoc files. Defaults to false.
395	Jdiff_enabled *bool
396}
397
398//
399// Common flags passed down to build rule
400//
401type droiddocBuilderFlags struct {
402	bootClasspathArgs  string
403	classpathArgs      string
404	sourcepathArgs     string
405	dokkaClasspathArgs string
406	aidlFlags          string
407	aidlDeps           android.Paths
408
409	doclavaStubsFlags string
410	doclavaDocsFlags  string
411	postDoclavaCmds   string
412
413	metalavaStubsFlags                string
414	metalavaAnnotationsFlags          string
415	metalavaMergeAnnoDirFlags         string
416	metalavaInclusionAnnotationsFlags string
417	metalavaApiLevelsAnnotationsFlags string
418
419	metalavaApiToXmlFlags string
420}
421
422func InitDroiddocModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
423	android.InitAndroidArchModule(module, hod, android.MultilibCommon)
424	android.InitDefaultableModule(module)
425}
426
427func apiCheckEnabled(apiToCheck ApiToCheck, apiVersionTag string) bool {
428	if String(apiToCheck.Api_file) != "" && String(apiToCheck.Removed_api_file) != "" {
429		return true
430	} else if String(apiToCheck.Api_file) != "" {
431		panic("for " + apiVersionTag + " removed_api_file has to be non-empty!")
432	} else if String(apiToCheck.Removed_api_file) != "" {
433		panic("for " + apiVersionTag + " api_file has to be non-empty!")
434	}
435
436	return false
437}
438
439func ignoreMissingModules(ctx android.BottomUpMutatorContext, apiToCheck *ApiToCheck) {
440	api_file := String(apiToCheck.Api_file)
441	removed_api_file := String(apiToCheck.Removed_api_file)
442
443	api_module := android.SrcIsModule(api_file)
444	removed_api_module := android.SrcIsModule(removed_api_file)
445
446	if api_module == "" || removed_api_module == "" {
447		return
448	}
449
450	if ctx.OtherModuleExists(api_module) || ctx.OtherModuleExists(removed_api_module) {
451		return
452	}
453
454	apiToCheck.Api_file = nil
455	apiToCheck.Removed_api_file = nil
456}
457
458type ApiFilePath interface {
459	ApiFilePath() android.Path
460}
461
462func transformUpdateApi(ctx android.ModuleContext, destApiFile, destRemovedApiFile,
463	srcApiFile, srcRemovedApiFile android.Path, output android.WritablePath) {
464	ctx.Build(pctx, android.BuildParams{
465		Rule:        updateApi,
466		Description: "Update API",
467		Output:      output,
468		Implicits: append(android.Paths{}, srcApiFile, srcRemovedApiFile,
469			destApiFile, destRemovedApiFile),
470		Args: map[string]string{
471			"destApiFile":        destApiFile.String(),
472			"srcApiFile":         srcApiFile.String(),
473			"destRemovedApiFile": destRemovedApiFile.String(),
474			"srcRemovedApiFile":  srcRemovedApiFile.String(),
475		},
476	})
477}
478
479//
480// Javadoc
481//
482type Javadoc struct {
483	android.ModuleBase
484	android.DefaultableModuleBase
485
486	properties JavadocProperties
487
488	srcJars     android.Paths
489	srcFiles    android.Paths
490	sourcepaths android.Paths
491	argFiles    android.Paths
492
493	args string
494
495	docZip      android.WritablePath
496	stubsSrcJar android.WritablePath
497}
498
499func (j *Javadoc) Srcs() android.Paths {
500	return android.Paths{j.stubsSrcJar}
501}
502
503func JavadocFactory() android.Module {
504	module := &Javadoc{}
505
506	module.AddProperties(&module.properties)
507
508	InitDroiddocModule(module, android.HostAndDeviceSupported)
509	return module
510}
511
512func JavadocHostFactory() android.Module {
513	module := &Javadoc{}
514
515	module.AddProperties(&module.properties)
516
517	InitDroiddocModule(module, android.HostSupported)
518	return module
519}
520
521var _ android.SourceFileProducer = (*Javadoc)(nil)
522
523func (j *Javadoc) sdkVersion() string {
524	return String(j.properties.Sdk_version)
525}
526
527func (j *Javadoc) minSdkVersion() string {
528	return j.sdkVersion()
529}
530
531func (j *Javadoc) targetSdkVersion() string {
532	return j.sdkVersion()
533}
534
535func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) {
536	if ctx.Device() {
537		if !Bool(j.properties.No_standard_libs) {
538			sdkDep := decodeSdkDep(ctx, sdkContext(j))
539			if sdkDep.useDefaultLibs {
540				ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
541				if ctx.Config().TargetOpenJDK9() {
542					ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
543				}
544				if !Bool(j.properties.No_framework_libs) {
545					ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
546				}
547			} else if sdkDep.useModule {
548				if ctx.Config().TargetOpenJDK9() {
549					ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
550				}
551				ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.modules...)
552			}
553		}
554	}
555
556	ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
557	if j.properties.Srcs_lib != nil {
558		ctx.AddVariationDependencies(nil, srcsLibTag, *j.properties.Srcs_lib)
559	}
560}
561
562func (j *Javadoc) genWhitelistPathPrefixes(whitelistPathPrefixes map[string]bool) {
563	for _, dir := range j.properties.Srcs_lib_whitelist_dirs {
564		for _, pkg := range j.properties.Srcs_lib_whitelist_pkgs {
565			// convert foo.bar.baz to foo/bar/baz
566			pkgAsPath := filepath.Join(strings.Split(pkg, ".")...)
567			prefix := filepath.Join(dir, pkgAsPath)
568			if _, found := whitelistPathPrefixes[prefix]; !found {
569				whitelistPathPrefixes[prefix] = true
570			}
571		}
572	}
573}
574
575func (j *Javadoc) collectAidlFlags(ctx android.ModuleContext, deps deps) droiddocBuilderFlags {
576	var flags droiddocBuilderFlags
577
578	flags.aidlFlags, flags.aidlDeps = j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs)
579
580	return flags
581}
582
583func (j *Javadoc) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath,
584	aidlIncludeDirs android.Paths) (string, android.Paths) {
585
586	aidlIncludes := android.PathsForModuleSrc(ctx, j.properties.Aidl.Local_include_dirs)
587	aidlIncludes = append(aidlIncludes, android.PathsForSource(ctx, j.properties.Aidl.Include_dirs)...)
588
589	var flags []string
590	var deps android.Paths
591
592	if aidlPreprocess.Valid() {
593		flags = append(flags, "-p"+aidlPreprocess.String())
594		deps = append(deps, aidlPreprocess.Path())
595	} else {
596		flags = append(flags, android.JoinWithPrefix(aidlIncludeDirs.Strings(), "-I"))
597	}
598
599	flags = append(flags, android.JoinWithPrefix(aidlIncludes.Strings(), "-I"))
600	flags = append(flags, "-I"+android.PathForModuleSrc(ctx).String())
601	if src := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "src"); src.Valid() {
602		flags = append(flags, "-I"+src.String())
603	}
604
605	return strings.Join(flags, " "), deps
606}
607
608func (j *Javadoc) genSources(ctx android.ModuleContext, srcFiles android.Paths,
609	flags droiddocBuilderFlags) android.Paths {
610
611	outSrcFiles := make(android.Paths, 0, len(srcFiles))
612
613	for _, srcFile := range srcFiles {
614		switch srcFile.Ext() {
615		case ".aidl":
616			javaFile := genAidl(ctx, srcFile, flags.aidlFlags, flags.aidlDeps)
617			outSrcFiles = append(outSrcFiles, javaFile)
618		case ".sysprop":
619			javaFile := genSysprop(ctx, srcFile)
620			outSrcFiles = append(outSrcFiles, javaFile)
621		default:
622			outSrcFiles = append(outSrcFiles, srcFile)
623		}
624	}
625
626	return outSrcFiles
627}
628
629func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps {
630	var deps deps
631
632	sdkDep := decodeSdkDep(ctx, sdkContext(j))
633	if sdkDep.invalidVersion {
634		ctx.AddMissingDependencies(sdkDep.modules)
635	} else if sdkDep.useFiles {
636		deps.bootClasspath = append(deps.bootClasspath, sdkDep.jars...)
637	}
638
639	ctx.VisitDirectDeps(func(module android.Module) {
640		otherName := ctx.OtherModuleName(module)
641		tag := ctx.OtherModuleDependencyTag(module)
642
643		switch tag {
644		case bootClasspathTag:
645			if dep, ok := module.(Dependency); ok {
646				deps.bootClasspath = append(deps.bootClasspath, dep.ImplementationJars()...)
647			} else {
648				panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
649			}
650		case libTag:
651			switch dep := module.(type) {
652			case SdkLibraryDependency:
653				deps.classpath = append(deps.classpath, dep.SdkImplementationJars(ctx, j.sdkVersion())...)
654			case Dependency:
655				deps.classpath = append(deps.classpath, dep.HeaderJars()...)
656			case android.SourceFileProducer:
657				checkProducesJars(ctx, dep)
658				deps.classpath = append(deps.classpath, dep.Srcs()...)
659			default:
660				ctx.ModuleErrorf("depends on non-java module %q", otherName)
661			}
662		case srcsLibTag:
663			switch dep := module.(type) {
664			case Dependency:
665				srcs := dep.(SrcDependency).CompiledSrcs()
666				whitelistPathPrefixes := make(map[string]bool)
667				j.genWhitelistPathPrefixes(whitelistPathPrefixes)
668				for _, src := range srcs {
669					if _, ok := src.(android.WritablePath); ok { // generated sources
670						deps.srcs = append(deps.srcs, src)
671					} else { // select source path for documentation based on whitelist path prefixs.
672						for k := range whitelistPathPrefixes {
673							if strings.HasPrefix(src.Rel(), k) {
674								deps.srcs = append(deps.srcs, src)
675								break
676							}
677						}
678					}
679				}
680				deps.srcJars = append(deps.srcJars, dep.(SrcDependency).CompiledSrcJars()...)
681			default:
682				ctx.ModuleErrorf("depends on non-java module %q", otherName)
683			}
684		case systemModulesTag:
685			if deps.systemModules != nil {
686				panic("Found two system module dependencies")
687			}
688			sm := module.(*SystemModules)
689			if sm.outputFile == nil {
690				panic("Missing directory for system module dependency")
691			}
692			deps.systemModules = sm.outputFile
693		}
694	})
695	// do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs
696	// may contain filegroup or genrule.
697	srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
698	flags := j.collectAidlFlags(ctx, deps)
699	srcFiles = j.genSources(ctx, srcFiles, flags)
700
701	// srcs may depend on some genrule output.
702	j.srcJars = srcFiles.FilterByExt(".srcjar")
703	j.srcJars = append(j.srcJars, deps.srcJars...)
704
705	j.srcFiles = srcFiles.FilterOutByExt(".srcjar")
706	j.srcFiles = append(j.srcFiles, deps.srcs...)
707
708	j.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip")
709	j.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
710
711	if j.properties.Local_sourcepaths == nil && len(j.srcFiles) > 0 {
712		j.properties.Local_sourcepaths = append(j.properties.Local_sourcepaths, ".")
713	}
714	j.sourcepaths = android.PathsForModuleSrc(ctx, j.properties.Local_sourcepaths)
715
716	j.argFiles = android.PathsForModuleSrc(ctx, j.properties.Arg_files)
717	argFilesMap := map[string]string{}
718	argFileLabels := []string{}
719
720	for _, label := range j.properties.Arg_files {
721		var paths = android.PathsForModuleSrc(ctx, []string{label})
722		if _, exists := argFilesMap[label]; !exists {
723			argFilesMap[label] = strings.Join(paths.Strings(), " ")
724			argFileLabels = append(argFileLabels, label)
725		} else {
726			ctx.ModuleErrorf("multiple arg_files for %q, %q and %q",
727				label, argFilesMap[label], paths)
728		}
729	}
730
731	var err error
732	j.args, err = android.Expand(String(j.properties.Args), func(name string) (string, error) {
733		if strings.HasPrefix(name, "location ") {
734			label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
735			if paths, ok := argFilesMap[label]; ok {
736				return paths, nil
737			} else {
738				return "", fmt.Errorf("unknown location label %q, expecting one of %q",
739					label, strings.Join(argFileLabels, ", "))
740			}
741		} else if name == "genDir" {
742			return android.PathForModuleGen(ctx).String(), nil
743		}
744		return "", fmt.Errorf("unknown variable '$(%s)'", name)
745	})
746
747	if err != nil {
748		ctx.PropertyErrorf("args", "%s", err.Error())
749	}
750
751	return deps
752}
753
754func (j *Javadoc) DepsMutator(ctx android.BottomUpMutatorContext) {
755	j.addDeps(ctx)
756}
757
758func (j *Javadoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
759	deps := j.collectDeps(ctx)
760
761	var implicits android.Paths
762	implicits = append(implicits, deps.bootClasspath...)
763	implicits = append(implicits, deps.classpath...)
764
765	var bootClasspathArgs, classpathArgs, sourcepathArgs string
766
767	javaVersion := getJavaVersion(ctx, String(j.properties.Java_version), sdkContext(j))
768	if len(deps.bootClasspath) > 0 {
769		var systemModules classpath
770		if deps.systemModules != nil {
771			systemModules = append(systemModules, deps.systemModules)
772		}
773		bootClasspathArgs = systemModules.FormJavaSystemModulesPath("--system ", ctx.Device())
774		bootClasspathArgs = bootClasspathArgs + " --patch-module java.base=."
775	}
776	if len(deps.classpath.Strings()) > 0 {
777		classpathArgs = "-classpath " + strings.Join(deps.classpath.Strings(), ":")
778	}
779
780	implicits = append(implicits, j.srcJars...)
781	implicits = append(implicits, j.argFiles...)
782
783	opts := "-source " + javaVersion + " -J-Xmx1024m -XDignore.symbol.file -Xdoclint:none"
784
785	sourcepathArgs = "-sourcepath " + strings.Join(j.sourcepaths.Strings(), ":")
786
787	ctx.Build(pctx, android.BuildParams{
788		Rule:           javadoc,
789		Description:    "Javadoc",
790		Output:         j.stubsSrcJar,
791		ImplicitOutput: j.docZip,
792		Inputs:         j.srcFiles,
793		Implicits:      implicits,
794		Args: map[string]string{
795			"outDir":            android.PathForModuleOut(ctx, "out").String(),
796			"srcJarDir":         android.PathForModuleOut(ctx, "srcjars").String(),
797			"stubsDir":          android.PathForModuleOut(ctx, "stubsDir").String(),
798			"srcJars":           strings.Join(j.srcJars.Strings(), " "),
799			"opts":              opts,
800			"bootclasspathArgs": bootClasspathArgs,
801			"classpathArgs":     classpathArgs,
802			"sourcepathArgs":    sourcepathArgs,
803			"docZip":            j.docZip.String(),
804		},
805	})
806}
807
808//
809// Droiddoc
810//
811type Droiddoc struct {
812	Javadoc
813
814	properties        DroiddocProperties
815	apiFile           android.WritablePath
816	dexApiFile        android.WritablePath
817	privateApiFile    android.WritablePath
818	privateDexApiFile android.WritablePath
819	removedApiFile    android.WritablePath
820	removedDexApiFile android.WritablePath
821	exactApiFile      android.WritablePath
822	apiMappingFile    android.WritablePath
823	proguardFile      android.WritablePath
824
825	checkCurrentApiTimestamp      android.WritablePath
826	updateCurrentApiTimestamp     android.WritablePath
827	checkLastReleasedApiTimestamp android.WritablePath
828
829	apiFilePath android.Path
830}
831
832func DroiddocFactory() android.Module {
833	module := &Droiddoc{}
834
835	module.AddProperties(&module.properties,
836		&module.Javadoc.properties)
837
838	InitDroiddocModule(module, android.HostAndDeviceSupported)
839	return module
840}
841
842func DroiddocHostFactory() android.Module {
843	module := &Droiddoc{}
844
845	module.AddProperties(&module.properties,
846		&module.Javadoc.properties)
847
848	InitDroiddocModule(module, android.HostSupported)
849	return module
850}
851
852func (d *Droiddoc) ApiFilePath() android.Path {
853	return d.apiFilePath
854}
855
856func (d *Droiddoc) DepsMutator(ctx android.BottomUpMutatorContext) {
857	d.Javadoc.addDeps(ctx)
858
859	if Bool(d.properties.Check_api.Ignore_missing_latest_api) {
860		ignoreMissingModules(ctx, &d.properties.Check_api.Last_released)
861	}
862
863	if String(d.properties.Custom_template) != "" {
864		ctx.AddDependency(ctx.Module(), droiddocTemplateTag, String(d.properties.Custom_template))
865	}
866}
867
868func (d *Droiddoc) initBuilderFlags(ctx android.ModuleContext, implicits *android.Paths,
869	deps deps) (droiddocBuilderFlags, error) {
870	var flags droiddocBuilderFlags
871
872	*implicits = append(*implicits, deps.bootClasspath...)
873	*implicits = append(*implicits, deps.classpath...)
874
875	if len(deps.bootClasspath.Strings()) > 0 {
876		// For OpenJDK 8 we can use -bootclasspath to define the core libraries code.
877		flags.bootClasspathArgs = deps.bootClasspath.FormJavaClassPath("-bootclasspath")
878	}
879	flags.classpathArgs = deps.classpath.FormJavaClassPath("-classpath")
880	// Dokka doesn't support bootClasspath, so combine these two classpath vars for Dokka.
881	dokkaClasspath := classpath{}
882	dokkaClasspath = append(dokkaClasspath, deps.bootClasspath...)
883	dokkaClasspath = append(dokkaClasspath, deps.classpath...)
884	flags.dokkaClasspathArgs = dokkaClasspath.FormJavaClassPath("-classpath")
885
886	// TODO(nanzhang): Remove this if- statement once we finish migration for all Doclava
887	// based stubs generation.
888	// In the future, all the docs generation depends on Metalava stubs (droidstubs) srcjar
889	// dir. We need add the srcjar dir to -sourcepath arg, so that Javadoc can figure out
890	// the correct package name base path.
891	if len(d.Javadoc.properties.Local_sourcepaths) > 0 {
892		flags.sourcepathArgs = "-sourcepath " + strings.Join(d.Javadoc.sourcepaths.Strings(), ":")
893	} else {
894		flags.sourcepathArgs = "-sourcepath " + android.PathForModuleOut(ctx, "srcjars").String()
895	}
896
897	return flags, nil
898}
899
900func (d *Droiddoc) collectDoclavaDocsFlags(ctx android.ModuleContext, implicits *android.Paths,
901	jsilver, doclava android.Path) string {
902
903	*implicits = append(*implicits, jsilver)
904	*implicits = append(*implicits, doclava)
905
906	var date string
907	if runtime.GOOS == "darwin" {
908		date = `date -r`
909	} else {
910		date = `date -d`
911	}
912
913	// Droiddoc always gets "-source 1.8" because it doesn't support 1.9 sources.  For modules with 1.9
914	// sources, droiddoc will get sources produced by metalava which will have already stripped out the
915	// 1.9 language features.
916	args := " -source 1.8 -J-Xmx1600m -J-XX:-OmitStackTraceInFastThrow -XDignore.symbol.file " +
917		"-doclet com.google.doclava.Doclava -docletpath " + jsilver.String() + ":" + doclava.String() + " " +
918		"-hdf page.build " + ctx.Config().BuildId() + "-" + ctx.Config().BuildNumberFromFile() + " " +
919		`-hdf page.now "$$(` + date + ` @$$(cat ` + ctx.Config().Getenv("BUILD_DATETIME_FILE") + `) "+%d %b %Y %k:%M")" `
920
921	if String(d.properties.Custom_template) == "" {
922		// TODO: This is almost always droiddoc-templates-sdk
923		ctx.PropertyErrorf("custom_template", "must specify a template")
924	}
925
926	ctx.VisitDirectDepsWithTag(droiddocTemplateTag, func(m android.Module) {
927		if t, ok := m.(*ExportedDroiddocDir); ok {
928			*implicits = append(*implicits, t.deps...)
929			args = args + " -templatedir " + t.dir.String()
930		} else {
931			ctx.PropertyErrorf("custom_template", "module %q is not a droiddoc_template", ctx.OtherModuleName(m))
932		}
933	})
934
935	if len(d.properties.Html_dirs) > 0 {
936		htmlDir := d.properties.Html_dirs[0]
937		*implicits = append(*implicits, android.PathsForModuleSrc(ctx, []string{filepath.Join(d.properties.Html_dirs[0], "**/*")})...)
938		args = args + " -htmldir " + htmlDir
939	}
940
941	if len(d.properties.Html_dirs) > 1 {
942		htmlDir2 := d.properties.Html_dirs[1]
943		*implicits = append(*implicits, android.PathsForModuleSrc(ctx, []string{filepath.Join(htmlDir2, "**/*")})...)
944		args = args + " -htmldir2 " + htmlDir2
945	}
946
947	if len(d.properties.Html_dirs) > 2 {
948		ctx.PropertyErrorf("html_dirs", "Droiddoc only supports up to 2 html dirs")
949	}
950
951	knownTags := android.PathsForModuleSrc(ctx, d.properties.Knowntags)
952	*implicits = append(*implicits, knownTags...)
953
954	for _, kt := range knownTags {
955		args = args + " -knowntags " + kt.String()
956	}
957
958	for _, hdf := range d.properties.Hdf {
959		args = args + " -hdf " + hdf
960	}
961
962	if String(d.properties.Proofread_file) != "" {
963		proofreadFile := android.PathForModuleOut(ctx, String(d.properties.Proofread_file))
964		args = args + " -proofread " + proofreadFile.String()
965	}
966
967	if String(d.properties.Todo_file) != "" {
968		// tricky part:
969		// we should not compute full path for todo_file through PathForModuleOut().
970		// the non-standard doclet will get the full path relative to "-o".
971		args = args + " -todo " + String(d.properties.Todo_file)
972	}
973
974	if String(d.properties.Resourcesdir) != "" {
975		// TODO: should we add files under resourcesDir to the implicits? It seems that
976		// resourcesDir is one sub dir of htmlDir
977		resourcesDir := android.PathForModuleSrc(ctx, String(d.properties.Resourcesdir))
978		args = args + " -resourcesdir " + resourcesDir.String()
979	}
980
981	if String(d.properties.Resourcesoutdir) != "" {
982		// TODO: it seems -resourceoutdir reference/android/images/ didn't get generated anywhere.
983		args = args + " -resourcesoutdir " + String(d.properties.Resourcesoutdir)
984	}
985	return args
986}
987
988func (d *Droiddoc) collectStubsFlags(ctx android.ModuleContext,
989	implicitOutputs *android.WritablePaths) string {
990	var doclavaFlags string
991	if apiCheckEnabled(d.properties.Check_api.Current, "current") ||
992		apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") ||
993		String(d.properties.Api_filename) != "" {
994		d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt")
995		doclavaFlags += " -api " + d.apiFile.String()
996		*implicitOutputs = append(*implicitOutputs, d.apiFile)
997		d.apiFilePath = d.apiFile
998	}
999
1000	if apiCheckEnabled(d.properties.Check_api.Current, "current") ||
1001		apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") ||
1002		String(d.properties.Removed_api_filename) != "" {
1003		d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt")
1004		doclavaFlags += " -removedApi " + d.removedApiFile.String()
1005		*implicitOutputs = append(*implicitOutputs, d.removedApiFile)
1006	}
1007
1008	if String(d.properties.Private_api_filename) != "" {
1009		d.privateApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_api_filename))
1010		doclavaFlags += " -privateApi " + d.privateApiFile.String()
1011		*implicitOutputs = append(*implicitOutputs, d.privateApiFile)
1012	}
1013
1014	if String(d.properties.Dex_api_filename) != "" {
1015		d.dexApiFile = android.PathForModuleOut(ctx, String(d.properties.Dex_api_filename))
1016		doclavaFlags += " -dexApi " + d.dexApiFile.String()
1017		*implicitOutputs = append(*implicitOutputs, d.dexApiFile)
1018	}
1019
1020	if String(d.properties.Private_dex_api_filename) != "" {
1021		d.privateDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_dex_api_filename))
1022		doclavaFlags += " -privateDexApi " + d.privateDexApiFile.String()
1023		*implicitOutputs = append(*implicitOutputs, d.privateDexApiFile)
1024	}
1025
1026	if String(d.properties.Removed_dex_api_filename) != "" {
1027		d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename))
1028		doclavaFlags += " -removedDexApi " + d.removedDexApiFile.String()
1029		*implicitOutputs = append(*implicitOutputs, d.removedDexApiFile)
1030	}
1031
1032	if String(d.properties.Exact_api_filename) != "" {
1033		d.exactApiFile = android.PathForModuleOut(ctx, String(d.properties.Exact_api_filename))
1034		doclavaFlags += " -exactApi " + d.exactApiFile.String()
1035		*implicitOutputs = append(*implicitOutputs, d.exactApiFile)
1036	}
1037
1038	if String(d.properties.Dex_mapping_filename) != "" {
1039		d.apiMappingFile = android.PathForModuleOut(ctx, String(d.properties.Dex_mapping_filename))
1040		doclavaFlags += " -apiMapping " + d.apiMappingFile.String()
1041		*implicitOutputs = append(*implicitOutputs, d.apiMappingFile)
1042	}
1043
1044	if String(d.properties.Proguard_filename) != "" {
1045		d.proguardFile = android.PathForModuleOut(ctx, String(d.properties.Proguard_filename))
1046		doclavaFlags += " -proguard " + d.proguardFile.String()
1047		*implicitOutputs = append(*implicitOutputs, d.proguardFile)
1048	}
1049
1050	if BoolDefault(d.properties.Create_stubs, true) {
1051		doclavaFlags += " -stubs " + android.PathForModuleOut(ctx, "stubsDir").String()
1052	}
1053
1054	if Bool(d.properties.Write_sdk_values) {
1055		doclavaFlags += " -sdkvalues " + android.PathForModuleOut(ctx, "out").String()
1056	}
1057
1058	return doclavaFlags
1059}
1060
1061func (d *Droiddoc) getPostDoclavaCmds(ctx android.ModuleContext, implicits *android.Paths) string {
1062	var cmds string
1063	if String(d.properties.Static_doc_index_redirect) != "" {
1064		static_doc_index_redirect := ctx.ExpandSource(String(d.properties.Static_doc_index_redirect),
1065			"static_doc_index_redirect")
1066		*implicits = append(*implicits, static_doc_index_redirect)
1067		cmds = cmds + " && cp " + static_doc_index_redirect.String() + " " +
1068			android.PathForModuleOut(ctx, "out", "index.html").String()
1069	}
1070
1071	if String(d.properties.Static_doc_properties) != "" {
1072		static_doc_properties := ctx.ExpandSource(String(d.properties.Static_doc_properties),
1073			"static_doc_properties")
1074		*implicits = append(*implicits, static_doc_properties)
1075		cmds = cmds + " && cp " + static_doc_properties.String() + " " +
1076			android.PathForModuleOut(ctx, "out", "source.properties").String()
1077	}
1078	return cmds
1079}
1080
1081func (d *Droiddoc) transformDoclava(ctx android.ModuleContext, implicits android.Paths,
1082	implicitOutputs android.WritablePaths,
1083	bootclasspathArgs, classpathArgs, sourcepathArgs, opts, postDoclavaCmds string) {
1084	ctx.Build(pctx, android.BuildParams{
1085		Rule:            javadoc,
1086		Description:     "Doclava",
1087		Output:          d.Javadoc.stubsSrcJar,
1088		Inputs:          d.Javadoc.srcFiles,
1089		Implicits:       implicits,
1090		ImplicitOutputs: implicitOutputs,
1091		Args: map[string]string{
1092			"outDir":            android.PathForModuleOut(ctx, "out").String(),
1093			"srcJarDir":         android.PathForModuleOut(ctx, "srcjars").String(),
1094			"stubsDir":          android.PathForModuleOut(ctx, "stubsDir").String(),
1095			"srcJars":           strings.Join(d.Javadoc.srcJars.Strings(), " "),
1096			"opts":              opts,
1097			"bootclasspathArgs": bootclasspathArgs,
1098			"classpathArgs":     classpathArgs,
1099			"sourcepathArgs":    sourcepathArgs,
1100			"docZip":            d.Javadoc.docZip.String(),
1101			"postDoclavaCmds":   postDoclavaCmds,
1102		},
1103	})
1104}
1105
1106func (d *Droiddoc) transformCheckApi(ctx android.ModuleContext, apiFile, removedApiFile android.Path,
1107	checkApiClasspath classpath, msg, opts string, output android.WritablePath) {
1108	ctx.Build(pctx, android.BuildParams{
1109		Rule:        apiCheck,
1110		Description: "Doclava Check API",
1111		Output:      output,
1112		Inputs:      nil,
1113		Implicits: append(android.Paths{apiFile, removedApiFile, d.apiFile, d.removedApiFile},
1114			checkApiClasspath...),
1115		Args: map[string]string{
1116			"msg":                   msg,
1117			"classpath":             checkApiClasspath.FormJavaClassPath(""),
1118			"opts":                  opts,
1119			"apiFile":               apiFile.String(),
1120			"apiFileToCheck":        d.apiFile.String(),
1121			"removedApiFile":        removedApiFile.String(),
1122			"removedApiFileToCheck": d.removedApiFile.String(),
1123		},
1124	})
1125}
1126
1127func (d *Droiddoc) transformDokka(ctx android.ModuleContext, implicits android.Paths,
1128	classpathArgs, opts string) {
1129	ctx.Build(pctx, android.BuildParams{
1130		Rule:        dokka,
1131		Description: "Dokka",
1132		Output:      d.Javadoc.stubsSrcJar,
1133		Inputs:      d.Javadoc.srcFiles,
1134		Implicits:   implicits,
1135		Args: map[string]string{
1136			"outDir":        android.PathForModuleOut(ctx, "dokka-out").String(),
1137			"srcJarDir":     android.PathForModuleOut(ctx, "dokka-srcjars").String(),
1138			"stubsDir":      android.PathForModuleOut(ctx, "dokka-stubsDir").String(),
1139			"srcJars":       strings.Join(d.Javadoc.srcJars.Strings(), " "),
1140			"classpathArgs": classpathArgs,
1141			"opts":          opts,
1142			"docZip":        d.Javadoc.docZip.String(),
1143		},
1144	})
1145}
1146
1147func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
1148	deps := d.Javadoc.collectDeps(ctx)
1149
1150	jsilver := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jsilver.jar")
1151	doclava := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "doclava.jar")
1152	java8Home := ctx.Config().Getenv("ANDROID_JAVA8_HOME")
1153	checkApiClasspath := classpath{jsilver, doclava, android.PathForSource(ctx, java8Home, "lib/tools.jar")}
1154
1155	var implicits android.Paths
1156	implicits = append(implicits, d.Javadoc.srcJars...)
1157	implicits = append(implicits, d.Javadoc.argFiles...)
1158
1159	var implicitOutputs android.WritablePaths
1160	implicitOutputs = append(implicitOutputs, d.Javadoc.docZip)
1161	for _, o := range d.Javadoc.properties.Out {
1162		implicitOutputs = append(implicitOutputs, android.PathForModuleGen(ctx, o))
1163	}
1164
1165	flags, err := d.initBuilderFlags(ctx, &implicits, deps)
1166	if err != nil {
1167		return
1168	}
1169
1170	flags.doclavaStubsFlags = d.collectStubsFlags(ctx, &implicitOutputs)
1171	if Bool(d.properties.Dokka_enabled) {
1172		d.transformDokka(ctx, implicits, flags.classpathArgs, d.Javadoc.args)
1173	} else {
1174		flags.doclavaDocsFlags = d.collectDoclavaDocsFlags(ctx, &implicits, jsilver, doclava)
1175		flags.postDoclavaCmds = d.getPostDoclavaCmds(ctx, &implicits)
1176		d.transformDoclava(ctx, implicits, implicitOutputs, flags.bootClasspathArgs, flags.classpathArgs,
1177			flags.sourcepathArgs, flags.doclavaDocsFlags+flags.doclavaStubsFlags+" "+d.Javadoc.args,
1178			flags.postDoclavaCmds)
1179	}
1180
1181	if apiCheckEnabled(d.properties.Check_api.Current, "current") &&
1182		!ctx.Config().IsPdkBuild() {
1183		apiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Api_file),
1184			"check_api.current.api_file")
1185		removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Removed_api_file),
1186			"check_api.current_removed_api_file")
1187
1188		d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp")
1189		d.transformCheckApi(ctx, apiFile, removedApiFile, checkApiClasspath,
1190			fmt.Sprintf(`\n******************************\n`+
1191				`You have tried to change the API from what has been previously approved.\n\n`+
1192				`To make these errors go away, you have two choices:\n`+
1193				`   1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+
1194				`      errors above.\n\n`+
1195				`   2. You can update current.txt by executing the following command:\n`+
1196				`         make %s-update-current-api\n\n`+
1197				`      To submit the revised current.txt to the main Android repository,\n`+
1198				`      you will need approval.\n`+
1199				`******************************\n`, ctx.ModuleName()), String(d.properties.Check_api.Current.Args),
1200			d.checkCurrentApiTimestamp)
1201
1202		d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp")
1203		transformUpdateApi(ctx, apiFile, removedApiFile, d.apiFile, d.removedApiFile,
1204			d.updateCurrentApiTimestamp)
1205	}
1206
1207	if apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") &&
1208		!ctx.Config().IsPdkBuild() {
1209		apiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Api_file),
1210			"check_api.last_released.api_file")
1211		removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Removed_api_file),
1212			"check_api.last_released.removed_api_file")
1213
1214		d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "check_last_released_api.timestamp")
1215		d.transformCheckApi(ctx, apiFile, removedApiFile, checkApiClasspath,
1216			`\n******************************\n`+
1217				`You have tried to change the API from what has been previously released in\n`+
1218				`an SDK.  Please fix the errors listed above.\n`+
1219				`******************************\n`, String(d.properties.Check_api.Last_released.Args),
1220			d.checkLastReleasedApiTimestamp)
1221	}
1222}
1223
1224//
1225// Droidstubs
1226//
1227type Droidstubs struct {
1228	Javadoc
1229
1230	properties              DroidstubsProperties
1231	apiFile                 android.WritablePath
1232	apiXmlFile              android.WritablePath
1233	lastReleasedApiXmlFile  android.WritablePath
1234	dexApiFile              android.WritablePath
1235	privateApiFile          android.WritablePath
1236	privateDexApiFile       android.WritablePath
1237	removedApiFile          android.WritablePath
1238	removedDexApiFile       android.WritablePath
1239	apiMappingFile          android.WritablePath
1240	exactApiFile            android.WritablePath
1241	proguardFile            android.WritablePath
1242	nullabilityWarningsFile android.WritablePath
1243
1244	checkCurrentApiTimestamp      android.WritablePath
1245	updateCurrentApiTimestamp     android.WritablePath
1246	checkLastReleasedApiTimestamp android.WritablePath
1247
1248	checkNullabilityWarningsTimestamp android.WritablePath
1249
1250	annotationsZip android.WritablePath
1251	apiVersionsXml android.WritablePath
1252
1253	apiFilePath android.Path
1254
1255	jdiffDocZip      android.WritablePath
1256	jdiffStubsSrcJar android.WritablePath
1257}
1258
1259func DroidstubsFactory() android.Module {
1260	module := &Droidstubs{}
1261
1262	module.AddProperties(&module.properties,
1263		&module.Javadoc.properties)
1264
1265	InitDroiddocModule(module, android.HostAndDeviceSupported)
1266	return module
1267}
1268
1269func DroidstubsHostFactory() android.Module {
1270	module := &Droidstubs{}
1271
1272	module.AddProperties(&module.properties,
1273		&module.Javadoc.properties)
1274
1275	InitDroiddocModule(module, android.HostSupported)
1276	return module
1277}
1278
1279func (d *Droidstubs) ApiFilePath() android.Path {
1280	return d.apiFilePath
1281}
1282
1283func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) {
1284	d.Javadoc.addDeps(ctx)
1285
1286	if Bool(d.properties.Check_api.Ignore_missing_latest_api) {
1287		ignoreMissingModules(ctx, &d.properties.Check_api.Last_released)
1288	}
1289
1290	if len(d.properties.Merge_annotations_dirs) != 0 {
1291		for _, mergeAnnotationsDir := range d.properties.Merge_annotations_dirs {
1292			ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir)
1293		}
1294	}
1295
1296	if len(d.properties.Merge_inclusion_annotations_dirs) != 0 {
1297		for _, mergeInclusionAnnotationsDir := range d.properties.Merge_inclusion_annotations_dirs {
1298			ctx.AddDependency(ctx.Module(), metalavaMergeInclusionAnnotationsDirTag, mergeInclusionAnnotationsDir)
1299		}
1300	}
1301
1302	if len(d.properties.Api_levels_annotations_dirs) != 0 {
1303		for _, apiLevelsAnnotationsDir := range d.properties.Api_levels_annotations_dirs {
1304			ctx.AddDependency(ctx.Module(), metalavaAPILevelsAnnotationsDirTag, apiLevelsAnnotationsDir)
1305		}
1306	}
1307}
1308
1309func (d *Droidstubs) initBuilderFlags(ctx android.ModuleContext, implicits *android.Paths,
1310	deps deps) (droiddocBuilderFlags, error) {
1311	var flags droiddocBuilderFlags
1312
1313	*implicits = append(*implicits, deps.bootClasspath...)
1314	*implicits = append(*implicits, deps.classpath...)
1315
1316	// continue to use -bootclasspath even if Metalava under -source 1.9 is enabled
1317	// since it doesn't support system modules yet.
1318	if len(deps.bootClasspath.Strings()) > 0 {
1319		// For OpenJDK 8 we can use -bootclasspath to define the core libraries code.
1320		flags.bootClasspathArgs = deps.bootClasspath.FormJavaClassPath("-bootclasspath")
1321	}
1322	flags.classpathArgs = deps.classpath.FormJavaClassPath("-classpath")
1323
1324	flags.sourcepathArgs = "-sourcepath \"" + strings.Join(d.Javadoc.sourcepaths.Strings(), ":") + "\""
1325	return flags, nil
1326}
1327
1328func (d *Droidstubs) collectStubsFlags(ctx android.ModuleContext,
1329	implicitOutputs *android.WritablePaths) string {
1330	var metalavaFlags string
1331	if apiCheckEnabled(d.properties.Check_api.Current, "current") ||
1332		apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") ||
1333		String(d.properties.Api_filename) != "" {
1334		d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt")
1335		metalavaFlags = metalavaFlags + " --api " + d.apiFile.String()
1336		*implicitOutputs = append(*implicitOutputs, d.apiFile)
1337		d.apiFilePath = d.apiFile
1338	}
1339
1340	if apiCheckEnabled(d.properties.Check_api.Current, "current") ||
1341		apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") ||
1342		String(d.properties.Removed_api_filename) != "" {
1343		d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt")
1344		metalavaFlags = metalavaFlags + " --removed-api " + d.removedApiFile.String()
1345		*implicitOutputs = append(*implicitOutputs, d.removedApiFile)
1346	}
1347
1348	if String(d.properties.Private_api_filename) != "" {
1349		d.privateApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_api_filename))
1350		metalavaFlags = metalavaFlags + " --private-api " + d.privateApiFile.String()
1351		*implicitOutputs = append(*implicitOutputs, d.privateApiFile)
1352	}
1353
1354	if String(d.properties.Dex_api_filename) != "" {
1355		d.dexApiFile = android.PathForModuleOut(ctx, String(d.properties.Dex_api_filename))
1356		metalavaFlags += " --dex-api " + d.dexApiFile.String()
1357		*implicitOutputs = append(*implicitOutputs, d.dexApiFile)
1358	}
1359
1360	if String(d.properties.Private_dex_api_filename) != "" {
1361		d.privateDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_dex_api_filename))
1362		metalavaFlags = metalavaFlags + " --private-dex-api " + d.privateDexApiFile.String()
1363		*implicitOutputs = append(*implicitOutputs, d.privateDexApiFile)
1364	}
1365
1366	if String(d.properties.Removed_dex_api_filename) != "" {
1367		d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename))
1368		metalavaFlags = metalavaFlags + " --removed-dex-api " + d.removedDexApiFile.String()
1369		*implicitOutputs = append(*implicitOutputs, d.removedDexApiFile)
1370	}
1371
1372	if String(d.properties.Exact_api_filename) != "" {
1373		d.exactApiFile = android.PathForModuleOut(ctx, String(d.properties.Exact_api_filename))
1374		metalavaFlags = metalavaFlags + " --exact-api " + d.exactApiFile.String()
1375		*implicitOutputs = append(*implicitOutputs, d.exactApiFile)
1376	}
1377
1378	if String(d.properties.Dex_mapping_filename) != "" {
1379		d.apiMappingFile = android.PathForModuleOut(ctx, String(d.properties.Dex_mapping_filename))
1380		metalavaFlags = metalavaFlags + " --dex-api-mapping " + d.apiMappingFile.String()
1381		*implicitOutputs = append(*implicitOutputs, d.apiMappingFile)
1382	}
1383
1384	if String(d.properties.Proguard_filename) != "" {
1385		d.proguardFile = android.PathForModuleOut(ctx, String(d.properties.Proguard_filename))
1386		metalavaFlags += " --proguard " + d.proguardFile.String()
1387		*implicitOutputs = append(*implicitOutputs, d.proguardFile)
1388	}
1389
1390	if Bool(d.properties.Write_sdk_values) {
1391		metalavaFlags = metalavaFlags + " --sdk-values " + android.PathForModuleOut(ctx, "out").String()
1392	}
1393
1394	if Bool(d.properties.Create_doc_stubs) {
1395		metalavaFlags += " --doc-stubs " + android.PathForModuleOut(ctx, "stubsDir").String()
1396	} else {
1397		metalavaFlags += " --stubs " + android.PathForModuleOut(ctx, "stubsDir").String()
1398	}
1399	return metalavaFlags
1400}
1401
1402func (d *Droidstubs) collectAnnotationsFlags(ctx android.ModuleContext,
1403	implicits *android.Paths, implicitOutputs *android.WritablePaths) (string, string) {
1404	var flags, mergeAnnoDirFlags string
1405	if Bool(d.properties.Annotations_enabled) {
1406		flags += " --include-annotations"
1407		validatingNullability :=
1408			strings.Contains(d.Javadoc.args, "--validate-nullability-from-merged-stubs") ||
1409				String(d.properties.Validate_nullability_from_list) != ""
1410		migratingNullability := String(d.properties.Previous_api) != ""
1411		if !(migratingNullability || validatingNullability) {
1412			ctx.PropertyErrorf("previous_api",
1413				"has to be non-empty if annotations was enabled (unless validating nullability)")
1414		}
1415		if migratingNullability {
1416			previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
1417			*implicits = append(*implicits, previousApi)
1418			flags += " --migrate-nullness " + previousApi.String()
1419		}
1420		if s := String(d.properties.Validate_nullability_from_list); s != "" {
1421			flags += " --validate-nullability-from-list " + android.PathForModuleSrc(ctx, s).String()
1422		}
1423		if validatingNullability {
1424			d.nullabilityWarningsFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_nullability_warnings.txt")
1425			*implicitOutputs = append(*implicitOutputs, d.nullabilityWarningsFile)
1426			flags += " --nullability-warnings-txt " + d.nullabilityWarningsFile.String()
1427		}
1428
1429		d.annotationsZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"_annotations.zip")
1430		*implicitOutputs = append(*implicitOutputs, d.annotationsZip)
1431
1432		flags += " --extract-annotations " + d.annotationsZip.String()
1433
1434		if len(d.properties.Merge_annotations_dirs) == 0 {
1435			ctx.PropertyErrorf("merge_annotations_dirs",
1436				"has to be non-empty if annotations was enabled!")
1437		}
1438		ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
1439			if t, ok := m.(*ExportedDroiddocDir); ok {
1440				*implicits = append(*implicits, t.deps...)
1441				mergeAnnoDirFlags += " --merge-qualifier-annotations " + t.dir.String()
1442			} else {
1443				ctx.PropertyErrorf("merge_annotations_dirs",
1444					"module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
1445			}
1446		})
1447		flags += mergeAnnoDirFlags
1448		// TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
1449		flags += " --hide HiddenTypedefConstant --hide SuperfluousPrefix --hide AnnotationExtraction"
1450	}
1451
1452	return flags, mergeAnnoDirFlags
1453}
1454
1455func (d *Droidstubs) collectInclusionAnnotationsFlags(ctx android.ModuleContext,
1456	implicits *android.Paths, implicitOutputs *android.WritablePaths) string {
1457	var flags string
1458	ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) {
1459		if t, ok := m.(*ExportedDroiddocDir); ok {
1460			*implicits = append(*implicits, t.deps...)
1461			flags += " --merge-inclusion-annotations " + t.dir.String()
1462		} else {
1463			ctx.PropertyErrorf("merge_inclusion_annotations_dirs",
1464				"module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
1465		}
1466	})
1467
1468	return flags
1469}
1470
1471func (d *Droidstubs) collectAPILevelsAnnotationsFlags(ctx android.ModuleContext,
1472	implicits *android.Paths, implicitOutputs *android.WritablePaths) string {
1473	var flags string
1474	if Bool(d.properties.Api_levels_annotations_enabled) {
1475		d.apiVersionsXml = android.PathForModuleOut(ctx, "api-versions.xml")
1476		*implicitOutputs = append(*implicitOutputs, d.apiVersionsXml)
1477
1478		if len(d.properties.Api_levels_annotations_dirs) == 0 {
1479			ctx.PropertyErrorf("api_levels_annotations_dirs",
1480				"has to be non-empty if api levels annotations was enabled!")
1481		}
1482
1483		flags = " --generate-api-levels " + d.apiVersionsXml.String() + " --apply-api-levels " +
1484			d.apiVersionsXml.String() + " --current-version " + ctx.Config().PlatformSdkVersion() +
1485			" --current-codename " + ctx.Config().PlatformSdkCodename() + " "
1486
1487		ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
1488			if t, ok := m.(*ExportedDroiddocDir); ok {
1489				var androidJars android.Paths
1490				for _, dep := range t.deps {
1491					if strings.HasSuffix(dep.String(), "android.jar") {
1492						androidJars = append(androidJars, dep)
1493					}
1494				}
1495				*implicits = append(*implicits, androidJars...)
1496				flags += " --android-jar-pattern " + t.dir.String() + "/%/public/android.jar "
1497			} else {
1498				ctx.PropertyErrorf("api_levels_annotations_dirs",
1499					"module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
1500			}
1501		})
1502
1503	}
1504
1505	return flags
1506}
1507
1508func (d *Droidstubs) collectApiToXmlFlags(ctx android.ModuleContext, implicits *android.Paths,
1509	implicitOutputs *android.WritablePaths) string {
1510	var flags string
1511	if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() {
1512		if d.apiFile.String() == "" {
1513			ctx.ModuleErrorf("API signature file has to be specified in Metalava when jdiff is enabled.")
1514		}
1515
1516		d.apiXmlFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.xml")
1517		*implicitOutputs = append(*implicitOutputs, d.apiXmlFile)
1518
1519		flags = " --api-xml " + d.apiXmlFile.String()
1520
1521		if String(d.properties.Check_api.Last_released.Api_file) == "" {
1522			ctx.PropertyErrorf("check_api.last_released.api_file",
1523				"has to be non-empty if jdiff was enabled!")
1524		}
1525		lastReleasedApi := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Api_file),
1526			"check_api.last_released.api_file")
1527		*implicits = append(*implicits, lastReleasedApi)
1528
1529		d.lastReleasedApiXmlFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_last_released_api.xml")
1530		*implicitOutputs = append(*implicitOutputs, d.lastReleasedApiXmlFile)
1531
1532		flags += " --convert-to-jdiff " + lastReleasedApi.String() + " " +
1533			d.lastReleasedApiXmlFile.String()
1534	}
1535
1536	return flags
1537}
1538
1539func (d *Droidstubs) transformMetalava(ctx android.ModuleContext, implicits android.Paths,
1540	implicitOutputs android.WritablePaths, javaVersion,
1541	bootclasspathArgs, classpathArgs, sourcepathArgs, opts string) {
1542
1543	ctx.Build(pctx, android.BuildParams{
1544		Rule:            metalava,
1545		Description:     "Metalava",
1546		Output:          d.Javadoc.stubsSrcJar,
1547		Inputs:          d.Javadoc.srcFiles,
1548		Implicits:       implicits,
1549		ImplicitOutputs: implicitOutputs,
1550		Args: map[string]string{
1551			"outDir":            android.PathForModuleOut(ctx, "out").String(),
1552			"srcJarDir":         android.PathForModuleOut(ctx, "srcjars").String(),
1553			"stubsDir":          android.PathForModuleOut(ctx, "stubsDir").String(),
1554			"srcJars":           strings.Join(d.Javadoc.srcJars.Strings(), " "),
1555			"javaVersion":       javaVersion,
1556			"bootclasspathArgs": bootclasspathArgs,
1557			"classpathArgs":     classpathArgs,
1558			"sourcepathArgs":    sourcepathArgs,
1559			"opts":              opts,
1560		},
1561	})
1562}
1563
1564func (d *Droidstubs) transformCheckApi(ctx android.ModuleContext,
1565	apiFile, removedApiFile android.Path, implicits android.Paths,
1566	javaVersion, bootclasspathArgs, classpathArgs, sourcepathArgs, opts, subdir, msg string,
1567	output android.WritablePath) {
1568	ctx.Build(pctx, android.BuildParams{
1569		Rule:        metalavaApiCheck,
1570		Description: "Metalava Check API",
1571		Output:      output,
1572		Inputs:      d.Javadoc.srcFiles,
1573		Implicits: append(android.Paths{apiFile, removedApiFile, d.apiFile, d.removedApiFile},
1574			implicits...),
1575		Args: map[string]string{
1576			"srcJarDir":         android.PathForModuleOut(ctx, subdir, "srcjars").String(),
1577			"srcJars":           strings.Join(d.Javadoc.srcJars.Strings(), " "),
1578			"javaVersion":       javaVersion,
1579			"bootclasspathArgs": bootclasspathArgs,
1580			"classpathArgs":     classpathArgs,
1581			"sourcepathArgs":    sourcepathArgs,
1582			"opts":              opts,
1583			"msg":               msg,
1584		},
1585	})
1586}
1587
1588func (d *Droidstubs) transformJdiff(ctx android.ModuleContext, implicits android.Paths,
1589	implicitOutputs android.WritablePaths,
1590	bootclasspathArgs, classpathArgs, sourcepathArgs, opts string) {
1591	ctx.Build(pctx, android.BuildParams{
1592		Rule:            javadoc,
1593		Description:     "Jdiff",
1594		Output:          d.jdiffStubsSrcJar,
1595		Inputs:          d.Javadoc.srcFiles,
1596		Implicits:       implicits,
1597		ImplicitOutputs: implicitOutputs,
1598		Args: map[string]string{
1599			"outDir":            android.PathForModuleOut(ctx, "jdiff-out").String(),
1600			"srcJarDir":         android.PathForModuleOut(ctx, "jdiff-srcjars").String(),
1601			"stubsDir":          android.PathForModuleOut(ctx, "jdiff-stubsDir").String(),
1602			"srcJars":           strings.Join(d.Javadoc.srcJars.Strings(), " "),
1603			"opts":              opts,
1604			"bootclasspathArgs": bootclasspathArgs,
1605			"classpathArgs":     classpathArgs,
1606			"sourcepathArgs":    sourcepathArgs,
1607			"docZip":            d.jdiffDocZip.String(),
1608		},
1609	})
1610}
1611
1612func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
1613	deps := d.Javadoc.collectDeps(ctx)
1614
1615	javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), sdkContext(d))
1616
1617	var implicits android.Paths
1618	implicits = append(implicits, d.Javadoc.srcJars...)
1619	implicits = append(implicits, d.Javadoc.argFiles...)
1620
1621	var implicitOutputs android.WritablePaths
1622	for _, o := range d.Javadoc.properties.Out {
1623		implicitOutputs = append(implicitOutputs, android.PathForModuleGen(ctx, o))
1624	}
1625
1626	flags, err := d.initBuilderFlags(ctx, &implicits, deps)
1627	metalavaCheckApiImplicits := implicits
1628	jdiffImplicits := implicits
1629
1630	if err != nil {
1631		return
1632	}
1633
1634	flags.metalavaStubsFlags = d.collectStubsFlags(ctx, &implicitOutputs)
1635	flags.metalavaAnnotationsFlags, flags.metalavaMergeAnnoDirFlags =
1636		d.collectAnnotationsFlags(ctx, &implicits, &implicitOutputs)
1637	flags.metalavaInclusionAnnotationsFlags = d.collectInclusionAnnotationsFlags(ctx, &implicits, &implicitOutputs)
1638	flags.metalavaApiLevelsAnnotationsFlags = d.collectAPILevelsAnnotationsFlags(ctx, &implicits, &implicitOutputs)
1639	flags.metalavaApiToXmlFlags = d.collectApiToXmlFlags(ctx, &implicits, &implicitOutputs)
1640
1641	if strings.Contains(d.Javadoc.args, "--generate-documentation") {
1642		// Currently Metalava have the ability to invoke Javadoc in a seperate process.
1643		// Pass "-nodocs" to suppress the Javadoc invocation when Metalava receives
1644		// "--generate-documentation" arg. This is not needed when Metalava removes this feature.
1645		d.Javadoc.args = d.Javadoc.args + " -nodocs "
1646	}
1647	d.transformMetalava(ctx, implicits, implicitOutputs, javaVersion,
1648		flags.bootClasspathArgs, flags.classpathArgs, flags.sourcepathArgs,
1649		flags.metalavaStubsFlags+flags.metalavaAnnotationsFlags+flags.metalavaInclusionAnnotationsFlags+
1650			flags.metalavaApiLevelsAnnotationsFlags+flags.metalavaApiToXmlFlags+" "+d.Javadoc.args)
1651
1652	if apiCheckEnabled(d.properties.Check_api.Current, "current") &&
1653		!ctx.Config().IsPdkBuild() {
1654		apiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Api_file),
1655			"check_api.current.api_file")
1656		removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Removed_api_file),
1657			"check_api.current_removed_api_file")
1658
1659		d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp")
1660		opts := " " + d.Javadoc.args + " --check-compatibility:api:current " + apiFile.String() +
1661			" --check-compatibility:removed:current " + removedApiFile.String() +
1662			flags.metalavaInclusionAnnotationsFlags + flags.metalavaMergeAnnoDirFlags + " "
1663
1664		d.transformCheckApi(ctx, apiFile, removedApiFile, metalavaCheckApiImplicits,
1665			javaVersion, flags.bootClasspathArgs, flags.classpathArgs, flags.sourcepathArgs, opts, "current-apicheck",
1666			fmt.Sprintf(`\n******************************\n`+
1667				`You have tried to change the API from what has been previously approved.\n\n`+
1668				`To make these errors go away, you have two choices:\n`+
1669				`   1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+
1670				`      errors above.\n\n`+
1671				`   2. You can update current.txt by executing the following command:\n`+
1672				`         make %s-update-current-api\n\n`+
1673				`      To submit the revised current.txt to the main Android repository,\n`+
1674				`      you will need approval.\n`+
1675				`******************************\n`, ctx.ModuleName()),
1676			d.checkCurrentApiTimestamp)
1677
1678		d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp")
1679		transformUpdateApi(ctx, apiFile, removedApiFile, d.apiFile, d.removedApiFile,
1680			d.updateCurrentApiTimestamp)
1681	}
1682
1683	if apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") &&
1684		!ctx.Config().IsPdkBuild() {
1685		apiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Api_file),
1686			"check_api.last_released.api_file")
1687		removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Removed_api_file),
1688			"check_api.last_released.removed_api_file")
1689
1690		d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "check_last_released_api.timestamp")
1691		opts := " " + d.Javadoc.args + " --check-compatibility:api:released " + apiFile.String() +
1692			flags.metalavaInclusionAnnotationsFlags + " --check-compatibility:removed:released " +
1693			removedApiFile.String() + flags.metalavaMergeAnnoDirFlags + " "
1694
1695		d.transformCheckApi(ctx, apiFile, removedApiFile, metalavaCheckApiImplicits,
1696			javaVersion, flags.bootClasspathArgs, flags.classpathArgs, flags.sourcepathArgs, opts, "last-apicheck",
1697			`\n******************************\n`+
1698				`You have tried to change the API from what has been previously released in\n`+
1699				`an SDK.  Please fix the errors listed above.\n`+
1700				`******************************\n`,
1701			d.checkLastReleasedApiTimestamp)
1702	}
1703
1704	if String(d.properties.Check_nullability_warnings) != "" {
1705		if d.nullabilityWarningsFile == nil {
1706			ctx.PropertyErrorf("check_nullability_warnings",
1707				"Cannot specify check_nullability_warnings unless validating nullability")
1708		}
1709		checkNullabilityWarnings := ctx.ExpandSource(String(d.properties.Check_nullability_warnings),
1710			"check_nullability_warnings")
1711		d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "check_nullability_warnings.timestamp")
1712		msg := fmt.Sprintf(`\n******************************\n`+
1713			`The warnings encountered during nullability annotation validation did\n`+
1714			`not match the checked in file of expected warnings. The diffs are shown\n`+
1715			`above. You have two options:\n`+
1716			`   1. Resolve the differences by editing the nullability annotations.\n`+
1717			`   2. Update the file of expected warnings by running:\n`+
1718			`         cp %s %s\n`+
1719			`       and submitting the updated file as part of your change.`,
1720			d.nullabilityWarningsFile, checkNullabilityWarnings)
1721		ctx.Build(pctx, android.BuildParams{
1722			Rule:        nullabilityWarningsCheck,
1723			Description: "Nullability Warnings Check",
1724			Output:      d.checkNullabilityWarningsTimestamp,
1725			Implicits:   android.Paths{checkNullabilityWarnings, d.nullabilityWarningsFile},
1726			Args: map[string]string{
1727				"expected": checkNullabilityWarnings.String(),
1728				"actual":   d.nullabilityWarningsFile.String(),
1729				"msg":      msg,
1730			},
1731		})
1732	}
1733
1734	if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() {
1735
1736		// Please sync with android-api-council@ before making any changes for the name of jdiffDocZip below
1737		// since there's cron job downstream that fetch this .zip file periodically.
1738		// See b/116221385 for reference.
1739		d.jdiffDocZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"jdiff-docs.zip")
1740		d.jdiffStubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"jdiff-stubs.srcjar")
1741
1742		var jdiffImplicitOutputs android.WritablePaths
1743		jdiffImplicitOutputs = append(jdiffImplicitOutputs, d.jdiffDocZip)
1744
1745		jdiff := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jdiff.jar")
1746		jdiffImplicits = append(jdiffImplicits, android.Paths{jdiff, d.apiXmlFile, d.lastReleasedApiXmlFile}...)
1747
1748		opts := " -encoding UTF-8 -source 1.8 -J-Xmx1600m -XDignore.symbol.file " +
1749			"-doclet jdiff.JDiff -docletpath " + jdiff.String() + " -quiet " +
1750			"-newapi " + strings.TrimSuffix(d.apiXmlFile.Base(), d.apiXmlFile.Ext()) +
1751			" -newapidir " + filepath.Dir(d.apiXmlFile.String()) +
1752			" -oldapi " + strings.TrimSuffix(d.lastReleasedApiXmlFile.Base(), d.lastReleasedApiXmlFile.Ext()) +
1753			" -oldapidir " + filepath.Dir(d.lastReleasedApiXmlFile.String())
1754
1755		d.transformJdiff(ctx, jdiffImplicits, jdiffImplicitOutputs, flags.bootClasspathArgs, flags.classpathArgs,
1756			flags.sourcepathArgs, opts)
1757	}
1758}
1759
1760//
1761// Exported Droiddoc Directory
1762//
1763var droiddocTemplateTag = dependencyTag{name: "droiddoc-template"}
1764var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"}
1765var metalavaMergeInclusionAnnotationsDirTag = dependencyTag{name: "metalava-merge-inclusion-annotations-dir"}
1766var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"}
1767
1768type ExportedDroiddocDirProperties struct {
1769	// path to the directory containing Droiddoc related files.
1770	Path *string
1771}
1772
1773type ExportedDroiddocDir struct {
1774	android.ModuleBase
1775
1776	properties ExportedDroiddocDirProperties
1777
1778	deps android.Paths
1779	dir  android.Path
1780}
1781
1782func ExportedDroiddocDirFactory() android.Module {
1783	module := &ExportedDroiddocDir{}
1784	module.AddProperties(&module.properties)
1785	android.InitAndroidModule(module)
1786	return module
1787}
1788
1789func (d *ExportedDroiddocDir) DepsMutator(android.BottomUpMutatorContext) {}
1790
1791func (d *ExportedDroiddocDir) GenerateAndroidBuildActions(ctx android.ModuleContext) {
1792	path := String(d.properties.Path)
1793	d.dir = android.PathForModuleSrc(ctx, path)
1794	d.deps = android.PathsForModuleSrc(ctx, []string{filepath.Join(path, "**/*")})
1795}
1796
1797//
1798// Defaults
1799//
1800type DocDefaults struct {
1801	android.ModuleBase
1802	android.DefaultsModuleBase
1803}
1804
1805func (*DocDefaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
1806}
1807
1808func DocDefaultsFactory() android.Module {
1809	module := &DocDefaults{}
1810
1811	module.AddProperties(
1812		&JavadocProperties{},
1813		&DroiddocProperties{},
1814	)
1815
1816	android.InitDefaultsModule(module)
1817
1818	return module
1819}
1820
1821func StubsDefaultsFactory() android.Module {
1822	module := &DocDefaults{}
1823
1824	module.AddProperties(
1825		&JavadocProperties{},
1826		&DroidstubsProperties{},
1827	)
1828
1829	android.InitDefaultsModule(module)
1830
1831	return module
1832}
1833