blob: 059f98c44eb7105ff6fea1e9c30bbb5ac83e87ce [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
51 android.SdkBase
52
53 properties DroidstubsProperties
Paul Duffinc71d2b72022-08-16 15:24:01 +000054 apiFile android.Path
55 removedApiFile android.Path
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
Colin Cross2207f872021-03-24 12:39:08 -070069 metadataZip android.WritablePath
70 metadataDir android.WritablePath
71}
72
73type DroidstubsProperties struct {
74 // The generated public API filename by Metalava, defaults to <module>_api.txt
75 Api_filename *string
76
77 // the generated removed API filename by Metalava, defaults to <module>_removed.txt
78 Removed_api_filename *string
79
Colin Cross2207f872021-03-24 12:39:08 -070080 Check_api struct {
81 Last_released ApiToCheck
82
83 Current ApiToCheck
84
85 Api_lint struct {
86 Enabled *bool
87
88 // If set, performs api_lint on any new APIs not found in the given signature file
89 New_since *string `android:"path"`
90
91 // If not blank, path to the baseline txt file for approved API lint violations.
92 Baseline_file *string `android:"path"`
93 }
94 }
95
96 // user can specify the version of previous released API file in order to do compatibility check.
97 Previous_api *string `android:"path"`
98
99 // is set to true, Metalava will allow framework SDK to contain annotations.
100 Annotations_enabled *bool
101
102 // a list of top-level directories containing files to merge qualifier annotations (i.e. those intended to be included in the stubs written) from.
103 Merge_annotations_dirs []string
104
105 // a list of top-level directories containing Java stub files to merge show/hide annotations from.
106 Merge_inclusion_annotations_dirs []string
107
108 // a file containing a list of classes to do nullability validation for.
109 Validate_nullability_from_list *string
110
111 // a file containing expected warnings produced by validation of nullability annotations.
112 Check_nullability_warnings *string
113
114 // if set to true, allow Metalava to generate doc_stubs source files. Defaults to false.
115 Create_doc_stubs *bool
116
117 // if set to true, cause Metalava to output Javadoc comments in the stubs source files. Defaults to false.
118 // Has no effect if create_doc_stubs: true.
119 Output_javadoc_comments *bool
120
121 // if set to false then do not write out stubs. Defaults to true.
122 //
123 // TODO(b/146727827): Remove capability when we do not need to generate stubs and API separately.
124 Generate_stubs *bool
125
126 // if set to true, provides a hint to the build system that this rule uses a lot of memory,
127 // whicih can be used for scheduling purposes
128 High_mem *bool
129
satayev783195c2021-06-23 21:49:57 +0100130 // if set to true, Metalava will allow framework SDK to contain API levels annotations.
Colin Cross2207f872021-03-24 12:39:08 -0700131 Api_levels_annotations_enabled *bool
132
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000133 // Apply the api levels database created by this module rather than generating one in this droidstubs.
134 Api_levels_module *string
135
Colin Cross2207f872021-03-24 12:39:08 -0700136 // the dirs which Metalava extracts API levels annotations from.
137 Api_levels_annotations_dirs []string
138
Cole Faust051fa912022-10-05 12:45:42 -0700139 // 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 +0100140 Api_levels_sdk_type *string
141
Colin Cross2207f872021-03-24 12:39:08 -0700142 // the filename which Metalava extracts API levels annotations from. Defaults to android.jar.
143 Api_levels_jar_filename *string
144
145 // if set to true, collect the values used by the Dev tools and
146 // write them in files packaged with the SDK. Defaults to false.
147 Write_sdk_values *bool
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200148
149 // path or filegroup to file defining extension an SDK name <-> numerical ID mapping and
150 // what APIs exist in which SDKs; passed to metalava via --sdk-extensions-info
151 Extensions_info_file *string `android:"path"`
Colin Cross2207f872021-03-24 12:39:08 -0700152}
153
Anton Hansson52609322021-05-05 10:36:05 +0100154// Used by xsd_config
155type ApiFilePath interface {
156 ApiFilePath() android.Path
157}
158
159type ApiStubsSrcProvider interface {
160 StubsSrcJar() android.Path
161}
162
163// Provider of information about API stubs, used by java_sdk_library.
164type ApiStubsProvider interface {
Anton Hanssond78eb762021-09-21 15:25:12 +0100165 AnnotationsZip() android.Path
Anton Hansson52609322021-05-05 10:36:05 +0100166 ApiFilePath
167 RemovedApiFilePath() android.Path
168
169 ApiStubsSrcProvider
170}
171
Colin Cross2207f872021-03-24 12:39:08 -0700172// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
173// documented, filtering out hidden classes and methods. The resulting .java files are intended to be passed to
174// a droiddoc module to generate documentation.
175func DroidstubsFactory() android.Module {
176 module := &Droidstubs{}
177
178 module.AddProperties(&module.properties,
179 &module.Javadoc.properties)
180
181 InitDroiddocModule(module, android.HostAndDeviceSupported)
182 android.InitSdkAwareModule(module)
183 return module
184}
185
186// droidstubs_host passes sources files through Metalava to generate stub .java files that only contain the API
187// to be documented, filtering out hidden classes and methods. The resulting .java files are intended to be
188// passed to a droiddoc_host module to generate documentation. Use a droidstubs_host instead of a droidstubs
189// module when symbols needed by the source files are provided by java_library_host modules.
190func DroidstubsHostFactory() android.Module {
191 module := &Droidstubs{}
192
193 module.AddProperties(&module.properties,
194 &module.Javadoc.properties)
195
196 InitDroiddocModule(module, android.HostSupported)
197 return module
198}
199
200func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) {
201 switch tag {
202 case "":
203 return android.Paths{d.stubsSrcJar}, nil
204 case ".docs.zip":
205 return android.Paths{d.docZip}, nil
206 case ".api.txt", android.DefaultDistTag:
207 // This is the default dist path for dist properties that have no tag property.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000208 return android.Paths{d.apiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700209 case ".removed-api.txt":
Paul Duffinc71d2b72022-08-16 15:24:01 +0000210 return android.Paths{d.removedApiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700211 case ".annotations.zip":
212 return android.Paths{d.annotationsZip}, nil
213 case ".api_versions.xml":
214 return android.Paths{d.apiVersionsXml}, nil
215 default:
216 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
217 }
218}
219
Anton Hanssond78eb762021-09-21 15:25:12 +0100220func (d *Droidstubs) AnnotationsZip() android.Path {
221 return d.annotationsZip
222}
223
Colin Cross2207f872021-03-24 12:39:08 -0700224func (d *Droidstubs) ApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000225 return d.apiFile
Colin Cross2207f872021-03-24 12:39:08 -0700226}
227
228func (d *Droidstubs) RemovedApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000229 return d.removedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700230}
231
232func (d *Droidstubs) StubsSrcJar() android.Path {
233 return d.stubsSrcJar
234}
235
236var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"}
237var metalavaMergeInclusionAnnotationsDirTag = dependencyTag{name: "metalava-merge-inclusion-annotations-dir"}
238var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"}
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000239var metalavaAPILevelsModuleTag = dependencyTag{name: "metalava-api-levels-module-tag"}
Colin Cross2207f872021-03-24 12:39:08 -0700240
241func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) {
242 d.Javadoc.addDeps(ctx)
243
244 if len(d.properties.Merge_annotations_dirs) != 0 {
245 for _, mergeAnnotationsDir := range d.properties.Merge_annotations_dirs {
246 ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir)
247 }
248 }
249
250 if len(d.properties.Merge_inclusion_annotations_dirs) != 0 {
251 for _, mergeInclusionAnnotationsDir := range d.properties.Merge_inclusion_annotations_dirs {
252 ctx.AddDependency(ctx.Module(), metalavaMergeInclusionAnnotationsDirTag, mergeInclusionAnnotationsDir)
253 }
254 }
255
256 if len(d.properties.Api_levels_annotations_dirs) != 0 {
257 for _, apiLevelsAnnotationsDir := range d.properties.Api_levels_annotations_dirs {
258 ctx.AddDependency(ctx.Module(), metalavaAPILevelsAnnotationsDirTag, apiLevelsAnnotationsDir)
259 }
260 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000261
262 if d.properties.Api_levels_module != nil {
263 ctx.AddDependency(ctx.Module(), metalavaAPILevelsModuleTag, proptools.String(d.properties.Api_levels_module))
264 }
Colin Cross2207f872021-03-24 12:39:08 -0700265}
266
267func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) {
268 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
269 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
270 String(d.properties.Api_filename) != "" {
271 filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000272 uncheckedApiFile := android.PathForModuleOut(ctx, "metalava", filename)
273 cmd.FlagWithOutput("--api ", uncheckedApiFile)
274 d.apiFile = uncheckedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700275 } else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" {
276 // If check api is disabled then make the source file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000277 d.apiFile = android.PathForModuleSrc(ctx, sourceApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700278 }
279
280 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
281 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
282 String(d.properties.Removed_api_filename) != "" {
283 filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000284 uncheckedRemovedFile := android.PathForModuleOut(ctx, "metalava", filename)
285 cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile)
286 d.removedApiFile = uncheckedRemovedFile
Colin Cross2207f872021-03-24 12:39:08 -0700287 } else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" {
288 // If check api is disabled then make the source removed api file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000289 d.removedApiFile = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700290 }
291
Colin Cross2207f872021-03-24 12:39:08 -0700292 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700293 d.metadataDir = android.PathForModuleOut(ctx, "metalava", "metadata")
Colin Cross2207f872021-03-24 12:39:08 -0700294 cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
295 }
296
297 if stubsDir.Valid() {
298 if Bool(d.properties.Create_doc_stubs) {
299 cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
300 } else {
301 cmd.FlagWithArg("--stubs ", stubsDir.String())
302 if !Bool(d.properties.Output_javadoc_comments) {
303 cmd.Flag("--exclude-documentation-from-stubs")
304 }
305 }
306 }
307}
308
309func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
310 if Bool(d.properties.Annotations_enabled) {
311 cmd.Flag("--include-annotations")
312
Andrei Onea4985e512021-04-29 16:29:34 +0100313 cmd.FlagWithArg("--exclude-annotation ", "androidx.annotation.RequiresApi")
314
Colin Cross2207f872021-03-24 12:39:08 -0700315 validatingNullability :=
Colin Crossbc139922021-03-25 18:33:16 -0700316 strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") ||
Colin Cross2207f872021-03-24 12:39:08 -0700317 String(d.properties.Validate_nullability_from_list) != ""
318
319 migratingNullability := String(d.properties.Previous_api) != ""
320 if migratingNullability {
321 previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
322 cmd.FlagWithInput("--migrate-nullness ", previousApi)
323 }
324
325 if s := String(d.properties.Validate_nullability_from_list); s != "" {
326 cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
327 }
328
329 if validatingNullability {
Colin Crosscb77f752021-03-24 12:04:44 -0700330 d.nullabilityWarningsFile = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_nullability_warnings.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700331 cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile)
332 }
333
Colin Crosscb77f752021-03-24 12:04:44 -0700334 d.annotationsZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_annotations.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700335 cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip)
336
337 if len(d.properties.Merge_annotations_dirs) != 0 {
338 d.mergeAnnoDirFlags(ctx, cmd)
339 }
340
341 // TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
342 cmd.FlagWithArg("--hide ", "HiddenTypedefConstant").
343 FlagWithArg("--hide ", "SuperfluousPrefix").
Sam Gilbert049af112022-03-04 16:03:53 -0500344 FlagWithArg("--hide ", "AnnotationExtraction").
345 // b/222738070
Sam Gilbert675f0b42022-03-08 11:24:44 -0500346 FlagWithArg("--hide ", "BannedThrow").
347 // b/223382732
348 FlagWithArg("--hide ", "ChangedDefault")
Colin Cross2207f872021-03-24 12:39:08 -0700349 }
350}
351
352func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
353 ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
354 if t, ok := m.(*ExportedDroiddocDir); ok {
355 cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps)
356 } else {
357 ctx.PropertyErrorf("merge_annotations_dirs",
358 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
359 }
360 })
361}
362
363func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
364 ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) {
365 if t, ok := m.(*ExportedDroiddocDir); ok {
366 cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps)
367 } else {
368 ctx.PropertyErrorf("merge_inclusion_annotations_dirs",
369 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
370 }
371 })
372}
373
374func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000375 var apiVersions android.Path
376 if proptools.Bool(d.properties.Api_levels_annotations_enabled) {
377 d.apiLevelsGenerationFlags(ctx, cmd)
378 apiVersions = d.apiVersionsXml
379 } else {
380 ctx.VisitDirectDepsWithTag(metalavaAPILevelsModuleTag, func(m android.Module) {
381 if s, ok := m.(*Droidstubs); ok {
382 apiVersions = s.apiVersionsXml
383 } else {
384 ctx.PropertyErrorf("api_levels_module",
385 "module %q is not a droidstubs module", ctx.OtherModuleName(m))
386 }
387 })
Colin Cross2207f872021-03-24 12:39:08 -0700388 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000389 if apiVersions != nil {
390 cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion().String())
391 cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename())
392 cmd.FlagWithInput("--apply-api-levels ", apiVersions)
393 }
394}
Colin Cross2207f872021-03-24 12:39:08 -0700395
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000396func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Colin Cross2207f872021-03-24 12:39:08 -0700397 if len(d.properties.Api_levels_annotations_dirs) == 0 {
398 ctx.PropertyErrorf("api_levels_annotations_dirs",
399 "has to be non-empty if api levels annotations was enabled!")
400 }
401
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000402 d.apiVersionsXml = android.PathForModuleOut(ctx, "metalava", "api-versions.xml")
Colin Cross2207f872021-03-24 12:39:08 -0700403 cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml)
Colin Cross2207f872021-03-24 12:39:08 -0700404
405 filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar")
406
satayev783195c2021-06-23 21:49:57 +0100407 var dirs []string
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200408 var extensions_dir string
Colin Cross2207f872021-03-24 12:39:08 -0700409 ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
410 if t, ok := m.(*ExportedDroiddocDir); ok {
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200411 extRegex := regexp.MustCompile(t.dir.String() + `/extensions/[0-9]+/public/.*\.jar`)
412
413 // Grab the first extensions_dir and we find while scanning ExportedDroiddocDir.deps;
414 // ideally this should be read from prebuiltApis.properties.Extensions_*
Colin Cross2207f872021-03-24 12:39:08 -0700415 for _, dep := range t.deps {
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200416 if extRegex.MatchString(dep.String()) && d.properties.Extensions_info_file != nil {
417 if extensions_dir == "" {
418 extensions_dir = t.dir.String() + "/extensions"
419 }
420 cmd.Implicit(dep)
421 }
Colin Cross5f6ffc72021-03-29 21:54:45 -0700422 if dep.Base() == filename {
423 cmd.Implicit(dep)
424 }
425 if filename != "android.jar" && dep.Base() == "android.jar" {
426 // Metalava implicitly searches these patterns:
427 // prebuilts/tools/common/api-versions/android-%/android.jar
428 // prebuilts/sdk/%/public/android.jar
429 // Add android.jar files from the api_levels_annotations_dirs directories to try
430 // to satisfy these patterns. If Metalava can't find a match for an API level
431 // between 1 and 28 in at least one pattern it will fail.
Colin Cross2207f872021-03-24 12:39:08 -0700432 cmd.Implicit(dep)
433 }
434 }
satayev783195c2021-06-23 21:49:57 +0100435
436 dirs = append(dirs, t.dir.String())
Colin Cross2207f872021-03-24 12:39:08 -0700437 } else {
438 ctx.PropertyErrorf("api_levels_annotations_dirs",
439 "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
440 }
441 })
satayev783195c2021-06-23 21:49:57 +0100442
443 // Add all relevant --android-jar-pattern patterns for Metalava.
444 // When parsing a stub jar for a specific version, Metalava picks the first pattern that defines
445 // an actual file present on disk (in the order the patterns were passed). For system APIs for
446 // privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs
Pedro Loureirocc203502021-10-04 17:24:00 +0000447 // for older releases. Similarly, module-lib falls back to system API.
448 var sdkDirs []string
449 switch proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") {
Cole Faust051fa912022-10-05 12:45:42 -0700450 case "system-server":
451 sdkDirs = []string{"system-server", "module-lib", "system", "public"}
Pedro Loureirocc203502021-10-04 17:24:00 +0000452 case "module-lib":
453 sdkDirs = []string{"module-lib", "system", "public"}
454 case "system":
455 sdkDirs = []string{"system", "public"}
456 case "public":
457 sdkDirs = []string{"public"}
458 default:
459 ctx.PropertyErrorf("api_levels_sdk_type", "needs to be one of %v", allowedApiLevelSdkTypes)
460 return
satayev783195c2021-06-23 21:49:57 +0100461 }
Pedro Loureirocc203502021-10-04 17:24:00 +0000462
463 for _, sdkDir := range sdkDirs {
464 for _, dir := range dirs {
465 cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, filename))
466 }
satayev783195c2021-06-23 21:49:57 +0100467 }
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200468
469 if d.properties.Extensions_info_file != nil {
470 if extensions_dir == "" {
471 ctx.ModuleErrorf("extensions_info_file set, but no SDK extension dirs found")
472 }
473 info_file := android.PathForModuleSrc(ctx, *d.properties.Extensions_info_file)
474 cmd.Implicit(info_file)
475 cmd.FlagWithArg("--sdk-extensions-root ", extensions_dir)
476 cmd.FlagWithArg("--sdk-extensions-info ", info_file.String())
477 }
Colin Cross2207f872021-03-24 12:39:08 -0700478}
479
Colin Crosse52c2ac2022-03-28 17:03:35 -0700480func metalavaUseRbe(ctx android.ModuleContext) bool {
481 return ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA")
482}
483
Colin Cross2207f872021-03-24 12:39:08 -0700484func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
Anton Hansson556e8142021-06-04 16:20:25 +0100485 srcJarList android.Path, bootclasspath, classpath classpath, homeDir android.WritablePath) *android.RuleBuilderCommand {
Colin Cross2207f872021-03-24 12:39:08 -0700486 rule.Command().Text("rm -rf").Flag(homeDir.String())
487 rule.Command().Text("mkdir -p").Flag(homeDir.String())
488
Anton Hansson556e8142021-06-04 16:20:25 +0100489 cmd := rule.Command()
Colin Cross2207f872021-03-24 12:39:08 -0700490 cmd.FlagWithArg("ANDROID_PREFS_ROOT=", homeDir.String())
491
Colin Crosse52c2ac2022-03-28 17:03:35 -0700492 if metalavaUseRbe(ctx) {
Colin Cross2207f872021-03-24 12:39:08 -0700493 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
Colin Cross8095c292021-03-30 16:40:48 -0700494 execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
495 labels := map[string]string{"type": "tool", "name": "metalava"}
496 // TODO: metalava pool rejects these jobs
497 pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
498 rule.Rewrapper(&remoteexec.REParams{
499 Labels: labels,
500 ExecStrategy: execStrategy,
501 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
502 Platform: map[string]string{remoteexec.PoolKey: pool},
503 })
Colin Cross2207f872021-03-24 12:39:08 -0700504 }
505
Colin Cross6aa5c402021-03-24 12:28:50 -0700506 cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
Colin Cross2207f872021-03-24 12:39:08 -0700507 Flag(config.JavacVmFlags).
508 Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED").
509 FlagWithArg("-encoding ", "UTF-8").
510 FlagWithArg("-source ", javaVersion.String()).
511 FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs).
512 FlagWithInput("@", srcJarList)
513
Colin Cross2207f872021-03-24 12:39:08 -0700514 if len(bootclasspath) > 0 {
515 cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":")
516 }
517
518 if len(classpath) > 0 {
519 cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
520 }
521
Colin Cross2207f872021-03-24 12:39:08 -0700522 cmd.Flag("--no-banner").
523 Flag("--color").
524 Flag("--quiet").
525 Flag("--format=v2").
526 FlagWithArg("--repeat-errors-max ", "10").
Sam Gilbert09cb5db2021-10-06 11:28:28 -0400527 FlagWithArg("--hide ", "UnresolvedImport").
Ember Rose7c57af32022-04-01 10:34:44 -0400528 FlagWithArg("--hide ", "InvalidNullabilityOverride").
Sam Gilbert28e41282022-03-09 15:24:48 +0000529 // b/223382732
530 FlagWithArg("--hide ", "ChangedDefault")
Colin Cross2207f872021-03-24 12:39:08 -0700531
532 return cmd
533}
534
535func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
536 deps := d.Javadoc.collectDeps(ctx)
537
Jiyong Parkf1691d22021-03-29 20:11:58 +0900538 javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d))
Colin Cross2207f872021-03-24 12:39:08 -0700539
540 // Create rule for metalava
541
Colin Crosscb77f752021-03-24 12:04:44 -0700542 srcJarDir := android.PathForModuleOut(ctx, "metalava", "srcjars")
Colin Cross2207f872021-03-24 12:39:08 -0700543
544 rule := android.NewRuleBuilder(pctx, ctx)
545
Colin Cross8095c292021-03-30 16:40:48 -0700546 rule.Sbox(android.PathForModuleOut(ctx, "metalava"),
547 android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
548 SandboxInputs()
Colin Cross6aa5c402021-03-24 12:28:50 -0700549
Colin Cross2207f872021-03-24 12:39:08 -0700550 if BoolDefault(d.properties.High_mem, false) {
551 // This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel.
552 rule.HighMem()
553 }
554
555 generateStubs := BoolDefault(d.properties.Generate_stubs, true)
556 var stubsDir android.OptionalPath
557 if generateStubs {
Colin Crosscb77f752021-03-24 12:04:44 -0700558 d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
559 stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "metalava", "stubsDir"))
Colin Cross2207f872021-03-24 12:39:08 -0700560 rule.Command().Text("rm -rf").Text(stubsDir.String())
561 rule.Command().Text("mkdir -p").Text(stubsDir.String())
562 }
563
564 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
565
Colin Crosscb77f752021-03-24 12:04:44 -0700566 homeDir := android.PathForModuleOut(ctx, "metalava", "home")
Colin Cross2207f872021-03-24 12:39:08 -0700567 cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
Anton Hansson556e8142021-06-04 16:20:25 +0100568 deps.bootClasspath, deps.classpath, homeDir)
Colin Cross2207f872021-03-24 12:39:08 -0700569 cmd.Implicits(d.Javadoc.implicits)
570
571 d.stubsFlags(ctx, cmd, stubsDir)
572
573 d.annotationsFlags(ctx, cmd)
574 d.inclusionAnnotationsFlags(ctx, cmd)
575 d.apiLevelsAnnotationsFlags(ctx, cmd)
576
Colin Crossbc139922021-03-25 18:33:16 -0700577 d.expandArgs(ctx, cmd)
Colin Cross2207f872021-03-24 12:39:08 -0700578
Colin Cross2207f872021-03-24 12:39:08 -0700579 for _, o := range d.Javadoc.properties.Out {
580 cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
581 }
582
583 // Add options for the other optional tasks: API-lint and check-released.
584 // We generate separate timestamp files for them.
585
586 doApiLint := false
587 doCheckReleased := false
588
589 // Add API lint options.
590
591 if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) {
592 doApiLint = true
593
594 newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since)
595 if newSince.Valid() {
596 cmd.FlagWithInput("--api-lint ", newSince.Path())
597 } else {
598 cmd.Flag("--api-lint")
599 }
Colin Crosscb77f752021-03-24 12:04:44 -0700600 d.apiLintReport = android.PathForModuleOut(ctx, "metalava", "api_lint_report.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700601 cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO: Change to ":api-lint"
602
Colin Cross0d532412021-03-25 09:38:45 -0700603 // TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released.
Colin Cross2207f872021-03-24 12:39:08 -0700604 if d.Name() != "android.car-system-stubs-docs" &&
605 d.Name() != "android.car-stubs-docs" {
606 cmd.Flag("--lints-as-errors")
607 cmd.Flag("--warnings-as-errors") // Most lints are actually warnings.
608 }
609
610 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700611 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "api_lint_baseline.txt")
612 d.apiLintTimestamp = android.PathForModuleOut(ctx, "metalava", "api_lint.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700613
614 // Note this string includes a special shell quote $' ... ', which decodes the "\n"s.
Colin Cross2207f872021-03-24 12:39:08 -0700615 //
616 // TODO: metalava also has a slightly different message hardcoded. Should we unify this
617 // message and metalava's one?
618 msg := `$'` + // Enclose with $' ... '
619 `************************************************************\n` +
620 `Your API changes are triggering API Lint warnings or errors.\n` +
621 `To make these errors go away, fix the code according to the\n` +
622 `error and/or warning messages above.\n` +
623 `\n` +
624 `If it is not possible to do so, there are workarounds:\n` +
625 `\n` +
Aurimas Liutikasb23b7452021-05-24 18:00:37 +0000626 `1. You can suppress the errors with @SuppressLint("<id>")\n` +
627 ` where the <id> is given in brackets in the error message above.\n`
Colin Cross2207f872021-03-24 12:39:08 -0700628
629 if baselineFile.Valid() {
630 cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path())
631 cmd.FlagWithOutput("--update-baseline:api-lint ", updatedBaselineOutput)
632
633 msg += fmt.Sprintf(``+
634 `2. You can update the baseline by executing the following\n`+
635 ` command:\n`+
Colin Cross63eeda02021-04-15 19:01:57 -0700636 ` (cd $ANDROID_BUILD_TOP && cp \\\n`+
637 ` "%s" \\\n`+
638 ` "%s")\n`+
Colin Cross2207f872021-03-24 12:39:08 -0700639 ` To submit the revised baseline.txt to the main Android\n`+
640 ` repository, you will need approval.\n`, updatedBaselineOutput, baselineFile.Path())
641 } else {
642 msg += fmt.Sprintf(``+
643 `2. You can add a baseline file of existing lint failures\n`+
644 ` to the build rule of %s.\n`, d.Name())
645 }
646 // Note the message ends with a ' (single quote), to close the $' ... ' .
647 msg += `************************************************************\n'`
648
649 cmd.FlagWithArg("--error-message:api-lint ", msg)
650 }
651
652 // Add "check released" options. (Detect incompatible API changes from the last public release)
653
654 if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") {
655 doCheckReleased = true
656
657 if len(d.Javadoc.properties.Out) > 0 {
658 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
659 }
660
661 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
662 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
663 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700664 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "last_released_baseline.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700665
Colin Crosscb77f752021-03-24 12:04:44 -0700666 d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_last_released_api.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700667
668 cmd.FlagWithInput("--check-compatibility:api:released ", apiFile)
669 cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile)
670
671 if baselineFile.Valid() {
672 cmd.FlagWithInput("--baseline:compatibility:released ", baselineFile.Path())
673 cmd.FlagWithOutput("--update-baseline:compatibility:released ", updatedBaselineOutput)
674 }
675
676 // Note this string includes quote ($' ... '), which decodes the "\n"s.
677 msg := `$'\n******************************\n` +
678 `You have tried to change the API from what has been previously released in\n` +
679 `an SDK. Please fix the errors listed above.\n` +
680 `******************************\n'`
681
682 cmd.FlagWithArg("--error-message:compatibility:released ", msg)
683 }
684
Colin Cross2207f872021-03-24 12:39:08 -0700685 if generateStubs {
686 rule.Command().
687 BuiltTool("soong_zip").
688 Flag("-write_if_changed").
689 Flag("-jar").
690 FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
691 FlagWithArg("-C ", stubsDir.String()).
692 FlagWithArg("-D ", stubsDir.String())
693 }
694
695 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700696 d.metadataZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-metadata.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700697 rule.Command().
698 BuiltTool("soong_zip").
699 Flag("-write_if_changed").
700 Flag("-d").
701 FlagWithOutput("-o ", d.metadataZip).
702 FlagWithArg("-C ", d.metadataDir.String()).
703 FlagWithArg("-D ", d.metadataDir.String())
704 }
705
706 // TODO: We don't really need two separate API files, but this is a reminiscence of how
707 // we used to run metalava separately for API lint and the "last_released" check. Unify them.
708 if doApiLint {
709 rule.Command().Text("touch").Output(d.apiLintTimestamp)
710 }
711 if doCheckReleased {
712 rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp)
713 }
714
Colin Cross6aa5c402021-03-24 12:28:50 -0700715 // TODO(b/183630617): rewrapper doesn't support restat rules
Colin Crosse52c2ac2022-03-28 17:03:35 -0700716 if !metalavaUseRbe(ctx) {
717 rule.Restat()
718 }
Colin Cross2207f872021-03-24 12:39:08 -0700719
720 zipSyncCleanupCmd(rule, srcJarDir)
721
Paul Duffinc166b682022-05-27 12:23:08 +0000722 rule.Build("metalava", "metalava merged")
723
Paul Duffine7a86642022-08-16 15:43:20 +0000724 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
725
726 if len(d.Javadoc.properties.Out) > 0 {
727 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
728 }
729
730 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
731 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
732 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)
733
734 if baselineFile.Valid() {
735 ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
736 }
737
738 d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp")
739
740 rule := android.NewRuleBuilder(pctx, ctx)
741
742 // Diff command line.
743 // -F matches the closest "opening" line, such as "package android {"
744 // and " public class Intent {".
745 diff := `diff -u -F '{ *$'`
746
747 rule.Command().Text("( true")
748 rule.Command().
749 Text(diff).
750 Input(apiFile).Input(d.apiFile)
751
752 rule.Command().
753 Text(diff).
754 Input(removedApiFile).Input(d.removedApiFile)
755
756 msg := fmt.Sprintf(`\n******************************\n`+
757 `You have tried to change the API from what has been previously approved.\n\n`+
758 `To make these errors go away, you have two choices:\n`+
759 ` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
760 ` to the new methods, etc. shown in the above diff.\n\n`+
761 ` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+
762 ` m %s-update-current-api\n\n`+
763 ` To submit the revised current.txt to the main Android repository,\n`+
764 ` you will need approval.\n`+
765 `******************************\n`, ctx.ModuleName())
766
767 rule.Command().
768 Text("touch").Output(d.checkCurrentApiTimestamp).
769 Text(") || (").
770 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
771 Text("; exit 38").
772 Text(")")
773
774 rule.Build("metalavaCurrentApiCheck", "check current API")
775
776 d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "update_current_api.timestamp")
777
778 // update API rule
779 rule = android.NewRuleBuilder(pctx, ctx)
780
781 rule.Command().Text("( true")
782
783 rule.Command().
784 Text("cp").Flag("-f").
785 Input(d.apiFile).Flag(apiFile.String())
786
787 rule.Command().
788 Text("cp").Flag("-f").
789 Input(d.removedApiFile).Flag(removedApiFile.String())
790
791 msg = "failed to update public API"
792
793 rule.Command().
794 Text("touch").Output(d.updateCurrentApiTimestamp).
795 Text(") || (").
796 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
797 Text("; exit 38").
798 Text(")")
799
800 rule.Build("metalavaCurrentApiUpdate", "update current API")
801 }
802
Colin Cross2207f872021-03-24 12:39:08 -0700803 if String(d.properties.Check_nullability_warnings) != "" {
804 if d.nullabilityWarningsFile == nil {
805 ctx.PropertyErrorf("check_nullability_warnings",
806 "Cannot specify check_nullability_warnings unless validating nullability")
807 }
808
809 checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings))
810
Colin Crosscb77f752021-03-24 12:04:44 -0700811 d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "metalava", "check_nullability_warnings.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700812
813 msg := fmt.Sprintf(`\n******************************\n`+
814 `The warnings encountered during nullability annotation validation did\n`+
815 `not match the checked in file of expected warnings. The diffs are shown\n`+
816 `above. You have two options:\n`+
817 ` 1. Resolve the differences by editing the nullability annotations.\n`+
818 ` 2. Update the file of expected warnings by running:\n`+
819 ` cp %s %s\n`+
820 ` and submitting the updated file as part of your change.`,
821 d.nullabilityWarningsFile, checkNullabilityWarnings)
822
823 rule := android.NewRuleBuilder(pctx, ctx)
824
825 rule.Command().
826 Text("(").
827 Text("diff").Input(checkNullabilityWarnings).Input(d.nullabilityWarningsFile).
828 Text("&&").
829 Text("touch").Output(d.checkNullabilityWarningsTimestamp).
830 Text(") || (").
831 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
832 Text("; exit 38").
833 Text(")")
834
835 rule.Build("nullabilityWarningsCheck", "nullability warnings check")
836 }
837}
838
Spandan Das0b555e32022-11-28 18:48:51 +0000839var _ android.ApiProvider = (*Droidstubs)(nil)
840
841type bazelJavaApiContributionAttributes struct {
842 Api bazel.LabelAttribute
843 Api_surface *string
844}
845
846func (d *Droidstubs) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
847 props := bazel.BazelTargetModuleProperties{
848 Rule_class: "java_api_contribution",
849 Bzl_load_location: "//build/bazel/rules/apis:java_api_contribution.bzl",
850 }
851 apiFile := d.properties.Check_api.Current.Api_file
852 // Do not generate a target if check_api is not set
853 if apiFile == nil {
854 return
855 }
856 attrs := &bazelJavaApiContributionAttributes{
857 Api: *bazel.MakeLabelAttribute(
858 android.BazelLabelForModuleSrcSingle(ctx, proptools.String(apiFile)).Label,
859 ),
860 Api_surface: proptools.StringPtr(bazelApiSurfaceName(d.Name())),
861 }
862 ctx.CreateBazelTargetModule(props, android.CommonAttributes{
863 Name: android.ApiContributionTargetName(ctx.ModuleName()),
864 }, attrs)
865}
866
867// TODO (b/262014796): Export the API contributions of CorePlatformApi
868// A map to populate the api surface of a droidstub from a substring appearing in its name
869// This map assumes that droidstubs (either checked-in or created by java_sdk_library)
870// use a strict naming convention
871var (
872 droidstubsModuleNamingToSdkKind = map[string]android.SdkKind{
873 //public is commented out since the core libraries use public in their java_sdk_library names
874 "intracore": android.SdkIntraCore,
875 "intra.core": android.SdkIntraCore,
876 "system_server": android.SdkSystemServer,
877 "system-server": android.SdkSystemServer,
878 "system": android.SdkSystem,
879 "module_lib": android.SdkModule,
880 "module-lib": android.SdkModule,
881 "test": android.SdkTest,
Spandan Das4ac2aed2022-12-28 01:54:29 +0000882 "toolchain": android.SdkToolchain,
Spandan Das0b555e32022-11-28 18:48:51 +0000883 }
884)
885
886// A helper function that returns the api surface of the corresponding java_api_contribution Bazel target
887// The api_surface is populated using the naming convention of the droidstubs module.
888func bazelApiSurfaceName(name string) string {
889 // Sort the keys so that longer strings appear first
890 // Otherwise substrings like system will match both system and system_server
891 sortedKeys := make([]string, 0)
892 for key := range droidstubsModuleNamingToSdkKind {
893 sortedKeys = append(sortedKeys, key)
894 }
895 sort.Slice(sortedKeys, func(i, j int) bool {
896 return len(sortedKeys[i]) > len(sortedKeys[j])
897 })
898 for _, sortedKey := range sortedKeys {
899 if strings.Contains(name, sortedKey) {
900 sdkKind := droidstubsModuleNamingToSdkKind[sortedKey]
901 return sdkKind.String() + "api"
902 }
903 }
904 // Default is publicapi
905 return android.SdkPublic.String() + "api"
906}
907
Colin Cross2207f872021-03-24 12:39:08 -0700908func StubsDefaultsFactory() android.Module {
909 module := &DocDefaults{}
910
911 module.AddProperties(
912 &JavadocProperties{},
913 &DroidstubsProperties{},
914 )
915
916 android.InitDefaultsModule(module)
917
918 return module
919}
920
921var _ android.PrebuiltInterface = (*PrebuiltStubsSources)(nil)
922
923type PrebuiltStubsSourcesProperties struct {
924 Srcs []string `android:"path"`
925}
926
927type PrebuiltStubsSources struct {
928 android.ModuleBase
929 android.DefaultableModuleBase
930 prebuilt android.Prebuilt
931 android.SdkBase
932
933 properties PrebuiltStubsSourcesProperties
934
kgui67007242022-01-25 13:50:25 +0800935 stubsSrcJar android.Path
Colin Cross2207f872021-03-24 12:39:08 -0700936}
937
938func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
939 switch tag {
940 case "":
941 return android.Paths{p.stubsSrcJar}, nil
942 default:
943 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
944 }
945}
946
947func (d *PrebuiltStubsSources) StubsSrcJar() android.Path {
948 return d.stubsSrcJar
949}
950
951func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Cross2207f872021-03-24 12:39:08 -0700952 if len(p.properties.Srcs) != 1 {
Anton Hansson86758ac2021-11-03 14:44:12 +0000953 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 -0700954 return
955 }
956
Anton Hansson86758ac2021-11-03 14:44:12 +0000957 src := p.properties.Srcs[0]
958 if filepath.Ext(src) == ".srcjar" {
959 // This is a srcjar. We can use it directly.
960 p.stubsSrcJar = android.PathForModuleSrc(ctx, src)
961 } else {
962 outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
Colin Cross2207f872021-03-24 12:39:08 -0700963
Anton Hansson86758ac2021-11-03 14:44:12 +0000964 // This is a directory. Glob the contents just in case the directory does not exist.
965 srcGlob := src + "/**/*"
966 srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
Colin Cross2207f872021-03-24 12:39:08 -0700967
Anton Hansson86758ac2021-11-03 14:44:12 +0000968 // Although PathForModuleSrc can return nil if either the path doesn't exist or
969 // the path components are invalid it won't in this case because no components
970 // are specified and the module directory must exist in order to get this far.
971 srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, src)
Colin Cross2207f872021-03-24 12:39:08 -0700972
Anton Hansson86758ac2021-11-03 14:44:12 +0000973 rule := android.NewRuleBuilder(pctx, ctx)
974 rule.Command().
975 BuiltTool("soong_zip").
976 Flag("-write_if_changed").
977 Flag("-jar").
978 FlagWithOutput("-o ", outPath).
979 FlagWithArg("-C ", srcDir.String()).
980 FlagWithRspFileInputList("-r ", outPath.ReplaceExtension(ctx, "rsp"), srcPaths)
981 rule.Restat()
982 rule.Build("zip src", "Create srcjar from prebuilt source")
983 p.stubsSrcJar = outPath
984 }
Colin Cross2207f872021-03-24 12:39:08 -0700985}
986
987func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
988 return &p.prebuilt
989}
990
991func (p *PrebuiltStubsSources) Name() string {
992 return p.prebuilt.Name(p.ModuleBase.Name())
993}
994
995// prebuilt_stubs_sources imports a set of java source files as if they were
996// generated by droidstubs.
997//
998// By default, a prebuilt_stubs_sources has a single variant that expects a
999// set of `.java` files generated by droidstubs.
1000//
1001// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one
1002// for host modules.
1003//
1004// Intended only for use by sdk snapshots.
1005func PrebuiltStubsSourcesFactory() android.Module {
1006 module := &PrebuiltStubsSources{}
1007
1008 module.AddProperties(&module.properties)
1009
1010 android.InitPrebuiltModule(module, &module.properties.Srcs)
1011 android.InitSdkAwareModule(module)
1012 InitDroiddocModule(module, android.HostAndDeviceSupported)
1013 return module
1014}