blob: 5a84e051c566a0b8f8e03bcf062e73425fdd2b34 [file] [log] [blame]
Colin Cross2207f872021-03-24 12:39:08 -07001// Copyright 2021 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 "fmt"
Anton Hansson86758ac2021-11-03 14:44:12 +000019 "path/filepath"
Colin Cross2207f872021-03-24 12:39:08 -070020 "strings"
21
Keyife310a92022-01-07 15:42:18 +080022 "github.com/google/blueprint"
Colin Cross2207f872021-03-24 12:39:08 -070023 "github.com/google/blueprint/proptools"
24
25 "android/soong/android"
26 "android/soong/java/config"
27 "android/soong/remoteexec"
28)
29
Pedro Loureirocc203502021-10-04 17:24:00 +000030// The values allowed for Droidstubs' Api_levels_sdk_type
31var allowedApiLevelSdkTypes = []string{"public", "system", "module-lib"}
32
Colin Cross2207f872021-03-24 12:39:08 -070033func init() {
34 RegisterStubsBuildComponents(android.InitRegistrationContext)
35}
36
37func RegisterStubsBuildComponents(ctx android.RegistrationContext) {
38 ctx.RegisterModuleType("stubs_defaults", StubsDefaultsFactory)
39
40 ctx.RegisterModuleType("droidstubs", DroidstubsFactory)
41 ctx.RegisterModuleType("droidstubs_host", DroidstubsHostFactory)
42
43 ctx.RegisterModuleType("prebuilt_stubs_sources", PrebuiltStubsSourcesFactory)
44}
45
46//
47// Droidstubs
48//
49type Droidstubs struct {
50 Javadoc
51 android.SdkBase
52
53 properties DroidstubsProperties
54 apiFile android.WritablePath
55 apiXmlFile android.WritablePath
56 lastReleasedApiXmlFile android.WritablePath
57 privateApiFile android.WritablePath
58 removedApiFile android.WritablePath
Colin Cross2207f872021-03-24 12:39:08 -070059 nullabilityWarningsFile android.WritablePath
60
61 checkCurrentApiTimestamp android.WritablePath
62 updateCurrentApiTimestamp android.WritablePath
63 checkLastReleasedApiTimestamp android.WritablePath
64 apiLintTimestamp android.WritablePath
65 apiLintReport android.WritablePath
66
67 checkNullabilityWarningsTimestamp android.WritablePath
68
69 annotationsZip android.WritablePath
70 apiVersionsXml android.WritablePath
71
72 apiFilePath android.Path
73 removedApiFilePath android.Path
74
75 metadataZip android.WritablePath
76 metadataDir android.WritablePath
77}
78
79type DroidstubsProperties struct {
80 // The generated public API filename by Metalava, defaults to <module>_api.txt
81 Api_filename *string
82
83 // the generated removed API filename by Metalava, defaults to <module>_removed.txt
84 Removed_api_filename *string
85
Colin Cross2207f872021-03-24 12:39:08 -070086 Check_api struct {
87 Last_released ApiToCheck
88
89 Current ApiToCheck
90
91 Api_lint struct {
92 Enabled *bool
93
94 // If set, performs api_lint on any new APIs not found in the given signature file
95 New_since *string `android:"path"`
96
97 // If not blank, path to the baseline txt file for approved API lint violations.
98 Baseline_file *string `android:"path"`
99 }
100 }
101
102 // user can specify the version of previous released API file in order to do compatibility check.
103 Previous_api *string `android:"path"`
104
105 // is set to true, Metalava will allow framework SDK to contain annotations.
106 Annotations_enabled *bool
107
108 // a list of top-level directories containing files to merge qualifier annotations (i.e. those intended to be included in the stubs written) from.
109 Merge_annotations_dirs []string
110
111 // a list of top-level directories containing Java stub files to merge show/hide annotations from.
112 Merge_inclusion_annotations_dirs []string
113
114 // a file containing a list of classes to do nullability validation for.
115 Validate_nullability_from_list *string
116
117 // a file containing expected warnings produced by validation of nullability annotations.
118 Check_nullability_warnings *string
119
120 // if set to true, allow Metalava to generate doc_stubs source files. Defaults to false.
121 Create_doc_stubs *bool
122
123 // if set to true, cause Metalava to output Javadoc comments in the stubs source files. Defaults to false.
124 // Has no effect if create_doc_stubs: true.
125 Output_javadoc_comments *bool
126
127 // if set to false then do not write out stubs. Defaults to true.
128 //
129 // TODO(b/146727827): Remove capability when we do not need to generate stubs and API separately.
130 Generate_stubs *bool
131
132 // if set to true, provides a hint to the build system that this rule uses a lot of memory,
133 // whicih can be used for scheduling purposes
134 High_mem *bool
135
satayev783195c2021-06-23 21:49:57 +0100136 // if set to true, Metalava will allow framework SDK to contain API levels annotations.
Colin Cross2207f872021-03-24 12:39:08 -0700137 Api_levels_annotations_enabled *bool
138
139 // the dirs which Metalava extracts API levels annotations from.
140 Api_levels_annotations_dirs []string
141
Pedro Loureirocc203502021-10-04 17:24:00 +0000142 // the sdk kind which Metalava extracts API levels annotations from. Supports 'public', 'system' and 'module-lib' for now; defaults to public.
satayev783195c2021-06-23 21:49:57 +0100143 Api_levels_sdk_type *string
144
Colin Cross2207f872021-03-24 12:39:08 -0700145 // the filename which Metalava extracts API levels annotations from. Defaults to android.jar.
146 Api_levels_jar_filename *string
147
148 // if set to true, collect the values used by the Dev tools and
149 // write them in files packaged with the SDK. Defaults to false.
150 Write_sdk_values *bool
151}
152
Anton Hansson52609322021-05-05 10:36:05 +0100153// Used by xsd_config
154type ApiFilePath interface {
155 ApiFilePath() android.Path
156}
157
158type ApiStubsSrcProvider interface {
159 StubsSrcJar() android.Path
160}
161
162// Provider of information about API stubs, used by java_sdk_library.
163type ApiStubsProvider interface {
Anton Hanssond78eb762021-09-21 15:25:12 +0100164 AnnotationsZip() android.Path
Anton Hansson52609322021-05-05 10:36:05 +0100165 ApiFilePath
166 RemovedApiFilePath() android.Path
167
168 ApiStubsSrcProvider
169}
170
Colin Cross2207f872021-03-24 12:39:08 -0700171// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
172// documented, filtering out hidden classes and methods. The resulting .java files are intended to be passed to
173// a droiddoc module to generate documentation.
174func DroidstubsFactory() android.Module {
175 module := &Droidstubs{}
176
177 module.AddProperties(&module.properties,
178 &module.Javadoc.properties)
179
180 InitDroiddocModule(module, android.HostAndDeviceSupported)
181 android.InitSdkAwareModule(module)
182 return module
183}
184
185// droidstubs_host passes sources files through Metalava to generate stub .java files that only contain the API
186// to be documented, filtering out hidden classes and methods. The resulting .java files are intended to be
187// passed to a droiddoc_host module to generate documentation. Use a droidstubs_host instead of a droidstubs
188// module when symbols needed by the source files are provided by java_library_host modules.
189func DroidstubsHostFactory() android.Module {
190 module := &Droidstubs{}
191
192 module.AddProperties(&module.properties,
193 &module.Javadoc.properties)
194
195 InitDroiddocModule(module, android.HostSupported)
196 return module
197}
198
199func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) {
200 switch tag {
201 case "":
202 return android.Paths{d.stubsSrcJar}, nil
203 case ".docs.zip":
204 return android.Paths{d.docZip}, nil
205 case ".api.txt", android.DefaultDistTag:
206 // This is the default dist path for dist properties that have no tag property.
207 return android.Paths{d.apiFilePath}, nil
208 case ".removed-api.txt":
209 return android.Paths{d.removedApiFilePath}, nil
210 case ".annotations.zip":
211 return android.Paths{d.annotationsZip}, nil
212 case ".api_versions.xml":
213 return android.Paths{d.apiVersionsXml}, nil
214 default:
215 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
216 }
217}
218
Anton Hanssond78eb762021-09-21 15:25:12 +0100219func (d *Droidstubs) AnnotationsZip() android.Path {
220 return d.annotationsZip
221}
222
Colin Cross2207f872021-03-24 12:39:08 -0700223func (d *Droidstubs) ApiFilePath() android.Path {
224 return d.apiFilePath
225}
226
227func (d *Droidstubs) RemovedApiFilePath() android.Path {
228 return d.removedApiFilePath
229}
230
231func (d *Droidstubs) StubsSrcJar() android.Path {
232 return d.stubsSrcJar
233}
234
235var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"}
236var metalavaMergeInclusionAnnotationsDirTag = dependencyTag{name: "metalava-merge-inclusion-annotations-dir"}
237var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"}
238
239func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) {
240 d.Javadoc.addDeps(ctx)
241
242 if len(d.properties.Merge_annotations_dirs) != 0 {
243 for _, mergeAnnotationsDir := range d.properties.Merge_annotations_dirs {
244 ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir)
245 }
246 }
247
248 if len(d.properties.Merge_inclusion_annotations_dirs) != 0 {
249 for _, mergeInclusionAnnotationsDir := range d.properties.Merge_inclusion_annotations_dirs {
250 ctx.AddDependency(ctx.Module(), metalavaMergeInclusionAnnotationsDirTag, mergeInclusionAnnotationsDir)
251 }
252 }
253
254 if len(d.properties.Api_levels_annotations_dirs) != 0 {
255 for _, apiLevelsAnnotationsDir := range d.properties.Api_levels_annotations_dirs {
256 ctx.AddDependency(ctx.Module(), metalavaAPILevelsAnnotationsDirTag, apiLevelsAnnotationsDir)
257 }
258 }
259}
260
261func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) {
262 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
263 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
264 String(d.properties.Api_filename) != "" {
265 filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
Colin Crosscb77f752021-03-24 12:04:44 -0700266 d.apiFile = android.PathForModuleOut(ctx, "metalava", filename)
Colin Cross2207f872021-03-24 12:39:08 -0700267 cmd.FlagWithOutput("--api ", d.apiFile)
268 d.apiFilePath = d.apiFile
269 } else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" {
270 // If check api is disabled then make the source file available for export.
271 d.apiFilePath = android.PathForModuleSrc(ctx, sourceApiFile)
272 }
273
274 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
275 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
276 String(d.properties.Removed_api_filename) != "" {
277 filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
Colin Crosscb77f752021-03-24 12:04:44 -0700278 d.removedApiFile = android.PathForModuleOut(ctx, "metalava", filename)
Colin Cross2207f872021-03-24 12:39:08 -0700279 cmd.FlagWithOutput("--removed-api ", d.removedApiFile)
280 d.removedApiFilePath = d.removedApiFile
281 } else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" {
282 // If check api is disabled then make the source removed api file available for export.
283 d.removedApiFilePath = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
284 }
285
Colin Cross2207f872021-03-24 12:39:08 -0700286 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700287 d.metadataDir = android.PathForModuleOut(ctx, "metalava", "metadata")
Colin Cross2207f872021-03-24 12:39:08 -0700288 cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
289 }
290
291 if stubsDir.Valid() {
292 if Bool(d.properties.Create_doc_stubs) {
293 cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
294 } else {
295 cmd.FlagWithArg("--stubs ", stubsDir.String())
296 if !Bool(d.properties.Output_javadoc_comments) {
297 cmd.Flag("--exclude-documentation-from-stubs")
298 }
299 }
300 }
301}
302
303func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
304 if Bool(d.properties.Annotations_enabled) {
305 cmd.Flag("--include-annotations")
306
Andrei Onea4985e512021-04-29 16:29:34 +0100307 cmd.FlagWithArg("--exclude-annotation ", "androidx.annotation.RequiresApi")
308
Colin Cross2207f872021-03-24 12:39:08 -0700309 validatingNullability :=
Colin Crossbc139922021-03-25 18:33:16 -0700310 strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") ||
Colin Cross2207f872021-03-24 12:39:08 -0700311 String(d.properties.Validate_nullability_from_list) != ""
312
313 migratingNullability := String(d.properties.Previous_api) != ""
314 if migratingNullability {
315 previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
316 cmd.FlagWithInput("--migrate-nullness ", previousApi)
317 }
318
319 if s := String(d.properties.Validate_nullability_from_list); s != "" {
320 cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
321 }
322
323 if validatingNullability {
Colin Crosscb77f752021-03-24 12:04:44 -0700324 d.nullabilityWarningsFile = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_nullability_warnings.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700325 cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile)
326 }
327
Colin Crosscb77f752021-03-24 12:04:44 -0700328 d.annotationsZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_annotations.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700329 cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip)
330
331 if len(d.properties.Merge_annotations_dirs) != 0 {
332 d.mergeAnnoDirFlags(ctx, cmd)
333 }
334
335 // TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
336 cmd.FlagWithArg("--hide ", "HiddenTypedefConstant").
337 FlagWithArg("--hide ", "SuperfluousPrefix").
338 FlagWithArg("--hide ", "AnnotationExtraction")
339 }
340}
341
342func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
343 ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
344 if t, ok := m.(*ExportedDroiddocDir); ok {
345 cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps)
346 } else {
347 ctx.PropertyErrorf("merge_annotations_dirs",
348 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
349 }
350 })
351}
352
353func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
354 ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) {
355 if t, ok := m.(*ExportedDroiddocDir); ok {
356 cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps)
357 } else {
358 ctx.PropertyErrorf("merge_inclusion_annotations_dirs",
359 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
360 }
361 })
362}
363
364func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
365 if !Bool(d.properties.Api_levels_annotations_enabled) {
366 return
367 }
368
Colin Crosscb77f752021-03-24 12:04:44 -0700369 d.apiVersionsXml = android.PathForModuleOut(ctx, "metalava", "api-versions.xml")
Colin Cross2207f872021-03-24 12:39:08 -0700370
371 if len(d.properties.Api_levels_annotations_dirs) == 0 {
372 ctx.PropertyErrorf("api_levels_annotations_dirs",
373 "has to be non-empty if api levels annotations was enabled!")
374 }
375
376 cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml)
377 cmd.FlagWithInput("--apply-api-levels ", d.apiVersionsXml)
378 cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion().String())
379 cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename())
380
381 filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar")
382
satayev783195c2021-06-23 21:49:57 +0100383 var dirs []string
Colin Cross2207f872021-03-24 12:39:08 -0700384 ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
385 if t, ok := m.(*ExportedDroiddocDir); ok {
386 for _, dep := range t.deps {
Colin Cross5f6ffc72021-03-29 21:54:45 -0700387 if dep.Base() == filename {
388 cmd.Implicit(dep)
389 }
390 if filename != "android.jar" && dep.Base() == "android.jar" {
391 // Metalava implicitly searches these patterns:
392 // prebuilts/tools/common/api-versions/android-%/android.jar
393 // prebuilts/sdk/%/public/android.jar
394 // Add android.jar files from the api_levels_annotations_dirs directories to try
395 // to satisfy these patterns. If Metalava can't find a match for an API level
396 // between 1 and 28 in at least one pattern it will fail.
Colin Cross2207f872021-03-24 12:39:08 -0700397 cmd.Implicit(dep)
398 }
399 }
satayev783195c2021-06-23 21:49:57 +0100400
401 dirs = append(dirs, t.dir.String())
Colin Cross2207f872021-03-24 12:39:08 -0700402 } else {
403 ctx.PropertyErrorf("api_levels_annotations_dirs",
404 "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
405 }
406 })
satayev783195c2021-06-23 21:49:57 +0100407
408 // Add all relevant --android-jar-pattern patterns for Metalava.
409 // When parsing a stub jar for a specific version, Metalava picks the first pattern that defines
410 // an actual file present on disk (in the order the patterns were passed). For system APIs for
411 // privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs
Pedro Loureirocc203502021-10-04 17:24:00 +0000412 // for older releases. Similarly, module-lib falls back to system API.
413 var sdkDirs []string
414 switch proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") {
415 case "module-lib":
416 sdkDirs = []string{"module-lib", "system", "public"}
417 case "system":
418 sdkDirs = []string{"system", "public"}
419 case "public":
420 sdkDirs = []string{"public"}
421 default:
422 ctx.PropertyErrorf("api_levels_sdk_type", "needs to be one of %v", allowedApiLevelSdkTypes)
423 return
satayev783195c2021-06-23 21:49:57 +0100424 }
Pedro Loureirocc203502021-10-04 17:24:00 +0000425
426 for _, sdkDir := range sdkDirs {
427 for _, dir := range dirs {
428 cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, filename))
429 }
satayev783195c2021-06-23 21:49:57 +0100430 }
Colin Cross2207f872021-03-24 12:39:08 -0700431}
432
433func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
Anton Hansson556e8142021-06-04 16:20:25 +0100434 srcJarList android.Path, bootclasspath, classpath classpath, homeDir android.WritablePath) *android.RuleBuilderCommand {
Colin Cross2207f872021-03-24 12:39:08 -0700435 rule.Command().Text("rm -rf").Flag(homeDir.String())
436 rule.Command().Text("mkdir -p").Flag(homeDir.String())
437
Anton Hansson556e8142021-06-04 16:20:25 +0100438 cmd := rule.Command()
Colin Cross2207f872021-03-24 12:39:08 -0700439 cmd.FlagWithArg("ANDROID_PREFS_ROOT=", homeDir.String())
440
441 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA") {
442 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
Colin Cross8095c292021-03-30 16:40:48 -0700443 execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
444 labels := map[string]string{"type": "tool", "name": "metalava"}
445 // TODO: metalava pool rejects these jobs
446 pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
447 rule.Rewrapper(&remoteexec.REParams{
448 Labels: labels,
449 ExecStrategy: execStrategy,
450 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
451 Platform: map[string]string{remoteexec.PoolKey: pool},
452 })
Colin Cross2207f872021-03-24 12:39:08 -0700453 }
454
Colin Cross6aa5c402021-03-24 12:28:50 -0700455 cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
Colin Cross2207f872021-03-24 12:39:08 -0700456 Flag(config.JavacVmFlags).
457 Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED").
458 FlagWithArg("-encoding ", "UTF-8").
459 FlagWithArg("-source ", javaVersion.String()).
460 FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs).
461 FlagWithInput("@", srcJarList)
462
Colin Cross2207f872021-03-24 12:39:08 -0700463 if len(bootclasspath) > 0 {
464 cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":")
465 }
466
467 if len(classpath) > 0 {
468 cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
469 }
470
Colin Cross2207f872021-03-24 12:39:08 -0700471 cmd.Flag("--no-banner").
472 Flag("--color").
473 Flag("--quiet").
474 Flag("--format=v2").
475 FlagWithArg("--repeat-errors-max ", "10").
476 FlagWithArg("--hide ", "UnresolvedImport")
477
478 return cmd
479}
480
481func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
482 deps := d.Javadoc.collectDeps(ctx)
483
Jiyong Parkf1691d22021-03-29 20:11:58 +0900484 javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d))
Colin Cross2207f872021-03-24 12:39:08 -0700485
486 // Create rule for metalava
487
Colin Crosscb77f752021-03-24 12:04:44 -0700488 srcJarDir := android.PathForModuleOut(ctx, "metalava", "srcjars")
Colin Cross2207f872021-03-24 12:39:08 -0700489
490 rule := android.NewRuleBuilder(pctx, ctx)
491
Colin Cross8095c292021-03-30 16:40:48 -0700492 rule.Sbox(android.PathForModuleOut(ctx, "metalava"),
493 android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
494 SandboxInputs()
Colin Cross6aa5c402021-03-24 12:28:50 -0700495
Colin Cross2207f872021-03-24 12:39:08 -0700496 if BoolDefault(d.properties.High_mem, false) {
497 // This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel.
498 rule.HighMem()
499 }
500
501 generateStubs := BoolDefault(d.properties.Generate_stubs, true)
502 var stubsDir android.OptionalPath
503 if generateStubs {
Colin Crosscb77f752021-03-24 12:04:44 -0700504 d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
505 stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "metalava", "stubsDir"))
Colin Cross2207f872021-03-24 12:39:08 -0700506 rule.Command().Text("rm -rf").Text(stubsDir.String())
507 rule.Command().Text("mkdir -p").Text(stubsDir.String())
508 }
509
510 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
511
Colin Crosscb77f752021-03-24 12:04:44 -0700512 homeDir := android.PathForModuleOut(ctx, "metalava", "home")
Colin Cross2207f872021-03-24 12:39:08 -0700513 cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
Anton Hansson556e8142021-06-04 16:20:25 +0100514 deps.bootClasspath, deps.classpath, homeDir)
Colin Cross2207f872021-03-24 12:39:08 -0700515 cmd.Implicits(d.Javadoc.implicits)
516
517 d.stubsFlags(ctx, cmd, stubsDir)
518
519 d.annotationsFlags(ctx, cmd)
520 d.inclusionAnnotationsFlags(ctx, cmd)
521 d.apiLevelsAnnotationsFlags(ctx, cmd)
522
Colin Crossbc139922021-03-25 18:33:16 -0700523 d.expandArgs(ctx, cmd)
Colin Cross2207f872021-03-24 12:39:08 -0700524
Colin Cross2207f872021-03-24 12:39:08 -0700525 for _, o := range d.Javadoc.properties.Out {
526 cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
527 }
528
529 // Add options for the other optional tasks: API-lint and check-released.
530 // We generate separate timestamp files for them.
531
532 doApiLint := false
533 doCheckReleased := false
534
535 // Add API lint options.
536
537 if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) {
538 doApiLint = true
539
540 newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since)
541 if newSince.Valid() {
542 cmd.FlagWithInput("--api-lint ", newSince.Path())
543 } else {
544 cmd.Flag("--api-lint")
545 }
Colin Crosscb77f752021-03-24 12:04:44 -0700546 d.apiLintReport = android.PathForModuleOut(ctx, "metalava", "api_lint_report.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700547 cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO: Change to ":api-lint"
548
Colin Cross0d532412021-03-25 09:38:45 -0700549 // TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released.
Colin Cross2207f872021-03-24 12:39:08 -0700550 if d.Name() != "android.car-system-stubs-docs" &&
551 d.Name() != "android.car-stubs-docs" {
552 cmd.Flag("--lints-as-errors")
553 cmd.Flag("--warnings-as-errors") // Most lints are actually warnings.
554 }
555
556 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700557 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "api_lint_baseline.txt")
558 d.apiLintTimestamp = android.PathForModuleOut(ctx, "metalava", "api_lint.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700559
560 // Note this string includes a special shell quote $' ... ', which decodes the "\n"s.
Colin Cross2207f872021-03-24 12:39:08 -0700561 //
562 // TODO: metalava also has a slightly different message hardcoded. Should we unify this
563 // message and metalava's one?
564 msg := `$'` + // Enclose with $' ... '
565 `************************************************************\n` +
566 `Your API changes are triggering API Lint warnings or errors.\n` +
567 `To make these errors go away, fix the code according to the\n` +
568 `error and/or warning messages above.\n` +
569 `\n` +
570 `If it is not possible to do so, there are workarounds:\n` +
571 `\n` +
Aurimas Liutikasb23b7452021-05-24 18:00:37 +0000572 `1. You can suppress the errors with @SuppressLint("<id>")\n` +
573 ` where the <id> is given in brackets in the error message above.\n`
Colin Cross2207f872021-03-24 12:39:08 -0700574
575 if baselineFile.Valid() {
576 cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path())
577 cmd.FlagWithOutput("--update-baseline:api-lint ", updatedBaselineOutput)
578
579 msg += fmt.Sprintf(``+
580 `2. You can update the baseline by executing the following\n`+
581 ` command:\n`+
Colin Cross63eeda02021-04-15 19:01:57 -0700582 ` (cd $ANDROID_BUILD_TOP && cp \\\n`+
583 ` "%s" \\\n`+
584 ` "%s")\n`+
Colin Cross2207f872021-03-24 12:39:08 -0700585 ` To submit the revised baseline.txt to the main Android\n`+
586 ` repository, you will need approval.\n`, updatedBaselineOutput, baselineFile.Path())
587 } else {
588 msg += fmt.Sprintf(``+
589 `2. You can add a baseline file of existing lint failures\n`+
590 ` to the build rule of %s.\n`, d.Name())
591 }
592 // Note the message ends with a ' (single quote), to close the $' ... ' .
593 msg += `************************************************************\n'`
594
595 cmd.FlagWithArg("--error-message:api-lint ", msg)
596 }
597
598 // Add "check released" options. (Detect incompatible API changes from the last public release)
599
600 if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") {
601 doCheckReleased = true
602
603 if len(d.Javadoc.properties.Out) > 0 {
604 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
605 }
606
607 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
608 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
609 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700610 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "last_released_baseline.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700611
Colin Crosscb77f752021-03-24 12:04:44 -0700612 d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_last_released_api.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700613
614 cmd.FlagWithInput("--check-compatibility:api:released ", apiFile)
615 cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile)
616
617 if baselineFile.Valid() {
618 cmd.FlagWithInput("--baseline:compatibility:released ", baselineFile.Path())
619 cmd.FlagWithOutput("--update-baseline:compatibility:released ", updatedBaselineOutput)
620 }
621
622 // Note this string includes quote ($' ... '), which decodes the "\n"s.
623 msg := `$'\n******************************\n` +
624 `You have tried to change the API from what has been previously released in\n` +
625 `an SDK. Please fix the errors listed above.\n` +
626 `******************************\n'`
627
628 cmd.FlagWithArg("--error-message:compatibility:released ", msg)
629 }
630
Colin Cross2207f872021-03-24 12:39:08 -0700631 if generateStubs {
632 rule.Command().
633 BuiltTool("soong_zip").
634 Flag("-write_if_changed").
635 Flag("-jar").
636 FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
637 FlagWithArg("-C ", stubsDir.String()).
638 FlagWithArg("-D ", stubsDir.String())
639 }
640
641 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700642 d.metadataZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-metadata.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700643 rule.Command().
644 BuiltTool("soong_zip").
645 Flag("-write_if_changed").
646 Flag("-d").
647 FlagWithOutput("-o ", d.metadataZip).
648 FlagWithArg("-C ", d.metadataDir.String()).
649 FlagWithArg("-D ", d.metadataDir.String())
650 }
651
652 // TODO: We don't really need two separate API files, but this is a reminiscence of how
653 // we used to run metalava separately for API lint and the "last_released" check. Unify them.
654 if doApiLint {
655 rule.Command().Text("touch").Output(d.apiLintTimestamp)
656 }
657 if doCheckReleased {
658 rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp)
659 }
660
Colin Cross6aa5c402021-03-24 12:28:50 -0700661 // TODO(b/183630617): rewrapper doesn't support restat rules
Colin Cross8095c292021-03-30 16:40:48 -0700662 // rule.Restat()
Colin Cross2207f872021-03-24 12:39:08 -0700663
664 zipSyncCleanupCmd(rule, srcJarDir)
665
666 rule.Build("metalava", "metalava merged")
667
668 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
669
670 if len(d.Javadoc.properties.Out) > 0 {
671 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
672 }
673
674 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
675 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
676 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)
677
678 if baselineFile.Valid() {
679 ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
680 }
681
Colin Crosscb77f752021-03-24 12:04:44 -0700682 d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700683
684 rule := android.NewRuleBuilder(pctx, ctx)
685
686 // Diff command line.
687 // -F matches the closest "opening" line, such as "package android {"
688 // and " public class Intent {".
689 diff := `diff -u -F '{ *$'`
690
691 rule.Command().Text("( true")
692 rule.Command().
693 Text(diff).
694 Input(apiFile).Input(d.apiFile)
695
696 rule.Command().
697 Text(diff).
698 Input(removedApiFile).Input(d.removedApiFile)
699
700 msg := fmt.Sprintf(`\n******************************\n`+
701 `You have tried to change the API from what has been previously approved.\n\n`+
702 `To make these errors go away, you have two choices:\n`+
703 ` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
704 ` to the new methods, etc. shown in the above diff.\n\n`+
705 ` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+
706 ` m %s-update-current-api\n\n`+
707 ` To submit the revised current.txt to the main Android repository,\n`+
708 ` you will need approval.\n`+
709 `******************************\n`, ctx.ModuleName())
710
711 rule.Command().
712 Text("touch").Output(d.checkCurrentApiTimestamp).
713 Text(") || (").
714 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
715 Text("; exit 38").
716 Text(")")
717
718 rule.Build("metalavaCurrentApiCheck", "check current API")
719
Colin Crosscb77f752021-03-24 12:04:44 -0700720 d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "update_current_api.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700721
722 // update API rule
723 rule = android.NewRuleBuilder(pctx, ctx)
724
725 rule.Command().Text("( true")
726
727 rule.Command().
728 Text("cp").Flag("-f").
729 Input(d.apiFile).Flag(apiFile.String())
730
731 rule.Command().
732 Text("cp").Flag("-f").
733 Input(d.removedApiFile).Flag(removedApiFile.String())
734
735 msg = "failed to update public API"
736
737 rule.Command().
738 Text("touch").Output(d.updateCurrentApiTimestamp).
739 Text(") || (").
740 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
741 Text("; exit 38").
742 Text(")")
743
744 rule.Build("metalavaCurrentApiUpdate", "update current API")
745 }
746
747 if String(d.properties.Check_nullability_warnings) != "" {
748 if d.nullabilityWarningsFile == nil {
749 ctx.PropertyErrorf("check_nullability_warnings",
750 "Cannot specify check_nullability_warnings unless validating nullability")
751 }
752
753 checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings))
754
Colin Crosscb77f752021-03-24 12:04:44 -0700755 d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "metalava", "check_nullability_warnings.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700756
757 msg := fmt.Sprintf(`\n******************************\n`+
758 `The warnings encountered during nullability annotation validation did\n`+
759 `not match the checked in file of expected warnings. The diffs are shown\n`+
760 `above. You have two options:\n`+
761 ` 1. Resolve the differences by editing the nullability annotations.\n`+
762 ` 2. Update the file of expected warnings by running:\n`+
763 ` cp %s %s\n`+
764 ` and submitting the updated file as part of your change.`,
765 d.nullabilityWarningsFile, checkNullabilityWarnings)
766
767 rule := android.NewRuleBuilder(pctx, ctx)
768
769 rule.Command().
770 Text("(").
771 Text("diff").Input(checkNullabilityWarnings).Input(d.nullabilityWarningsFile).
772 Text("&&").
773 Text("touch").Output(d.checkNullabilityWarningsTimestamp).
774 Text(") || (").
775 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
776 Text("; exit 38").
777 Text(")")
778
779 rule.Build("nullabilityWarningsCheck", "nullability warnings check")
780 }
781}
782
783func StubsDefaultsFactory() android.Module {
784 module := &DocDefaults{}
785
786 module.AddProperties(
787 &JavadocProperties{},
788 &DroidstubsProperties{},
789 )
790
791 android.InitDefaultsModule(module)
792
793 return module
794}
795
796var _ android.PrebuiltInterface = (*PrebuiltStubsSources)(nil)
797
798type PrebuiltStubsSourcesProperties struct {
799 Srcs []string `android:"path"`
800}
801
802type PrebuiltStubsSources struct {
803 android.ModuleBase
804 android.DefaultableModuleBase
805 prebuilt android.Prebuilt
806 android.SdkBase
807
808 properties PrebuiltStubsSourcesProperties
809
Keyife310a92022-01-07 15:42:18 +0800810 stubsSrcJar android.Path
811 jsonDataActions []blueprint.JSONDataAction
Colin Cross2207f872021-03-24 12:39:08 -0700812}
813
814func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
815 switch tag {
816 case "":
817 return android.Paths{p.stubsSrcJar}, nil
818 default:
819 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
820 }
821}
822
823func (d *PrebuiltStubsSources) StubsSrcJar() android.Path {
824 return d.stubsSrcJar
825}
826
Keyife310a92022-01-07 15:42:18 +0800827// AddJSONData is a temporary solution for droidstubs module to put action
828// related data into the module json graph.
829func (p *PrebuiltStubsSources) AddJSONData(d *map[string]interface{}) {
830 p.ModuleBase.AddJSONData(d)
831 (*d)["Actions"] = blueprint.FormatJSONDataActions(p.jsonDataActions)
832}
833
Colin Cross2207f872021-03-24 12:39:08 -0700834func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Cross2207f872021-03-24 12:39:08 -0700835 if len(p.properties.Srcs) != 1 {
Anton Hansson86758ac2021-11-03 14:44:12 +0000836 ctx.PropertyErrorf("srcs", "must only specify one directory path or srcjar, contains %d paths", len(p.properties.Srcs))
Colin Cross2207f872021-03-24 12:39:08 -0700837 return
838 }
839
Anton Hansson86758ac2021-11-03 14:44:12 +0000840 src := p.properties.Srcs[0]
Keyife310a92022-01-07 15:42:18 +0800841 var jsonDataAction blueprint.JSONDataAction
Anton Hansson86758ac2021-11-03 14:44:12 +0000842 if filepath.Ext(src) == ".srcjar" {
843 // This is a srcjar. We can use it directly.
844 p.stubsSrcJar = android.PathForModuleSrc(ctx, src)
Keyife310a92022-01-07 15:42:18 +0800845 jsonDataAction.Inputs = []string{src}
846 jsonDataAction.Outputs = []string{src}
Anton Hansson86758ac2021-11-03 14:44:12 +0000847 } else {
848 outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
Colin Cross2207f872021-03-24 12:39:08 -0700849
Anton Hansson86758ac2021-11-03 14:44:12 +0000850 // This is a directory. Glob the contents just in case the directory does not exist.
851 srcGlob := src + "/**/*"
852 srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
Colin Cross2207f872021-03-24 12:39:08 -0700853
Anton Hansson86758ac2021-11-03 14:44:12 +0000854 // Although PathForModuleSrc can return nil if either the path doesn't exist or
855 // the path components are invalid it won't in this case because no components
856 // are specified and the module directory must exist in order to get this far.
857 srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, src)
Colin Cross2207f872021-03-24 12:39:08 -0700858
Anton Hansson86758ac2021-11-03 14:44:12 +0000859 rule := android.NewRuleBuilder(pctx, ctx)
860 rule.Command().
861 BuiltTool("soong_zip").
862 Flag("-write_if_changed").
863 Flag("-jar").
864 FlagWithOutput("-o ", outPath).
865 FlagWithArg("-C ", srcDir.String()).
866 FlagWithRspFileInputList("-r ", outPath.ReplaceExtension(ctx, "rsp"), srcPaths)
867 rule.Restat()
868 rule.Build("zip src", "Create srcjar from prebuilt source")
869 p.stubsSrcJar = outPath
Keyife310a92022-01-07 15:42:18 +0800870 jsonDataAction.Inputs = srcPaths.Strings()
871 jsonDataAction.Outputs = []string{outPath.String()}
Anton Hansson86758ac2021-11-03 14:44:12 +0000872 }
Keyife310a92022-01-07 15:42:18 +0800873 p.jsonDataActions = []blueprint.JSONDataAction{jsonDataAction}
Colin Cross2207f872021-03-24 12:39:08 -0700874}
875
876func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
877 return &p.prebuilt
878}
879
880func (p *PrebuiltStubsSources) Name() string {
881 return p.prebuilt.Name(p.ModuleBase.Name())
882}
883
884// prebuilt_stubs_sources imports a set of java source files as if they were
885// generated by droidstubs.
886//
887// By default, a prebuilt_stubs_sources has a single variant that expects a
888// set of `.java` files generated by droidstubs.
889//
890// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one
891// for host modules.
892//
893// Intended only for use by sdk snapshots.
894func PrebuiltStubsSourcesFactory() android.Module {
895 module := &PrebuiltStubsSources{}
896
897 module.AddProperties(&module.properties)
898
899 android.InitPrebuiltModule(module, &module.properties.Srcs)
900 android.InitSdkAwareModule(module)
901 InitDroiddocModule(module, android.HostAndDeviceSupported)
902 return module
903}