blob: 8baf4d357e2ec7ac5bf28a02c867cdfaeeefd9fb [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
22 "github.com/google/blueprint/proptools"
23
24 "android/soong/android"
25 "android/soong/java/config"
26 "android/soong/remoteexec"
27)
28
Pedro Loureirocc203502021-10-04 17:24:00 +000029// The values allowed for Droidstubs' Api_levels_sdk_type
30var allowedApiLevelSdkTypes = []string{"public", "system", "module-lib"}
31
Colin Cross2207f872021-03-24 12:39:08 -070032func init() {
33 RegisterStubsBuildComponents(android.InitRegistrationContext)
34}
35
36func RegisterStubsBuildComponents(ctx android.RegistrationContext) {
37 ctx.RegisterModuleType("stubs_defaults", StubsDefaultsFactory)
38
39 ctx.RegisterModuleType("droidstubs", DroidstubsFactory)
40 ctx.RegisterModuleType("droidstubs_host", DroidstubsHostFactory)
41
42 ctx.RegisterModuleType("prebuilt_stubs_sources", PrebuiltStubsSourcesFactory)
43}
44
Colin Cross2207f872021-03-24 12:39:08 -070045// Droidstubs
Colin Cross2207f872021-03-24 12:39:08 -070046type Droidstubs struct {
47 Javadoc
48 android.SdkBase
49
50 properties DroidstubsProperties
51 apiFile android.WritablePath
52 apiXmlFile android.WritablePath
53 lastReleasedApiXmlFile android.WritablePath
54 privateApiFile android.WritablePath
55 removedApiFile android.WritablePath
Colin Cross2207f872021-03-24 12:39:08 -070056 nullabilityWarningsFile android.WritablePath
57
58 checkCurrentApiTimestamp android.WritablePath
59 updateCurrentApiTimestamp android.WritablePath
60 checkLastReleasedApiTimestamp android.WritablePath
61 apiLintTimestamp android.WritablePath
62 apiLintReport android.WritablePath
63
64 checkNullabilityWarningsTimestamp android.WritablePath
65
66 annotationsZip android.WritablePath
67 apiVersionsXml android.WritablePath
68
69 apiFilePath android.Path
70 removedApiFilePath android.Path
71
72 metadataZip android.WritablePath
73 metadataDir android.WritablePath
74}
75
76type DroidstubsProperties struct {
77 // The generated public API filename by Metalava, defaults to <module>_api.txt
78 Api_filename *string
79
80 // the generated removed API filename by Metalava, defaults to <module>_removed.txt
81 Removed_api_filename *string
82
Colin Cross2207f872021-03-24 12:39:08 -070083 Check_api struct {
84 Last_released ApiToCheck
85
86 Current ApiToCheck
87
88 Api_lint struct {
89 Enabled *bool
90
91 // If set, performs api_lint on any new APIs not found in the given signature file
92 New_since *string `android:"path"`
93
94 // If not blank, path to the baseline txt file for approved API lint violations.
95 Baseline_file *string `android:"path"`
96 }
97 }
98
99 // user can specify the version of previous released API file in order to do compatibility check.
100 Previous_api *string `android:"path"`
101
102 // is set to true, Metalava will allow framework SDK to contain annotations.
103 Annotations_enabled *bool
104
105 // a list of top-level directories containing files to merge qualifier annotations (i.e. those intended to be included in the stubs written) from.
106 Merge_annotations_dirs []string
107
108 // a list of top-level directories containing Java stub files to merge show/hide annotations from.
109 Merge_inclusion_annotations_dirs []string
110
111 // a file containing a list of classes to do nullability validation for.
112 Validate_nullability_from_list *string
113
114 // a file containing expected warnings produced by validation of nullability annotations.
115 Check_nullability_warnings *string
116
117 // if set to true, allow Metalava to generate doc_stubs source files. Defaults to false.
118 Create_doc_stubs *bool
119
120 // if set to true, cause Metalava to output Javadoc comments in the stubs source files. Defaults to false.
121 // Has no effect if create_doc_stubs: true.
122 Output_javadoc_comments *bool
123
124 // if set to false then do not write out stubs. Defaults to true.
125 //
126 // TODO(b/146727827): Remove capability when we do not need to generate stubs and API separately.
127 Generate_stubs *bool
128
129 // if set to true, provides a hint to the build system that this rule uses a lot of memory,
130 // whicih can be used for scheduling purposes
131 High_mem *bool
132
satayev783195c2021-06-23 21:49:57 +0100133 // if set to true, Metalava will allow framework SDK to contain API levels annotations.
Colin Cross2207f872021-03-24 12:39:08 -0700134 Api_levels_annotations_enabled *bool
135
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000136 // Apply the api levels database created by this module rather than generating one in this droidstubs.
137 Api_levels_module *string
138
Colin Cross2207f872021-03-24 12:39:08 -0700139 // 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"}
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000238var metalavaAPILevelsModuleTag = dependencyTag{name: "metalava-api-levels-module-tag"}
Colin Cross2207f872021-03-24 12:39:08 -0700239
240func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) {
241 d.Javadoc.addDeps(ctx)
242
243 if len(d.properties.Merge_annotations_dirs) != 0 {
244 for _, mergeAnnotationsDir := range d.properties.Merge_annotations_dirs {
245 ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir)
246 }
247 }
248
249 if len(d.properties.Merge_inclusion_annotations_dirs) != 0 {
250 for _, mergeInclusionAnnotationsDir := range d.properties.Merge_inclusion_annotations_dirs {
251 ctx.AddDependency(ctx.Module(), metalavaMergeInclusionAnnotationsDirTag, mergeInclusionAnnotationsDir)
252 }
253 }
254
255 if len(d.properties.Api_levels_annotations_dirs) != 0 {
256 for _, apiLevelsAnnotationsDir := range d.properties.Api_levels_annotations_dirs {
257 ctx.AddDependency(ctx.Module(), metalavaAPILevelsAnnotationsDirTag, apiLevelsAnnotationsDir)
258 }
259 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000260
261 if d.properties.Api_levels_module != nil {
262 ctx.AddDependency(ctx.Module(), metalavaAPILevelsModuleTag, proptools.String(d.properties.Api_levels_module))
263 }
Colin Cross2207f872021-03-24 12:39:08 -0700264}
265
266func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) {
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.Api_filename) != "" {
270 filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
Colin Crosscb77f752021-03-24 12:04:44 -0700271 d.apiFile = android.PathForModuleOut(ctx, "metalava", filename)
Colin Cross2207f872021-03-24 12:39:08 -0700272 cmd.FlagWithOutput("--api ", d.apiFile)
273 d.apiFilePath = d.apiFile
274 } else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" {
275 // If check api is disabled then make the source file available for export.
276 d.apiFilePath = android.PathForModuleSrc(ctx, sourceApiFile)
277 }
278
279 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
280 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
281 String(d.properties.Removed_api_filename) != "" {
282 filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
Colin Crosscb77f752021-03-24 12:04:44 -0700283 d.removedApiFile = android.PathForModuleOut(ctx, "metalava", filename)
Colin Cross2207f872021-03-24 12:39:08 -0700284 cmd.FlagWithOutput("--removed-api ", d.removedApiFile)
285 d.removedApiFilePath = d.removedApiFile
286 } else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" {
287 // If check api is disabled then make the source removed api file available for export.
288 d.removedApiFilePath = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
289 }
290
Colin Cross2207f872021-03-24 12:39:08 -0700291 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700292 d.metadataDir = android.PathForModuleOut(ctx, "metalava", "metadata")
Colin Cross2207f872021-03-24 12:39:08 -0700293 cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
294 }
295
296 if stubsDir.Valid() {
297 if Bool(d.properties.Create_doc_stubs) {
298 cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
299 } else {
300 cmd.FlagWithArg("--stubs ", stubsDir.String())
301 if !Bool(d.properties.Output_javadoc_comments) {
302 cmd.Flag("--exclude-documentation-from-stubs")
303 }
304 }
305 }
306}
307
308func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
309 if Bool(d.properties.Annotations_enabled) {
310 cmd.Flag("--include-annotations")
311
Andrei Onea4985e512021-04-29 16:29:34 +0100312 cmd.FlagWithArg("--exclude-annotation ", "androidx.annotation.RequiresApi")
313
Colin Cross2207f872021-03-24 12:39:08 -0700314 validatingNullability :=
Colin Crossbc139922021-03-25 18:33:16 -0700315 strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") ||
Colin Cross2207f872021-03-24 12:39:08 -0700316 String(d.properties.Validate_nullability_from_list) != ""
317
318 migratingNullability := String(d.properties.Previous_api) != ""
319 if migratingNullability {
320 previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
321 cmd.FlagWithInput("--migrate-nullness ", previousApi)
322 }
323
324 if s := String(d.properties.Validate_nullability_from_list); s != "" {
325 cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
326 }
327
328 if validatingNullability {
Colin Crosscb77f752021-03-24 12:04:44 -0700329 d.nullabilityWarningsFile = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_nullability_warnings.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700330 cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile)
331 }
332
Colin Crosscb77f752021-03-24 12:04:44 -0700333 d.annotationsZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_annotations.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700334 cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip)
335
336 if len(d.properties.Merge_annotations_dirs) != 0 {
337 d.mergeAnnoDirFlags(ctx, cmd)
338 }
339
340 // TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
341 cmd.FlagWithArg("--hide ", "HiddenTypedefConstant").
342 FlagWithArg("--hide ", "SuperfluousPrefix").
Sam Gilbert049af112022-03-04 16:03:53 -0500343 FlagWithArg("--hide ", "AnnotationExtraction").
344 // b/222738070
Sam Gilbert675f0b42022-03-08 11:24:44 -0500345 FlagWithArg("--hide ", "BannedThrow").
346 // b/223382732
347 FlagWithArg("--hide ", "ChangedDefault")
Colin Cross2207f872021-03-24 12:39:08 -0700348 }
349}
350
351func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
352 ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
353 if t, ok := m.(*ExportedDroiddocDir); ok {
354 cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps)
355 } else {
356 ctx.PropertyErrorf("merge_annotations_dirs",
357 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
358 }
359 })
360}
361
362func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
363 ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) {
364 if t, ok := m.(*ExportedDroiddocDir); ok {
365 cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps)
366 } else {
367 ctx.PropertyErrorf("merge_inclusion_annotations_dirs",
368 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
369 }
370 })
371}
372
373func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000374 var apiVersions android.Path
375 if proptools.Bool(d.properties.Api_levels_annotations_enabled) {
376 d.apiLevelsGenerationFlags(ctx, cmd)
377 apiVersions = d.apiVersionsXml
378 } else {
379 ctx.VisitDirectDepsWithTag(metalavaAPILevelsModuleTag, func(m android.Module) {
380 if s, ok := m.(*Droidstubs); ok {
381 apiVersions = s.apiVersionsXml
382 } else {
383 ctx.PropertyErrorf("api_levels_module",
384 "module %q is not a droidstubs module", ctx.OtherModuleName(m))
385 }
386 })
Colin Cross2207f872021-03-24 12:39:08 -0700387 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000388 if apiVersions != nil {
389 cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion().String())
390 cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename())
391 cmd.FlagWithInput("--apply-api-levels ", apiVersions)
392 }
393}
Colin Cross2207f872021-03-24 12:39:08 -0700394
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000395func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Colin Cross2207f872021-03-24 12:39:08 -0700396 if len(d.properties.Api_levels_annotations_dirs) == 0 {
397 ctx.PropertyErrorf("api_levels_annotations_dirs",
398 "has to be non-empty if api levels annotations was enabled!")
399 }
400
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000401 d.apiVersionsXml = android.PathForModuleOut(ctx, "metalava", "api-versions.xml")
Colin Cross2207f872021-03-24 12:39:08 -0700402 cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml)
Colin Cross2207f872021-03-24 12:39:08 -0700403
404 filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar")
405
satayev783195c2021-06-23 21:49:57 +0100406 var dirs []string
Colin Cross2207f872021-03-24 12:39:08 -0700407 ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
408 if t, ok := m.(*ExportedDroiddocDir); ok {
409 for _, dep := range t.deps {
Colin Cross5f6ffc72021-03-29 21:54:45 -0700410 if dep.Base() == filename {
411 cmd.Implicit(dep)
412 }
413 if filename != "android.jar" && dep.Base() == "android.jar" {
414 // Metalava implicitly searches these patterns:
415 // prebuilts/tools/common/api-versions/android-%/android.jar
416 // prebuilts/sdk/%/public/android.jar
417 // Add android.jar files from the api_levels_annotations_dirs directories to try
418 // to satisfy these patterns. If Metalava can't find a match for an API level
419 // between 1 and 28 in at least one pattern it will fail.
Colin Cross2207f872021-03-24 12:39:08 -0700420 cmd.Implicit(dep)
421 }
422 }
satayev783195c2021-06-23 21:49:57 +0100423
424 dirs = append(dirs, t.dir.String())
Colin Cross2207f872021-03-24 12:39:08 -0700425 } else {
426 ctx.PropertyErrorf("api_levels_annotations_dirs",
427 "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
428 }
429 })
satayev783195c2021-06-23 21:49:57 +0100430
431 // Add all relevant --android-jar-pattern patterns for Metalava.
432 // When parsing a stub jar for a specific version, Metalava picks the first pattern that defines
433 // an actual file present on disk (in the order the patterns were passed). For system APIs for
434 // privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs
Pedro Loureirocc203502021-10-04 17:24:00 +0000435 // for older releases. Similarly, module-lib falls back to system API.
436 var sdkDirs []string
437 switch proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") {
438 case "module-lib":
439 sdkDirs = []string{"module-lib", "system", "public"}
440 case "system":
441 sdkDirs = []string{"system", "public"}
442 case "public":
443 sdkDirs = []string{"public"}
444 default:
445 ctx.PropertyErrorf("api_levels_sdk_type", "needs to be one of %v", allowedApiLevelSdkTypes)
446 return
satayev783195c2021-06-23 21:49:57 +0100447 }
Pedro Loureirocc203502021-10-04 17:24:00 +0000448
449 for _, sdkDir := range sdkDirs {
450 for _, dir := range dirs {
451 cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, filename))
452 }
satayev783195c2021-06-23 21:49:57 +0100453 }
Colin Cross2207f872021-03-24 12:39:08 -0700454}
455
Colin Crosse52c2ac2022-03-28 17:03:35 -0700456func metalavaUseRbe(ctx android.ModuleContext) bool {
457 return ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA")
458}
459
Colin Cross2207f872021-03-24 12:39:08 -0700460func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
Anton Hansson556e8142021-06-04 16:20:25 +0100461 srcJarList android.Path, bootclasspath, classpath classpath, homeDir android.WritablePath) *android.RuleBuilderCommand {
Colin Cross2207f872021-03-24 12:39:08 -0700462 rule.Command().Text("rm -rf").Flag(homeDir.String())
463 rule.Command().Text("mkdir -p").Flag(homeDir.String())
464
Anton Hansson556e8142021-06-04 16:20:25 +0100465 cmd := rule.Command()
Colin Cross2207f872021-03-24 12:39:08 -0700466 cmd.FlagWithArg("ANDROID_PREFS_ROOT=", homeDir.String())
467
Colin Crosse52c2ac2022-03-28 17:03:35 -0700468 if metalavaUseRbe(ctx) {
Colin Cross2207f872021-03-24 12:39:08 -0700469 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
Colin Cross8095c292021-03-30 16:40:48 -0700470 execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
471 labels := map[string]string{"type": "tool", "name": "metalava"}
472 // TODO: metalava pool rejects these jobs
473 pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
474 rule.Rewrapper(&remoteexec.REParams{
475 Labels: labels,
476 ExecStrategy: execStrategy,
477 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
478 Platform: map[string]string{remoteexec.PoolKey: pool},
479 })
Colin Cross2207f872021-03-24 12:39:08 -0700480 }
481
Colin Cross6aa5c402021-03-24 12:28:50 -0700482 cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
Colin Cross2207f872021-03-24 12:39:08 -0700483 Flag(config.JavacVmFlags).
484 Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED").
485 FlagWithArg("-encoding ", "UTF-8").
486 FlagWithArg("-source ", javaVersion.String()).
487 FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs).
488 FlagWithInput("@", srcJarList)
489
Colin Cross2207f872021-03-24 12:39:08 -0700490 if len(bootclasspath) > 0 {
491 cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":")
492 }
493
494 if len(classpath) > 0 {
495 cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
496 }
497
Colin Cross2207f872021-03-24 12:39:08 -0700498 cmd.Flag("--no-banner").
499 Flag("--color").
500 Flag("--quiet").
501 Flag("--format=v2").
502 FlagWithArg("--repeat-errors-max ", "10").
Sam Gilbert09cb5db2021-10-06 11:28:28 -0400503 FlagWithArg("--hide ", "UnresolvedImport").
Ember Rose7c57af32022-04-01 10:34:44 -0400504 FlagWithArg("--hide ", "InvalidNullabilityOverride").
Sam Gilbert28e41282022-03-09 15:24:48 +0000505 // b/223382732
506 FlagWithArg("--hide ", "ChangedDefault")
Colin Cross2207f872021-03-24 12:39:08 -0700507
508 return cmd
509}
510
511func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
512 deps := d.Javadoc.collectDeps(ctx)
513
Jiyong Parkf1691d22021-03-29 20:11:58 +0900514 javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d))
Colin Cross2207f872021-03-24 12:39:08 -0700515
516 // Create rule for metalava
517
Colin Crosscb77f752021-03-24 12:04:44 -0700518 srcJarDir := android.PathForModuleOut(ctx, "metalava", "srcjars")
Colin Cross2207f872021-03-24 12:39:08 -0700519
520 rule := android.NewRuleBuilder(pctx, ctx)
521
Colin Cross8095c292021-03-30 16:40:48 -0700522 rule.Sbox(android.PathForModuleOut(ctx, "metalava"),
523 android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
524 SandboxInputs()
Colin Cross6aa5c402021-03-24 12:28:50 -0700525
Colin Cross2207f872021-03-24 12:39:08 -0700526 if BoolDefault(d.properties.High_mem, false) {
527 // This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel.
528 rule.HighMem()
529 }
530
531 generateStubs := BoolDefault(d.properties.Generate_stubs, true)
532 var stubsDir android.OptionalPath
533 if generateStubs {
Colin Crosscb77f752021-03-24 12:04:44 -0700534 d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
535 stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "metalava", "stubsDir"))
Colin Cross2207f872021-03-24 12:39:08 -0700536 rule.Command().Text("rm -rf").Text(stubsDir.String())
537 rule.Command().Text("mkdir -p").Text(stubsDir.String())
538 }
539
540 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
541
Colin Crosscb77f752021-03-24 12:04:44 -0700542 homeDir := android.PathForModuleOut(ctx, "metalava", "home")
Colin Cross2207f872021-03-24 12:39:08 -0700543 cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
Anton Hansson556e8142021-06-04 16:20:25 +0100544 deps.bootClasspath, deps.classpath, homeDir)
Colin Cross2207f872021-03-24 12:39:08 -0700545 cmd.Implicits(d.Javadoc.implicits)
546
547 d.stubsFlags(ctx, cmd, stubsDir)
548
549 d.annotationsFlags(ctx, cmd)
550 d.inclusionAnnotationsFlags(ctx, cmd)
551 d.apiLevelsAnnotationsFlags(ctx, cmd)
552
Colin Crossbc139922021-03-25 18:33:16 -0700553 d.expandArgs(ctx, cmd)
Colin Cross2207f872021-03-24 12:39:08 -0700554
Colin Cross2207f872021-03-24 12:39:08 -0700555 for _, o := range d.Javadoc.properties.Out {
556 cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
557 }
558
559 // Add options for the other optional tasks: API-lint and check-released.
560 // We generate separate timestamp files for them.
561
562 doApiLint := false
563 doCheckReleased := false
564
565 // Add API lint options.
566
567 if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) {
568 doApiLint = true
569
570 newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since)
571 if newSince.Valid() {
572 cmd.FlagWithInput("--api-lint ", newSince.Path())
573 } else {
574 cmd.Flag("--api-lint")
575 }
Colin Crosscb77f752021-03-24 12:04:44 -0700576 d.apiLintReport = android.PathForModuleOut(ctx, "metalava", "api_lint_report.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700577 cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO: Change to ":api-lint"
578
Colin Cross0d532412021-03-25 09:38:45 -0700579 // TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released.
Colin Cross2207f872021-03-24 12:39:08 -0700580 if d.Name() != "android.car-system-stubs-docs" &&
581 d.Name() != "android.car-stubs-docs" {
582 cmd.Flag("--lints-as-errors")
583 cmd.Flag("--warnings-as-errors") // Most lints are actually warnings.
584 }
585
586 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700587 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "api_lint_baseline.txt")
588 d.apiLintTimestamp = android.PathForModuleOut(ctx, "metalava", "api_lint.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700589
590 // Note this string includes a special shell quote $' ... ', which decodes the "\n"s.
Colin Cross2207f872021-03-24 12:39:08 -0700591 //
592 // TODO: metalava also has a slightly different message hardcoded. Should we unify this
593 // message and metalava's one?
594 msg := `$'` + // Enclose with $' ... '
595 `************************************************************\n` +
596 `Your API changes are triggering API Lint warnings or errors.\n` +
597 `To make these errors go away, fix the code according to the\n` +
598 `error and/or warning messages above.\n` +
599 `\n` +
600 `If it is not possible to do so, there are workarounds:\n` +
601 `\n` +
Aurimas Liutikasb23b7452021-05-24 18:00:37 +0000602 `1. You can suppress the errors with @SuppressLint("<id>")\n` +
603 ` where the <id> is given in brackets in the error message above.\n`
Colin Cross2207f872021-03-24 12:39:08 -0700604
605 if baselineFile.Valid() {
606 cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path())
607 cmd.FlagWithOutput("--update-baseline:api-lint ", updatedBaselineOutput)
608
609 msg += fmt.Sprintf(``+
610 `2. You can update the baseline by executing the following\n`+
611 ` command:\n`+
Colin Cross63eeda02021-04-15 19:01:57 -0700612 ` (cd $ANDROID_BUILD_TOP && cp \\\n`+
613 ` "%s" \\\n`+
614 ` "%s")\n`+
Colin Cross2207f872021-03-24 12:39:08 -0700615 ` To submit the revised baseline.txt to the main Android\n`+
616 ` repository, you will need approval.\n`, updatedBaselineOutput, baselineFile.Path())
617 } else {
618 msg += fmt.Sprintf(``+
619 `2. You can add a baseline file of existing lint failures\n`+
620 ` to the build rule of %s.\n`, d.Name())
621 }
622 // Note the message ends with a ' (single quote), to close the $' ... ' .
623 msg += `************************************************************\n'`
624
625 cmd.FlagWithArg("--error-message:api-lint ", msg)
626 }
627
628 // Add "check released" options. (Detect incompatible API changes from the last public release)
629
630 if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") {
631 doCheckReleased = true
632
633 if len(d.Javadoc.properties.Out) > 0 {
634 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
635 }
636
637 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
638 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
639 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700640 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "last_released_baseline.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700641
Colin Crosscb77f752021-03-24 12:04:44 -0700642 d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_last_released_api.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700643
644 cmd.FlagWithInput("--check-compatibility:api:released ", apiFile)
645 cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile)
646
647 if baselineFile.Valid() {
648 cmd.FlagWithInput("--baseline:compatibility:released ", baselineFile.Path())
649 cmd.FlagWithOutput("--update-baseline:compatibility:released ", updatedBaselineOutput)
650 }
651
652 // Note this string includes quote ($' ... '), which decodes the "\n"s.
653 msg := `$'\n******************************\n` +
654 `You have tried to change the API from what has been previously released in\n` +
655 `an SDK. Please fix the errors listed above.\n` +
656 `******************************\n'`
657
658 cmd.FlagWithArg("--error-message:compatibility:released ", msg)
659 }
660
Colin Cross2207f872021-03-24 12:39:08 -0700661 if generateStubs {
662 rule.Command().
663 BuiltTool("soong_zip").
664 Flag("-write_if_changed").
665 Flag("-jar").
666 FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
667 FlagWithArg("-C ", stubsDir.String()).
668 FlagWithArg("-D ", stubsDir.String())
669 }
670
671 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700672 d.metadataZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-metadata.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700673 rule.Command().
674 BuiltTool("soong_zip").
675 Flag("-write_if_changed").
676 Flag("-d").
677 FlagWithOutput("-o ", d.metadataZip).
678 FlagWithArg("-C ", d.metadataDir.String()).
679 FlagWithArg("-D ", d.metadataDir.String())
680 }
681
682 // TODO: We don't really need two separate API files, but this is a reminiscence of how
683 // we used to run metalava separately for API lint and the "last_released" check. Unify them.
684 if doApiLint {
685 rule.Command().Text("touch").Output(d.apiLintTimestamp)
686 }
687 if doCheckReleased {
688 rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp)
689 }
690
Colin Cross6aa5c402021-03-24 12:28:50 -0700691 // TODO(b/183630617): rewrapper doesn't support restat rules
Colin Crosse52c2ac2022-03-28 17:03:35 -0700692 if !metalavaUseRbe(ctx) {
693 rule.Restat()
694 }
Colin Cross2207f872021-03-24 12:39:08 -0700695
696 zipSyncCleanupCmd(rule, srcJarDir)
697
Paul Duffinc166b682022-05-27 12:23:08 +0000698 rule.Build("metalava", "metalava merged")
699
Paul Duffine7a86642022-08-16 15:43:20 +0000700 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
701
702 if len(d.Javadoc.properties.Out) > 0 {
703 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
704 }
705
706 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
707 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
708 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)
709
710 if baselineFile.Valid() {
711 ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
712 }
713
714 d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp")
715
716 rule := android.NewRuleBuilder(pctx, ctx)
717
718 // Diff command line.
719 // -F matches the closest "opening" line, such as "package android {"
720 // and " public class Intent {".
721 diff := `diff -u -F '{ *$'`
722
723 rule.Command().Text("( true")
724 rule.Command().
725 Text(diff).
726 Input(apiFile).Input(d.apiFile)
727
728 rule.Command().
729 Text(diff).
730 Input(removedApiFile).Input(d.removedApiFile)
731
732 msg := fmt.Sprintf(`\n******************************\n`+
733 `You have tried to change the API from what has been previously approved.\n\n`+
734 `To make these errors go away, you have two choices:\n`+
735 ` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
736 ` to the new methods, etc. shown in the above diff.\n\n`+
737 ` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+
738 ` m %s-update-current-api\n\n`+
739 ` To submit the revised current.txt to the main Android repository,\n`+
740 ` you will need approval.\n`+
741 `******************************\n`, ctx.ModuleName())
742
743 rule.Command().
744 Text("touch").Output(d.checkCurrentApiTimestamp).
745 Text(") || (").
746 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
747 Text("; exit 38").
748 Text(")")
749
750 rule.Build("metalavaCurrentApiCheck", "check current API")
751
752 d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "update_current_api.timestamp")
753
754 // update API rule
755 rule = android.NewRuleBuilder(pctx, ctx)
756
757 rule.Command().Text("( true")
758
759 rule.Command().
760 Text("cp").Flag("-f").
761 Input(d.apiFile).Flag(apiFile.String())
762
763 rule.Command().
764 Text("cp").Flag("-f").
765 Input(d.removedApiFile).Flag(removedApiFile.String())
766
767 msg = "failed to update public API"
768
769 rule.Command().
770 Text("touch").Output(d.updateCurrentApiTimestamp).
771 Text(") || (").
772 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
773 Text("; exit 38").
774 Text(")")
775
776 rule.Build("metalavaCurrentApiUpdate", "update current API")
777 }
778
Colin Cross2207f872021-03-24 12:39:08 -0700779 if String(d.properties.Check_nullability_warnings) != "" {
780 if d.nullabilityWarningsFile == nil {
781 ctx.PropertyErrorf("check_nullability_warnings",
782 "Cannot specify check_nullability_warnings unless validating nullability")
783 }
784
785 checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings))
786
Colin Crosscb77f752021-03-24 12:04:44 -0700787 d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "metalava", "check_nullability_warnings.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700788
789 msg := fmt.Sprintf(`\n******************************\n`+
790 `The warnings encountered during nullability annotation validation did\n`+
791 `not match the checked in file of expected warnings. The diffs are shown\n`+
792 `above. You have two options:\n`+
793 ` 1. Resolve the differences by editing the nullability annotations.\n`+
794 ` 2. Update the file of expected warnings by running:\n`+
795 ` cp %s %s\n`+
796 ` and submitting the updated file as part of your change.`,
797 d.nullabilityWarningsFile, checkNullabilityWarnings)
798
799 rule := android.NewRuleBuilder(pctx, ctx)
800
801 rule.Command().
802 Text("(").
803 Text("diff").Input(checkNullabilityWarnings).Input(d.nullabilityWarningsFile).
804 Text("&&").
805 Text("touch").Output(d.checkNullabilityWarningsTimestamp).
806 Text(") || (").
807 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
808 Text("; exit 38").
809 Text(")")
810
811 rule.Build("nullabilityWarningsCheck", "nullability warnings check")
812 }
813}
814
815func StubsDefaultsFactory() android.Module {
816 module := &DocDefaults{}
817
818 module.AddProperties(
819 &JavadocProperties{},
820 &DroidstubsProperties{},
821 )
822
823 android.InitDefaultsModule(module)
824
825 return module
826}
827
828var _ android.PrebuiltInterface = (*PrebuiltStubsSources)(nil)
829
830type PrebuiltStubsSourcesProperties struct {
831 Srcs []string `android:"path"`
832}
833
834type PrebuiltStubsSources struct {
835 android.ModuleBase
836 android.DefaultableModuleBase
837 prebuilt android.Prebuilt
838 android.SdkBase
839
840 properties PrebuiltStubsSourcesProperties
841
kgui67007242022-01-25 13:50:25 +0800842 stubsSrcJar android.Path
Colin Cross2207f872021-03-24 12:39:08 -0700843}
844
845func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
846 switch tag {
847 case "":
848 return android.Paths{p.stubsSrcJar}, nil
849 default:
850 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
851 }
852}
853
854func (d *PrebuiltStubsSources) StubsSrcJar() android.Path {
855 return d.stubsSrcJar
856}
857
858func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Cross2207f872021-03-24 12:39:08 -0700859 if len(p.properties.Srcs) != 1 {
Anton Hansson86758ac2021-11-03 14:44:12 +0000860 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 -0700861 return
862 }
863
Anton Hansson86758ac2021-11-03 14:44:12 +0000864 src := p.properties.Srcs[0]
865 if filepath.Ext(src) == ".srcjar" {
866 // This is a srcjar. We can use it directly.
867 p.stubsSrcJar = android.PathForModuleSrc(ctx, src)
868 } else {
869 outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
Colin Cross2207f872021-03-24 12:39:08 -0700870
Anton Hansson86758ac2021-11-03 14:44:12 +0000871 // This is a directory. Glob the contents just in case the directory does not exist.
872 srcGlob := src + "/**/*"
873 srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
Colin Cross2207f872021-03-24 12:39:08 -0700874
Anton Hansson86758ac2021-11-03 14:44:12 +0000875 // Although PathForModuleSrc can return nil if either the path doesn't exist or
876 // the path components are invalid it won't in this case because no components
877 // are specified and the module directory must exist in order to get this far.
878 srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, src)
Colin Cross2207f872021-03-24 12:39:08 -0700879
Anton Hansson86758ac2021-11-03 14:44:12 +0000880 rule := android.NewRuleBuilder(pctx, ctx)
881 rule.Command().
882 BuiltTool("soong_zip").
883 Flag("-write_if_changed").
884 Flag("-jar").
885 FlagWithOutput("-o ", outPath).
886 FlagWithArg("-C ", srcDir.String()).
887 FlagWithRspFileInputList("-r ", outPath.ReplaceExtension(ctx, "rsp"), srcPaths)
888 rule.Restat()
889 rule.Build("zip src", "Create srcjar from prebuilt source")
890 p.stubsSrcJar = outPath
891 }
Colin Cross2207f872021-03-24 12:39:08 -0700892}
893
894func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
895 return &p.prebuilt
896}
897
898func (p *PrebuiltStubsSources) Name() string {
899 return p.prebuilt.Name(p.ModuleBase.Name())
900}
901
902// prebuilt_stubs_sources imports a set of java source files as if they were
903// generated by droidstubs.
904//
905// By default, a prebuilt_stubs_sources has a single variant that expects a
906// set of `.java` files generated by droidstubs.
907//
908// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one
909// for host modules.
910//
911// Intended only for use by sdk snapshots.
912func PrebuiltStubsSourcesFactory() android.Module {
913 module := &PrebuiltStubsSources{}
914
915 module.AddProperties(&module.properties)
916
917 android.InitPrebuiltModule(module, &module.properties.Srcs)
918 android.InitSdkAwareModule(module)
919 InitDroiddocModule(module, android.HostAndDeviceSupported)
920 return module
921}