blob: 6b8d21f8c9c21d31cb6e836b78db9c0cb5c2c187 [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"
27 "android/soong/java/config"
28 "android/soong/remoteexec"
29)
30
Pedro Loureirocc203502021-10-04 17:24:00 +000031// The values allowed for Droidstubs' Api_levels_sdk_type
Cole Faust051fa912022-10-05 12:45:42 -070032var allowedApiLevelSdkTypes = []string{"public", "system", "module-lib", "system-server"}
Pedro Loureirocc203502021-10-04 17:24:00 +000033
Colin Cross2207f872021-03-24 12:39:08 -070034func init() {
35 RegisterStubsBuildComponents(android.InitRegistrationContext)
36}
37
38func RegisterStubsBuildComponents(ctx android.RegistrationContext) {
39 ctx.RegisterModuleType("stubs_defaults", StubsDefaultsFactory)
40
41 ctx.RegisterModuleType("droidstubs", DroidstubsFactory)
42 ctx.RegisterModuleType("droidstubs_host", DroidstubsHostFactory)
43
44 ctx.RegisterModuleType("prebuilt_stubs_sources", PrebuiltStubsSourcesFactory)
45}
46
Colin Cross2207f872021-03-24 12:39:08 -070047// Droidstubs
Colin Cross2207f872021-03-24 12:39:08 -070048type Droidstubs struct {
49 Javadoc
Spandan Das2cc80ba2023-10-27 17:21:52 +000050 embeddableInModuleAndImport
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,
Liz Kammer170dd722023-10-16 15:08:39 -0400126 // which can be used for scheduling purposes
Colin Cross2207f872021-03-24 12:39:08 -0700127 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"`
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000151
152 // API surface of this module. If set, the module contributes to an API surface.
153 // For the full list of available API surfaces, refer to soong/android/sdk_version.go
154 Api_surface *string
Colin Cross2207f872021-03-24 12:39:08 -0700155}
156
Anton Hansson52609322021-05-05 10:36:05 +0100157// Used by xsd_config
158type ApiFilePath interface {
159 ApiFilePath() android.Path
160}
161
162type ApiStubsSrcProvider interface {
163 StubsSrcJar() android.Path
164}
165
166// Provider of information about API stubs, used by java_sdk_library.
167type ApiStubsProvider interface {
Anton Hanssond78eb762021-09-21 15:25:12 +0100168 AnnotationsZip() android.Path
Anton Hansson52609322021-05-05 10:36:05 +0100169 ApiFilePath
170 RemovedApiFilePath() android.Path
171
172 ApiStubsSrcProvider
173}
174
Jihoon Kang063ec002023-06-28 01:16:23 +0000175type currentApiTimestampProvider interface {
176 CurrentApiTimestamp() android.Path
177}
178
Colin Cross2207f872021-03-24 12:39:08 -0700179// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
180// documented, filtering out hidden classes and methods. The resulting .java files are intended to be passed to
181// a droiddoc module to generate documentation.
182func DroidstubsFactory() android.Module {
183 module := &Droidstubs{}
184
185 module.AddProperties(&module.properties,
186 &module.Javadoc.properties)
Spandan Das2cc80ba2023-10-27 17:21:52 +0000187 module.initModuleAndImport(module)
Colin Cross2207f872021-03-24 12:39:08 -0700188
189 InitDroiddocModule(module, android.HostAndDeviceSupported)
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000190
191 module.SetDefaultableHook(func(ctx android.DefaultableHookContext) {
192 module.createApiContribution(ctx)
193 })
Colin Cross2207f872021-03-24 12:39:08 -0700194 return module
195}
196
197// droidstubs_host passes sources files through Metalava to generate stub .java files that only contain the API
198// to be documented, filtering out hidden classes and methods. The resulting .java files are intended to be
199// passed to a droiddoc_host module to generate documentation. Use a droidstubs_host instead of a droidstubs
200// module when symbols needed by the source files are provided by java_library_host modules.
201func DroidstubsHostFactory() android.Module {
202 module := &Droidstubs{}
203
204 module.AddProperties(&module.properties,
205 &module.Javadoc.properties)
206
207 InitDroiddocModule(module, android.HostSupported)
208 return module
209}
210
211func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) {
212 switch tag {
213 case "":
214 return android.Paths{d.stubsSrcJar}, nil
215 case ".docs.zip":
216 return android.Paths{d.docZip}, nil
217 case ".api.txt", android.DefaultDistTag:
218 // This is the default dist path for dist properties that have no tag property.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000219 return android.Paths{d.apiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700220 case ".removed-api.txt":
Paul Duffinc71d2b72022-08-16 15:24:01 +0000221 return android.Paths{d.removedApiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700222 case ".annotations.zip":
223 return android.Paths{d.annotationsZip}, nil
224 case ".api_versions.xml":
225 return android.Paths{d.apiVersionsXml}, nil
226 default:
227 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
228 }
229}
230
Anton Hanssond78eb762021-09-21 15:25:12 +0100231func (d *Droidstubs) AnnotationsZip() android.Path {
232 return d.annotationsZip
233}
234
Colin Cross2207f872021-03-24 12:39:08 -0700235func (d *Droidstubs) ApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000236 return d.apiFile
Colin Cross2207f872021-03-24 12:39:08 -0700237}
238
239func (d *Droidstubs) RemovedApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000240 return d.removedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700241}
242
243func (d *Droidstubs) StubsSrcJar() android.Path {
244 return d.stubsSrcJar
245}
246
Jihoon Kang063ec002023-06-28 01:16:23 +0000247func (d *Droidstubs) CurrentApiTimestamp() android.Path {
248 return d.checkCurrentApiTimestamp
249}
250
Colin Cross2207f872021-03-24 12:39:08 -0700251var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"}
252var metalavaMergeInclusionAnnotationsDirTag = dependencyTag{name: "metalava-merge-inclusion-annotations-dir"}
253var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"}
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000254var metalavaAPILevelsModuleTag = dependencyTag{name: "metalava-api-levels-module-tag"}
Jihoon Kang063ec002023-06-28 01:16:23 +0000255var metalavaCurrentApiTimestampTag = dependencyTag{name: "metalava-current-api-timestamp-tag"}
Colin Cross2207f872021-03-24 12:39:08 -0700256
257func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) {
258 d.Javadoc.addDeps(ctx)
259
260 if len(d.properties.Merge_annotations_dirs) != 0 {
261 for _, mergeAnnotationsDir := range d.properties.Merge_annotations_dirs {
262 ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir)
263 }
264 }
265
266 if len(d.properties.Merge_inclusion_annotations_dirs) != 0 {
267 for _, mergeInclusionAnnotationsDir := range d.properties.Merge_inclusion_annotations_dirs {
268 ctx.AddDependency(ctx.Module(), metalavaMergeInclusionAnnotationsDirTag, mergeInclusionAnnotationsDir)
269 }
270 }
271
272 if len(d.properties.Api_levels_annotations_dirs) != 0 {
273 for _, apiLevelsAnnotationsDir := range d.properties.Api_levels_annotations_dirs {
274 ctx.AddDependency(ctx.Module(), metalavaAPILevelsAnnotationsDirTag, apiLevelsAnnotationsDir)
275 }
276 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000277
278 if d.properties.Api_levels_module != nil {
279 ctx.AddDependency(ctx.Module(), metalavaAPILevelsModuleTag, proptools.String(d.properties.Api_levels_module))
280 }
Colin Cross2207f872021-03-24 12:39:08 -0700281}
282
283func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) {
284 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
285 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
286 String(d.properties.Api_filename) != "" {
287 filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000288 uncheckedApiFile := android.PathForModuleOut(ctx, "metalava", filename)
289 cmd.FlagWithOutput("--api ", uncheckedApiFile)
290 d.apiFile = uncheckedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700291 } else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" {
292 // If check api is disabled then make the source file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000293 d.apiFile = android.PathForModuleSrc(ctx, sourceApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700294 }
295
296 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
297 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
298 String(d.properties.Removed_api_filename) != "" {
299 filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000300 uncheckedRemovedFile := android.PathForModuleOut(ctx, "metalava", filename)
301 cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile)
302 d.removedApiFile = uncheckedRemovedFile
Colin Cross2207f872021-03-24 12:39:08 -0700303 } else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" {
304 // If check api is disabled then make the source removed api file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000305 d.removedApiFile = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700306 }
307
Colin Cross2207f872021-03-24 12:39:08 -0700308 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700309 d.metadataDir = android.PathForModuleOut(ctx, "metalava", "metadata")
Colin Cross2207f872021-03-24 12:39:08 -0700310 cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
311 }
312
313 if stubsDir.Valid() {
314 if Bool(d.properties.Create_doc_stubs) {
315 cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
316 } else {
317 cmd.FlagWithArg("--stubs ", stubsDir.String())
318 if !Bool(d.properties.Output_javadoc_comments) {
319 cmd.Flag("--exclude-documentation-from-stubs")
320 }
321 }
322 }
323}
324
325func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
326 if Bool(d.properties.Annotations_enabled) {
Liz Kammere09e20e2023-10-16 15:07:54 -0400327 cmd.Flag(config.MetalavaAnnotationsFlags)
Andrei Onea4985e512021-04-29 16:29:34 +0100328
Colin Cross2207f872021-03-24 12:39:08 -0700329 validatingNullability :=
Colin Crossbc139922021-03-25 18:33:16 -0700330 strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") ||
Colin Cross2207f872021-03-24 12:39:08 -0700331 String(d.properties.Validate_nullability_from_list) != ""
332
333 migratingNullability := String(d.properties.Previous_api) != ""
334 if migratingNullability {
335 previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
336 cmd.FlagWithInput("--migrate-nullness ", previousApi)
337 }
338
339 if s := String(d.properties.Validate_nullability_from_list); s != "" {
340 cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
341 }
342
343 if validatingNullability {
Colin Crosscb77f752021-03-24 12:04:44 -0700344 d.nullabilityWarningsFile = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_nullability_warnings.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700345 cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile)
346 }
347
Colin Crosscb77f752021-03-24 12:04:44 -0700348 d.annotationsZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_annotations.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700349 cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip)
350
351 if len(d.properties.Merge_annotations_dirs) != 0 {
352 d.mergeAnnoDirFlags(ctx, cmd)
353 }
354
Liz Kammere09e20e2023-10-16 15:07:54 -0400355 cmd.Flag(config.MetalavaAnnotationsWarningsFlags)
Colin Cross2207f872021-03-24 12:39:08 -0700356 }
357}
358
359func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
360 ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
361 if t, ok := m.(*ExportedDroiddocDir); ok {
362 cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps)
363 } else {
364 ctx.PropertyErrorf("merge_annotations_dirs",
365 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
366 }
367 })
368}
369
370func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
371 ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) {
372 if t, ok := m.(*ExportedDroiddocDir); ok {
373 cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps)
374 } else {
375 ctx.PropertyErrorf("merge_inclusion_annotations_dirs",
376 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
377 }
378 })
379}
380
381func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000382 var apiVersions android.Path
383 if proptools.Bool(d.properties.Api_levels_annotations_enabled) {
384 d.apiLevelsGenerationFlags(ctx, cmd)
385 apiVersions = d.apiVersionsXml
386 } else {
387 ctx.VisitDirectDepsWithTag(metalavaAPILevelsModuleTag, func(m android.Module) {
388 if s, ok := m.(*Droidstubs); ok {
389 apiVersions = s.apiVersionsXml
390 } else {
391 ctx.PropertyErrorf("api_levels_module",
392 "module %q is not a droidstubs module", ctx.OtherModuleName(m))
393 }
394 })
Colin Cross2207f872021-03-24 12:39:08 -0700395 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000396 if apiVersions != nil {
397 cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion().String())
398 cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename())
399 cmd.FlagWithInput("--apply-api-levels ", apiVersions)
400 }
401}
Colin Cross2207f872021-03-24 12:39:08 -0700402
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000403func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Colin Cross2207f872021-03-24 12:39:08 -0700404 if len(d.properties.Api_levels_annotations_dirs) == 0 {
405 ctx.PropertyErrorf("api_levels_annotations_dirs",
406 "has to be non-empty if api levels annotations was enabled!")
407 }
408
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000409 d.apiVersionsXml = android.PathForModuleOut(ctx, "metalava", "api-versions.xml")
Colin Cross2207f872021-03-24 12:39:08 -0700410 cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml)
Colin Cross2207f872021-03-24 12:39:08 -0700411
412 filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar")
413
satayev783195c2021-06-23 21:49:57 +0100414 var dirs []string
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200415 var extensions_dir string
Colin Cross2207f872021-03-24 12:39:08 -0700416 ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
417 if t, ok := m.(*ExportedDroiddocDir); ok {
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200418 extRegex := regexp.MustCompile(t.dir.String() + `/extensions/[0-9]+/public/.*\.jar`)
419
420 // Grab the first extensions_dir and we find while scanning ExportedDroiddocDir.deps;
421 // ideally this should be read from prebuiltApis.properties.Extensions_*
Colin Cross2207f872021-03-24 12:39:08 -0700422 for _, dep := range t.deps {
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200423 if extRegex.MatchString(dep.String()) && d.properties.Extensions_info_file != nil {
424 if extensions_dir == "" {
425 extensions_dir = t.dir.String() + "/extensions"
426 }
427 cmd.Implicit(dep)
428 }
Colin Cross5f6ffc72021-03-29 21:54:45 -0700429 if dep.Base() == filename {
430 cmd.Implicit(dep)
431 }
432 if filename != "android.jar" && dep.Base() == "android.jar" {
433 // Metalava implicitly searches these patterns:
434 // prebuilts/tools/common/api-versions/android-%/android.jar
435 // prebuilts/sdk/%/public/android.jar
436 // Add android.jar files from the api_levels_annotations_dirs directories to try
437 // to satisfy these patterns. If Metalava can't find a match for an API level
438 // between 1 and 28 in at least one pattern it will fail.
Colin Cross2207f872021-03-24 12:39:08 -0700439 cmd.Implicit(dep)
440 }
441 }
satayev783195c2021-06-23 21:49:57 +0100442
443 dirs = append(dirs, t.dir.String())
Colin Cross2207f872021-03-24 12:39:08 -0700444 } else {
445 ctx.PropertyErrorf("api_levels_annotations_dirs",
446 "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
447 }
448 })
satayev783195c2021-06-23 21:49:57 +0100449
450 // Add all relevant --android-jar-pattern patterns for Metalava.
451 // When parsing a stub jar for a specific version, Metalava picks the first pattern that defines
452 // an actual file present on disk (in the order the patterns were passed). For system APIs for
453 // privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs
Pedro Loureirocc203502021-10-04 17:24:00 +0000454 // for older releases. Similarly, module-lib falls back to system API.
455 var sdkDirs []string
456 switch proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") {
Cole Faust051fa912022-10-05 12:45:42 -0700457 case "system-server":
458 sdkDirs = []string{"system-server", "module-lib", "system", "public"}
Pedro Loureirocc203502021-10-04 17:24:00 +0000459 case "module-lib":
460 sdkDirs = []string{"module-lib", "system", "public"}
461 case "system":
462 sdkDirs = []string{"system", "public"}
463 case "public":
464 sdkDirs = []string{"public"}
465 default:
466 ctx.PropertyErrorf("api_levels_sdk_type", "needs to be one of %v", allowedApiLevelSdkTypes)
467 return
satayev783195c2021-06-23 21:49:57 +0100468 }
Pedro Loureirocc203502021-10-04 17:24:00 +0000469
470 for _, sdkDir := range sdkDirs {
471 for _, dir := range dirs {
472 cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, filename))
473 }
satayev783195c2021-06-23 21:49:57 +0100474 }
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200475
476 if d.properties.Extensions_info_file != nil {
477 if extensions_dir == "" {
478 ctx.ModuleErrorf("extensions_info_file set, but no SDK extension dirs found")
479 }
480 info_file := android.PathForModuleSrc(ctx, *d.properties.Extensions_info_file)
481 cmd.Implicit(info_file)
482 cmd.FlagWithArg("--sdk-extensions-root ", extensions_dir)
483 cmd.FlagWithArg("--sdk-extensions-info ", info_file.String())
484 }
Colin Cross2207f872021-03-24 12:39:08 -0700485}
486
Colin Crosse52c2ac2022-03-28 17:03:35 -0700487func metalavaUseRbe(ctx android.ModuleContext) bool {
488 return ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA")
489}
490
Colin Cross2207f872021-03-24 12:39:08 -0700491func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
Anton Hansson556e8142021-06-04 16:20:25 +0100492 srcJarList android.Path, bootclasspath, classpath classpath, homeDir android.WritablePath) *android.RuleBuilderCommand {
Colin Cross2207f872021-03-24 12:39:08 -0700493 rule.Command().Text("rm -rf").Flag(homeDir.String())
494 rule.Command().Text("mkdir -p").Flag(homeDir.String())
495
Anton Hansson556e8142021-06-04 16:20:25 +0100496 cmd := rule.Command()
Colin Cross2207f872021-03-24 12:39:08 -0700497 cmd.FlagWithArg("ANDROID_PREFS_ROOT=", homeDir.String())
498
Colin Crosse52c2ac2022-03-28 17:03:35 -0700499 if metalavaUseRbe(ctx) {
Colin Cross2207f872021-03-24 12:39:08 -0700500 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
Colin Cross8095c292021-03-30 16:40:48 -0700501 execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
Anas Sulaiman9d7a36d2023-11-21 23:00:07 +0000502 compare := ctx.Config().IsEnvTrue("RBE_METALAVA_COMPARE")
503 remoteUpdateCache := !ctx.Config().IsEnvFalse("RBE_METALAVA_REMOTE_UPDATE_CACHE")
Colin Cross8095c292021-03-30 16:40:48 -0700504 labels := map[string]string{"type": "tool", "name": "metalava"}
505 // TODO: metalava pool rejects these jobs
506 pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
507 rule.Rewrapper(&remoteexec.REParams{
Anas Sulaiman9d7a36d2023-11-21 23:00:07 +0000508 Labels: labels,
509 ExecStrategy: execStrategy,
510 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
511 Platform: map[string]string{remoteexec.PoolKey: pool},
512 Compare: compare,
513 NumLocalRuns: 1,
514 NumRemoteRuns: 1,
515 NoRemoteUpdateCache: !remoteUpdateCache,
Colin Cross8095c292021-03-30 16:40:48 -0700516 })
Colin Cross2207f872021-03-24 12:39:08 -0700517 }
518
Colin Cross6aa5c402021-03-24 12:28:50 -0700519 cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
Colin Cross2207f872021-03-24 12:39:08 -0700520 Flag(config.JavacVmFlags).
Liz Kammere09e20e2023-10-16 15:07:54 -0400521 Flag(config.MetalavaAddOpens).
Paul Duffin808211e2023-08-09 12:36:08 +0100522 FlagWithArg("--java-source ", javaVersion.String()).
Colin Cross2207f872021-03-24 12:39:08 -0700523 FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs).
524 FlagWithInput("@", srcJarList)
525
Paul Duffinf8aaaa12023-08-10 15:16:35 +0100526 // Metalava does not differentiate between bootclasspath and classpath and has not done so for
527 // years, so it is unlikely to change any time soon.
528 combinedPaths := append(([]android.Path)(nil), bootclasspath.Paths()...)
529 combinedPaths = append(combinedPaths, classpath.Paths()...)
530 if len(combinedPaths) > 0 {
531 cmd.FlagWithInputList("--classpath ", combinedPaths, ":")
Colin Cross2207f872021-03-24 12:39:08 -0700532 }
533
Liz Kammere09e20e2023-10-16 15:07:54 -0400534 cmd.Flag(config.MetalavaFlags)
Jihoon Kangc8313892023-09-20 00:54:47 +0000535 if ctx.DeviceConfig().HideFlaggedApis() {
Liz Kammere09e20e2023-10-16 15:07:54 -0400536 cmd.Flag(config.MetalavaHideFlaggedApis)
Jihoon Kangc8313892023-09-20 00:54:47 +0000537 }
538
Colin Cross2207f872021-03-24 12:39:08 -0700539 return cmd
540}
541
542func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
543 deps := d.Javadoc.collectDeps(ctx)
544
Jiyong Parkf1691d22021-03-29 20:11:58 +0900545 javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d))
Colin Cross2207f872021-03-24 12:39:08 -0700546
547 // Create rule for metalava
548
Colin Crosscb77f752021-03-24 12:04:44 -0700549 srcJarDir := android.PathForModuleOut(ctx, "metalava", "srcjars")
Colin Cross2207f872021-03-24 12:39:08 -0700550
551 rule := android.NewRuleBuilder(pctx, ctx)
552
Colin Cross8095c292021-03-30 16:40:48 -0700553 rule.Sbox(android.PathForModuleOut(ctx, "metalava"),
554 android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
555 SandboxInputs()
Colin Cross6aa5c402021-03-24 12:28:50 -0700556
Colin Cross2207f872021-03-24 12:39:08 -0700557 if BoolDefault(d.properties.High_mem, false) {
558 // This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel.
559 rule.HighMem()
560 }
561
562 generateStubs := BoolDefault(d.properties.Generate_stubs, true)
563 var stubsDir android.OptionalPath
564 if generateStubs {
Colin Crosscb77f752021-03-24 12:04:44 -0700565 d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
566 stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "metalava", "stubsDir"))
Colin Cross2207f872021-03-24 12:39:08 -0700567 rule.Command().Text("rm -rf").Text(stubsDir.String())
568 rule.Command().Text("mkdir -p").Text(stubsDir.String())
569 }
570
571 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
572
Colin Crosscb77f752021-03-24 12:04:44 -0700573 homeDir := android.PathForModuleOut(ctx, "metalava", "home")
Colin Cross2207f872021-03-24 12:39:08 -0700574 cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
Anton Hansson556e8142021-06-04 16:20:25 +0100575 deps.bootClasspath, deps.classpath, homeDir)
Colin Cross2207f872021-03-24 12:39:08 -0700576 cmd.Implicits(d.Javadoc.implicits)
577
578 d.stubsFlags(ctx, cmd, stubsDir)
579
580 d.annotationsFlags(ctx, cmd)
581 d.inclusionAnnotationsFlags(ctx, cmd)
582 d.apiLevelsAnnotationsFlags(ctx, cmd)
583
Colin Crossbc139922021-03-25 18:33:16 -0700584 d.expandArgs(ctx, cmd)
Colin Cross2207f872021-03-24 12:39:08 -0700585
Colin Cross2207f872021-03-24 12:39:08 -0700586 for _, o := range d.Javadoc.properties.Out {
587 cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
588 }
589
590 // Add options for the other optional tasks: API-lint and check-released.
591 // We generate separate timestamp files for them.
592
593 doApiLint := false
594 doCheckReleased := false
595
596 // Add API lint options.
597
598 if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) {
599 doApiLint = true
600
601 newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since)
602 if newSince.Valid() {
603 cmd.FlagWithInput("--api-lint ", newSince.Path())
604 } else {
605 cmd.Flag("--api-lint")
606 }
Colin Crosscb77f752021-03-24 12:04:44 -0700607 d.apiLintReport = android.PathForModuleOut(ctx, "metalava", "api_lint_report.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700608 cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO: Change to ":api-lint"
609
Colin Cross0d532412021-03-25 09:38:45 -0700610 // TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released.
Colin Cross2207f872021-03-24 12:39:08 -0700611 if d.Name() != "android.car-system-stubs-docs" &&
612 d.Name() != "android.car-stubs-docs" {
613 cmd.Flag("--lints-as-errors")
614 cmd.Flag("--warnings-as-errors") // Most lints are actually warnings.
615 }
616
617 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700618 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "api_lint_baseline.txt")
619 d.apiLintTimestamp = android.PathForModuleOut(ctx, "metalava", "api_lint.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700620
621 // Note this string includes a special shell quote $' ... ', which decodes the "\n"s.
Colin Cross2207f872021-03-24 12:39:08 -0700622 //
623 // TODO: metalava also has a slightly different message hardcoded. Should we unify this
624 // message and metalava's one?
625 msg := `$'` + // Enclose with $' ... '
626 `************************************************************\n` +
627 `Your API changes are triggering API Lint warnings or errors.\n` +
628 `To make these errors go away, fix the code according to the\n` +
629 `error and/or warning messages above.\n` +
630 `\n` +
631 `If it is not possible to do so, there are workarounds:\n` +
632 `\n` +
Aurimas Liutikasb23b7452021-05-24 18:00:37 +0000633 `1. You can suppress the errors with @SuppressLint("<id>")\n` +
634 ` where the <id> is given in brackets in the error message above.\n`
Colin Cross2207f872021-03-24 12:39:08 -0700635
636 if baselineFile.Valid() {
637 cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path())
638 cmd.FlagWithOutput("--update-baseline:api-lint ", updatedBaselineOutput)
639
640 msg += fmt.Sprintf(``+
641 `2. You can update the baseline by executing the following\n`+
642 ` command:\n`+
Colin Cross63eeda02021-04-15 19:01:57 -0700643 ` (cd $ANDROID_BUILD_TOP && cp \\\n`+
644 ` "%s" \\\n`+
645 ` "%s")\n`+
Colin Cross2207f872021-03-24 12:39:08 -0700646 ` To submit the revised baseline.txt to the main Android\n`+
647 ` repository, you will need approval.\n`, updatedBaselineOutput, baselineFile.Path())
648 } else {
649 msg += fmt.Sprintf(``+
650 `2. You can add a baseline file of existing lint failures\n`+
651 ` to the build rule of %s.\n`, d.Name())
652 }
653 // Note the message ends with a ' (single quote), to close the $' ... ' .
654 msg += `************************************************************\n'`
655
656 cmd.FlagWithArg("--error-message:api-lint ", msg)
657 }
658
659 // Add "check released" options. (Detect incompatible API changes from the last public release)
660
661 if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") {
662 doCheckReleased = true
663
664 if len(d.Javadoc.properties.Out) > 0 {
665 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
666 }
667
668 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
669 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
670 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700671 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "last_released_baseline.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700672
Colin Crosscb77f752021-03-24 12:04:44 -0700673 d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_last_released_api.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700674
675 cmd.FlagWithInput("--check-compatibility:api:released ", apiFile)
676 cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile)
677
678 if baselineFile.Valid() {
679 cmd.FlagWithInput("--baseline:compatibility:released ", baselineFile.Path())
680 cmd.FlagWithOutput("--update-baseline:compatibility:released ", updatedBaselineOutput)
681 }
682
683 // Note this string includes quote ($' ... '), which decodes the "\n"s.
684 msg := `$'\n******************************\n` +
685 `You have tried to change the API from what has been previously released in\n` +
686 `an SDK. Please fix the errors listed above.\n` +
687 `******************************\n'`
688
689 cmd.FlagWithArg("--error-message:compatibility:released ", msg)
690 }
691
Paul Duffin10a23c22023-08-11 22:47:31 +0100692 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
693 // Pass the current API file into metalava so it can use it as the basis for determining how to
694 // generate the output signature files (both api and removed).
695 currentApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
696 cmd.FlagWithInput("--use-same-format-as ", currentApiFile)
697 }
698
Colin Cross2207f872021-03-24 12:39:08 -0700699 if generateStubs {
700 rule.Command().
701 BuiltTool("soong_zip").
702 Flag("-write_if_changed").
703 Flag("-jar").
704 FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
705 FlagWithArg("-C ", stubsDir.String()).
706 FlagWithArg("-D ", stubsDir.String())
707 }
708
709 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700710 d.metadataZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-metadata.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700711 rule.Command().
712 BuiltTool("soong_zip").
713 Flag("-write_if_changed").
714 Flag("-d").
715 FlagWithOutput("-o ", d.metadataZip).
716 FlagWithArg("-C ", d.metadataDir.String()).
717 FlagWithArg("-D ", d.metadataDir.String())
718 }
719
720 // TODO: We don't really need two separate API files, but this is a reminiscence of how
721 // we used to run metalava separately for API lint and the "last_released" check. Unify them.
722 if doApiLint {
723 rule.Command().Text("touch").Output(d.apiLintTimestamp)
724 }
725 if doCheckReleased {
726 rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp)
727 }
728
Colin Cross6aa5c402021-03-24 12:28:50 -0700729 // TODO(b/183630617): rewrapper doesn't support restat rules
Colin Crosse52c2ac2022-03-28 17:03:35 -0700730 if !metalavaUseRbe(ctx) {
731 rule.Restat()
732 }
Colin Cross2207f872021-03-24 12:39:08 -0700733
734 zipSyncCleanupCmd(rule, srcJarDir)
735
Paul Duffinc166b682022-05-27 12:23:08 +0000736 rule.Build("metalava", "metalava merged")
737
Paul Duffine7a86642022-08-16 15:43:20 +0000738 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
739
740 if len(d.Javadoc.properties.Out) > 0 {
741 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
742 }
743
744 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
745 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
746 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)
747
748 if baselineFile.Valid() {
749 ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
750 }
751
752 d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp")
753
754 rule := android.NewRuleBuilder(pctx, ctx)
755
756 // Diff command line.
757 // -F matches the closest "opening" line, such as "package android {"
758 // and " public class Intent {".
759 diff := `diff -u -F '{ *$'`
760
761 rule.Command().Text("( true")
762 rule.Command().
763 Text(diff).
764 Input(apiFile).Input(d.apiFile)
765
766 rule.Command().
767 Text(diff).
768 Input(removedApiFile).Input(d.removedApiFile)
769
770 msg := fmt.Sprintf(`\n******************************\n`+
771 `You have tried to change the API from what has been previously approved.\n\n`+
772 `To make these errors go away, you have two choices:\n`+
773 ` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
774 ` to the new methods, etc. shown in the above diff.\n\n`+
775 ` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+
776 ` m %s-update-current-api\n\n`+
777 ` To submit the revised current.txt to the main Android repository,\n`+
778 ` you will need approval.\n`+
Jihoon Kang3ea64672023-11-03 00:40:26 +0000779 `If your build failed due to stub validation, you can resolve the errors with\n`+
780 `either of the two choices above and try re-building the target.\n`+
781 `If the mismatch between the stubs and the current.txt is intended,\n`+
782 `you can try re-building the target by executing the following command:\n`+
783 `m DISABLE_STUB_VALIDATION=true <your build target>\n`+
Paul Duffine7a86642022-08-16 15:43:20 +0000784 `******************************\n`, ctx.ModuleName())
785
786 rule.Command().
787 Text("touch").Output(d.checkCurrentApiTimestamp).
788 Text(") || (").
789 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
790 Text("; exit 38").
791 Text(")")
792
793 rule.Build("metalavaCurrentApiCheck", "check current API")
794
795 d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "update_current_api.timestamp")
796
797 // update API rule
798 rule = android.NewRuleBuilder(pctx, ctx)
799
800 rule.Command().Text("( true")
801
802 rule.Command().
803 Text("cp").Flag("-f").
804 Input(d.apiFile).Flag(apiFile.String())
805
806 rule.Command().
807 Text("cp").Flag("-f").
808 Input(d.removedApiFile).Flag(removedApiFile.String())
809
810 msg = "failed to update public API"
811
812 rule.Command().
813 Text("touch").Output(d.updateCurrentApiTimestamp).
814 Text(") || (").
815 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
816 Text("; exit 38").
817 Text(")")
818
819 rule.Build("metalavaCurrentApiUpdate", "update current API")
820 }
821
Colin Cross2207f872021-03-24 12:39:08 -0700822 if String(d.properties.Check_nullability_warnings) != "" {
823 if d.nullabilityWarningsFile == nil {
824 ctx.PropertyErrorf("check_nullability_warnings",
825 "Cannot specify check_nullability_warnings unless validating nullability")
826 }
827
828 checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings))
829
Colin Crosscb77f752021-03-24 12:04:44 -0700830 d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "metalava", "check_nullability_warnings.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700831
832 msg := fmt.Sprintf(`\n******************************\n`+
833 `The warnings encountered during nullability annotation validation did\n`+
834 `not match the checked in file of expected warnings. The diffs are shown\n`+
835 `above. You have two options:\n`+
836 ` 1. Resolve the differences by editing the nullability annotations.\n`+
837 ` 2. Update the file of expected warnings by running:\n`+
838 ` cp %s %s\n`+
839 ` and submitting the updated file as part of your change.`,
840 d.nullabilityWarningsFile, checkNullabilityWarnings)
841
842 rule := android.NewRuleBuilder(pctx, ctx)
843
844 rule.Command().
845 Text("(").
846 Text("diff").Input(checkNullabilityWarnings).Input(d.nullabilityWarningsFile).
847 Text("&&").
848 Text("touch").Output(d.checkNullabilityWarningsTimestamp).
849 Text(") || (").
850 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
851 Text("; exit 38").
852 Text(")")
853
854 rule.Build("nullabilityWarningsCheck", "nullability warnings check")
855 }
856}
857
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000858func (d *Droidstubs) createApiContribution(ctx android.DefaultableHookContext) {
859 api_file := d.properties.Check_api.Current.Api_file
860 api_surface := d.properties.Api_surface
861
862 props := struct {
863 Name *string
864 Api_surface *string
865 Api_file *string
Jihoon Kang42b589c2023-02-03 22:56:13 +0000866 Visibility []string
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000867 }{}
868
869 props.Name = proptools.StringPtr(d.Name() + ".api.contribution")
870 props.Api_surface = api_surface
871 props.Api_file = api_file
Jihoon Kang42b589c2023-02-03 22:56:13 +0000872 props.Visibility = []string{"//visibility:override", "//visibility:public"}
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000873
874 ctx.CreateModule(ApiContributionFactory, &props)
875}
876
Spandan Das0b555e32022-11-28 18:48:51 +0000877// TODO (b/262014796): Export the API contributions of CorePlatformApi
878// A map to populate the api surface of a droidstub from a substring appearing in its name
879// This map assumes that droidstubs (either checked-in or created by java_sdk_library)
880// use a strict naming convention
881var (
882 droidstubsModuleNamingToSdkKind = map[string]android.SdkKind{
883 //public is commented out since the core libraries use public in their java_sdk_library names
884 "intracore": android.SdkIntraCore,
885 "intra.core": android.SdkIntraCore,
886 "system_server": android.SdkSystemServer,
887 "system-server": android.SdkSystemServer,
888 "system": android.SdkSystem,
889 "module_lib": android.SdkModule,
890 "module-lib": android.SdkModule,
Spandan Dasda977552023-01-26 20:45:16 +0000891 "platform.api": android.SdkCorePlatform,
Spandan Das0b555e32022-11-28 18:48:51 +0000892 "test": android.SdkTest,
Spandan Das4ac2aed2022-12-28 01:54:29 +0000893 "toolchain": android.SdkToolchain,
Spandan Das0b555e32022-11-28 18:48:51 +0000894 }
895)
896
897// A helper function that returns the api surface of the corresponding java_api_contribution Bazel target
898// The api_surface is populated using the naming convention of the droidstubs module.
899func bazelApiSurfaceName(name string) string {
900 // Sort the keys so that longer strings appear first
901 // Otherwise substrings like system will match both system and system_server
902 sortedKeys := make([]string, 0)
903 for key := range droidstubsModuleNamingToSdkKind {
904 sortedKeys = append(sortedKeys, key)
905 }
906 sort.Slice(sortedKeys, func(i, j int) bool {
907 return len(sortedKeys[i]) > len(sortedKeys[j])
908 })
909 for _, sortedKey := range sortedKeys {
910 if strings.Contains(name, sortedKey) {
911 sdkKind := droidstubsModuleNamingToSdkKind[sortedKey]
912 return sdkKind.String() + "api"
913 }
914 }
915 // Default is publicapi
916 return android.SdkPublic.String() + "api"
917}
918
Colin Cross2207f872021-03-24 12:39:08 -0700919func StubsDefaultsFactory() android.Module {
920 module := &DocDefaults{}
921
922 module.AddProperties(
923 &JavadocProperties{},
924 &DroidstubsProperties{},
925 )
926
927 android.InitDefaultsModule(module)
928
929 return module
930}
931
932var _ android.PrebuiltInterface = (*PrebuiltStubsSources)(nil)
933
934type PrebuiltStubsSourcesProperties struct {
935 Srcs []string `android:"path"`
936}
937
938type PrebuiltStubsSources struct {
939 android.ModuleBase
940 android.DefaultableModuleBase
Spandan Das2cc80ba2023-10-27 17:21:52 +0000941 embeddableInModuleAndImport
942
Colin Cross2207f872021-03-24 12:39:08 -0700943 prebuilt android.Prebuilt
Colin Cross2207f872021-03-24 12:39:08 -0700944
945 properties PrebuiltStubsSourcesProperties
946
kgui67007242022-01-25 13:50:25 +0800947 stubsSrcJar android.Path
Colin Cross2207f872021-03-24 12:39:08 -0700948}
949
950func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
951 switch tag {
952 case "":
953 return android.Paths{p.stubsSrcJar}, nil
954 default:
955 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
956 }
957}
958
959func (d *PrebuiltStubsSources) StubsSrcJar() android.Path {
960 return d.stubsSrcJar
961}
962
963func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Cross2207f872021-03-24 12:39:08 -0700964 if len(p.properties.Srcs) != 1 {
Anton Hansson86758ac2021-11-03 14:44:12 +0000965 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 -0700966 return
967 }
968
Anton Hansson86758ac2021-11-03 14:44:12 +0000969 src := p.properties.Srcs[0]
970 if filepath.Ext(src) == ".srcjar" {
971 // This is a srcjar. We can use it directly.
972 p.stubsSrcJar = android.PathForModuleSrc(ctx, src)
973 } else {
974 outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
Colin Cross2207f872021-03-24 12:39:08 -0700975
Anton Hansson86758ac2021-11-03 14:44:12 +0000976 // This is a directory. Glob the contents just in case the directory does not exist.
977 srcGlob := src + "/**/*"
978 srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
Colin Cross2207f872021-03-24 12:39:08 -0700979
Anton Hansson86758ac2021-11-03 14:44:12 +0000980 // Although PathForModuleSrc can return nil if either the path doesn't exist or
981 // the path components are invalid it won't in this case because no components
982 // are specified and the module directory must exist in order to get this far.
983 srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, src)
Colin Cross2207f872021-03-24 12:39:08 -0700984
Anton Hansson86758ac2021-11-03 14:44:12 +0000985 rule := android.NewRuleBuilder(pctx, ctx)
986 rule.Command().
987 BuiltTool("soong_zip").
988 Flag("-write_if_changed").
989 Flag("-jar").
990 FlagWithOutput("-o ", outPath).
991 FlagWithArg("-C ", srcDir.String()).
992 FlagWithRspFileInputList("-r ", outPath.ReplaceExtension(ctx, "rsp"), srcPaths)
993 rule.Restat()
994 rule.Build("zip src", "Create srcjar from prebuilt source")
995 p.stubsSrcJar = outPath
996 }
Colin Cross2207f872021-03-24 12:39:08 -0700997}
998
999func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
1000 return &p.prebuilt
1001}
1002
1003func (p *PrebuiltStubsSources) Name() string {
1004 return p.prebuilt.Name(p.ModuleBase.Name())
1005}
1006
1007// prebuilt_stubs_sources imports a set of java source files as if they were
1008// generated by droidstubs.
1009//
1010// By default, a prebuilt_stubs_sources has a single variant that expects a
1011// set of `.java` files generated by droidstubs.
1012//
1013// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one
1014// for host modules.
1015//
1016// Intended only for use by sdk snapshots.
1017func PrebuiltStubsSourcesFactory() android.Module {
1018 module := &PrebuiltStubsSources{}
1019
1020 module.AddProperties(&module.properties)
Spandan Das2cc80ba2023-10-27 17:21:52 +00001021 module.initModuleAndImport(module)
Colin Cross2207f872021-03-24 12:39:08 -07001022
1023 android.InitPrebuiltModule(module, &module.properties.Srcs)
Colin Cross2207f872021-03-24 12:39:08 -07001024 InitDroiddocModule(module, android.HostAndDeviceSupported)
1025 return module
1026}