blob: 4bbe70ac4bc7e4aacac2ed9e5a0cada7a59a9758 [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"
Mårten Kongstad802ae0f2022-07-27 13:47:32 +020020 "regexp"
Spandan Das0b555e32022-11-28 18:48:51 +000021 "sort"
Colin Cross2207f872021-03-24 12:39:08 -070022 "strings"
23
24 "github.com/google/blueprint/proptools"
25
26 "android/soong/android"
Spandan Das0b555e32022-11-28 18:48:51 +000027 "android/soong/bazel"
Colin Cross2207f872021-03-24 12:39:08 -070028 "android/soong/java/config"
29 "android/soong/remoteexec"
30)
31
Pedro Loureirocc203502021-10-04 17:24:00 +000032// The values allowed for Droidstubs' Api_levels_sdk_type
Cole Faust051fa912022-10-05 12:45:42 -070033var allowedApiLevelSdkTypes = []string{"public", "system", "module-lib", "system-server"}
Pedro Loureirocc203502021-10-04 17:24:00 +000034
Colin Cross2207f872021-03-24 12:39:08 -070035func init() {
36 RegisterStubsBuildComponents(android.InitRegistrationContext)
37}
38
39func RegisterStubsBuildComponents(ctx android.RegistrationContext) {
40 ctx.RegisterModuleType("stubs_defaults", StubsDefaultsFactory)
41
42 ctx.RegisterModuleType("droidstubs", DroidstubsFactory)
43 ctx.RegisterModuleType("droidstubs_host", DroidstubsHostFactory)
44
45 ctx.RegisterModuleType("prebuilt_stubs_sources", PrebuiltStubsSourcesFactory)
46}
47
Colin Cross2207f872021-03-24 12:39:08 -070048// Droidstubs
Colin Cross2207f872021-03-24 12:39:08 -070049type Droidstubs struct {
50 Javadoc
Colin Cross2207f872021-03-24 12:39:08 -070051
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
Cole Faust051fa912022-10-05 12:45:42 -0700138 // the sdk kind which Metalava extracts API levels annotations from. Supports 'public', 'system', 'module-lib' and 'system-server'; 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
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200147
148 // path or filegroup to file defining extension an SDK name <-> numerical ID mapping and
149 // what APIs exist in which SDKs; passed to metalava via --sdk-extensions-info
150 Extensions_info_file *string `android:"path"`
Colin Cross2207f872021-03-24 12:39:08 -0700151}
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)
Colin Cross2207f872021-03-24 12:39:08 -0700181 return module
182}
183
184// droidstubs_host passes sources files through Metalava to generate stub .java files that only contain the API
185// to be documented, filtering out hidden classes and methods. The resulting .java files are intended to be
186// passed to a droiddoc_host module to generate documentation. Use a droidstubs_host instead of a droidstubs
187// module when symbols needed by the source files are provided by java_library_host modules.
188func DroidstubsHostFactory() android.Module {
189 module := &Droidstubs{}
190
191 module.AddProperties(&module.properties,
192 &module.Javadoc.properties)
193
194 InitDroiddocModule(module, android.HostSupported)
195 return module
196}
197
198func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) {
199 switch tag {
200 case "":
201 return android.Paths{d.stubsSrcJar}, nil
202 case ".docs.zip":
203 return android.Paths{d.docZip}, nil
204 case ".api.txt", android.DefaultDistTag:
205 // This is the default dist path for dist properties that have no tag property.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000206 return android.Paths{d.apiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700207 case ".removed-api.txt":
Paul Duffinc71d2b72022-08-16 15:24:01 +0000208 return android.Paths{d.removedApiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700209 case ".annotations.zip":
210 return android.Paths{d.annotationsZip}, nil
211 case ".api_versions.xml":
212 return android.Paths{d.apiVersionsXml}, nil
213 default:
214 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
215 }
216}
217
Anton Hanssond78eb762021-09-21 15:25:12 +0100218func (d *Droidstubs) AnnotationsZip() android.Path {
219 return d.annotationsZip
220}
221
Colin Cross2207f872021-03-24 12:39:08 -0700222func (d *Droidstubs) ApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000223 return d.apiFile
Colin Cross2207f872021-03-24 12:39:08 -0700224}
225
226func (d *Droidstubs) RemovedApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000227 return d.removedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700228}
229
230func (d *Droidstubs) StubsSrcJar() android.Path {
231 return d.stubsSrcJar
232}
233
234var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"}
235var metalavaMergeInclusionAnnotationsDirTag = dependencyTag{name: "metalava-merge-inclusion-annotations-dir"}
236var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"}
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000237var metalavaAPILevelsModuleTag = dependencyTag{name: "metalava-api-levels-module-tag"}
Colin Cross2207f872021-03-24 12:39:08 -0700238
239func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) {
240 d.Javadoc.addDeps(ctx)
241
242 if len(d.properties.Merge_annotations_dirs) != 0 {
243 for _, mergeAnnotationsDir := range d.properties.Merge_annotations_dirs {
244 ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir)
245 }
246 }
247
248 if len(d.properties.Merge_inclusion_annotations_dirs) != 0 {
249 for _, mergeInclusionAnnotationsDir := range d.properties.Merge_inclusion_annotations_dirs {
250 ctx.AddDependency(ctx.Module(), metalavaMergeInclusionAnnotationsDirTag, mergeInclusionAnnotationsDir)
251 }
252 }
253
254 if len(d.properties.Api_levels_annotations_dirs) != 0 {
255 for _, apiLevelsAnnotationsDir := range d.properties.Api_levels_annotations_dirs {
256 ctx.AddDependency(ctx.Module(), metalavaAPILevelsAnnotationsDirTag, apiLevelsAnnotationsDir)
257 }
258 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000259
260 if d.properties.Api_levels_module != nil {
261 ctx.AddDependency(ctx.Module(), metalavaAPILevelsModuleTag, proptools.String(d.properties.Api_levels_module))
262 }
Colin Cross2207f872021-03-24 12:39:08 -0700263}
264
265func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) {
266 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
267 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
268 String(d.properties.Api_filename) != "" {
269 filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000270 uncheckedApiFile := android.PathForModuleOut(ctx, "metalava", filename)
271 cmd.FlagWithOutput("--api ", uncheckedApiFile)
272 d.apiFile = uncheckedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700273 } else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" {
274 // If check api is disabled then make the source file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000275 d.apiFile = android.PathForModuleSrc(ctx, sourceApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700276 }
277
278 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
279 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
280 String(d.properties.Removed_api_filename) != "" {
281 filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000282 uncheckedRemovedFile := android.PathForModuleOut(ctx, "metalava", filename)
283 cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile)
284 d.removedApiFile = uncheckedRemovedFile
Colin Cross2207f872021-03-24 12:39:08 -0700285 } else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" {
286 // If check api is disabled then make the source removed api file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000287 d.removedApiFile = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700288 }
289
Colin Cross2207f872021-03-24 12:39:08 -0700290 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700291 d.metadataDir = android.PathForModuleOut(ctx, "metalava", "metadata")
Colin Cross2207f872021-03-24 12:39:08 -0700292 cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
293 }
294
295 if stubsDir.Valid() {
296 if Bool(d.properties.Create_doc_stubs) {
297 cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
298 } else {
299 cmd.FlagWithArg("--stubs ", stubsDir.String())
300 if !Bool(d.properties.Output_javadoc_comments) {
301 cmd.Flag("--exclude-documentation-from-stubs")
302 }
303 }
304 }
305}
306
307func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
308 if Bool(d.properties.Annotations_enabled) {
309 cmd.Flag("--include-annotations")
310
Andrei Onea4985e512021-04-29 16:29:34 +0100311 cmd.FlagWithArg("--exclude-annotation ", "androidx.annotation.RequiresApi")
312
Colin Cross2207f872021-03-24 12:39:08 -0700313 validatingNullability :=
Colin Crossbc139922021-03-25 18:33:16 -0700314 strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") ||
Colin Cross2207f872021-03-24 12:39:08 -0700315 String(d.properties.Validate_nullability_from_list) != ""
316
317 migratingNullability := String(d.properties.Previous_api) != ""
318 if migratingNullability {
319 previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
320 cmd.FlagWithInput("--migrate-nullness ", previousApi)
321 }
322
323 if s := String(d.properties.Validate_nullability_from_list); s != "" {
324 cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
325 }
326
327 if validatingNullability {
Colin Crosscb77f752021-03-24 12:04:44 -0700328 d.nullabilityWarningsFile = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_nullability_warnings.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700329 cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile)
330 }
331
Colin Crosscb77f752021-03-24 12:04:44 -0700332 d.annotationsZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_annotations.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700333 cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip)
334
335 if len(d.properties.Merge_annotations_dirs) != 0 {
336 d.mergeAnnoDirFlags(ctx, cmd)
337 }
338
339 // TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
340 cmd.FlagWithArg("--hide ", "HiddenTypedefConstant").
341 FlagWithArg("--hide ", "SuperfluousPrefix").
Sam Gilbert049af112022-03-04 16:03:53 -0500342 FlagWithArg("--hide ", "AnnotationExtraction").
343 // b/222738070
Sam Gilbert675f0b42022-03-08 11:24:44 -0500344 FlagWithArg("--hide ", "BannedThrow").
345 // b/223382732
346 FlagWithArg("--hide ", "ChangedDefault")
Colin Cross2207f872021-03-24 12:39:08 -0700347 }
348}
349
350func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
351 ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
352 if t, ok := m.(*ExportedDroiddocDir); ok {
353 cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps)
354 } else {
355 ctx.PropertyErrorf("merge_annotations_dirs",
356 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
357 }
358 })
359}
360
361func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
362 ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) {
363 if t, ok := m.(*ExportedDroiddocDir); ok {
364 cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps)
365 } else {
366 ctx.PropertyErrorf("merge_inclusion_annotations_dirs",
367 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
368 }
369 })
370}
371
372func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000373 var apiVersions android.Path
374 if proptools.Bool(d.properties.Api_levels_annotations_enabled) {
375 d.apiLevelsGenerationFlags(ctx, cmd)
376 apiVersions = d.apiVersionsXml
377 } else {
378 ctx.VisitDirectDepsWithTag(metalavaAPILevelsModuleTag, func(m android.Module) {
379 if s, ok := m.(*Droidstubs); ok {
380 apiVersions = s.apiVersionsXml
381 } else {
382 ctx.PropertyErrorf("api_levels_module",
383 "module %q is not a droidstubs module", ctx.OtherModuleName(m))
384 }
385 })
Colin Cross2207f872021-03-24 12:39:08 -0700386 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000387 if apiVersions != nil {
388 cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion().String())
389 cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename())
390 cmd.FlagWithInput("--apply-api-levels ", apiVersions)
391 }
392}
Colin Cross2207f872021-03-24 12:39:08 -0700393
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000394func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Colin Cross2207f872021-03-24 12:39:08 -0700395 if len(d.properties.Api_levels_annotations_dirs) == 0 {
396 ctx.PropertyErrorf("api_levels_annotations_dirs",
397 "has to be non-empty if api levels annotations was enabled!")
398 }
399
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000400 d.apiVersionsXml = android.PathForModuleOut(ctx, "metalava", "api-versions.xml")
Colin Cross2207f872021-03-24 12:39:08 -0700401 cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml)
Colin Cross2207f872021-03-24 12:39:08 -0700402
403 filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar")
404
satayev783195c2021-06-23 21:49:57 +0100405 var dirs []string
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200406 var extensions_dir string
Colin Cross2207f872021-03-24 12:39:08 -0700407 ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
408 if t, ok := m.(*ExportedDroiddocDir); ok {
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200409 extRegex := regexp.MustCompile(t.dir.String() + `/extensions/[0-9]+/public/.*\.jar`)
410
411 // Grab the first extensions_dir and we find while scanning ExportedDroiddocDir.deps;
412 // ideally this should be read from prebuiltApis.properties.Extensions_*
Colin Cross2207f872021-03-24 12:39:08 -0700413 for _, dep := range t.deps {
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200414 if extRegex.MatchString(dep.String()) && d.properties.Extensions_info_file != nil {
415 if extensions_dir == "" {
416 extensions_dir = t.dir.String() + "/extensions"
417 }
418 cmd.Implicit(dep)
419 }
Colin Cross5f6ffc72021-03-29 21:54:45 -0700420 if dep.Base() == filename {
421 cmd.Implicit(dep)
422 }
423 if filename != "android.jar" && dep.Base() == "android.jar" {
424 // Metalava implicitly searches these patterns:
425 // prebuilts/tools/common/api-versions/android-%/android.jar
426 // prebuilts/sdk/%/public/android.jar
427 // Add android.jar files from the api_levels_annotations_dirs directories to try
428 // to satisfy these patterns. If Metalava can't find a match for an API level
429 // between 1 and 28 in at least one pattern it will fail.
Colin Cross2207f872021-03-24 12:39:08 -0700430 cmd.Implicit(dep)
431 }
432 }
satayev783195c2021-06-23 21:49:57 +0100433
434 dirs = append(dirs, t.dir.String())
Colin Cross2207f872021-03-24 12:39:08 -0700435 } else {
436 ctx.PropertyErrorf("api_levels_annotations_dirs",
437 "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
438 }
439 })
satayev783195c2021-06-23 21:49:57 +0100440
441 // Add all relevant --android-jar-pattern patterns for Metalava.
442 // When parsing a stub jar for a specific version, Metalava picks the first pattern that defines
443 // an actual file present on disk (in the order the patterns were passed). For system APIs for
444 // privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs
Pedro Loureirocc203502021-10-04 17:24:00 +0000445 // for older releases. Similarly, module-lib falls back to system API.
446 var sdkDirs []string
447 switch proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") {
Cole Faust051fa912022-10-05 12:45:42 -0700448 case "system-server":
449 sdkDirs = []string{"system-server", "module-lib", "system", "public"}
Pedro Loureirocc203502021-10-04 17:24:00 +0000450 case "module-lib":
451 sdkDirs = []string{"module-lib", "system", "public"}
452 case "system":
453 sdkDirs = []string{"system", "public"}
454 case "public":
455 sdkDirs = []string{"public"}
456 default:
457 ctx.PropertyErrorf("api_levels_sdk_type", "needs to be one of %v", allowedApiLevelSdkTypes)
458 return
satayev783195c2021-06-23 21:49:57 +0100459 }
Pedro Loureirocc203502021-10-04 17:24:00 +0000460
461 for _, sdkDir := range sdkDirs {
462 for _, dir := range dirs {
463 cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, filename))
464 }
satayev783195c2021-06-23 21:49:57 +0100465 }
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200466
467 if d.properties.Extensions_info_file != nil {
468 if extensions_dir == "" {
469 ctx.ModuleErrorf("extensions_info_file set, but no SDK extension dirs found")
470 }
471 info_file := android.PathForModuleSrc(ctx, *d.properties.Extensions_info_file)
472 cmd.Implicit(info_file)
473 cmd.FlagWithArg("--sdk-extensions-root ", extensions_dir)
474 cmd.FlagWithArg("--sdk-extensions-info ", info_file.String())
475 }
Colin Cross2207f872021-03-24 12:39:08 -0700476}
477
Colin Crosse52c2ac2022-03-28 17:03:35 -0700478func metalavaUseRbe(ctx android.ModuleContext) bool {
479 return ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA")
480}
481
Colin Cross2207f872021-03-24 12:39:08 -0700482func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
Anton Hansson556e8142021-06-04 16:20:25 +0100483 srcJarList android.Path, bootclasspath, classpath classpath, homeDir android.WritablePath) *android.RuleBuilderCommand {
Colin Cross2207f872021-03-24 12:39:08 -0700484 rule.Command().Text("rm -rf").Flag(homeDir.String())
485 rule.Command().Text("mkdir -p").Flag(homeDir.String())
486
Anton Hansson556e8142021-06-04 16:20:25 +0100487 cmd := rule.Command()
Colin Cross2207f872021-03-24 12:39:08 -0700488 cmd.FlagWithArg("ANDROID_PREFS_ROOT=", homeDir.String())
489
Colin Crosse52c2ac2022-03-28 17:03:35 -0700490 if metalavaUseRbe(ctx) {
Colin Cross2207f872021-03-24 12:39:08 -0700491 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
Colin Cross8095c292021-03-30 16:40:48 -0700492 execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
493 labels := map[string]string{"type": "tool", "name": "metalava"}
494 // TODO: metalava pool rejects these jobs
495 pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
496 rule.Rewrapper(&remoteexec.REParams{
497 Labels: labels,
498 ExecStrategy: execStrategy,
499 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
500 Platform: map[string]string{remoteexec.PoolKey: pool},
501 })
Colin Cross2207f872021-03-24 12:39:08 -0700502 }
503
Colin Cross6aa5c402021-03-24 12:28:50 -0700504 cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
Colin Cross2207f872021-03-24 12:39:08 -0700505 Flag(config.JavacVmFlags).
506 Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED").
507 FlagWithArg("-encoding ", "UTF-8").
508 FlagWithArg("-source ", javaVersion.String()).
509 FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs).
510 FlagWithInput("@", srcJarList)
511
Colin Cross2207f872021-03-24 12:39:08 -0700512 if len(bootclasspath) > 0 {
513 cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":")
514 }
515
516 if len(classpath) > 0 {
517 cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
518 }
519
Colin Cross2207f872021-03-24 12:39:08 -0700520 cmd.Flag("--no-banner").
521 Flag("--color").
522 Flag("--quiet").
523 Flag("--format=v2").
524 FlagWithArg("--repeat-errors-max ", "10").
Sam Gilbert09cb5db2021-10-06 11:28:28 -0400525 FlagWithArg("--hide ", "UnresolvedImport").
Ember Rose7c57af32022-04-01 10:34:44 -0400526 FlagWithArg("--hide ", "InvalidNullabilityOverride").
Sam Gilbert28e41282022-03-09 15:24:48 +0000527 // b/223382732
528 FlagWithArg("--hide ", "ChangedDefault")
Colin Cross2207f872021-03-24 12:39:08 -0700529
530 return cmd
531}
532
533func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
534 deps := d.Javadoc.collectDeps(ctx)
535
Jiyong Parkf1691d22021-03-29 20:11:58 +0900536 javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d))
Colin Cross2207f872021-03-24 12:39:08 -0700537
538 // Create rule for metalava
539
Colin Crosscb77f752021-03-24 12:04:44 -0700540 srcJarDir := android.PathForModuleOut(ctx, "metalava", "srcjars")
Colin Cross2207f872021-03-24 12:39:08 -0700541
542 rule := android.NewRuleBuilder(pctx, ctx)
543
Colin Cross8095c292021-03-30 16:40:48 -0700544 rule.Sbox(android.PathForModuleOut(ctx, "metalava"),
545 android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
546 SandboxInputs()
Colin Cross6aa5c402021-03-24 12:28:50 -0700547
Colin Cross2207f872021-03-24 12:39:08 -0700548 if BoolDefault(d.properties.High_mem, false) {
549 // This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel.
550 rule.HighMem()
551 }
552
553 generateStubs := BoolDefault(d.properties.Generate_stubs, true)
554 var stubsDir android.OptionalPath
555 if generateStubs {
Colin Crosscb77f752021-03-24 12:04:44 -0700556 d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
557 stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "metalava", "stubsDir"))
Colin Cross2207f872021-03-24 12:39:08 -0700558 rule.Command().Text("rm -rf").Text(stubsDir.String())
559 rule.Command().Text("mkdir -p").Text(stubsDir.String())
560 }
561
562 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
563
Colin Crosscb77f752021-03-24 12:04:44 -0700564 homeDir := android.PathForModuleOut(ctx, "metalava", "home")
Colin Cross2207f872021-03-24 12:39:08 -0700565 cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
Anton Hansson556e8142021-06-04 16:20:25 +0100566 deps.bootClasspath, deps.classpath, homeDir)
Colin Cross2207f872021-03-24 12:39:08 -0700567 cmd.Implicits(d.Javadoc.implicits)
568
569 d.stubsFlags(ctx, cmd, stubsDir)
570
571 d.annotationsFlags(ctx, cmd)
572 d.inclusionAnnotationsFlags(ctx, cmd)
573 d.apiLevelsAnnotationsFlags(ctx, cmd)
574
Colin Crossbc139922021-03-25 18:33:16 -0700575 d.expandArgs(ctx, cmd)
Colin Cross2207f872021-03-24 12:39:08 -0700576
Colin Cross2207f872021-03-24 12:39:08 -0700577 for _, o := range d.Javadoc.properties.Out {
578 cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
579 }
580
581 // Add options for the other optional tasks: API-lint and check-released.
582 // We generate separate timestamp files for them.
583
584 doApiLint := false
585 doCheckReleased := false
586
587 // Add API lint options.
588
589 if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) {
590 doApiLint = true
591
592 newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since)
593 if newSince.Valid() {
594 cmd.FlagWithInput("--api-lint ", newSince.Path())
595 } else {
596 cmd.Flag("--api-lint")
597 }
Colin Crosscb77f752021-03-24 12:04:44 -0700598 d.apiLintReport = android.PathForModuleOut(ctx, "metalava", "api_lint_report.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700599 cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO: Change to ":api-lint"
600
Colin Cross0d532412021-03-25 09:38:45 -0700601 // TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released.
Colin Cross2207f872021-03-24 12:39:08 -0700602 if d.Name() != "android.car-system-stubs-docs" &&
603 d.Name() != "android.car-stubs-docs" {
604 cmd.Flag("--lints-as-errors")
605 cmd.Flag("--warnings-as-errors") // Most lints are actually warnings.
606 }
607
608 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700609 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "api_lint_baseline.txt")
610 d.apiLintTimestamp = android.PathForModuleOut(ctx, "metalava", "api_lint.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700611
612 // Note this string includes a special shell quote $' ... ', which decodes the "\n"s.
Colin Cross2207f872021-03-24 12:39:08 -0700613 //
614 // TODO: metalava also has a slightly different message hardcoded. Should we unify this
615 // message and metalava's one?
616 msg := `$'` + // Enclose with $' ... '
617 `************************************************************\n` +
618 `Your API changes are triggering API Lint warnings or errors.\n` +
619 `To make these errors go away, fix the code according to the\n` +
620 `error and/or warning messages above.\n` +
621 `\n` +
622 `If it is not possible to do so, there are workarounds:\n` +
623 `\n` +
Aurimas Liutikasb23b7452021-05-24 18:00:37 +0000624 `1. You can suppress the errors with @SuppressLint("<id>")\n` +
625 ` where the <id> is given in brackets in the error message above.\n`
Colin Cross2207f872021-03-24 12:39:08 -0700626
627 if baselineFile.Valid() {
628 cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path())
629 cmd.FlagWithOutput("--update-baseline:api-lint ", updatedBaselineOutput)
630
631 msg += fmt.Sprintf(``+
632 `2. You can update the baseline by executing the following\n`+
633 ` command:\n`+
Colin Cross63eeda02021-04-15 19:01:57 -0700634 ` (cd $ANDROID_BUILD_TOP && cp \\\n`+
635 ` "%s" \\\n`+
636 ` "%s")\n`+
Colin Cross2207f872021-03-24 12:39:08 -0700637 ` To submit the revised baseline.txt to the main Android\n`+
638 ` repository, you will need approval.\n`, updatedBaselineOutput, baselineFile.Path())
639 } else {
640 msg += fmt.Sprintf(``+
641 `2. You can add a baseline file of existing lint failures\n`+
642 ` to the build rule of %s.\n`, d.Name())
643 }
644 // Note the message ends with a ' (single quote), to close the $' ... ' .
645 msg += `************************************************************\n'`
646
647 cmd.FlagWithArg("--error-message:api-lint ", msg)
648 }
649
650 // Add "check released" options. (Detect incompatible API changes from the last public release)
651
652 if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") {
653 doCheckReleased = true
654
655 if len(d.Javadoc.properties.Out) > 0 {
656 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
657 }
658
659 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
660 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
661 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700662 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "last_released_baseline.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700663
Colin Crosscb77f752021-03-24 12:04:44 -0700664 d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_last_released_api.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700665
666 cmd.FlagWithInput("--check-compatibility:api:released ", apiFile)
667 cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile)
668
669 if baselineFile.Valid() {
670 cmd.FlagWithInput("--baseline:compatibility:released ", baselineFile.Path())
671 cmd.FlagWithOutput("--update-baseline:compatibility:released ", updatedBaselineOutput)
672 }
673
674 // Note this string includes quote ($' ... '), which decodes the "\n"s.
675 msg := `$'\n******************************\n` +
676 `You have tried to change the API from what has been previously released in\n` +
677 `an SDK. Please fix the errors listed above.\n` +
678 `******************************\n'`
679
680 cmd.FlagWithArg("--error-message:compatibility:released ", msg)
681 }
682
Colin Cross2207f872021-03-24 12:39:08 -0700683 if generateStubs {
684 rule.Command().
685 BuiltTool("soong_zip").
686 Flag("-write_if_changed").
687 Flag("-jar").
688 FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
689 FlagWithArg("-C ", stubsDir.String()).
690 FlagWithArg("-D ", stubsDir.String())
691 }
692
693 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700694 d.metadataZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-metadata.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700695 rule.Command().
696 BuiltTool("soong_zip").
697 Flag("-write_if_changed").
698 Flag("-d").
699 FlagWithOutput("-o ", d.metadataZip).
700 FlagWithArg("-C ", d.metadataDir.String()).
701 FlagWithArg("-D ", d.metadataDir.String())
702 }
703
704 // TODO: We don't really need two separate API files, but this is a reminiscence of how
705 // we used to run metalava separately for API lint and the "last_released" check. Unify them.
706 if doApiLint {
707 rule.Command().Text("touch").Output(d.apiLintTimestamp)
708 }
709 if doCheckReleased {
710 rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp)
711 }
712
Colin Cross6aa5c402021-03-24 12:28:50 -0700713 // TODO(b/183630617): rewrapper doesn't support restat rules
Colin Crosse52c2ac2022-03-28 17:03:35 -0700714 if !metalavaUseRbe(ctx) {
715 rule.Restat()
716 }
Colin Cross2207f872021-03-24 12:39:08 -0700717
718 zipSyncCleanupCmd(rule, srcJarDir)
719
Paul Duffinc166b682022-05-27 12:23:08 +0000720 rule.Build("metalava", "metalava merged")
721
Paul Duffine7a86642022-08-16 15:43:20 +0000722 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
723
724 if len(d.Javadoc.properties.Out) > 0 {
725 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
726 }
727
728 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
729 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
730 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)
731
732 if baselineFile.Valid() {
733 ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
734 }
735
736 d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp")
737
738 rule := android.NewRuleBuilder(pctx, ctx)
739
740 // Diff command line.
741 // -F matches the closest "opening" line, such as "package android {"
742 // and " public class Intent {".
743 diff := `diff -u -F '{ *$'`
744
745 rule.Command().Text("( true")
746 rule.Command().
747 Text(diff).
748 Input(apiFile).Input(d.apiFile)
749
750 rule.Command().
751 Text(diff).
752 Input(removedApiFile).Input(d.removedApiFile)
753
754 msg := fmt.Sprintf(`\n******************************\n`+
755 `You have tried to change the API from what has been previously approved.\n\n`+
756 `To make these errors go away, you have two choices:\n`+
757 ` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
758 ` to the new methods, etc. shown in the above diff.\n\n`+
759 ` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+
760 ` m %s-update-current-api\n\n`+
761 ` To submit the revised current.txt to the main Android repository,\n`+
762 ` you will need approval.\n`+
763 `******************************\n`, ctx.ModuleName())
764
765 rule.Command().
766 Text("touch").Output(d.checkCurrentApiTimestamp).
767 Text(") || (").
768 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
769 Text("; exit 38").
770 Text(")")
771
772 rule.Build("metalavaCurrentApiCheck", "check current API")
773
774 d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "update_current_api.timestamp")
775
776 // update API rule
777 rule = android.NewRuleBuilder(pctx, ctx)
778
779 rule.Command().Text("( true")
780
781 rule.Command().
782 Text("cp").Flag("-f").
783 Input(d.apiFile).Flag(apiFile.String())
784
785 rule.Command().
786 Text("cp").Flag("-f").
787 Input(d.removedApiFile).Flag(removedApiFile.String())
788
789 msg = "failed to update public API"
790
791 rule.Command().
792 Text("touch").Output(d.updateCurrentApiTimestamp).
793 Text(") || (").
794 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
795 Text("; exit 38").
796 Text(")")
797
798 rule.Build("metalavaCurrentApiUpdate", "update current API")
799 }
800
Colin Cross2207f872021-03-24 12:39:08 -0700801 if String(d.properties.Check_nullability_warnings) != "" {
802 if d.nullabilityWarningsFile == nil {
803 ctx.PropertyErrorf("check_nullability_warnings",
804 "Cannot specify check_nullability_warnings unless validating nullability")
805 }
806
807 checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings))
808
Colin Crosscb77f752021-03-24 12:04:44 -0700809 d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "metalava", "check_nullability_warnings.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700810
811 msg := fmt.Sprintf(`\n******************************\n`+
812 `The warnings encountered during nullability annotation validation did\n`+
813 `not match the checked in file of expected warnings. The diffs are shown\n`+
814 `above. You have two options:\n`+
815 ` 1. Resolve the differences by editing the nullability annotations.\n`+
816 ` 2. Update the file of expected warnings by running:\n`+
817 ` cp %s %s\n`+
818 ` and submitting the updated file as part of your change.`,
819 d.nullabilityWarningsFile, checkNullabilityWarnings)
820
821 rule := android.NewRuleBuilder(pctx, ctx)
822
823 rule.Command().
824 Text("(").
825 Text("diff").Input(checkNullabilityWarnings).Input(d.nullabilityWarningsFile).
826 Text("&&").
827 Text("touch").Output(d.checkNullabilityWarningsTimestamp).
828 Text(") || (").
829 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
830 Text("; exit 38").
831 Text(")")
832
833 rule.Build("nullabilityWarningsCheck", "nullability warnings check")
834 }
835}
836
Spandan Das0b555e32022-11-28 18:48:51 +0000837var _ android.ApiProvider = (*Droidstubs)(nil)
838
839type bazelJavaApiContributionAttributes struct {
840 Api bazel.LabelAttribute
841 Api_surface *string
842}
843
844func (d *Droidstubs) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
845 props := bazel.BazelTargetModuleProperties{
846 Rule_class: "java_api_contribution",
847 Bzl_load_location: "//build/bazel/rules/apis:java_api_contribution.bzl",
848 }
849 apiFile := d.properties.Check_api.Current.Api_file
850 // Do not generate a target if check_api is not set
851 if apiFile == nil {
852 return
853 }
854 attrs := &bazelJavaApiContributionAttributes{
855 Api: *bazel.MakeLabelAttribute(
856 android.BazelLabelForModuleSrcSingle(ctx, proptools.String(apiFile)).Label,
857 ),
858 Api_surface: proptools.StringPtr(bazelApiSurfaceName(d.Name())),
859 }
860 ctx.CreateBazelTargetModule(props, android.CommonAttributes{
861 Name: android.ApiContributionTargetName(ctx.ModuleName()),
862 }, attrs)
863}
864
865// TODO (b/262014796): Export the API contributions of CorePlatformApi
866// A map to populate the api surface of a droidstub from a substring appearing in its name
867// This map assumes that droidstubs (either checked-in or created by java_sdk_library)
868// use a strict naming convention
869var (
870 droidstubsModuleNamingToSdkKind = map[string]android.SdkKind{
871 //public is commented out since the core libraries use public in their java_sdk_library names
872 "intracore": android.SdkIntraCore,
873 "intra.core": android.SdkIntraCore,
874 "system_server": android.SdkSystemServer,
875 "system-server": android.SdkSystemServer,
876 "system": android.SdkSystem,
877 "module_lib": android.SdkModule,
878 "module-lib": android.SdkModule,
879 "test": android.SdkTest,
Spandan Das4ac2aed2022-12-28 01:54:29 +0000880 "toolchain": android.SdkToolchain,
Spandan Das0b555e32022-11-28 18:48:51 +0000881 }
882)
883
884// A helper function that returns the api surface of the corresponding java_api_contribution Bazel target
885// The api_surface is populated using the naming convention of the droidstubs module.
886func bazelApiSurfaceName(name string) string {
887 // Sort the keys so that longer strings appear first
888 // Otherwise substrings like system will match both system and system_server
889 sortedKeys := make([]string, 0)
890 for key := range droidstubsModuleNamingToSdkKind {
891 sortedKeys = append(sortedKeys, key)
892 }
893 sort.Slice(sortedKeys, func(i, j int) bool {
894 return len(sortedKeys[i]) > len(sortedKeys[j])
895 })
896 for _, sortedKey := range sortedKeys {
897 if strings.Contains(name, sortedKey) {
898 sdkKind := droidstubsModuleNamingToSdkKind[sortedKey]
899 return sdkKind.String() + "api"
900 }
901 }
902 // Default is publicapi
903 return android.SdkPublic.String() + "api"
904}
905
Colin Cross2207f872021-03-24 12:39:08 -0700906func StubsDefaultsFactory() android.Module {
907 module := &DocDefaults{}
908
909 module.AddProperties(
910 &JavadocProperties{},
911 &DroidstubsProperties{},
912 )
913
914 android.InitDefaultsModule(module)
915
916 return module
917}
918
919var _ android.PrebuiltInterface = (*PrebuiltStubsSources)(nil)
920
921type PrebuiltStubsSourcesProperties struct {
922 Srcs []string `android:"path"`
923}
924
925type PrebuiltStubsSources struct {
926 android.ModuleBase
927 android.DefaultableModuleBase
928 prebuilt android.Prebuilt
Colin Cross2207f872021-03-24 12:39:08 -0700929
930 properties PrebuiltStubsSourcesProperties
931
kgui67007242022-01-25 13:50:25 +0800932 stubsSrcJar android.Path
Colin Cross2207f872021-03-24 12:39:08 -0700933}
934
935func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
936 switch tag {
937 case "":
938 return android.Paths{p.stubsSrcJar}, nil
939 default:
940 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
941 }
942}
943
944func (d *PrebuiltStubsSources) StubsSrcJar() android.Path {
945 return d.stubsSrcJar
946}
947
948func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Cross2207f872021-03-24 12:39:08 -0700949 if len(p.properties.Srcs) != 1 {
Anton Hansson86758ac2021-11-03 14:44:12 +0000950 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 -0700951 return
952 }
953
Anton Hansson86758ac2021-11-03 14:44:12 +0000954 src := p.properties.Srcs[0]
955 if filepath.Ext(src) == ".srcjar" {
956 // This is a srcjar. We can use it directly.
957 p.stubsSrcJar = android.PathForModuleSrc(ctx, src)
958 } else {
959 outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
Colin Cross2207f872021-03-24 12:39:08 -0700960
Anton Hansson86758ac2021-11-03 14:44:12 +0000961 // This is a directory. Glob the contents just in case the directory does not exist.
962 srcGlob := src + "/**/*"
963 srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
Colin Cross2207f872021-03-24 12:39:08 -0700964
Anton Hansson86758ac2021-11-03 14:44:12 +0000965 // Although PathForModuleSrc can return nil if either the path doesn't exist or
966 // the path components are invalid it won't in this case because no components
967 // are specified and the module directory must exist in order to get this far.
968 srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, src)
Colin Cross2207f872021-03-24 12:39:08 -0700969
Anton Hansson86758ac2021-11-03 14:44:12 +0000970 rule := android.NewRuleBuilder(pctx, ctx)
971 rule.Command().
972 BuiltTool("soong_zip").
973 Flag("-write_if_changed").
974 Flag("-jar").
975 FlagWithOutput("-o ", outPath).
976 FlagWithArg("-C ", srcDir.String()).
977 FlagWithRspFileInputList("-r ", outPath.ReplaceExtension(ctx, "rsp"), srcPaths)
978 rule.Restat()
979 rule.Build("zip src", "Create srcjar from prebuilt source")
980 p.stubsSrcJar = outPath
981 }
Colin Cross2207f872021-03-24 12:39:08 -0700982}
983
984func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
985 return &p.prebuilt
986}
987
988func (p *PrebuiltStubsSources) Name() string {
989 return p.prebuilt.Name(p.ModuleBase.Name())
990}
991
992// prebuilt_stubs_sources imports a set of java source files as if they were
993// generated by droidstubs.
994//
995// By default, a prebuilt_stubs_sources has a single variant that expects a
996// set of `.java` files generated by droidstubs.
997//
998// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one
999// for host modules.
1000//
1001// Intended only for use by sdk snapshots.
1002func PrebuiltStubsSourcesFactory() android.Module {
1003 module := &PrebuiltStubsSources{}
1004
1005 module.AddProperties(&module.properties)
1006
1007 android.InitPrebuiltModule(module, &module.properties.Srcs)
Colin Cross2207f872021-03-24 12:39:08 -07001008 InitDroiddocModule(module, android.HostAndDeviceSupported)
1009 return module
1010}