blob: a1a8c2e7d51f2c6a2f9a13fe0e25272486c83900 [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 Hanssonfb41d462021-11-03 14:44:12 +000019 "path/filepath"
Colin Cross2207f872021-03-24 12:39:08 -070020 "strings"
21
22 "github.com/google/blueprint/proptools"
23
24 "android/soong/android"
25 "android/soong/java/config"
26 "android/soong/remoteexec"
27)
28
29func init() {
30 RegisterStubsBuildComponents(android.InitRegistrationContext)
31}
32
33func RegisterStubsBuildComponents(ctx android.RegistrationContext) {
34 ctx.RegisterModuleType("stubs_defaults", StubsDefaultsFactory)
35
36 ctx.RegisterModuleType("droidstubs", DroidstubsFactory)
37 ctx.RegisterModuleType("droidstubs_host", DroidstubsHostFactory)
38
39 ctx.RegisterModuleType("prebuilt_stubs_sources", PrebuiltStubsSourcesFactory)
40}
41
42//
43// Droidstubs
44//
45type Droidstubs struct {
46 Javadoc
47 android.SdkBase
48
49 properties DroidstubsProperties
50 apiFile android.WritablePath
51 apiXmlFile android.WritablePath
52 lastReleasedApiXmlFile android.WritablePath
53 privateApiFile android.WritablePath
54 removedApiFile android.WritablePath
Colin Cross2207f872021-03-24 12:39:08 -070055 nullabilityWarningsFile android.WritablePath
56
57 checkCurrentApiTimestamp android.WritablePath
58 updateCurrentApiTimestamp android.WritablePath
59 checkLastReleasedApiTimestamp android.WritablePath
60 apiLintTimestamp android.WritablePath
61 apiLintReport android.WritablePath
62
63 checkNullabilityWarningsTimestamp android.WritablePath
64
65 annotationsZip android.WritablePath
66 apiVersionsXml android.WritablePath
67
68 apiFilePath android.Path
69 removedApiFilePath android.Path
70
71 metadataZip android.WritablePath
72 metadataDir android.WritablePath
73}
74
75type DroidstubsProperties struct {
76 // The generated public API filename by Metalava, defaults to <module>_api.txt
77 Api_filename *string
78
79 // the generated removed API filename by Metalava, defaults to <module>_removed.txt
80 Removed_api_filename *string
81
Colin Cross2207f872021-03-24 12:39:08 -070082 Check_api struct {
83 Last_released ApiToCheck
84
85 Current ApiToCheck
86
87 Api_lint struct {
88 Enabled *bool
89
90 // If set, performs api_lint on any new APIs not found in the given signature file
91 New_since *string `android:"path"`
92
93 // If not blank, path to the baseline txt file for approved API lint violations.
94 Baseline_file *string `android:"path"`
95 }
96 }
97
98 // user can specify the version of previous released API file in order to do compatibility check.
99 Previous_api *string `android:"path"`
100
101 // is set to true, Metalava will allow framework SDK to contain annotations.
102 Annotations_enabled *bool
103
104 // a list of top-level directories containing files to merge qualifier annotations (i.e. those intended to be included in the stubs written) from.
105 Merge_annotations_dirs []string
106
107 // a list of top-level directories containing Java stub files to merge show/hide annotations from.
108 Merge_inclusion_annotations_dirs []string
109
110 // a file containing a list of classes to do nullability validation for.
111 Validate_nullability_from_list *string
112
113 // a file containing expected warnings produced by validation of nullability annotations.
114 Check_nullability_warnings *string
115
116 // if set to true, allow Metalava to generate doc_stubs source files. Defaults to false.
117 Create_doc_stubs *bool
118
119 // if set to true, cause Metalava to output Javadoc comments in the stubs source files. Defaults to false.
120 // Has no effect if create_doc_stubs: true.
121 Output_javadoc_comments *bool
122
123 // if set to false then do not write out stubs. Defaults to true.
124 //
125 // TODO(b/146727827): Remove capability when we do not need to generate stubs and API separately.
126 Generate_stubs *bool
127
128 // if set to true, provides a hint to the build system that this rule uses a lot of memory,
129 // whicih can be used for scheduling purposes
130 High_mem *bool
131
132 // is set to true, Metalava will allow framework SDK to contain API levels annotations.
133 Api_levels_annotations_enabled *bool
134
135 // the dirs which Metalava extracts API levels annotations from.
136 Api_levels_annotations_dirs []string
137
138 // the filename which Metalava extracts API levels annotations from. Defaults to android.jar.
139 Api_levels_jar_filename *string
140
141 // if set to true, collect the values used by the Dev tools and
142 // write them in files packaged with the SDK. Defaults to false.
143 Write_sdk_values *bool
144}
145
Anton Hansson52609322021-05-05 10:36:05 +0100146// Used by xsd_config
147type ApiFilePath interface {
148 ApiFilePath() android.Path
149}
150
151type ApiStubsSrcProvider interface {
152 StubsSrcJar() android.Path
153}
154
155// Provider of information about API stubs, used by java_sdk_library.
156type ApiStubsProvider interface {
Anton Hansson3adf3c52021-09-21 15:25:12 +0100157 AnnotationsZip() android.Path
Anton Hansson52609322021-05-05 10:36:05 +0100158 ApiFilePath
159 RemovedApiFilePath() android.Path
160
161 ApiStubsSrcProvider
162}
163
Colin Cross2207f872021-03-24 12:39:08 -0700164// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
165// documented, filtering out hidden classes and methods. The resulting .java files are intended to be passed to
166// a droiddoc module to generate documentation.
167func DroidstubsFactory() android.Module {
168 module := &Droidstubs{}
169
170 module.AddProperties(&module.properties,
171 &module.Javadoc.properties)
172
173 InitDroiddocModule(module, android.HostAndDeviceSupported)
174 android.InitSdkAwareModule(module)
175 return module
176}
177
178// droidstubs_host passes sources files through Metalava to generate stub .java files that only contain the API
179// to be documented, filtering out hidden classes and methods. The resulting .java files are intended to be
180// passed to a droiddoc_host module to generate documentation. Use a droidstubs_host instead of a droidstubs
181// module when symbols needed by the source files are provided by java_library_host modules.
182func DroidstubsHostFactory() android.Module {
183 module := &Droidstubs{}
184
185 module.AddProperties(&module.properties,
186 &module.Javadoc.properties)
187
188 InitDroiddocModule(module, android.HostSupported)
189 return module
190}
191
192func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) {
193 switch tag {
194 case "":
195 return android.Paths{d.stubsSrcJar}, nil
196 case ".docs.zip":
197 return android.Paths{d.docZip}, nil
198 case ".api.txt", android.DefaultDistTag:
199 // This is the default dist path for dist properties that have no tag property.
200 return android.Paths{d.apiFilePath}, nil
201 case ".removed-api.txt":
202 return android.Paths{d.removedApiFilePath}, nil
203 case ".annotations.zip":
204 return android.Paths{d.annotationsZip}, nil
205 case ".api_versions.xml":
206 return android.Paths{d.apiVersionsXml}, nil
207 default:
208 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
209 }
210}
211
Anton Hansson3adf3c52021-09-21 15:25:12 +0100212func (d *Droidstubs) AnnotationsZip() android.Path {
213 return d.annotationsZip
214}
215
Colin Cross2207f872021-03-24 12:39:08 -0700216func (d *Droidstubs) ApiFilePath() android.Path {
217 return d.apiFilePath
218}
219
220func (d *Droidstubs) RemovedApiFilePath() android.Path {
221 return d.removedApiFilePath
222}
223
224func (d *Droidstubs) StubsSrcJar() android.Path {
225 return d.stubsSrcJar
226}
227
228var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"}
229var metalavaMergeInclusionAnnotationsDirTag = dependencyTag{name: "metalava-merge-inclusion-annotations-dir"}
230var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"}
231
232func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) {
233 d.Javadoc.addDeps(ctx)
234
235 if len(d.properties.Merge_annotations_dirs) != 0 {
236 for _, mergeAnnotationsDir := range d.properties.Merge_annotations_dirs {
237 ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir)
238 }
239 }
240
241 if len(d.properties.Merge_inclusion_annotations_dirs) != 0 {
242 for _, mergeInclusionAnnotationsDir := range d.properties.Merge_inclusion_annotations_dirs {
243 ctx.AddDependency(ctx.Module(), metalavaMergeInclusionAnnotationsDirTag, mergeInclusionAnnotationsDir)
244 }
245 }
246
247 if len(d.properties.Api_levels_annotations_dirs) != 0 {
248 for _, apiLevelsAnnotationsDir := range d.properties.Api_levels_annotations_dirs {
249 ctx.AddDependency(ctx.Module(), metalavaAPILevelsAnnotationsDirTag, apiLevelsAnnotationsDir)
250 }
251 }
252}
253
254func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) {
255 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
256 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
257 String(d.properties.Api_filename) != "" {
258 filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
Colin Crosscb77f752021-03-24 12:04:44 -0700259 d.apiFile = android.PathForModuleOut(ctx, "metalava", filename)
Colin Cross2207f872021-03-24 12:39:08 -0700260 cmd.FlagWithOutput("--api ", d.apiFile)
261 d.apiFilePath = d.apiFile
262 } else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" {
263 // If check api is disabled then make the source file available for export.
264 d.apiFilePath = android.PathForModuleSrc(ctx, sourceApiFile)
265 }
266
267 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
268 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
269 String(d.properties.Removed_api_filename) != "" {
270 filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
Colin Crosscb77f752021-03-24 12:04:44 -0700271 d.removedApiFile = android.PathForModuleOut(ctx, "metalava", filename)
Colin Cross2207f872021-03-24 12:39:08 -0700272 cmd.FlagWithOutput("--removed-api ", d.removedApiFile)
273 d.removedApiFilePath = d.removedApiFile
274 } else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" {
275 // If check api is disabled then make the source removed api file available for export.
276 d.removedApiFilePath = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
277 }
278
Colin Cross2207f872021-03-24 12:39:08 -0700279 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700280 d.metadataDir = android.PathForModuleOut(ctx, "metalava", "metadata")
Colin Cross2207f872021-03-24 12:39:08 -0700281 cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
282 }
283
284 if stubsDir.Valid() {
285 if Bool(d.properties.Create_doc_stubs) {
286 cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
287 } else {
288 cmd.FlagWithArg("--stubs ", stubsDir.String())
289 if !Bool(d.properties.Output_javadoc_comments) {
290 cmd.Flag("--exclude-documentation-from-stubs")
291 }
292 }
293 }
294}
295
296func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
297 if Bool(d.properties.Annotations_enabled) {
298 cmd.Flag("--include-annotations")
299
Andrei Onea4985e512021-04-29 16:29:34 +0100300 cmd.FlagWithArg("--exclude-annotation ", "androidx.annotation.RequiresApi")
301
Colin Cross2207f872021-03-24 12:39:08 -0700302 validatingNullability :=
Colin Crossbc139922021-03-25 18:33:16 -0700303 strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") ||
Colin Cross2207f872021-03-24 12:39:08 -0700304 String(d.properties.Validate_nullability_from_list) != ""
305
306 migratingNullability := String(d.properties.Previous_api) != ""
307 if migratingNullability {
308 previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
309 cmd.FlagWithInput("--migrate-nullness ", previousApi)
310 }
311
312 if s := String(d.properties.Validate_nullability_from_list); s != "" {
313 cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
314 }
315
316 if validatingNullability {
Colin Crosscb77f752021-03-24 12:04:44 -0700317 d.nullabilityWarningsFile = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_nullability_warnings.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700318 cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile)
319 }
320
Colin Crosscb77f752021-03-24 12:04:44 -0700321 d.annotationsZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_annotations.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700322 cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip)
323
324 if len(d.properties.Merge_annotations_dirs) != 0 {
325 d.mergeAnnoDirFlags(ctx, cmd)
326 }
327
328 // TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
329 cmd.FlagWithArg("--hide ", "HiddenTypedefConstant").
330 FlagWithArg("--hide ", "SuperfluousPrefix").
331 FlagWithArg("--hide ", "AnnotationExtraction")
332 }
333}
334
335func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
336 ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
337 if t, ok := m.(*ExportedDroiddocDir); ok {
338 cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps)
339 } else {
340 ctx.PropertyErrorf("merge_annotations_dirs",
341 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
342 }
343 })
344}
345
346func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
347 ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) {
348 if t, ok := m.(*ExportedDroiddocDir); ok {
349 cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps)
350 } else {
351 ctx.PropertyErrorf("merge_inclusion_annotations_dirs",
352 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
353 }
354 })
355}
356
357func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
358 if !Bool(d.properties.Api_levels_annotations_enabled) {
359 return
360 }
361
Colin Crosscb77f752021-03-24 12:04:44 -0700362 d.apiVersionsXml = android.PathForModuleOut(ctx, "metalava", "api-versions.xml")
Colin Cross2207f872021-03-24 12:39:08 -0700363
364 if len(d.properties.Api_levels_annotations_dirs) == 0 {
365 ctx.PropertyErrorf("api_levels_annotations_dirs",
366 "has to be non-empty if api levels annotations was enabled!")
367 }
368
369 cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml)
370 cmd.FlagWithInput("--apply-api-levels ", d.apiVersionsXml)
371 cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion().String())
Jeff Sharkey46d18db2021-06-07 11:10:14 -0600372 cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename())
Colin Cross2207f872021-03-24 12:39:08 -0700373
374 filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar")
375
376 ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
377 if t, ok := m.(*ExportedDroiddocDir); ok {
378 for _, dep := range t.deps {
Colin Cross5f6ffc72021-03-29 21:54:45 -0700379 if dep.Base() == filename {
380 cmd.Implicit(dep)
381 }
382 if filename != "android.jar" && dep.Base() == "android.jar" {
383 // Metalava implicitly searches these patterns:
384 // prebuilts/tools/common/api-versions/android-%/android.jar
385 // prebuilts/sdk/%/public/android.jar
386 // Add android.jar files from the api_levels_annotations_dirs directories to try
387 // to satisfy these patterns. If Metalava can't find a match for an API level
388 // between 1 and 28 in at least one pattern it will fail.
Colin Cross2207f872021-03-24 12:39:08 -0700389 cmd.Implicit(dep)
390 }
391 }
392 cmd.FlagWithArg("--android-jar-pattern ", t.dir.String()+"/%/public/"+filename)
393 } else {
394 ctx.PropertyErrorf("api_levels_annotations_dirs",
395 "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
396 }
397 })
398}
399
400func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
Anton Hansson363aae42021-06-04 16:20:25 +0100401 srcJarList android.Path, bootclasspath, classpath classpath, homeDir android.WritablePath) *android.RuleBuilderCommand {
Colin Cross2207f872021-03-24 12:39:08 -0700402 rule.Command().Text("rm -rf").Flag(homeDir.String())
403 rule.Command().Text("mkdir -p").Flag(homeDir.String())
404
Anton Hansson363aae42021-06-04 16:20:25 +0100405 cmd := rule.Command()
Colin Cross2207f872021-03-24 12:39:08 -0700406 cmd.FlagWithArg("ANDROID_PREFS_ROOT=", homeDir.String())
407
408 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA") {
409 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
Colin Cross8095c292021-03-30 16:40:48 -0700410 execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
411 labels := map[string]string{"type": "tool", "name": "metalava"}
412 // TODO: metalava pool rejects these jobs
413 pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
414 rule.Rewrapper(&remoteexec.REParams{
415 Labels: labels,
416 ExecStrategy: execStrategy,
417 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
418 Platform: map[string]string{remoteexec.PoolKey: pool},
419 })
Colin Cross2207f872021-03-24 12:39:08 -0700420 }
421
Colin Cross6aa5c402021-03-24 12:28:50 -0700422 cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
Colin Cross2207f872021-03-24 12:39:08 -0700423 Flag(config.JavacVmFlags).
424 Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED").
425 FlagWithArg("-encoding ", "UTF-8").
426 FlagWithArg("-source ", javaVersion.String()).
427 FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs).
428 FlagWithInput("@", srcJarList)
429
Colin Cross2207f872021-03-24 12:39:08 -0700430 if len(bootclasspath) > 0 {
431 cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":")
432 }
433
434 if len(classpath) > 0 {
435 cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
436 }
437
Colin Cross2207f872021-03-24 12:39:08 -0700438 cmd.Flag("--no-banner").
439 Flag("--color").
440 Flag("--quiet").
441 Flag("--format=v2").
442 FlagWithArg("--repeat-errors-max ", "10").
443 FlagWithArg("--hide ", "UnresolvedImport")
444
445 return cmd
446}
447
448func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
449 deps := d.Javadoc.collectDeps(ctx)
450
Jiyong Parkf1691d22021-03-29 20:11:58 +0900451 javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d))
Colin Cross2207f872021-03-24 12:39:08 -0700452
453 // Create rule for metalava
454
Colin Crosscb77f752021-03-24 12:04:44 -0700455 srcJarDir := android.PathForModuleOut(ctx, "metalava", "srcjars")
Colin Cross2207f872021-03-24 12:39:08 -0700456
457 rule := android.NewRuleBuilder(pctx, ctx)
458
Colin Cross8095c292021-03-30 16:40:48 -0700459 rule.Sbox(android.PathForModuleOut(ctx, "metalava"),
460 android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
461 SandboxInputs()
Colin Cross6aa5c402021-03-24 12:28:50 -0700462
Colin Cross2207f872021-03-24 12:39:08 -0700463 if BoolDefault(d.properties.High_mem, false) {
464 // This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel.
465 rule.HighMem()
466 }
467
468 generateStubs := BoolDefault(d.properties.Generate_stubs, true)
469 var stubsDir android.OptionalPath
470 if generateStubs {
Colin Crosscb77f752021-03-24 12:04:44 -0700471 d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
472 stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "metalava", "stubsDir"))
Colin Cross2207f872021-03-24 12:39:08 -0700473 rule.Command().Text("rm -rf").Text(stubsDir.String())
474 rule.Command().Text("mkdir -p").Text(stubsDir.String())
475 }
476
477 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
478
Colin Crosscb77f752021-03-24 12:04:44 -0700479 homeDir := android.PathForModuleOut(ctx, "metalava", "home")
Colin Cross2207f872021-03-24 12:39:08 -0700480 cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
Anton Hansson363aae42021-06-04 16:20:25 +0100481 deps.bootClasspath, deps.classpath, homeDir)
Colin Cross2207f872021-03-24 12:39:08 -0700482 cmd.Implicits(d.Javadoc.implicits)
483
484 d.stubsFlags(ctx, cmd, stubsDir)
485
486 d.annotationsFlags(ctx, cmd)
487 d.inclusionAnnotationsFlags(ctx, cmd)
488 d.apiLevelsAnnotationsFlags(ctx, cmd)
489
Colin Crossbc139922021-03-25 18:33:16 -0700490 d.expandArgs(ctx, cmd)
Colin Cross2207f872021-03-24 12:39:08 -0700491
Colin Cross2207f872021-03-24 12:39:08 -0700492 for _, o := range d.Javadoc.properties.Out {
493 cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
494 }
495
496 // Add options for the other optional tasks: API-lint and check-released.
497 // We generate separate timestamp files for them.
498
499 doApiLint := false
500 doCheckReleased := false
501
502 // Add API lint options.
503
504 if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) {
505 doApiLint = true
506
507 newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since)
508 if newSince.Valid() {
509 cmd.FlagWithInput("--api-lint ", newSince.Path())
510 } else {
511 cmd.Flag("--api-lint")
512 }
Colin Crosscb77f752021-03-24 12:04:44 -0700513 d.apiLintReport = android.PathForModuleOut(ctx, "metalava", "api_lint_report.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700514 cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO: Change to ":api-lint"
515
Colin Cross0d532412021-03-25 09:38:45 -0700516 // TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released.
Colin Cross2207f872021-03-24 12:39:08 -0700517 if d.Name() != "android.car-system-stubs-docs" &&
518 d.Name() != "android.car-stubs-docs" {
519 cmd.Flag("--lints-as-errors")
520 cmd.Flag("--warnings-as-errors") // Most lints are actually warnings.
521 }
522
523 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700524 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "api_lint_baseline.txt")
525 d.apiLintTimestamp = android.PathForModuleOut(ctx, "metalava", "api_lint.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700526
527 // Note this string includes a special shell quote $' ... ', which decodes the "\n"s.
Colin Cross2207f872021-03-24 12:39:08 -0700528 //
529 // TODO: metalava also has a slightly different message hardcoded. Should we unify this
530 // message and metalava's one?
531 msg := `$'` + // Enclose with $' ... '
532 `************************************************************\n` +
533 `Your API changes are triggering API Lint warnings or errors.\n` +
534 `To make these errors go away, fix the code according to the\n` +
535 `error and/or warning messages above.\n` +
536 `\n` +
537 `If it is not possible to do so, there are workarounds:\n` +
538 `\n` +
539 `1. You can suppress the errors with @SuppressLint("<id>")\n`
540
541 if baselineFile.Valid() {
542 cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path())
543 cmd.FlagWithOutput("--update-baseline:api-lint ", updatedBaselineOutput)
544
545 msg += fmt.Sprintf(``+
546 `2. You can update the baseline by executing the following\n`+
547 ` command:\n`+
Colin Cross63eeda02021-04-15 19:01:57 -0700548 ` (cd $ANDROID_BUILD_TOP && cp \\\n`+
549 ` "%s" \\\n`+
550 ` "%s")\n`+
Colin Cross2207f872021-03-24 12:39:08 -0700551 ` To submit the revised baseline.txt to the main Android\n`+
552 ` repository, you will need approval.\n`, updatedBaselineOutput, baselineFile.Path())
553 } else {
554 msg += fmt.Sprintf(``+
555 `2. You can add a baseline file of existing lint failures\n`+
556 ` to the build rule of %s.\n`, d.Name())
557 }
558 // Note the message ends with a ' (single quote), to close the $' ... ' .
559 msg += `************************************************************\n'`
560
561 cmd.FlagWithArg("--error-message:api-lint ", msg)
562 }
563
564 // Add "check released" options. (Detect incompatible API changes from the last public release)
565
566 if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") {
567 doCheckReleased = true
568
569 if len(d.Javadoc.properties.Out) > 0 {
570 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
571 }
572
573 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
574 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
575 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700576 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "last_released_baseline.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700577
Colin Crosscb77f752021-03-24 12:04:44 -0700578 d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_last_released_api.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700579
580 cmd.FlagWithInput("--check-compatibility:api:released ", apiFile)
581 cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile)
582
583 if baselineFile.Valid() {
584 cmd.FlagWithInput("--baseline:compatibility:released ", baselineFile.Path())
585 cmd.FlagWithOutput("--update-baseline:compatibility:released ", updatedBaselineOutput)
586 }
587
588 // Note this string includes quote ($' ... '), which decodes the "\n"s.
589 msg := `$'\n******************************\n` +
590 `You have tried to change the API from what has been previously released in\n` +
591 `an SDK. Please fix the errors listed above.\n` +
592 `******************************\n'`
593
594 cmd.FlagWithArg("--error-message:compatibility:released ", msg)
595 }
596
Colin Cross2207f872021-03-24 12:39:08 -0700597 if generateStubs {
598 rule.Command().
599 BuiltTool("soong_zip").
600 Flag("-write_if_changed").
601 Flag("-jar").
602 FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
603 FlagWithArg("-C ", stubsDir.String()).
604 FlagWithArg("-D ", stubsDir.String())
605 }
606
607 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700608 d.metadataZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-metadata.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700609 rule.Command().
610 BuiltTool("soong_zip").
611 Flag("-write_if_changed").
612 Flag("-d").
613 FlagWithOutput("-o ", d.metadataZip).
614 FlagWithArg("-C ", d.metadataDir.String()).
615 FlagWithArg("-D ", d.metadataDir.String())
616 }
617
618 // TODO: We don't really need two separate API files, but this is a reminiscence of how
619 // we used to run metalava separately for API lint and the "last_released" check. Unify them.
620 if doApiLint {
621 rule.Command().Text("touch").Output(d.apiLintTimestamp)
622 }
623 if doCheckReleased {
624 rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp)
625 }
626
Colin Cross6aa5c402021-03-24 12:28:50 -0700627 // TODO(b/183630617): rewrapper doesn't support restat rules
Colin Cross8095c292021-03-30 16:40:48 -0700628 // rule.Restat()
Colin Cross2207f872021-03-24 12:39:08 -0700629
630 zipSyncCleanupCmd(rule, srcJarDir)
631
632 rule.Build("metalava", "metalava merged")
633
634 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
635
636 if len(d.Javadoc.properties.Out) > 0 {
637 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
638 }
639
640 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
641 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
642 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)
643
644 if baselineFile.Valid() {
645 ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
646 }
647
Colin Crosscb77f752021-03-24 12:04:44 -0700648 d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700649
650 rule := android.NewRuleBuilder(pctx, ctx)
651
652 // Diff command line.
653 // -F matches the closest "opening" line, such as "package android {"
654 // and " public class Intent {".
655 diff := `diff -u -F '{ *$'`
656
657 rule.Command().Text("( true")
658 rule.Command().
659 Text(diff).
660 Input(apiFile).Input(d.apiFile)
661
662 rule.Command().
663 Text(diff).
664 Input(removedApiFile).Input(d.removedApiFile)
665
666 msg := fmt.Sprintf(`\n******************************\n`+
667 `You have tried to change the API from what has been previously approved.\n\n`+
668 `To make these errors go away, you have two choices:\n`+
669 ` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
670 ` to the new methods, etc. shown in the above diff.\n\n`+
671 ` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+
672 ` m %s-update-current-api\n\n`+
673 ` To submit the revised current.txt to the main Android repository,\n`+
674 ` you will need approval.\n`+
675 `******************************\n`, ctx.ModuleName())
676
677 rule.Command().
678 Text("touch").Output(d.checkCurrentApiTimestamp).
679 Text(") || (").
680 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
681 Text("; exit 38").
682 Text(")")
683
684 rule.Build("metalavaCurrentApiCheck", "check current API")
685
Colin Crosscb77f752021-03-24 12:04:44 -0700686 d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "update_current_api.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700687
688 // update API rule
689 rule = android.NewRuleBuilder(pctx, ctx)
690
691 rule.Command().Text("( true")
692
693 rule.Command().
694 Text("cp").Flag("-f").
695 Input(d.apiFile).Flag(apiFile.String())
696
697 rule.Command().
698 Text("cp").Flag("-f").
699 Input(d.removedApiFile).Flag(removedApiFile.String())
700
701 msg = "failed to update public API"
702
703 rule.Command().
704 Text("touch").Output(d.updateCurrentApiTimestamp).
705 Text(") || (").
706 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
707 Text("; exit 38").
708 Text(")")
709
710 rule.Build("metalavaCurrentApiUpdate", "update current API")
711 }
712
713 if String(d.properties.Check_nullability_warnings) != "" {
714 if d.nullabilityWarningsFile == nil {
715 ctx.PropertyErrorf("check_nullability_warnings",
716 "Cannot specify check_nullability_warnings unless validating nullability")
717 }
718
719 checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings))
720
Colin Crosscb77f752021-03-24 12:04:44 -0700721 d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "metalava", "check_nullability_warnings.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700722
723 msg := fmt.Sprintf(`\n******************************\n`+
724 `The warnings encountered during nullability annotation validation did\n`+
725 `not match the checked in file of expected warnings. The diffs are shown\n`+
726 `above. You have two options:\n`+
727 ` 1. Resolve the differences by editing the nullability annotations.\n`+
728 ` 2. Update the file of expected warnings by running:\n`+
729 ` cp %s %s\n`+
730 ` and submitting the updated file as part of your change.`,
731 d.nullabilityWarningsFile, checkNullabilityWarnings)
732
733 rule := android.NewRuleBuilder(pctx, ctx)
734
735 rule.Command().
736 Text("(").
737 Text("diff").Input(checkNullabilityWarnings).Input(d.nullabilityWarningsFile).
738 Text("&&").
739 Text("touch").Output(d.checkNullabilityWarningsTimestamp).
740 Text(") || (").
741 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
742 Text("; exit 38").
743 Text(")")
744
745 rule.Build("nullabilityWarningsCheck", "nullability warnings check")
746 }
747}
748
749func StubsDefaultsFactory() android.Module {
750 module := &DocDefaults{}
751
752 module.AddProperties(
753 &JavadocProperties{},
754 &DroidstubsProperties{},
755 )
756
757 android.InitDefaultsModule(module)
758
759 return module
760}
761
762var _ android.PrebuiltInterface = (*PrebuiltStubsSources)(nil)
763
764type PrebuiltStubsSourcesProperties struct {
765 Srcs []string `android:"path"`
766}
767
768type PrebuiltStubsSources struct {
769 android.ModuleBase
770 android.DefaultableModuleBase
771 prebuilt android.Prebuilt
772 android.SdkBase
773
774 properties PrebuiltStubsSourcesProperties
775
Anton Hanssonfb41d462021-11-03 14:44:12 +0000776 stubsSrcJar android.Path
Colin Cross2207f872021-03-24 12:39:08 -0700777}
778
779func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
780 switch tag {
781 case "":
782 return android.Paths{p.stubsSrcJar}, nil
783 default:
784 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
785 }
786}
787
788func (d *PrebuiltStubsSources) StubsSrcJar() android.Path {
789 return d.stubsSrcJar
790}
791
792func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Cross2207f872021-03-24 12:39:08 -0700793 if len(p.properties.Srcs) != 1 {
Anton Hanssonfb41d462021-11-03 14:44:12 +0000794 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 -0700795 return
796 }
797
Anton Hanssonfb41d462021-11-03 14:44:12 +0000798 src := p.properties.Srcs[0]
799 if filepath.Ext(src) == ".srcjar" {
800 // This is a srcjar. We can use it directly.
801 p.stubsSrcJar = android.PathForModuleSrc(ctx, src)
802 } else {
803 outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
Colin Cross2207f872021-03-24 12:39:08 -0700804
Anton Hanssonfb41d462021-11-03 14:44:12 +0000805 // This is a directory. Glob the contents just in case the directory does not exist.
806 srcGlob := src + "/**/*"
807 srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
Colin Cross2207f872021-03-24 12:39:08 -0700808
Anton Hanssonfb41d462021-11-03 14:44:12 +0000809 // Although PathForModuleSrc can return nil if either the path doesn't exist or
810 // the path components are invalid it won't in this case because no components
811 // are specified and the module directory must exist in order to get this far.
812 srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, src)
Colin Cross2207f872021-03-24 12:39:08 -0700813
Anton Hanssonfb41d462021-11-03 14:44:12 +0000814 rule := android.NewRuleBuilder(pctx, ctx)
815 rule.Command().
816 BuiltTool("soong_zip").
817 Flag("-write_if_changed").
818 Flag("-jar").
819 FlagWithOutput("-o ", outPath).
820 FlagWithArg("-C ", srcDir.String()).
821 FlagWithRspFileInputList("-r ", outPath.ReplaceExtension(ctx, "rsp"), srcPaths)
822 rule.Restat()
823 rule.Build("zip src", "Create srcjar from prebuilt source")
824 p.stubsSrcJar = outPath
825 }
Colin Cross2207f872021-03-24 12:39:08 -0700826}
827
828func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
829 return &p.prebuilt
830}
831
832func (p *PrebuiltStubsSources) Name() string {
833 return p.prebuilt.Name(p.ModuleBase.Name())
834}
835
836// prebuilt_stubs_sources imports a set of java source files as if they were
837// generated by droidstubs.
838//
839// By default, a prebuilt_stubs_sources has a single variant that expects a
840// set of `.java` files generated by droidstubs.
841//
842// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one
843// for host modules.
844//
845// Intended only for use by sdk snapshots.
846func PrebuiltStubsSourcesFactory() android.Module {
847 module := &PrebuiltStubsSources{}
848
849 module.AddProperties(&module.properties)
850
851 android.InitPrebuiltModule(module, &module.properties.Srcs)
852 android.InitSdkAwareModule(module)
853 InitDroiddocModule(module, android.HostAndDeviceSupported)
854 return module
855}