blob: 68e32b2a59eaa2cc923658d655289c9ce70f699e [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
45//
46// Droidstubs
47//
48type Droidstubs struct {
49 Javadoc
50 android.SdkBase
51
52 properties DroidstubsProperties
Paul Duffinc71d2b72022-08-16 15:24:01 +000053 apiFile android.Path
54 removedApiFile android.Path
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
Colin Cross2207f872021-03-24 12:39:08 -070068 metadataZip android.WritablePath
69 metadataDir android.WritablePath
70}
71
72type DroidstubsProperties struct {
73 // The generated public API filename by Metalava, defaults to <module>_api.txt
74 Api_filename *string
75
76 // the generated removed API filename by Metalava, defaults to <module>_removed.txt
77 Removed_api_filename *string
78
Colin Cross2207f872021-03-24 12:39:08 -070079 Check_api struct {
80 Last_released ApiToCheck
81
82 Current ApiToCheck
83
84 Api_lint struct {
85 Enabled *bool
86
87 // If set, performs api_lint on any new APIs not found in the given signature file
88 New_since *string `android:"path"`
89
90 // If not blank, path to the baseline txt file for approved API lint violations.
91 Baseline_file *string `android:"path"`
92 }
93 }
94
95 // user can specify the version of previous released API file in order to do compatibility check.
96 Previous_api *string `android:"path"`
97
98 // is set to true, Metalava will allow framework SDK to contain annotations.
99 Annotations_enabled *bool
100
101 // a list of top-level directories containing files to merge qualifier annotations (i.e. those intended to be included in the stubs written) from.
102 Merge_annotations_dirs []string
103
104 // a list of top-level directories containing Java stub files to merge show/hide annotations from.
105 Merge_inclusion_annotations_dirs []string
106
107 // a file containing a list of classes to do nullability validation for.
108 Validate_nullability_from_list *string
109
110 // a file containing expected warnings produced by validation of nullability annotations.
111 Check_nullability_warnings *string
112
113 // if set to true, allow Metalava to generate doc_stubs source files. Defaults to false.
114 Create_doc_stubs *bool
115
116 // if set to true, cause Metalava to output Javadoc comments in the stubs source files. Defaults to false.
117 // Has no effect if create_doc_stubs: true.
118 Output_javadoc_comments *bool
119
120 // if set to false then do not write out stubs. Defaults to true.
121 //
122 // TODO(b/146727827): Remove capability when we do not need to generate stubs and API separately.
123 Generate_stubs *bool
124
125 // if set to true, provides a hint to the build system that this rule uses a lot of memory,
126 // whicih can be used for scheduling purposes
127 High_mem *bool
128
satayev783195c2021-06-23 21:49:57 +0100129 // if set to true, Metalava will allow framework SDK to contain API levels annotations.
Colin Cross2207f872021-03-24 12:39:08 -0700130 Api_levels_annotations_enabled *bool
131
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000132 // Apply the api levels database created by this module rather than generating one in this droidstubs.
133 Api_levels_module *string
134
Colin Cross2207f872021-03-24 12:39:08 -0700135 // the dirs which Metalava extracts API levels annotations from.
136 Api_levels_annotations_dirs []string
137
Pedro Loureirocc203502021-10-04 17:24:00 +0000138 // 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 +0100139 Api_levels_sdk_type *string
140
Colin Cross2207f872021-03-24 12:39:08 -0700141 // the filename which Metalava extracts API levels annotations from. Defaults to android.jar.
142 Api_levels_jar_filename *string
143
144 // if set to true, collect the values used by the Dev tools and
145 // write them in files packaged with the SDK. Defaults to false.
146 Write_sdk_values *bool
147}
148
Anton Hansson52609322021-05-05 10:36:05 +0100149// Used by xsd_config
150type ApiFilePath interface {
151 ApiFilePath() android.Path
152}
153
154type ApiStubsSrcProvider interface {
155 StubsSrcJar() android.Path
156}
157
158// Provider of information about API stubs, used by java_sdk_library.
159type ApiStubsProvider interface {
Anton Hanssond78eb762021-09-21 15:25:12 +0100160 AnnotationsZip() android.Path
Anton Hansson52609322021-05-05 10:36:05 +0100161 ApiFilePath
162 RemovedApiFilePath() android.Path
163
164 ApiStubsSrcProvider
165}
166
Colin Cross2207f872021-03-24 12:39:08 -0700167// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
168// documented, filtering out hidden classes and methods. The resulting .java files are intended to be passed to
169// a droiddoc module to generate documentation.
170func DroidstubsFactory() android.Module {
171 module := &Droidstubs{}
172
173 module.AddProperties(&module.properties,
174 &module.Javadoc.properties)
175
176 InitDroiddocModule(module, android.HostAndDeviceSupported)
177 android.InitSdkAwareModule(module)
178 return module
179}
180
181// droidstubs_host passes sources files through Metalava to generate stub .java files that only contain the API
182// to be documented, filtering out hidden classes and methods. The resulting .java files are intended to be
183// passed to a droiddoc_host module to generate documentation. Use a droidstubs_host instead of a droidstubs
184// module when symbols needed by the source files are provided by java_library_host modules.
185func DroidstubsHostFactory() android.Module {
186 module := &Droidstubs{}
187
188 module.AddProperties(&module.properties,
189 &module.Javadoc.properties)
190
191 InitDroiddocModule(module, android.HostSupported)
192 return module
193}
194
195func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) {
196 switch tag {
197 case "":
198 return android.Paths{d.stubsSrcJar}, nil
199 case ".docs.zip":
200 return android.Paths{d.docZip}, nil
201 case ".api.txt", android.DefaultDistTag:
202 // This is the default dist path for dist properties that have no tag property.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000203 return android.Paths{d.apiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700204 case ".removed-api.txt":
Paul Duffinc71d2b72022-08-16 15:24:01 +0000205 return android.Paths{d.removedApiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700206 case ".annotations.zip":
207 return android.Paths{d.annotationsZip}, nil
208 case ".api_versions.xml":
209 return android.Paths{d.apiVersionsXml}, nil
210 default:
211 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
212 }
213}
214
Anton Hanssond78eb762021-09-21 15:25:12 +0100215func (d *Droidstubs) AnnotationsZip() android.Path {
216 return d.annotationsZip
217}
218
Colin Cross2207f872021-03-24 12:39:08 -0700219func (d *Droidstubs) ApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000220 return d.apiFile
Colin Cross2207f872021-03-24 12:39:08 -0700221}
222
223func (d *Droidstubs) RemovedApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000224 return d.removedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700225}
226
227func (d *Droidstubs) StubsSrcJar() android.Path {
228 return d.stubsSrcJar
229}
230
231var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"}
232var metalavaMergeInclusionAnnotationsDirTag = dependencyTag{name: "metalava-merge-inclusion-annotations-dir"}
233var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"}
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000234var metalavaAPILevelsModuleTag = dependencyTag{name: "metalava-api-levels-module-tag"}
Colin Cross2207f872021-03-24 12:39:08 -0700235
236func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) {
237 d.Javadoc.addDeps(ctx)
238
239 if len(d.properties.Merge_annotations_dirs) != 0 {
240 for _, mergeAnnotationsDir := range d.properties.Merge_annotations_dirs {
241 ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir)
242 }
243 }
244
245 if len(d.properties.Merge_inclusion_annotations_dirs) != 0 {
246 for _, mergeInclusionAnnotationsDir := range d.properties.Merge_inclusion_annotations_dirs {
247 ctx.AddDependency(ctx.Module(), metalavaMergeInclusionAnnotationsDirTag, mergeInclusionAnnotationsDir)
248 }
249 }
250
251 if len(d.properties.Api_levels_annotations_dirs) != 0 {
252 for _, apiLevelsAnnotationsDir := range d.properties.Api_levels_annotations_dirs {
253 ctx.AddDependency(ctx.Module(), metalavaAPILevelsAnnotationsDirTag, apiLevelsAnnotationsDir)
254 }
255 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000256
257 if d.properties.Api_levels_module != nil {
258 ctx.AddDependency(ctx.Module(), metalavaAPILevelsModuleTag, proptools.String(d.properties.Api_levels_module))
259 }
Colin Cross2207f872021-03-24 12:39:08 -0700260}
261
262func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) {
263 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
264 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
265 String(d.properties.Api_filename) != "" {
266 filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000267 uncheckedApiFile := android.PathForModuleOut(ctx, "metalava", filename)
268 cmd.FlagWithOutput("--api ", uncheckedApiFile)
269 d.apiFile = uncheckedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700270 } else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" {
271 // If check api is disabled then make the source file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000272 d.apiFile = android.PathForModuleSrc(ctx, sourceApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700273 }
274
275 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
276 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
277 String(d.properties.Removed_api_filename) != "" {
278 filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000279 uncheckedRemovedFile := android.PathForModuleOut(ctx, "metalava", filename)
280 cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile)
281 d.removedApiFile = uncheckedRemovedFile
Colin Cross2207f872021-03-24 12:39:08 -0700282 } else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" {
283 // If check api is disabled then make the source removed api file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000284 d.removedApiFile = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700285 }
286
Colin Cross2207f872021-03-24 12:39:08 -0700287 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700288 d.metadataDir = android.PathForModuleOut(ctx, "metalava", "metadata")
Colin Cross2207f872021-03-24 12:39:08 -0700289 cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
290 }
291
292 if stubsDir.Valid() {
293 if Bool(d.properties.Create_doc_stubs) {
294 cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
295 } else {
296 cmd.FlagWithArg("--stubs ", stubsDir.String())
297 if !Bool(d.properties.Output_javadoc_comments) {
298 cmd.Flag("--exclude-documentation-from-stubs")
299 }
300 }
301 }
302}
303
304func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
305 if Bool(d.properties.Annotations_enabled) {
306 cmd.Flag("--include-annotations")
307
Andrei Onea4985e512021-04-29 16:29:34 +0100308 cmd.FlagWithArg("--exclude-annotation ", "androidx.annotation.RequiresApi")
309
Colin Cross2207f872021-03-24 12:39:08 -0700310 validatingNullability :=
Colin Crossbc139922021-03-25 18:33:16 -0700311 strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") ||
Colin Cross2207f872021-03-24 12:39:08 -0700312 String(d.properties.Validate_nullability_from_list) != ""
313
314 migratingNullability := String(d.properties.Previous_api) != ""
315 if migratingNullability {
316 previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
317 cmd.FlagWithInput("--migrate-nullness ", previousApi)
318 }
319
320 if s := String(d.properties.Validate_nullability_from_list); s != "" {
321 cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
322 }
323
324 if validatingNullability {
Colin Crosscb77f752021-03-24 12:04:44 -0700325 d.nullabilityWarningsFile = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_nullability_warnings.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700326 cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile)
327 }
328
Colin Crosscb77f752021-03-24 12:04:44 -0700329 d.annotationsZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_annotations.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700330 cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip)
331
332 if len(d.properties.Merge_annotations_dirs) != 0 {
333 d.mergeAnnoDirFlags(ctx, cmd)
334 }
335
336 // TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
337 cmd.FlagWithArg("--hide ", "HiddenTypedefConstant").
338 FlagWithArg("--hide ", "SuperfluousPrefix").
Sam Gilbert049af112022-03-04 16:03:53 -0500339 FlagWithArg("--hide ", "AnnotationExtraction").
340 // b/222738070
Sam Gilbert675f0b42022-03-08 11:24:44 -0500341 FlagWithArg("--hide ", "BannedThrow").
342 // b/223382732
343 FlagWithArg("--hide ", "ChangedDefault")
Colin Cross2207f872021-03-24 12:39:08 -0700344 }
345}
346
347func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
348 ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
349 if t, ok := m.(*ExportedDroiddocDir); ok {
350 cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps)
351 } else {
352 ctx.PropertyErrorf("merge_annotations_dirs",
353 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
354 }
355 })
356}
357
358func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
359 ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) {
360 if t, ok := m.(*ExportedDroiddocDir); ok {
361 cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps)
362 } else {
363 ctx.PropertyErrorf("merge_inclusion_annotations_dirs",
364 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
365 }
366 })
367}
368
369func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000370 var apiVersions android.Path
371 if proptools.Bool(d.properties.Api_levels_annotations_enabled) {
372 d.apiLevelsGenerationFlags(ctx, cmd)
373 apiVersions = d.apiVersionsXml
374 } else {
375 ctx.VisitDirectDepsWithTag(metalavaAPILevelsModuleTag, func(m android.Module) {
376 if s, ok := m.(*Droidstubs); ok {
377 apiVersions = s.apiVersionsXml
378 } else {
379 ctx.PropertyErrorf("api_levels_module",
380 "module %q is not a droidstubs module", ctx.OtherModuleName(m))
381 }
382 })
Colin Cross2207f872021-03-24 12:39:08 -0700383 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000384 if apiVersions != nil {
385 cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion().String())
386 cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename())
387 cmd.FlagWithInput("--apply-api-levels ", apiVersions)
388 }
389}
Colin Cross2207f872021-03-24 12:39:08 -0700390
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000391func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Colin Cross2207f872021-03-24 12:39:08 -0700392 if len(d.properties.Api_levels_annotations_dirs) == 0 {
393 ctx.PropertyErrorf("api_levels_annotations_dirs",
394 "has to be non-empty if api levels annotations was enabled!")
395 }
396
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000397 d.apiVersionsXml = android.PathForModuleOut(ctx, "metalava", "api-versions.xml")
Colin Cross2207f872021-03-24 12:39:08 -0700398 cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml)
Colin Cross2207f872021-03-24 12:39:08 -0700399
400 filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar")
401
satayev783195c2021-06-23 21:49:57 +0100402 var dirs []string
Colin Cross2207f872021-03-24 12:39:08 -0700403 ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
404 if t, ok := m.(*ExportedDroiddocDir); ok {
405 for _, dep := range t.deps {
Colin Cross5f6ffc72021-03-29 21:54:45 -0700406 if dep.Base() == filename {
407 cmd.Implicit(dep)
408 }
409 if filename != "android.jar" && dep.Base() == "android.jar" {
410 // Metalava implicitly searches these patterns:
411 // prebuilts/tools/common/api-versions/android-%/android.jar
412 // prebuilts/sdk/%/public/android.jar
413 // Add android.jar files from the api_levels_annotations_dirs directories to try
414 // to satisfy these patterns. If Metalava can't find a match for an API level
415 // between 1 and 28 in at least one pattern it will fail.
Colin Cross2207f872021-03-24 12:39:08 -0700416 cmd.Implicit(dep)
417 }
418 }
satayev783195c2021-06-23 21:49:57 +0100419
420 dirs = append(dirs, t.dir.String())
Colin Cross2207f872021-03-24 12:39:08 -0700421 } else {
422 ctx.PropertyErrorf("api_levels_annotations_dirs",
423 "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
424 }
425 })
satayev783195c2021-06-23 21:49:57 +0100426
427 // Add all relevant --android-jar-pattern patterns for Metalava.
428 // When parsing a stub jar for a specific version, Metalava picks the first pattern that defines
429 // an actual file present on disk (in the order the patterns were passed). For system APIs for
430 // privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs
Pedro Loureirocc203502021-10-04 17:24:00 +0000431 // for older releases. Similarly, module-lib falls back to system API.
432 var sdkDirs []string
433 switch proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") {
434 case "module-lib":
435 sdkDirs = []string{"module-lib", "system", "public"}
436 case "system":
437 sdkDirs = []string{"system", "public"}
438 case "public":
439 sdkDirs = []string{"public"}
440 default:
441 ctx.PropertyErrorf("api_levels_sdk_type", "needs to be one of %v", allowedApiLevelSdkTypes)
442 return
satayev783195c2021-06-23 21:49:57 +0100443 }
Pedro Loureirocc203502021-10-04 17:24:00 +0000444
445 for _, sdkDir := range sdkDirs {
446 for _, dir := range dirs {
447 cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, filename))
448 }
satayev783195c2021-06-23 21:49:57 +0100449 }
Colin Cross2207f872021-03-24 12:39:08 -0700450}
451
Colin Crosse52c2ac2022-03-28 17:03:35 -0700452func metalavaUseRbe(ctx android.ModuleContext) bool {
453 return ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA")
454}
455
Colin Cross2207f872021-03-24 12:39:08 -0700456func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
Anton Hansson556e8142021-06-04 16:20:25 +0100457 srcJarList android.Path, bootclasspath, classpath classpath, homeDir android.WritablePath) *android.RuleBuilderCommand {
Colin Cross2207f872021-03-24 12:39:08 -0700458 rule.Command().Text("rm -rf").Flag(homeDir.String())
459 rule.Command().Text("mkdir -p").Flag(homeDir.String())
460
Anton Hansson556e8142021-06-04 16:20:25 +0100461 cmd := rule.Command()
Colin Cross2207f872021-03-24 12:39:08 -0700462 cmd.FlagWithArg("ANDROID_PREFS_ROOT=", homeDir.String())
463
Colin Crosse52c2ac2022-03-28 17:03:35 -0700464 if metalavaUseRbe(ctx) {
Colin Cross2207f872021-03-24 12:39:08 -0700465 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
Colin Cross8095c292021-03-30 16:40:48 -0700466 execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
467 labels := map[string]string{"type": "tool", "name": "metalava"}
468 // TODO: metalava pool rejects these jobs
469 pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
470 rule.Rewrapper(&remoteexec.REParams{
471 Labels: labels,
472 ExecStrategy: execStrategy,
473 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
474 Platform: map[string]string{remoteexec.PoolKey: pool},
475 })
Colin Cross2207f872021-03-24 12:39:08 -0700476 }
477
Colin Cross6aa5c402021-03-24 12:28:50 -0700478 cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
Colin Cross2207f872021-03-24 12:39:08 -0700479 Flag(config.JavacVmFlags).
480 Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED").
481 FlagWithArg("-encoding ", "UTF-8").
482 FlagWithArg("-source ", javaVersion.String()).
483 FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs).
484 FlagWithInput("@", srcJarList)
485
Colin Cross2207f872021-03-24 12:39:08 -0700486 if len(bootclasspath) > 0 {
487 cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":")
488 }
489
490 if len(classpath) > 0 {
491 cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
492 }
493
Colin Cross2207f872021-03-24 12:39:08 -0700494 cmd.Flag("--no-banner").
495 Flag("--color").
496 Flag("--quiet").
497 Flag("--format=v2").
498 FlagWithArg("--repeat-errors-max ", "10").
Sam Gilbert09cb5db2021-10-06 11:28:28 -0400499 FlagWithArg("--hide ", "UnresolvedImport").
Ember Rose7c57af32022-04-01 10:34:44 -0400500 FlagWithArg("--hide ", "InvalidNullabilityOverride").
Sam Gilbert28e41282022-03-09 15:24:48 +0000501 // b/223382732
502 FlagWithArg("--hide ", "ChangedDefault")
Colin Cross2207f872021-03-24 12:39:08 -0700503
504 return cmd
505}
506
507func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
508 deps := d.Javadoc.collectDeps(ctx)
509
Jiyong Parkf1691d22021-03-29 20:11:58 +0900510 javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d))
Colin Cross2207f872021-03-24 12:39:08 -0700511
512 // Create rule for metalava
513
Colin Crosscb77f752021-03-24 12:04:44 -0700514 srcJarDir := android.PathForModuleOut(ctx, "metalava", "srcjars")
Colin Cross2207f872021-03-24 12:39:08 -0700515
516 rule := android.NewRuleBuilder(pctx, ctx)
517
Colin Cross8095c292021-03-30 16:40:48 -0700518 rule.Sbox(android.PathForModuleOut(ctx, "metalava"),
519 android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
520 SandboxInputs()
Colin Cross6aa5c402021-03-24 12:28:50 -0700521
Colin Cross2207f872021-03-24 12:39:08 -0700522 if BoolDefault(d.properties.High_mem, false) {
523 // This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel.
524 rule.HighMem()
525 }
526
527 generateStubs := BoolDefault(d.properties.Generate_stubs, true)
528 var stubsDir android.OptionalPath
529 if generateStubs {
Colin Crosscb77f752021-03-24 12:04:44 -0700530 d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
531 stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "metalava", "stubsDir"))
Colin Cross2207f872021-03-24 12:39:08 -0700532 rule.Command().Text("rm -rf").Text(stubsDir.String())
533 rule.Command().Text("mkdir -p").Text(stubsDir.String())
534 }
535
536 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
537
Colin Crosscb77f752021-03-24 12:04:44 -0700538 homeDir := android.PathForModuleOut(ctx, "metalava", "home")
Colin Cross2207f872021-03-24 12:39:08 -0700539 cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
Anton Hansson556e8142021-06-04 16:20:25 +0100540 deps.bootClasspath, deps.classpath, homeDir)
Colin Cross2207f872021-03-24 12:39:08 -0700541 cmd.Implicits(d.Javadoc.implicits)
542
543 d.stubsFlags(ctx, cmd, stubsDir)
544
545 d.annotationsFlags(ctx, cmd)
546 d.inclusionAnnotationsFlags(ctx, cmd)
547 d.apiLevelsAnnotationsFlags(ctx, cmd)
548
Colin Crossbc139922021-03-25 18:33:16 -0700549 d.expandArgs(ctx, cmd)
Colin Cross2207f872021-03-24 12:39:08 -0700550
Colin Cross2207f872021-03-24 12:39:08 -0700551 for _, o := range d.Javadoc.properties.Out {
552 cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
553 }
554
555 // Add options for the other optional tasks: API-lint and check-released.
556 // We generate separate timestamp files for them.
557
558 doApiLint := false
559 doCheckReleased := false
560
561 // Add API lint options.
562
563 if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) {
564 doApiLint = true
565
566 newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since)
567 if newSince.Valid() {
568 cmd.FlagWithInput("--api-lint ", newSince.Path())
569 } else {
570 cmd.Flag("--api-lint")
571 }
Colin Crosscb77f752021-03-24 12:04:44 -0700572 d.apiLintReport = android.PathForModuleOut(ctx, "metalava", "api_lint_report.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700573 cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO: Change to ":api-lint"
574
Colin Cross0d532412021-03-25 09:38:45 -0700575 // TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released.
Colin Cross2207f872021-03-24 12:39:08 -0700576 if d.Name() != "android.car-system-stubs-docs" &&
577 d.Name() != "android.car-stubs-docs" {
578 cmd.Flag("--lints-as-errors")
579 cmd.Flag("--warnings-as-errors") // Most lints are actually warnings.
580 }
581
582 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700583 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "api_lint_baseline.txt")
584 d.apiLintTimestamp = android.PathForModuleOut(ctx, "metalava", "api_lint.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700585
586 // Note this string includes a special shell quote $' ... ', which decodes the "\n"s.
Colin Cross2207f872021-03-24 12:39:08 -0700587 //
588 // TODO: metalava also has a slightly different message hardcoded. Should we unify this
589 // message and metalava's one?
590 msg := `$'` + // Enclose with $' ... '
591 `************************************************************\n` +
592 `Your API changes are triggering API Lint warnings or errors.\n` +
593 `To make these errors go away, fix the code according to the\n` +
594 `error and/or warning messages above.\n` +
595 `\n` +
596 `If it is not possible to do so, there are workarounds:\n` +
597 `\n` +
Aurimas Liutikasb23b7452021-05-24 18:00:37 +0000598 `1. You can suppress the errors with @SuppressLint("<id>")\n` +
599 ` where the <id> is given in brackets in the error message above.\n`
Colin Cross2207f872021-03-24 12:39:08 -0700600
601 if baselineFile.Valid() {
602 cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path())
603 cmd.FlagWithOutput("--update-baseline:api-lint ", updatedBaselineOutput)
604
605 msg += fmt.Sprintf(``+
606 `2. You can update the baseline by executing the following\n`+
607 ` command:\n`+
Colin Cross63eeda02021-04-15 19:01:57 -0700608 ` (cd $ANDROID_BUILD_TOP && cp \\\n`+
609 ` "%s" \\\n`+
610 ` "%s")\n`+
Colin Cross2207f872021-03-24 12:39:08 -0700611 ` To submit the revised baseline.txt to the main Android\n`+
612 ` repository, you will need approval.\n`, updatedBaselineOutput, baselineFile.Path())
613 } else {
614 msg += fmt.Sprintf(``+
615 `2. You can add a baseline file of existing lint failures\n`+
616 ` to the build rule of %s.\n`, d.Name())
617 }
618 // Note the message ends with a ' (single quote), to close the $' ... ' .
619 msg += `************************************************************\n'`
620
621 cmd.FlagWithArg("--error-message:api-lint ", msg)
622 }
623
624 // Add "check released" options. (Detect incompatible API changes from the last public release)
625
626 if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") {
627 doCheckReleased = true
628
629 if len(d.Javadoc.properties.Out) > 0 {
630 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
631 }
632
633 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
634 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
635 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700636 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "last_released_baseline.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700637
Colin Crosscb77f752021-03-24 12:04:44 -0700638 d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_last_released_api.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700639
640 cmd.FlagWithInput("--check-compatibility:api:released ", apiFile)
641 cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile)
642
643 if baselineFile.Valid() {
644 cmd.FlagWithInput("--baseline:compatibility:released ", baselineFile.Path())
645 cmd.FlagWithOutput("--update-baseline:compatibility:released ", updatedBaselineOutput)
646 }
647
648 // Note this string includes quote ($' ... '), which decodes the "\n"s.
649 msg := `$'\n******************************\n` +
650 `You have tried to change the API from what has been previously released in\n` +
651 `an SDK. Please fix the errors listed above.\n` +
652 `******************************\n'`
653
654 cmd.FlagWithArg("--error-message:compatibility:released ", msg)
655 }
656
Colin Cross2207f872021-03-24 12:39:08 -0700657 if generateStubs {
658 rule.Command().
659 BuiltTool("soong_zip").
660 Flag("-write_if_changed").
661 Flag("-jar").
662 FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
663 FlagWithArg("-C ", stubsDir.String()).
664 FlagWithArg("-D ", stubsDir.String())
665 }
666
667 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700668 d.metadataZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-metadata.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700669 rule.Command().
670 BuiltTool("soong_zip").
671 Flag("-write_if_changed").
672 Flag("-d").
673 FlagWithOutput("-o ", d.metadataZip).
674 FlagWithArg("-C ", d.metadataDir.String()).
675 FlagWithArg("-D ", d.metadataDir.String())
676 }
677
678 // TODO: We don't really need two separate API files, but this is a reminiscence of how
679 // we used to run metalava separately for API lint and the "last_released" check. Unify them.
680 if doApiLint {
681 rule.Command().Text("touch").Output(d.apiLintTimestamp)
682 }
683 if doCheckReleased {
684 rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp)
685 }
686
Colin Cross6aa5c402021-03-24 12:28:50 -0700687 // TODO(b/183630617): rewrapper doesn't support restat rules
Colin Crosse52c2ac2022-03-28 17:03:35 -0700688 if !metalavaUseRbe(ctx) {
689 rule.Restat()
690 }
Colin Cross2207f872021-03-24 12:39:08 -0700691
692 zipSyncCleanupCmd(rule, srcJarDir)
693
Paul Duffinc166b682022-05-27 12:23:08 +0000694 rule.Build("metalava", "metalava merged")
695
Paul Duffine7a86642022-08-16 15:43:20 +0000696 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
697
698 if len(d.Javadoc.properties.Out) > 0 {
699 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
700 }
701
702 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
703 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
704 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)
705
706 if baselineFile.Valid() {
707 ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
708 }
709
710 d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp")
711
712 rule := android.NewRuleBuilder(pctx, ctx)
713
714 // Diff command line.
715 // -F matches the closest "opening" line, such as "package android {"
716 // and " public class Intent {".
717 diff := `diff -u -F '{ *$'`
718
719 rule.Command().Text("( true")
720 rule.Command().
721 Text(diff).
722 Input(apiFile).Input(d.apiFile)
723
724 rule.Command().
725 Text(diff).
726 Input(removedApiFile).Input(d.removedApiFile)
727
728 msg := fmt.Sprintf(`\n******************************\n`+
729 `You have tried to change the API from what has been previously approved.\n\n`+
730 `To make these errors go away, you have two choices:\n`+
731 ` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
732 ` to the new methods, etc. shown in the above diff.\n\n`+
733 ` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+
734 ` m %s-update-current-api\n\n`+
735 ` To submit the revised current.txt to the main Android repository,\n`+
736 ` you will need approval.\n`+
737 `******************************\n`, ctx.ModuleName())
738
739 rule.Command().
740 Text("touch").Output(d.checkCurrentApiTimestamp).
741 Text(") || (").
742 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
743 Text("; exit 38").
744 Text(")")
745
746 rule.Build("metalavaCurrentApiCheck", "check current API")
747
748 d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "update_current_api.timestamp")
749
750 // update API rule
751 rule = android.NewRuleBuilder(pctx, ctx)
752
753 rule.Command().Text("( true")
754
755 rule.Command().
756 Text("cp").Flag("-f").
757 Input(d.apiFile).Flag(apiFile.String())
758
759 rule.Command().
760 Text("cp").Flag("-f").
761 Input(d.removedApiFile).Flag(removedApiFile.String())
762
763 msg = "failed to update public API"
764
765 rule.Command().
766 Text("touch").Output(d.updateCurrentApiTimestamp).
767 Text(") || (").
768 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
769 Text("; exit 38").
770 Text(")")
771
772 rule.Build("metalavaCurrentApiUpdate", "update current API")
773 }
774
Colin Cross2207f872021-03-24 12:39:08 -0700775 if String(d.properties.Check_nullability_warnings) != "" {
776 if d.nullabilityWarningsFile == nil {
777 ctx.PropertyErrorf("check_nullability_warnings",
778 "Cannot specify check_nullability_warnings unless validating nullability")
779 }
780
781 checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings))
782
Colin Crosscb77f752021-03-24 12:04:44 -0700783 d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "metalava", "check_nullability_warnings.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700784
785 msg := fmt.Sprintf(`\n******************************\n`+
786 `The warnings encountered during nullability annotation validation did\n`+
787 `not match the checked in file of expected warnings. The diffs are shown\n`+
788 `above. You have two options:\n`+
789 ` 1. Resolve the differences by editing the nullability annotations.\n`+
790 ` 2. Update the file of expected warnings by running:\n`+
791 ` cp %s %s\n`+
792 ` and submitting the updated file as part of your change.`,
793 d.nullabilityWarningsFile, checkNullabilityWarnings)
794
795 rule := android.NewRuleBuilder(pctx, ctx)
796
797 rule.Command().
798 Text("(").
799 Text("diff").Input(checkNullabilityWarnings).Input(d.nullabilityWarningsFile).
800 Text("&&").
801 Text("touch").Output(d.checkNullabilityWarningsTimestamp).
802 Text(") || (").
803 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
804 Text("; exit 38").
805 Text(")")
806
807 rule.Build("nullabilityWarningsCheck", "nullability warnings check")
808 }
809}
810
811func StubsDefaultsFactory() android.Module {
812 module := &DocDefaults{}
813
814 module.AddProperties(
815 &JavadocProperties{},
816 &DroidstubsProperties{},
817 )
818
819 android.InitDefaultsModule(module)
820
821 return module
822}
823
824var _ android.PrebuiltInterface = (*PrebuiltStubsSources)(nil)
825
826type PrebuiltStubsSourcesProperties struct {
827 Srcs []string `android:"path"`
828}
829
830type PrebuiltStubsSources struct {
831 android.ModuleBase
832 android.DefaultableModuleBase
833 prebuilt android.Prebuilt
834 android.SdkBase
835
836 properties PrebuiltStubsSourcesProperties
837
kgui67007242022-01-25 13:50:25 +0800838 stubsSrcJar android.Path
Colin Cross2207f872021-03-24 12:39:08 -0700839}
840
841func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
842 switch tag {
843 case "":
844 return android.Paths{p.stubsSrcJar}, nil
845 default:
846 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
847 }
848}
849
850func (d *PrebuiltStubsSources) StubsSrcJar() android.Path {
851 return d.stubsSrcJar
852}
853
854func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Cross2207f872021-03-24 12:39:08 -0700855 if len(p.properties.Srcs) != 1 {
Anton Hansson86758ac2021-11-03 14:44:12 +0000856 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 -0700857 return
858 }
859
Anton Hansson86758ac2021-11-03 14:44:12 +0000860 src := p.properties.Srcs[0]
861 if filepath.Ext(src) == ".srcjar" {
862 // This is a srcjar. We can use it directly.
863 p.stubsSrcJar = android.PathForModuleSrc(ctx, src)
864 } else {
865 outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
Colin Cross2207f872021-03-24 12:39:08 -0700866
Anton Hansson86758ac2021-11-03 14:44:12 +0000867 // This is a directory. Glob the contents just in case the directory does not exist.
868 srcGlob := src + "/**/*"
869 srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
Colin Cross2207f872021-03-24 12:39:08 -0700870
Anton Hansson86758ac2021-11-03 14:44:12 +0000871 // Although PathForModuleSrc can return nil if either the path doesn't exist or
872 // the path components are invalid it won't in this case because no components
873 // are specified and the module directory must exist in order to get this far.
874 srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, src)
Colin Cross2207f872021-03-24 12:39:08 -0700875
Anton Hansson86758ac2021-11-03 14:44:12 +0000876 rule := android.NewRuleBuilder(pctx, ctx)
877 rule.Command().
878 BuiltTool("soong_zip").
879 Flag("-write_if_changed").
880 Flag("-jar").
881 FlagWithOutput("-o ", outPath).
882 FlagWithArg("-C ", srcDir.String()).
883 FlagWithRspFileInputList("-r ", outPath.ReplaceExtension(ctx, "rsp"), srcPaths)
884 rule.Restat()
885 rule.Build("zip src", "Create srcjar from prebuilt source")
886 p.stubsSrcJar = outPath
887 }
Colin Cross2207f872021-03-24 12:39:08 -0700888}
889
890func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
891 return &p.prebuilt
892}
893
894func (p *PrebuiltStubsSources) Name() string {
895 return p.prebuilt.Name(p.ModuleBase.Name())
896}
897
898// prebuilt_stubs_sources imports a set of java source files as if they were
899// generated by droidstubs.
900//
901// By default, a prebuilt_stubs_sources has a single variant that expects a
902// set of `.java` files generated by droidstubs.
903//
904// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one
905// for host modules.
906//
907// Intended only for use by sdk snapshots.
908func PrebuiltStubsSourcesFactory() android.Module {
909 module := &PrebuiltStubsSources{}
910
911 module.AddProperties(&module.properties)
912
913 android.InitPrebuiltModule(module, &module.properties.Srcs)
914 android.InitSdkAwareModule(module)
915 InitDroiddocModule(module, android.HostAndDeviceSupported)
916 return module
917}