blob: 5432ce7f5d218c52281b427c337ad99b155d27f6 [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
Colin Cross2207f872021-03-24 12:39:08 -070050
51 properties DroidstubsProperties
Paul Duffinc71d2b72022-08-16 15:24:01 +000052 apiFile android.Path
53 removedApiFile android.Path
Colin Cross2207f872021-03-24 12:39:08 -070054 nullabilityWarningsFile android.WritablePath
55
56 checkCurrentApiTimestamp android.WritablePath
57 updateCurrentApiTimestamp android.WritablePath
58 checkLastReleasedApiTimestamp android.WritablePath
59 apiLintTimestamp android.WritablePath
60 apiLintReport android.WritablePath
61
62 checkNullabilityWarningsTimestamp android.WritablePath
63
64 annotationsZip android.WritablePath
65 apiVersionsXml android.WritablePath
66
Colin Cross2207f872021-03-24 12:39:08 -070067 metadataZip android.WritablePath
68 metadataDir android.WritablePath
69}
70
71type DroidstubsProperties struct {
72 // The generated public API filename by Metalava, defaults to <module>_api.txt
73 Api_filename *string
74
75 // the generated removed API filename by Metalava, defaults to <module>_removed.txt
76 Removed_api_filename *string
77
Colin Cross2207f872021-03-24 12:39:08 -070078 Check_api struct {
79 Last_released ApiToCheck
80
81 Current ApiToCheck
82
83 Api_lint struct {
84 Enabled *bool
85
86 // If set, performs api_lint on any new APIs not found in the given signature file
87 New_since *string `android:"path"`
88
89 // If not blank, path to the baseline txt file for approved API lint violations.
90 Baseline_file *string `android:"path"`
91 }
92 }
93
94 // user can specify the version of previous released API file in order to do compatibility check.
95 Previous_api *string `android:"path"`
96
97 // is set to true, Metalava will allow framework SDK to contain annotations.
98 Annotations_enabled *bool
99
100 // a list of top-level directories containing files to merge qualifier annotations (i.e. those intended to be included in the stubs written) from.
101 Merge_annotations_dirs []string
102
103 // a list of top-level directories containing Java stub files to merge show/hide annotations from.
104 Merge_inclusion_annotations_dirs []string
105
106 // a file containing a list of classes to do nullability validation for.
107 Validate_nullability_from_list *string
108
109 // a file containing expected warnings produced by validation of nullability annotations.
110 Check_nullability_warnings *string
111
112 // if set to true, allow Metalava to generate doc_stubs source files. Defaults to false.
113 Create_doc_stubs *bool
114
115 // if set to true, cause Metalava to output Javadoc comments in the stubs source files. Defaults to false.
116 // Has no effect if create_doc_stubs: true.
117 Output_javadoc_comments *bool
118
119 // if set to false then do not write out stubs. Defaults to true.
120 //
121 // TODO(b/146727827): Remove capability when we do not need to generate stubs and API separately.
122 Generate_stubs *bool
123
124 // if set to true, provides a hint to the build system that this rule uses a lot of memory,
125 // whicih can be used for scheduling purposes
126 High_mem *bool
127
satayev783195c2021-06-23 21:49:57 +0100128 // if set to true, Metalava will allow framework SDK to contain API levels annotations.
Colin Cross2207f872021-03-24 12:39:08 -0700129 Api_levels_annotations_enabled *bool
130
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000131 // Apply the api levels database created by this module rather than generating one in this droidstubs.
132 Api_levels_module *string
133
Colin Cross2207f872021-03-24 12:39:08 -0700134 // the dirs which Metalava extracts API levels annotations from.
135 Api_levels_annotations_dirs []string
136
Cole Faust051fa912022-10-05 12:45:42 -0700137 // 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 +0100138 Api_levels_sdk_type *string
139
Colin Cross2207f872021-03-24 12:39:08 -0700140 // the filename which Metalava extracts API levels annotations from. Defaults to android.jar.
141 Api_levels_jar_filename *string
142
143 // if set to true, collect the values used by the Dev tools and
144 // write them in files packaged with the SDK. Defaults to false.
145 Write_sdk_values *bool
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200146
147 // path or filegroup to file defining extension an SDK name <-> numerical ID mapping and
148 // what APIs exist in which SDKs; passed to metalava via --sdk-extensions-info
149 Extensions_info_file *string `android:"path"`
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000150
151 // API surface of this module. If set, the module contributes to an API surface.
152 // For the full list of available API surfaces, refer to soong/android/sdk_version.go
153 Api_surface *string
Colin Cross2207f872021-03-24 12:39:08 -0700154}
155
Anton Hansson52609322021-05-05 10:36:05 +0100156// Used by xsd_config
157type ApiFilePath interface {
158 ApiFilePath() android.Path
159}
160
161type ApiStubsSrcProvider interface {
162 StubsSrcJar() android.Path
163}
164
165// Provider of information about API stubs, used by java_sdk_library.
166type ApiStubsProvider interface {
Anton Hanssond78eb762021-09-21 15:25:12 +0100167 AnnotationsZip() android.Path
Anton Hansson52609322021-05-05 10:36:05 +0100168 ApiFilePath
169 RemovedApiFilePath() android.Path
170
171 ApiStubsSrcProvider
172}
173
Colin Cross2207f872021-03-24 12:39:08 -0700174// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
175// documented, filtering out hidden classes and methods. The resulting .java files are intended to be passed to
176// a droiddoc module to generate documentation.
177func DroidstubsFactory() android.Module {
178 module := &Droidstubs{}
179
180 module.AddProperties(&module.properties,
181 &module.Javadoc.properties)
182
183 InitDroiddocModule(module, android.HostAndDeviceSupported)
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000184
185 module.SetDefaultableHook(func(ctx android.DefaultableHookContext) {
186 module.createApiContribution(ctx)
187 })
Colin Cross2207f872021-03-24 12:39:08 -0700188 return module
189}
190
191// droidstubs_host passes sources files through Metalava to generate stub .java files that only contain the API
192// to be documented, filtering out hidden classes and methods. The resulting .java files are intended to be
193// passed to a droiddoc_host module to generate documentation. Use a droidstubs_host instead of a droidstubs
194// module when symbols needed by the source files are provided by java_library_host modules.
195func DroidstubsHostFactory() android.Module {
196 module := &Droidstubs{}
197
198 module.AddProperties(&module.properties,
199 &module.Javadoc.properties)
200
201 InitDroiddocModule(module, android.HostSupported)
202 return module
203}
204
205func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) {
206 switch tag {
207 case "":
208 return android.Paths{d.stubsSrcJar}, nil
209 case ".docs.zip":
210 return android.Paths{d.docZip}, nil
211 case ".api.txt", android.DefaultDistTag:
212 // This is the default dist path for dist properties that have no tag property.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000213 return android.Paths{d.apiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700214 case ".removed-api.txt":
Paul Duffinc71d2b72022-08-16 15:24:01 +0000215 return android.Paths{d.removedApiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700216 case ".annotations.zip":
217 return android.Paths{d.annotationsZip}, nil
218 case ".api_versions.xml":
219 return android.Paths{d.apiVersionsXml}, nil
220 default:
221 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
222 }
223}
224
Anton Hanssond78eb762021-09-21 15:25:12 +0100225func (d *Droidstubs) AnnotationsZip() android.Path {
226 return d.annotationsZip
227}
228
Colin Cross2207f872021-03-24 12:39:08 -0700229func (d *Droidstubs) ApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000230 return d.apiFile
Colin Cross2207f872021-03-24 12:39:08 -0700231}
232
233func (d *Droidstubs) RemovedApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000234 return d.removedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700235}
236
237func (d *Droidstubs) StubsSrcJar() android.Path {
238 return d.stubsSrcJar
239}
240
241var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"}
242var metalavaMergeInclusionAnnotationsDirTag = dependencyTag{name: "metalava-merge-inclusion-annotations-dir"}
243var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"}
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000244var metalavaAPILevelsModuleTag = dependencyTag{name: "metalava-api-levels-module-tag"}
Colin Cross2207f872021-03-24 12:39:08 -0700245
246func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) {
247 d.Javadoc.addDeps(ctx)
248
249 if len(d.properties.Merge_annotations_dirs) != 0 {
250 for _, mergeAnnotationsDir := range d.properties.Merge_annotations_dirs {
251 ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir)
252 }
253 }
254
255 if len(d.properties.Merge_inclusion_annotations_dirs) != 0 {
256 for _, mergeInclusionAnnotationsDir := range d.properties.Merge_inclusion_annotations_dirs {
257 ctx.AddDependency(ctx.Module(), metalavaMergeInclusionAnnotationsDirTag, mergeInclusionAnnotationsDir)
258 }
259 }
260
261 if len(d.properties.Api_levels_annotations_dirs) != 0 {
262 for _, apiLevelsAnnotationsDir := range d.properties.Api_levels_annotations_dirs {
263 ctx.AddDependency(ctx.Module(), metalavaAPILevelsAnnotationsDirTag, apiLevelsAnnotationsDir)
264 }
265 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000266
267 if d.properties.Api_levels_module != nil {
268 ctx.AddDependency(ctx.Module(), metalavaAPILevelsModuleTag, proptools.String(d.properties.Api_levels_module))
269 }
Colin Cross2207f872021-03-24 12:39:08 -0700270}
271
272func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) {
273 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
274 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
275 String(d.properties.Api_filename) != "" {
276 filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000277 uncheckedApiFile := android.PathForModuleOut(ctx, "metalava", filename)
278 cmd.FlagWithOutput("--api ", uncheckedApiFile)
279 d.apiFile = uncheckedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700280 } else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" {
281 // If check api is disabled then make the source file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000282 d.apiFile = android.PathForModuleSrc(ctx, sourceApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700283 }
284
285 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
286 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
287 String(d.properties.Removed_api_filename) != "" {
288 filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000289 uncheckedRemovedFile := android.PathForModuleOut(ctx, "metalava", filename)
290 cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile)
291 d.removedApiFile = uncheckedRemovedFile
Colin Cross2207f872021-03-24 12:39:08 -0700292 } else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" {
293 // If check api is disabled then make the source removed api file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000294 d.removedApiFile = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700295 }
296
Colin Cross2207f872021-03-24 12:39:08 -0700297 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700298 d.metadataDir = android.PathForModuleOut(ctx, "metalava", "metadata")
Colin Cross2207f872021-03-24 12:39:08 -0700299 cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
300 }
301
302 if stubsDir.Valid() {
303 if Bool(d.properties.Create_doc_stubs) {
304 cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
305 } else {
306 cmd.FlagWithArg("--stubs ", stubsDir.String())
307 if !Bool(d.properties.Output_javadoc_comments) {
308 cmd.Flag("--exclude-documentation-from-stubs")
309 }
310 }
311 }
312}
313
314func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
315 if Bool(d.properties.Annotations_enabled) {
316 cmd.Flag("--include-annotations")
317
Andrei Onea4985e512021-04-29 16:29:34 +0100318 cmd.FlagWithArg("--exclude-annotation ", "androidx.annotation.RequiresApi")
319
Colin Cross2207f872021-03-24 12:39:08 -0700320 validatingNullability :=
Colin Crossbc139922021-03-25 18:33:16 -0700321 strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") ||
Colin Cross2207f872021-03-24 12:39:08 -0700322 String(d.properties.Validate_nullability_from_list) != ""
323
324 migratingNullability := String(d.properties.Previous_api) != ""
325 if migratingNullability {
326 previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
327 cmd.FlagWithInput("--migrate-nullness ", previousApi)
328 }
329
330 if s := String(d.properties.Validate_nullability_from_list); s != "" {
331 cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
332 }
333
334 if validatingNullability {
Colin Crosscb77f752021-03-24 12:04:44 -0700335 d.nullabilityWarningsFile = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_nullability_warnings.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700336 cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile)
337 }
338
Colin Crosscb77f752021-03-24 12:04:44 -0700339 d.annotationsZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_annotations.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700340 cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip)
341
342 if len(d.properties.Merge_annotations_dirs) != 0 {
343 d.mergeAnnoDirFlags(ctx, cmd)
344 }
345
346 // TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
347 cmd.FlagWithArg("--hide ", "HiddenTypedefConstant").
348 FlagWithArg("--hide ", "SuperfluousPrefix").
Sam Gilbert049af112022-03-04 16:03:53 -0500349 FlagWithArg("--hide ", "AnnotationExtraction").
350 // b/222738070
Sam Gilbert675f0b42022-03-08 11:24:44 -0500351 FlagWithArg("--hide ", "BannedThrow").
352 // b/223382732
353 FlagWithArg("--hide ", "ChangedDefault")
Colin Cross2207f872021-03-24 12:39:08 -0700354 }
355}
356
357func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
358 ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
359 if t, ok := m.(*ExportedDroiddocDir); ok {
360 cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps)
361 } else {
362 ctx.PropertyErrorf("merge_annotations_dirs",
363 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
364 }
365 })
366}
367
368func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
369 ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) {
370 if t, ok := m.(*ExportedDroiddocDir); ok {
371 cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps)
372 } else {
373 ctx.PropertyErrorf("merge_inclusion_annotations_dirs",
374 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
375 }
376 })
377}
378
379func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000380 var apiVersions android.Path
381 if proptools.Bool(d.properties.Api_levels_annotations_enabled) {
382 d.apiLevelsGenerationFlags(ctx, cmd)
383 apiVersions = d.apiVersionsXml
384 } else {
385 ctx.VisitDirectDepsWithTag(metalavaAPILevelsModuleTag, func(m android.Module) {
386 if s, ok := m.(*Droidstubs); ok {
387 apiVersions = s.apiVersionsXml
388 } else {
389 ctx.PropertyErrorf("api_levels_module",
390 "module %q is not a droidstubs module", ctx.OtherModuleName(m))
391 }
392 })
Colin Cross2207f872021-03-24 12:39:08 -0700393 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000394 if apiVersions != nil {
395 cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion().String())
396 cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename())
397 cmd.FlagWithInput("--apply-api-levels ", apiVersions)
398 }
399}
Colin Cross2207f872021-03-24 12:39:08 -0700400
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000401func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Colin Cross2207f872021-03-24 12:39:08 -0700402 if len(d.properties.Api_levels_annotations_dirs) == 0 {
403 ctx.PropertyErrorf("api_levels_annotations_dirs",
404 "has to be non-empty if api levels annotations was enabled!")
405 }
406
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000407 d.apiVersionsXml = android.PathForModuleOut(ctx, "metalava", "api-versions.xml")
Colin Cross2207f872021-03-24 12:39:08 -0700408 cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml)
Colin Cross2207f872021-03-24 12:39:08 -0700409
410 filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar")
411
satayev783195c2021-06-23 21:49:57 +0100412 var dirs []string
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200413 var extensions_dir string
Colin Cross2207f872021-03-24 12:39:08 -0700414 ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
415 if t, ok := m.(*ExportedDroiddocDir); ok {
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200416 extRegex := regexp.MustCompile(t.dir.String() + `/extensions/[0-9]+/public/.*\.jar`)
417
418 // Grab the first extensions_dir and we find while scanning ExportedDroiddocDir.deps;
419 // ideally this should be read from prebuiltApis.properties.Extensions_*
Colin Cross2207f872021-03-24 12:39:08 -0700420 for _, dep := range t.deps {
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200421 if extRegex.MatchString(dep.String()) && d.properties.Extensions_info_file != nil {
422 if extensions_dir == "" {
423 extensions_dir = t.dir.String() + "/extensions"
424 }
425 cmd.Implicit(dep)
426 }
Colin Cross5f6ffc72021-03-29 21:54:45 -0700427 if dep.Base() == filename {
428 cmd.Implicit(dep)
429 }
430 if filename != "android.jar" && dep.Base() == "android.jar" {
431 // Metalava implicitly searches these patterns:
432 // prebuilts/tools/common/api-versions/android-%/android.jar
433 // prebuilts/sdk/%/public/android.jar
434 // Add android.jar files from the api_levels_annotations_dirs directories to try
435 // to satisfy these patterns. If Metalava can't find a match for an API level
436 // between 1 and 28 in at least one pattern it will fail.
Colin Cross2207f872021-03-24 12:39:08 -0700437 cmd.Implicit(dep)
438 }
439 }
satayev783195c2021-06-23 21:49:57 +0100440
441 dirs = append(dirs, t.dir.String())
Colin Cross2207f872021-03-24 12:39:08 -0700442 } else {
443 ctx.PropertyErrorf("api_levels_annotations_dirs",
444 "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
445 }
446 })
satayev783195c2021-06-23 21:49:57 +0100447
448 // Add all relevant --android-jar-pattern patterns for Metalava.
449 // When parsing a stub jar for a specific version, Metalava picks the first pattern that defines
450 // an actual file present on disk (in the order the patterns were passed). For system APIs for
451 // privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs
Pedro Loureirocc203502021-10-04 17:24:00 +0000452 // for older releases. Similarly, module-lib falls back to system API.
453 var sdkDirs []string
454 switch proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") {
Cole Faust051fa912022-10-05 12:45:42 -0700455 case "system-server":
456 sdkDirs = []string{"system-server", "module-lib", "system", "public"}
Pedro Loureirocc203502021-10-04 17:24:00 +0000457 case "module-lib":
458 sdkDirs = []string{"module-lib", "system", "public"}
459 case "system":
460 sdkDirs = []string{"system", "public"}
461 case "public":
462 sdkDirs = []string{"public"}
463 default:
464 ctx.PropertyErrorf("api_levels_sdk_type", "needs to be one of %v", allowedApiLevelSdkTypes)
465 return
satayev783195c2021-06-23 21:49:57 +0100466 }
Pedro Loureirocc203502021-10-04 17:24:00 +0000467
468 for _, sdkDir := range sdkDirs {
469 for _, dir := range dirs {
470 cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, filename))
471 }
satayev783195c2021-06-23 21:49:57 +0100472 }
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200473
474 if d.properties.Extensions_info_file != nil {
475 if extensions_dir == "" {
476 ctx.ModuleErrorf("extensions_info_file set, but no SDK extension dirs found")
477 }
478 info_file := android.PathForModuleSrc(ctx, *d.properties.Extensions_info_file)
479 cmd.Implicit(info_file)
480 cmd.FlagWithArg("--sdk-extensions-root ", extensions_dir)
481 cmd.FlagWithArg("--sdk-extensions-info ", info_file.String())
482 }
Colin Cross2207f872021-03-24 12:39:08 -0700483}
484
Colin Crosse52c2ac2022-03-28 17:03:35 -0700485func metalavaUseRbe(ctx android.ModuleContext) bool {
486 return ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA")
487}
488
Colin Cross2207f872021-03-24 12:39:08 -0700489func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
Anton Hansson556e8142021-06-04 16:20:25 +0100490 srcJarList android.Path, bootclasspath, classpath classpath, homeDir android.WritablePath) *android.RuleBuilderCommand {
Colin Cross2207f872021-03-24 12:39:08 -0700491 rule.Command().Text("rm -rf").Flag(homeDir.String())
492 rule.Command().Text("mkdir -p").Flag(homeDir.String())
493
Anton Hansson556e8142021-06-04 16:20:25 +0100494 cmd := rule.Command()
Colin Cross2207f872021-03-24 12:39:08 -0700495 cmd.FlagWithArg("ANDROID_PREFS_ROOT=", homeDir.String())
496
Colin Crosse52c2ac2022-03-28 17:03:35 -0700497 if metalavaUseRbe(ctx) {
Colin Cross2207f872021-03-24 12:39:08 -0700498 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
Colin Cross8095c292021-03-30 16:40:48 -0700499 execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
500 labels := map[string]string{"type": "tool", "name": "metalava"}
501 // TODO: metalava pool rejects these jobs
502 pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
503 rule.Rewrapper(&remoteexec.REParams{
504 Labels: labels,
505 ExecStrategy: execStrategy,
506 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
507 Platform: map[string]string{remoteexec.PoolKey: pool},
508 })
Colin Cross2207f872021-03-24 12:39:08 -0700509 }
510
Colin Cross6aa5c402021-03-24 12:28:50 -0700511 cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
Colin Cross2207f872021-03-24 12:39:08 -0700512 Flag(config.JavacVmFlags).
513 Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED").
Paul Duffin808211e2023-08-09 12:36:08 +0100514 FlagWithArg("--java-source ", javaVersion.String()).
Colin Cross2207f872021-03-24 12:39:08 -0700515 FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs).
516 FlagWithInput("@", srcJarList)
517
Paul Duffinf8aaaa12023-08-10 15:16:35 +0100518 // Metalava does not differentiate between bootclasspath and classpath and has not done so for
519 // years, so it is unlikely to change any time soon.
520 combinedPaths := append(([]android.Path)(nil), bootclasspath.Paths()...)
521 combinedPaths = append(combinedPaths, classpath.Paths()...)
522 if len(combinedPaths) > 0 {
523 cmd.FlagWithInputList("--classpath ", combinedPaths, ":")
Colin Cross2207f872021-03-24 12:39:08 -0700524 }
525
Mårten Kongstadbd262442023-07-12 14:01:49 +0200526 cmd.Flag("--color").
Colin Cross2207f872021-03-24 12:39:08 -0700527 Flag("--quiet").
528 Flag("--format=v2").
529 FlagWithArg("--repeat-errors-max ", "10").
Sam Gilbert09cb5db2021-10-06 11:28:28 -0400530 FlagWithArg("--hide ", "UnresolvedImport").
Ember Rose7c57af32022-04-01 10:34:44 -0400531 FlagWithArg("--hide ", "InvalidNullabilityOverride").
Sam Gilbert28e41282022-03-09 15:24:48 +0000532 // b/223382732
533 FlagWithArg("--hide ", "ChangedDefault")
Colin Cross2207f872021-03-24 12:39:08 -0700534
Paul Duffin5b7035f2023-05-31 17:51:33 +0100535 // Force metalava to ignore classes on the classpath when an API file contains missing classes.
536 // See b/285140653 for more information.
537 cmd.FlagWithArg("--api-class-resolution ", "api")
538
Paul Duffin7202ffe2023-06-01 15:28:54 +0100539 // Force metalava to sort overloaded methods by their order in the source code.
540 // See b/285312164 for more information.
Paul Duffin629b9d22023-10-10 17:50:25 +0100541 // And add concrete overrides of abstract methods, see b/299366704 for more
542 // information.
543 cmd.FlagWithArg("--format-defaults ", "overloaded-method-order=source,add-additional-overrides=yes")
Paul Duffin7202ffe2023-06-01 15:28:54 +0100544
Jihoon Kangc8313892023-09-20 00:54:47 +0000545 if ctx.DeviceConfig().HideFlaggedApis() {
546 cmd.FlagWithArg("--hide-annotation ", "android.annotation.FlaggedApi")
547 }
548
Colin Cross2207f872021-03-24 12:39:08 -0700549 return cmd
550}
551
552func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
553 deps := d.Javadoc.collectDeps(ctx)
554
Jiyong Parkf1691d22021-03-29 20:11:58 +0900555 javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d))
Colin Cross2207f872021-03-24 12:39:08 -0700556
557 // Create rule for metalava
558
Colin Crosscb77f752021-03-24 12:04:44 -0700559 srcJarDir := android.PathForModuleOut(ctx, "metalava", "srcjars")
Colin Cross2207f872021-03-24 12:39:08 -0700560
561 rule := android.NewRuleBuilder(pctx, ctx)
562
Colin Cross8095c292021-03-30 16:40:48 -0700563 rule.Sbox(android.PathForModuleOut(ctx, "metalava"),
564 android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
565 SandboxInputs()
Colin Cross6aa5c402021-03-24 12:28:50 -0700566
Colin Cross2207f872021-03-24 12:39:08 -0700567 if BoolDefault(d.properties.High_mem, false) {
568 // This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel.
569 rule.HighMem()
570 }
571
572 generateStubs := BoolDefault(d.properties.Generate_stubs, true)
573 var stubsDir android.OptionalPath
574 if generateStubs {
Colin Crosscb77f752021-03-24 12:04:44 -0700575 d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
576 stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "metalava", "stubsDir"))
Colin Cross2207f872021-03-24 12:39:08 -0700577 rule.Command().Text("rm -rf").Text(stubsDir.String())
578 rule.Command().Text("mkdir -p").Text(stubsDir.String())
579 }
580
581 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
582
Colin Crosscb77f752021-03-24 12:04:44 -0700583 homeDir := android.PathForModuleOut(ctx, "metalava", "home")
Colin Cross2207f872021-03-24 12:39:08 -0700584 cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
Anton Hansson556e8142021-06-04 16:20:25 +0100585 deps.bootClasspath, deps.classpath, homeDir)
Colin Cross2207f872021-03-24 12:39:08 -0700586 cmd.Implicits(d.Javadoc.implicits)
587
588 d.stubsFlags(ctx, cmd, stubsDir)
589
590 d.annotationsFlags(ctx, cmd)
591 d.inclusionAnnotationsFlags(ctx, cmd)
592 d.apiLevelsAnnotationsFlags(ctx, cmd)
593
Colin Crossbc139922021-03-25 18:33:16 -0700594 d.expandArgs(ctx, cmd)
Colin Cross2207f872021-03-24 12:39:08 -0700595
Colin Cross2207f872021-03-24 12:39:08 -0700596 for _, o := range d.Javadoc.properties.Out {
597 cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
598 }
599
600 // Add options for the other optional tasks: API-lint and check-released.
601 // We generate separate timestamp files for them.
602
603 doApiLint := false
604 doCheckReleased := false
605
606 // Add API lint options.
607
608 if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) {
609 doApiLint = true
610
611 newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since)
612 if newSince.Valid() {
613 cmd.FlagWithInput("--api-lint ", newSince.Path())
614 } else {
615 cmd.Flag("--api-lint")
616 }
Colin Crosscb77f752021-03-24 12:04:44 -0700617 d.apiLintReport = android.PathForModuleOut(ctx, "metalava", "api_lint_report.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700618 cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO: Change to ":api-lint"
619
Colin Cross0d532412021-03-25 09:38:45 -0700620 // TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released.
Colin Cross2207f872021-03-24 12:39:08 -0700621 if d.Name() != "android.car-system-stubs-docs" &&
622 d.Name() != "android.car-stubs-docs" {
623 cmd.Flag("--lints-as-errors")
624 cmd.Flag("--warnings-as-errors") // Most lints are actually warnings.
625 }
626
627 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700628 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "api_lint_baseline.txt")
629 d.apiLintTimestamp = android.PathForModuleOut(ctx, "metalava", "api_lint.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700630
631 // Note this string includes a special shell quote $' ... ', which decodes the "\n"s.
Colin Cross2207f872021-03-24 12:39:08 -0700632 //
633 // TODO: metalava also has a slightly different message hardcoded. Should we unify this
634 // message and metalava's one?
635 msg := `$'` + // Enclose with $' ... '
636 `************************************************************\n` +
637 `Your API changes are triggering API Lint warnings or errors.\n` +
638 `To make these errors go away, fix the code according to the\n` +
639 `error and/or warning messages above.\n` +
640 `\n` +
641 `If it is not possible to do so, there are workarounds:\n` +
642 `\n` +
Aurimas Liutikasb23b7452021-05-24 18:00:37 +0000643 `1. You can suppress the errors with @SuppressLint("<id>")\n` +
644 ` where the <id> is given in brackets in the error message above.\n`
Colin Cross2207f872021-03-24 12:39:08 -0700645
646 if baselineFile.Valid() {
647 cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path())
648 cmd.FlagWithOutput("--update-baseline:api-lint ", updatedBaselineOutput)
649
650 msg += fmt.Sprintf(``+
651 `2. You can update the baseline by executing the following\n`+
652 ` command:\n`+
Colin Cross63eeda02021-04-15 19:01:57 -0700653 ` (cd $ANDROID_BUILD_TOP && cp \\\n`+
654 ` "%s" \\\n`+
655 ` "%s")\n`+
Colin Cross2207f872021-03-24 12:39:08 -0700656 ` To submit the revised baseline.txt to the main Android\n`+
657 ` repository, you will need approval.\n`, updatedBaselineOutput, baselineFile.Path())
658 } else {
659 msg += fmt.Sprintf(``+
660 `2. You can add a baseline file of existing lint failures\n`+
661 ` to the build rule of %s.\n`, d.Name())
662 }
663 // Note the message ends with a ' (single quote), to close the $' ... ' .
664 msg += `************************************************************\n'`
665
666 cmd.FlagWithArg("--error-message:api-lint ", msg)
667 }
668
669 // Add "check released" options. (Detect incompatible API changes from the last public release)
670
671 if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") {
672 doCheckReleased = true
673
674 if len(d.Javadoc.properties.Out) > 0 {
675 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
676 }
677
678 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
679 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
680 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700681 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "last_released_baseline.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700682
Colin Crosscb77f752021-03-24 12:04:44 -0700683 d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_last_released_api.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700684
685 cmd.FlagWithInput("--check-compatibility:api:released ", apiFile)
686 cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile)
687
688 if baselineFile.Valid() {
689 cmd.FlagWithInput("--baseline:compatibility:released ", baselineFile.Path())
690 cmd.FlagWithOutput("--update-baseline:compatibility:released ", updatedBaselineOutput)
691 }
692
693 // Note this string includes quote ($' ... '), which decodes the "\n"s.
694 msg := `$'\n******************************\n` +
695 `You have tried to change the API from what has been previously released in\n` +
696 `an SDK. Please fix the errors listed above.\n` +
697 `******************************\n'`
698
699 cmd.FlagWithArg("--error-message:compatibility:released ", msg)
700 }
701
Paul Duffin10a23c22023-08-11 22:47:31 +0100702 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
703 // Pass the current API file into metalava so it can use it as the basis for determining how to
704 // generate the output signature files (both api and removed).
705 currentApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
706 cmd.FlagWithInput("--use-same-format-as ", currentApiFile)
707 }
708
Colin Cross2207f872021-03-24 12:39:08 -0700709 if generateStubs {
710 rule.Command().
711 BuiltTool("soong_zip").
712 Flag("-write_if_changed").
713 Flag("-jar").
714 FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
715 FlagWithArg("-C ", stubsDir.String()).
716 FlagWithArg("-D ", stubsDir.String())
717 }
718
719 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700720 d.metadataZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-metadata.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700721 rule.Command().
722 BuiltTool("soong_zip").
723 Flag("-write_if_changed").
724 Flag("-d").
725 FlagWithOutput("-o ", d.metadataZip).
726 FlagWithArg("-C ", d.metadataDir.String()).
727 FlagWithArg("-D ", d.metadataDir.String())
728 }
729
730 // TODO: We don't really need two separate API files, but this is a reminiscence of how
731 // we used to run metalava separately for API lint and the "last_released" check. Unify them.
732 if doApiLint {
733 rule.Command().Text("touch").Output(d.apiLintTimestamp)
734 }
735 if doCheckReleased {
736 rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp)
737 }
738
Colin Cross6aa5c402021-03-24 12:28:50 -0700739 // TODO(b/183630617): rewrapper doesn't support restat rules
Colin Crosse52c2ac2022-03-28 17:03:35 -0700740 if !metalavaUseRbe(ctx) {
741 rule.Restat()
742 }
Colin Cross2207f872021-03-24 12:39:08 -0700743
744 zipSyncCleanupCmd(rule, srcJarDir)
745
Paul Duffinc166b682022-05-27 12:23:08 +0000746 rule.Build("metalava", "metalava merged")
747
Paul Duffine7a86642022-08-16 15:43:20 +0000748 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
749
750 if len(d.Javadoc.properties.Out) > 0 {
751 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
752 }
753
754 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
755 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
756 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)
757
758 if baselineFile.Valid() {
759 ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
760 }
761
762 d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp")
763
764 rule := android.NewRuleBuilder(pctx, ctx)
765
766 // Diff command line.
767 // -F matches the closest "opening" line, such as "package android {"
768 // and " public class Intent {".
769 diff := `diff -u -F '{ *$'`
770
771 rule.Command().Text("( true")
772 rule.Command().
773 Text(diff).
774 Input(apiFile).Input(d.apiFile)
775
776 rule.Command().
777 Text(diff).
778 Input(removedApiFile).Input(d.removedApiFile)
779
780 msg := fmt.Sprintf(`\n******************************\n`+
781 `You have tried to change the API from what has been previously approved.\n\n`+
782 `To make these errors go away, you have two choices:\n`+
783 ` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
784 ` to the new methods, etc. shown in the above diff.\n\n`+
785 ` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+
786 ` m %s-update-current-api\n\n`+
787 ` To submit the revised current.txt to the main Android repository,\n`+
788 ` you will need approval.\n`+
789 `******************************\n`, ctx.ModuleName())
790
791 rule.Command().
792 Text("touch").Output(d.checkCurrentApiTimestamp).
793 Text(") || (").
794 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
795 Text("; exit 38").
796 Text(")")
797
798 rule.Build("metalavaCurrentApiCheck", "check current API")
799
800 d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "update_current_api.timestamp")
801
802 // update API rule
803 rule = android.NewRuleBuilder(pctx, ctx)
804
805 rule.Command().Text("( true")
806
807 rule.Command().
808 Text("cp").Flag("-f").
809 Input(d.apiFile).Flag(apiFile.String())
810
811 rule.Command().
812 Text("cp").Flag("-f").
813 Input(d.removedApiFile).Flag(removedApiFile.String())
814
815 msg = "failed to update public API"
816
817 rule.Command().
818 Text("touch").Output(d.updateCurrentApiTimestamp).
819 Text(") || (").
820 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
821 Text("; exit 38").
822 Text(")")
823
824 rule.Build("metalavaCurrentApiUpdate", "update current API")
825 }
826
Colin Cross2207f872021-03-24 12:39:08 -0700827 if String(d.properties.Check_nullability_warnings) != "" {
828 if d.nullabilityWarningsFile == nil {
829 ctx.PropertyErrorf("check_nullability_warnings",
830 "Cannot specify check_nullability_warnings unless validating nullability")
831 }
832
833 checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings))
834
Colin Crosscb77f752021-03-24 12:04:44 -0700835 d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "metalava", "check_nullability_warnings.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700836
837 msg := fmt.Sprintf(`\n******************************\n`+
838 `The warnings encountered during nullability annotation validation did\n`+
839 `not match the checked in file of expected warnings. The diffs are shown\n`+
840 `above. You have two options:\n`+
841 ` 1. Resolve the differences by editing the nullability annotations.\n`+
842 ` 2. Update the file of expected warnings by running:\n`+
843 ` cp %s %s\n`+
844 ` and submitting the updated file as part of your change.`,
845 d.nullabilityWarningsFile, checkNullabilityWarnings)
846
847 rule := android.NewRuleBuilder(pctx, ctx)
848
849 rule.Command().
850 Text("(").
851 Text("diff").Input(checkNullabilityWarnings).Input(d.nullabilityWarningsFile).
852 Text("&&").
853 Text("touch").Output(d.checkNullabilityWarningsTimestamp).
854 Text(") || (").
855 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
856 Text("; exit 38").
857 Text(")")
858
859 rule.Build("nullabilityWarningsCheck", "nullability warnings check")
860 }
861}
862
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000863func (d *Droidstubs) createApiContribution(ctx android.DefaultableHookContext) {
864 api_file := d.properties.Check_api.Current.Api_file
865 api_surface := d.properties.Api_surface
866
867 props := struct {
868 Name *string
869 Api_surface *string
870 Api_file *string
Jihoon Kang42b589c2023-02-03 22:56:13 +0000871 Visibility []string
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000872 }{}
873
874 props.Name = proptools.StringPtr(d.Name() + ".api.contribution")
875 props.Api_surface = api_surface
876 props.Api_file = api_file
Jihoon Kang42b589c2023-02-03 22:56:13 +0000877 props.Visibility = []string{"//visibility:override", "//visibility:public"}
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000878
879 ctx.CreateModule(ApiContributionFactory, &props)
880}
881
Spandan Das0b555e32022-11-28 18:48:51 +0000882// TODO (b/262014796): Export the API contributions of CorePlatformApi
883// A map to populate the api surface of a droidstub from a substring appearing in its name
884// This map assumes that droidstubs (either checked-in or created by java_sdk_library)
885// use a strict naming convention
886var (
887 droidstubsModuleNamingToSdkKind = map[string]android.SdkKind{
888 //public is commented out since the core libraries use public in their java_sdk_library names
889 "intracore": android.SdkIntraCore,
890 "intra.core": android.SdkIntraCore,
891 "system_server": android.SdkSystemServer,
892 "system-server": android.SdkSystemServer,
893 "system": android.SdkSystem,
894 "module_lib": android.SdkModule,
895 "module-lib": android.SdkModule,
Spandan Dasda977552023-01-26 20:45:16 +0000896 "platform.api": android.SdkCorePlatform,
Spandan Das0b555e32022-11-28 18:48:51 +0000897 "test": android.SdkTest,
Spandan Das4ac2aed2022-12-28 01:54:29 +0000898 "toolchain": android.SdkToolchain,
Spandan Das0b555e32022-11-28 18:48:51 +0000899 }
900)
901
902// A helper function that returns the api surface of the corresponding java_api_contribution Bazel target
903// The api_surface is populated using the naming convention of the droidstubs module.
904func bazelApiSurfaceName(name string) string {
905 // Sort the keys so that longer strings appear first
906 // Otherwise substrings like system will match both system and system_server
907 sortedKeys := make([]string, 0)
908 for key := range droidstubsModuleNamingToSdkKind {
909 sortedKeys = append(sortedKeys, key)
910 }
911 sort.Slice(sortedKeys, func(i, j int) bool {
912 return len(sortedKeys[i]) > len(sortedKeys[j])
913 })
914 for _, sortedKey := range sortedKeys {
915 if strings.Contains(name, sortedKey) {
916 sdkKind := droidstubsModuleNamingToSdkKind[sortedKey]
917 return sdkKind.String() + "api"
918 }
919 }
920 // Default is publicapi
921 return android.SdkPublic.String() + "api"
922}
923
Colin Cross2207f872021-03-24 12:39:08 -0700924func StubsDefaultsFactory() android.Module {
925 module := &DocDefaults{}
926
927 module.AddProperties(
928 &JavadocProperties{},
929 &DroidstubsProperties{},
930 )
931
932 android.InitDefaultsModule(module)
933
934 return module
935}
936
937var _ android.PrebuiltInterface = (*PrebuiltStubsSources)(nil)
938
939type PrebuiltStubsSourcesProperties struct {
940 Srcs []string `android:"path"`
941}
942
943type PrebuiltStubsSources struct {
944 android.ModuleBase
945 android.DefaultableModuleBase
946 prebuilt android.Prebuilt
Colin Cross2207f872021-03-24 12:39:08 -0700947
948 properties PrebuiltStubsSourcesProperties
949
kgui67007242022-01-25 13:50:25 +0800950 stubsSrcJar android.Path
Colin Cross2207f872021-03-24 12:39:08 -0700951}
952
953func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
954 switch tag {
955 case "":
956 return android.Paths{p.stubsSrcJar}, nil
957 default:
958 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
959 }
960}
961
962func (d *PrebuiltStubsSources) StubsSrcJar() android.Path {
963 return d.stubsSrcJar
964}
965
966func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Cross2207f872021-03-24 12:39:08 -0700967 if len(p.properties.Srcs) != 1 {
Anton Hansson86758ac2021-11-03 14:44:12 +0000968 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 -0700969 return
970 }
971
Anton Hansson86758ac2021-11-03 14:44:12 +0000972 src := p.properties.Srcs[0]
973 if filepath.Ext(src) == ".srcjar" {
974 // This is a srcjar. We can use it directly.
975 p.stubsSrcJar = android.PathForModuleSrc(ctx, src)
976 } else {
977 outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
Colin Cross2207f872021-03-24 12:39:08 -0700978
Anton Hansson86758ac2021-11-03 14:44:12 +0000979 // This is a directory. Glob the contents just in case the directory does not exist.
980 srcGlob := src + "/**/*"
981 srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
Colin Cross2207f872021-03-24 12:39:08 -0700982
Anton Hansson86758ac2021-11-03 14:44:12 +0000983 // Although PathForModuleSrc can return nil if either the path doesn't exist or
984 // the path components are invalid it won't in this case because no components
985 // are specified and the module directory must exist in order to get this far.
986 srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, src)
Colin Cross2207f872021-03-24 12:39:08 -0700987
Anton Hansson86758ac2021-11-03 14:44:12 +0000988 rule := android.NewRuleBuilder(pctx, ctx)
989 rule.Command().
990 BuiltTool("soong_zip").
991 Flag("-write_if_changed").
992 Flag("-jar").
993 FlagWithOutput("-o ", outPath).
994 FlagWithArg("-C ", srcDir.String()).
995 FlagWithRspFileInputList("-r ", outPath.ReplaceExtension(ctx, "rsp"), srcPaths)
996 rule.Restat()
997 rule.Build("zip src", "Create srcjar from prebuilt source")
998 p.stubsSrcJar = outPath
999 }
Colin Cross2207f872021-03-24 12:39:08 -07001000}
1001
1002func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
1003 return &p.prebuilt
1004}
1005
1006func (p *PrebuiltStubsSources) Name() string {
1007 return p.prebuilt.Name(p.ModuleBase.Name())
1008}
1009
1010// prebuilt_stubs_sources imports a set of java source files as if they were
1011// generated by droidstubs.
1012//
1013// By default, a prebuilt_stubs_sources has a single variant that expects a
1014// set of `.java` files generated by droidstubs.
1015//
1016// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one
1017// for host modules.
1018//
1019// Intended only for use by sdk snapshots.
1020func PrebuiltStubsSourcesFactory() android.Module {
1021 module := &PrebuiltStubsSources{}
1022
1023 module.AddProperties(&module.properties)
1024
1025 android.InitPrebuiltModule(module, &module.properties.Srcs)
Colin Cross2207f872021-03-24 12:39:08 -07001026 InitDroiddocModule(module, android.HostAndDeviceSupported)
1027 return module
1028}