blob: f05ef1fdd6494bb14f044d1c71b9d73104cc1c35 [file] [log] [blame]
Colin Cross2207f872021-03-24 12:39:08 -07001// Copyright 2021 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package java
16
17import (
18 "fmt"
Anton Hansson86758ac2021-11-03 14:44:12 +000019 "path/filepath"
Mårten Kongstad802ae0f2022-07-27 13:47:32 +020020 "regexp"
Spandan Das0b555e32022-11-28 18:48:51 +000021 "sort"
Colin Cross2207f872021-03-24 12:39:08 -070022 "strings"
23
24 "github.com/google/blueprint/proptools"
25
26 "android/soong/android"
Spandan Das0b555e32022-11-28 18:48:51 +000027 "android/soong/bazel"
Colin Cross2207f872021-03-24 12:39:08 -070028 "android/soong/java/config"
29 "android/soong/remoteexec"
30)
31
Pedro Loureirocc203502021-10-04 17:24:00 +000032// The values allowed for Droidstubs' Api_levels_sdk_type
Cole Faust051fa912022-10-05 12:45:42 -070033var allowedApiLevelSdkTypes = []string{"public", "system", "module-lib", "system-server"}
Pedro Loureirocc203502021-10-04 17:24:00 +000034
Colin Cross2207f872021-03-24 12:39:08 -070035func init() {
36 RegisterStubsBuildComponents(android.InitRegistrationContext)
37}
38
39func RegisterStubsBuildComponents(ctx android.RegistrationContext) {
40 ctx.RegisterModuleType("stubs_defaults", StubsDefaultsFactory)
41
42 ctx.RegisterModuleType("droidstubs", DroidstubsFactory)
43 ctx.RegisterModuleType("droidstubs_host", DroidstubsHostFactory)
44
45 ctx.RegisterModuleType("prebuilt_stubs_sources", PrebuiltStubsSourcesFactory)
46}
47
Colin Cross2207f872021-03-24 12:39:08 -070048// Droidstubs
Colin Cross2207f872021-03-24 12:39:08 -070049type Droidstubs struct {
50 Javadoc
Colin Cross2207f872021-03-24 12:39:08 -070051
52 properties DroidstubsProperties
Paul Duffinc71d2b72022-08-16 15:24:01 +000053 apiFile android.Path
54 removedApiFile android.Path
Colin Cross2207f872021-03-24 12:39:08 -070055 nullabilityWarningsFile android.WritablePath
56
57 checkCurrentApiTimestamp android.WritablePath
58 updateCurrentApiTimestamp android.WritablePath
59 checkLastReleasedApiTimestamp android.WritablePath
60 apiLintTimestamp android.WritablePath
61 apiLintReport android.WritablePath
62
63 checkNullabilityWarningsTimestamp android.WritablePath
64
65 annotationsZip android.WritablePath
66 apiVersionsXml android.WritablePath
67
Colin Cross2207f872021-03-24 12:39:08 -070068 metadataZip android.WritablePath
69 metadataDir android.WritablePath
70}
71
72type DroidstubsProperties struct {
73 // The generated public API filename by Metalava, defaults to <module>_api.txt
74 Api_filename *string
75
76 // the generated removed API filename by Metalava, defaults to <module>_removed.txt
77 Removed_api_filename *string
78
Colin Cross2207f872021-03-24 12:39:08 -070079 Check_api struct {
80 Last_released ApiToCheck
81
82 Current ApiToCheck
83
84 Api_lint struct {
85 Enabled *bool
86
87 // If set, performs api_lint on any new APIs not found in the given signature file
88 New_since *string `android:"path"`
89
90 // If not blank, path to the baseline txt file for approved API lint violations.
91 Baseline_file *string `android:"path"`
92 }
93 }
94
95 // user can specify the version of previous released API file in order to do compatibility check.
96 Previous_api *string `android:"path"`
97
98 // is set to true, Metalava will allow framework SDK to contain annotations.
99 Annotations_enabled *bool
100
101 // a list of top-level directories containing files to merge qualifier annotations (i.e. those intended to be included in the stubs written) from.
102 Merge_annotations_dirs []string
103
104 // a list of top-level directories containing Java stub files to merge show/hide annotations from.
105 Merge_inclusion_annotations_dirs []string
106
107 // a file containing a list of classes to do nullability validation for.
108 Validate_nullability_from_list *string
109
110 // a file containing expected warnings produced by validation of nullability annotations.
111 Check_nullability_warnings *string
112
113 // if set to true, allow Metalava to generate doc_stubs source files. Defaults to false.
114 Create_doc_stubs *bool
115
116 // if set to true, cause Metalava to output Javadoc comments in the stubs source files. Defaults to false.
117 // Has no effect if create_doc_stubs: true.
118 Output_javadoc_comments *bool
119
120 // if set to false then do not write out stubs. Defaults to true.
121 //
122 // TODO(b/146727827): Remove capability when we do not need to generate stubs and API separately.
123 Generate_stubs *bool
124
125 // if set to true, provides a hint to the build system that this rule uses a lot of memory,
126 // whicih can be used for scheduling purposes
127 High_mem *bool
128
satayev783195c2021-06-23 21:49:57 +0100129 // if set to true, Metalava will allow framework SDK to contain API levels annotations.
Colin Cross2207f872021-03-24 12:39:08 -0700130 Api_levels_annotations_enabled *bool
131
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000132 // Apply the api levels database created by this module rather than generating one in this droidstubs.
133 Api_levels_module *string
134
Colin Cross2207f872021-03-24 12:39:08 -0700135 // the dirs which Metalava extracts API levels annotations from.
136 Api_levels_annotations_dirs []string
137
Cole Faust051fa912022-10-05 12:45:42 -0700138 // the sdk kind which Metalava extracts API levels annotations from. Supports 'public', 'system', 'module-lib' and 'system-server'; defaults to public.
satayev783195c2021-06-23 21:49:57 +0100139 Api_levels_sdk_type *string
140
Colin Cross2207f872021-03-24 12:39:08 -0700141 // the filename which Metalava extracts API levels annotations from. Defaults to android.jar.
142 Api_levels_jar_filename *string
143
144 // if set to true, collect the values used by the Dev tools and
145 // write them in files packaged with the SDK. Defaults to false.
146 Write_sdk_values *bool
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200147
148 // path or filegroup to file defining extension an SDK name <-> numerical ID mapping and
149 // what APIs exist in which SDKs; passed to metalava via --sdk-extensions-info
150 Extensions_info_file *string `android:"path"`
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
Colin Cross2207f872021-03-24 12:39:08 -0700175// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
176// documented, filtering out hidden classes and methods. The resulting .java files are intended to be passed to
177// a droiddoc module to generate documentation.
178func DroidstubsFactory() android.Module {
179 module := &Droidstubs{}
180
181 module.AddProperties(&module.properties,
182 &module.Javadoc.properties)
183
184 InitDroiddocModule(module, android.HostAndDeviceSupported)
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000185
186 module.SetDefaultableHook(func(ctx android.DefaultableHookContext) {
187 module.createApiContribution(ctx)
188 })
Colin Cross2207f872021-03-24 12:39:08 -0700189 return module
190}
191
192// droidstubs_host passes sources files through Metalava to generate stub .java files that only contain the API
193// to be documented, filtering out hidden classes and methods. The resulting .java files are intended to be
194// passed to a droiddoc_host module to generate documentation. Use a droidstubs_host instead of a droidstubs
195// module when symbols needed by the source files are provided by java_library_host modules.
196func DroidstubsHostFactory() android.Module {
197 module := &Droidstubs{}
198
199 module.AddProperties(&module.properties,
200 &module.Javadoc.properties)
201
202 InitDroiddocModule(module, android.HostSupported)
203 return module
204}
205
206func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) {
207 switch tag {
208 case "":
209 return android.Paths{d.stubsSrcJar}, nil
210 case ".docs.zip":
211 return android.Paths{d.docZip}, nil
212 case ".api.txt", android.DefaultDistTag:
213 // This is the default dist path for dist properties that have no tag property.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000214 return android.Paths{d.apiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700215 case ".removed-api.txt":
Paul Duffinc71d2b72022-08-16 15:24:01 +0000216 return android.Paths{d.removedApiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700217 case ".annotations.zip":
218 return android.Paths{d.annotationsZip}, nil
219 case ".api_versions.xml":
220 return android.Paths{d.apiVersionsXml}, nil
221 default:
222 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
223 }
224}
225
Anton Hanssond78eb762021-09-21 15:25:12 +0100226func (d *Droidstubs) AnnotationsZip() android.Path {
227 return d.annotationsZip
228}
229
Colin Cross2207f872021-03-24 12:39:08 -0700230func (d *Droidstubs) ApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000231 return d.apiFile
Colin Cross2207f872021-03-24 12:39:08 -0700232}
233
234func (d *Droidstubs) RemovedApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000235 return d.removedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700236}
237
238func (d *Droidstubs) StubsSrcJar() android.Path {
239 return d.stubsSrcJar
240}
241
242var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"}
243var metalavaMergeInclusionAnnotationsDirTag = dependencyTag{name: "metalava-merge-inclusion-annotations-dir"}
244var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"}
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000245var metalavaAPILevelsModuleTag = dependencyTag{name: "metalava-api-levels-module-tag"}
Colin Cross2207f872021-03-24 12:39:08 -0700246
247func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) {
248 d.Javadoc.addDeps(ctx)
249
250 if len(d.properties.Merge_annotations_dirs) != 0 {
251 for _, mergeAnnotationsDir := range d.properties.Merge_annotations_dirs {
252 ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir)
253 }
254 }
255
256 if len(d.properties.Merge_inclusion_annotations_dirs) != 0 {
257 for _, mergeInclusionAnnotationsDir := range d.properties.Merge_inclusion_annotations_dirs {
258 ctx.AddDependency(ctx.Module(), metalavaMergeInclusionAnnotationsDirTag, mergeInclusionAnnotationsDir)
259 }
260 }
261
262 if len(d.properties.Api_levels_annotations_dirs) != 0 {
263 for _, apiLevelsAnnotationsDir := range d.properties.Api_levels_annotations_dirs {
264 ctx.AddDependency(ctx.Module(), metalavaAPILevelsAnnotationsDirTag, apiLevelsAnnotationsDir)
265 }
266 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000267
268 if d.properties.Api_levels_module != nil {
269 ctx.AddDependency(ctx.Module(), metalavaAPILevelsModuleTag, proptools.String(d.properties.Api_levels_module))
270 }
Colin Cross2207f872021-03-24 12:39:08 -0700271}
272
273func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) {
274 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
275 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
276 String(d.properties.Api_filename) != "" {
277 filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000278 uncheckedApiFile := android.PathForModuleOut(ctx, "metalava", filename)
279 cmd.FlagWithOutput("--api ", uncheckedApiFile)
280 d.apiFile = uncheckedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700281 } else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" {
282 // If check api is disabled then make the source file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000283 d.apiFile = android.PathForModuleSrc(ctx, sourceApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700284 }
285
286 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
287 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
288 String(d.properties.Removed_api_filename) != "" {
289 filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000290 uncheckedRemovedFile := android.PathForModuleOut(ctx, "metalava", filename)
291 cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile)
292 d.removedApiFile = uncheckedRemovedFile
Colin Cross2207f872021-03-24 12:39:08 -0700293 } else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" {
294 // If check api is disabled then make the source removed api file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000295 d.removedApiFile = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700296 }
297
Colin Cross2207f872021-03-24 12:39:08 -0700298 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700299 d.metadataDir = android.PathForModuleOut(ctx, "metalava", "metadata")
Colin Cross2207f872021-03-24 12:39:08 -0700300 cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
301 }
302
303 if stubsDir.Valid() {
304 if Bool(d.properties.Create_doc_stubs) {
305 cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
306 } else {
307 cmd.FlagWithArg("--stubs ", stubsDir.String())
308 if !Bool(d.properties.Output_javadoc_comments) {
309 cmd.Flag("--exclude-documentation-from-stubs")
310 }
311 }
312 }
313}
314
315func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
316 if Bool(d.properties.Annotations_enabled) {
317 cmd.Flag("--include-annotations")
318
Andrei Onea4985e512021-04-29 16:29:34 +0100319 cmd.FlagWithArg("--exclude-annotation ", "androidx.annotation.RequiresApi")
320
Colin Cross2207f872021-03-24 12:39:08 -0700321 validatingNullability :=
Colin Crossbc139922021-03-25 18:33:16 -0700322 strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") ||
Colin Cross2207f872021-03-24 12:39:08 -0700323 String(d.properties.Validate_nullability_from_list) != ""
324
325 migratingNullability := String(d.properties.Previous_api) != ""
326 if migratingNullability {
327 previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
328 cmd.FlagWithInput("--migrate-nullness ", previousApi)
329 }
330
331 if s := String(d.properties.Validate_nullability_from_list); s != "" {
332 cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
333 }
334
335 if validatingNullability {
Colin Crosscb77f752021-03-24 12:04:44 -0700336 d.nullabilityWarningsFile = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_nullability_warnings.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700337 cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile)
338 }
339
Colin Crosscb77f752021-03-24 12:04:44 -0700340 d.annotationsZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_annotations.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700341 cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip)
342
343 if len(d.properties.Merge_annotations_dirs) != 0 {
344 d.mergeAnnoDirFlags(ctx, cmd)
345 }
346
347 // TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
348 cmd.FlagWithArg("--hide ", "HiddenTypedefConstant").
349 FlagWithArg("--hide ", "SuperfluousPrefix").
Sam Gilbert049af112022-03-04 16:03:53 -0500350 FlagWithArg("--hide ", "AnnotationExtraction").
351 // b/222738070
Sam Gilbert675f0b42022-03-08 11:24:44 -0500352 FlagWithArg("--hide ", "BannedThrow").
353 // b/223382732
354 FlagWithArg("--hide ", "ChangedDefault")
Colin Cross2207f872021-03-24 12:39:08 -0700355 }
356}
357
358func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
359 ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
360 if t, ok := m.(*ExportedDroiddocDir); ok {
361 cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps)
362 } else {
363 ctx.PropertyErrorf("merge_annotations_dirs",
364 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
365 }
366 })
367}
368
369func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
370 ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) {
371 if t, ok := m.(*ExportedDroiddocDir); ok {
372 cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps)
373 } else {
374 ctx.PropertyErrorf("merge_inclusion_annotations_dirs",
375 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
376 }
377 })
378}
379
380func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000381 var apiVersions android.Path
382 if proptools.Bool(d.properties.Api_levels_annotations_enabled) {
383 d.apiLevelsGenerationFlags(ctx, cmd)
384 apiVersions = d.apiVersionsXml
385 } else {
386 ctx.VisitDirectDepsWithTag(metalavaAPILevelsModuleTag, func(m android.Module) {
387 if s, ok := m.(*Droidstubs); ok {
388 apiVersions = s.apiVersionsXml
389 } else {
390 ctx.PropertyErrorf("api_levels_module",
391 "module %q is not a droidstubs module", ctx.OtherModuleName(m))
392 }
393 })
Colin Cross2207f872021-03-24 12:39:08 -0700394 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000395 if apiVersions != nil {
396 cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion().String())
397 cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename())
398 cmd.FlagWithInput("--apply-api-levels ", apiVersions)
399 }
400}
Colin Cross2207f872021-03-24 12:39:08 -0700401
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000402func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Colin Cross2207f872021-03-24 12:39:08 -0700403 if len(d.properties.Api_levels_annotations_dirs) == 0 {
404 ctx.PropertyErrorf("api_levels_annotations_dirs",
405 "has to be non-empty if api levels annotations was enabled!")
406 }
407
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000408 d.apiVersionsXml = android.PathForModuleOut(ctx, "metalava", "api-versions.xml")
Colin Cross2207f872021-03-24 12:39:08 -0700409 cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml)
Colin Cross2207f872021-03-24 12:39:08 -0700410
411 filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar")
412
satayev783195c2021-06-23 21:49:57 +0100413 var dirs []string
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200414 var extensions_dir string
Colin Cross2207f872021-03-24 12:39:08 -0700415 ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
416 if t, ok := m.(*ExportedDroiddocDir); ok {
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200417 extRegex := regexp.MustCompile(t.dir.String() + `/extensions/[0-9]+/public/.*\.jar`)
418
419 // Grab the first extensions_dir and we find while scanning ExportedDroiddocDir.deps;
420 // ideally this should be read from prebuiltApis.properties.Extensions_*
Colin Cross2207f872021-03-24 12:39:08 -0700421 for _, dep := range t.deps {
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200422 if extRegex.MatchString(dep.String()) && d.properties.Extensions_info_file != nil {
423 if extensions_dir == "" {
424 extensions_dir = t.dir.String() + "/extensions"
425 }
426 cmd.Implicit(dep)
427 }
Colin Cross5f6ffc72021-03-29 21:54:45 -0700428 if dep.Base() == filename {
429 cmd.Implicit(dep)
430 }
431 if filename != "android.jar" && dep.Base() == "android.jar" {
432 // Metalava implicitly searches these patterns:
433 // prebuilts/tools/common/api-versions/android-%/android.jar
434 // prebuilts/sdk/%/public/android.jar
435 // Add android.jar files from the api_levels_annotations_dirs directories to try
436 // to satisfy these patterns. If Metalava can't find a match for an API level
437 // between 1 and 28 in at least one pattern it will fail.
Colin Cross2207f872021-03-24 12:39:08 -0700438 cmd.Implicit(dep)
439 }
440 }
satayev783195c2021-06-23 21:49:57 +0100441
442 dirs = append(dirs, t.dir.String())
Colin Cross2207f872021-03-24 12:39:08 -0700443 } else {
444 ctx.PropertyErrorf("api_levels_annotations_dirs",
445 "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
446 }
447 })
satayev783195c2021-06-23 21:49:57 +0100448
449 // Add all relevant --android-jar-pattern patterns for Metalava.
450 // When parsing a stub jar for a specific version, Metalava picks the first pattern that defines
451 // an actual file present on disk (in the order the patterns were passed). For system APIs for
452 // privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs
Pedro Loureirocc203502021-10-04 17:24:00 +0000453 // for older releases. Similarly, module-lib falls back to system API.
454 var sdkDirs []string
455 switch proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") {
Cole Faust051fa912022-10-05 12:45:42 -0700456 case "system-server":
457 sdkDirs = []string{"system-server", "module-lib", "system", "public"}
Pedro Loureirocc203502021-10-04 17:24:00 +0000458 case "module-lib":
459 sdkDirs = []string{"module-lib", "system", "public"}
460 case "system":
461 sdkDirs = []string{"system", "public"}
462 case "public":
463 sdkDirs = []string{"public"}
464 default:
465 ctx.PropertyErrorf("api_levels_sdk_type", "needs to be one of %v", allowedApiLevelSdkTypes)
466 return
satayev783195c2021-06-23 21:49:57 +0100467 }
Pedro Loureirocc203502021-10-04 17:24:00 +0000468
469 for _, sdkDir := range sdkDirs {
470 for _, dir := range dirs {
471 cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, filename))
472 }
satayev783195c2021-06-23 21:49:57 +0100473 }
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200474
475 if d.properties.Extensions_info_file != nil {
476 if extensions_dir == "" {
477 ctx.ModuleErrorf("extensions_info_file set, but no SDK extension dirs found")
478 }
479 info_file := android.PathForModuleSrc(ctx, *d.properties.Extensions_info_file)
480 cmd.Implicit(info_file)
481 cmd.FlagWithArg("--sdk-extensions-root ", extensions_dir)
482 cmd.FlagWithArg("--sdk-extensions-info ", info_file.String())
483 }
Colin Cross2207f872021-03-24 12:39:08 -0700484}
485
Colin Crosse52c2ac2022-03-28 17:03:35 -0700486func metalavaUseRbe(ctx android.ModuleContext) bool {
487 return ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA")
488}
489
Colin Cross2207f872021-03-24 12:39:08 -0700490func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
Anton Hansson556e8142021-06-04 16:20:25 +0100491 srcJarList android.Path, bootclasspath, classpath classpath, homeDir android.WritablePath) *android.RuleBuilderCommand {
Colin Cross2207f872021-03-24 12:39:08 -0700492 rule.Command().Text("rm -rf").Flag(homeDir.String())
493 rule.Command().Text("mkdir -p").Flag(homeDir.String())
494
Anton Hansson556e8142021-06-04 16:20:25 +0100495 cmd := rule.Command()
Colin Cross2207f872021-03-24 12:39:08 -0700496 cmd.FlagWithArg("ANDROID_PREFS_ROOT=", homeDir.String())
497
Colin Crosse52c2ac2022-03-28 17:03:35 -0700498 if metalavaUseRbe(ctx) {
Colin Cross2207f872021-03-24 12:39:08 -0700499 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
Colin Cross8095c292021-03-30 16:40:48 -0700500 execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
501 labels := map[string]string{"type": "tool", "name": "metalava"}
502 // TODO: metalava pool rejects these jobs
503 pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
504 rule.Rewrapper(&remoteexec.REParams{
505 Labels: labels,
506 ExecStrategy: execStrategy,
507 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
508 Platform: map[string]string{remoteexec.PoolKey: pool},
509 })
Colin Cross2207f872021-03-24 12:39:08 -0700510 }
511
Colin Cross6aa5c402021-03-24 12:28:50 -0700512 cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
Colin Cross2207f872021-03-24 12:39:08 -0700513 Flag(config.JavacVmFlags).
514 Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED").
Paul Duffin808211e2023-08-09 12:36:08 +0100515 FlagWithArg("--java-source ", javaVersion.String()).
Colin Cross2207f872021-03-24 12:39:08 -0700516 FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs).
517 FlagWithInput("@", srcJarList)
518
Paul Duffinf8aaaa12023-08-10 15:16:35 +0100519 // Metalava does not differentiate between bootclasspath and classpath and has not done so for
520 // years, so it is unlikely to change any time soon.
521 combinedPaths := append(([]android.Path)(nil), bootclasspath.Paths()...)
522 combinedPaths = append(combinedPaths, classpath.Paths()...)
523 if len(combinedPaths) > 0 {
524 cmd.FlagWithInputList("--classpath ", combinedPaths, ":")
Colin Cross2207f872021-03-24 12:39:08 -0700525 }
526
Mårten Kongstadbd262442023-07-12 14:01:49 +0200527 cmd.Flag("--color").
Colin Cross2207f872021-03-24 12:39:08 -0700528 Flag("--quiet").
529 Flag("--format=v2").
530 FlagWithArg("--repeat-errors-max ", "10").
Sam Gilbert09cb5db2021-10-06 11:28:28 -0400531 FlagWithArg("--hide ", "UnresolvedImport").
Ember Rose7c57af32022-04-01 10:34:44 -0400532 FlagWithArg("--hide ", "InvalidNullabilityOverride").
Sam Gilbert28e41282022-03-09 15:24:48 +0000533 // b/223382732
534 FlagWithArg("--hide ", "ChangedDefault")
Colin Cross2207f872021-03-24 12:39:08 -0700535
Paul Duffin5b7035f2023-05-31 17:51:33 +0100536 // Force metalava to ignore classes on the classpath when an API file contains missing classes.
537 // See b/285140653 for more information.
538 cmd.FlagWithArg("--api-class-resolution ", "api")
539
Paul Duffin7202ffe2023-06-01 15:28:54 +0100540 // Force metalava to sort overloaded methods by their order in the source code.
541 // See b/285312164 for more information.
542 cmd.FlagWithArg("--api-overloaded-method-order ", "source")
543
Colin Cross2207f872021-03-24 12:39:08 -0700544 return cmd
545}
546
547func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
548 deps := d.Javadoc.collectDeps(ctx)
549
Jiyong Parkf1691d22021-03-29 20:11:58 +0900550 javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d))
Colin Cross2207f872021-03-24 12:39:08 -0700551
552 // Create rule for metalava
553
Colin Crosscb77f752021-03-24 12:04:44 -0700554 srcJarDir := android.PathForModuleOut(ctx, "metalava", "srcjars")
Colin Cross2207f872021-03-24 12:39:08 -0700555
556 rule := android.NewRuleBuilder(pctx, ctx)
557
Colin Cross8095c292021-03-30 16:40:48 -0700558 rule.Sbox(android.PathForModuleOut(ctx, "metalava"),
559 android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
560 SandboxInputs()
Colin Cross6aa5c402021-03-24 12:28:50 -0700561
Colin Cross2207f872021-03-24 12:39:08 -0700562 if BoolDefault(d.properties.High_mem, false) {
563 // This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel.
564 rule.HighMem()
565 }
566
567 generateStubs := BoolDefault(d.properties.Generate_stubs, true)
568 var stubsDir android.OptionalPath
569 if generateStubs {
Colin Crosscb77f752021-03-24 12:04:44 -0700570 d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
571 stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "metalava", "stubsDir"))
Colin Cross2207f872021-03-24 12:39:08 -0700572 rule.Command().Text("rm -rf").Text(stubsDir.String())
573 rule.Command().Text("mkdir -p").Text(stubsDir.String())
574 }
575
576 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
577
Colin Crosscb77f752021-03-24 12:04:44 -0700578 homeDir := android.PathForModuleOut(ctx, "metalava", "home")
Colin Cross2207f872021-03-24 12:39:08 -0700579 cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
Anton Hansson556e8142021-06-04 16:20:25 +0100580 deps.bootClasspath, deps.classpath, homeDir)
Colin Cross2207f872021-03-24 12:39:08 -0700581 cmd.Implicits(d.Javadoc.implicits)
582
583 d.stubsFlags(ctx, cmd, stubsDir)
584
585 d.annotationsFlags(ctx, cmd)
586 d.inclusionAnnotationsFlags(ctx, cmd)
587 d.apiLevelsAnnotationsFlags(ctx, cmd)
588
Colin Crossbc139922021-03-25 18:33:16 -0700589 d.expandArgs(ctx, cmd)
Colin Cross2207f872021-03-24 12:39:08 -0700590
Colin Cross2207f872021-03-24 12:39:08 -0700591 for _, o := range d.Javadoc.properties.Out {
592 cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
593 }
594
595 // Add options for the other optional tasks: API-lint and check-released.
596 // We generate separate timestamp files for them.
597
598 doApiLint := false
599 doCheckReleased := false
600
601 // Add API lint options.
602
603 if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) {
604 doApiLint = true
605
606 newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since)
607 if newSince.Valid() {
608 cmd.FlagWithInput("--api-lint ", newSince.Path())
609 } else {
610 cmd.Flag("--api-lint")
611 }
Colin Crosscb77f752021-03-24 12:04:44 -0700612 d.apiLintReport = android.PathForModuleOut(ctx, "metalava", "api_lint_report.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700613 cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO: Change to ":api-lint"
614
Colin Cross0d532412021-03-25 09:38:45 -0700615 // TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released.
Colin Cross2207f872021-03-24 12:39:08 -0700616 if d.Name() != "android.car-system-stubs-docs" &&
617 d.Name() != "android.car-stubs-docs" {
618 cmd.Flag("--lints-as-errors")
619 cmd.Flag("--warnings-as-errors") // Most lints are actually warnings.
620 }
621
622 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700623 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "api_lint_baseline.txt")
624 d.apiLintTimestamp = android.PathForModuleOut(ctx, "metalava", "api_lint.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700625
626 // Note this string includes a special shell quote $' ... ', which decodes the "\n"s.
Colin Cross2207f872021-03-24 12:39:08 -0700627 //
628 // TODO: metalava also has a slightly different message hardcoded. Should we unify this
629 // message and metalava's one?
630 msg := `$'` + // Enclose with $' ... '
631 `************************************************************\n` +
632 `Your API changes are triggering API Lint warnings or errors.\n` +
633 `To make these errors go away, fix the code according to the\n` +
634 `error and/or warning messages above.\n` +
635 `\n` +
636 `If it is not possible to do so, there are workarounds:\n` +
637 `\n` +
Aurimas Liutikasb23b7452021-05-24 18:00:37 +0000638 `1. You can suppress the errors with @SuppressLint("<id>")\n` +
639 ` where the <id> is given in brackets in the error message above.\n`
Colin Cross2207f872021-03-24 12:39:08 -0700640
641 if baselineFile.Valid() {
642 cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path())
643 cmd.FlagWithOutput("--update-baseline:api-lint ", updatedBaselineOutput)
644
645 msg += fmt.Sprintf(``+
646 `2. You can update the baseline by executing the following\n`+
647 ` command:\n`+
Colin Cross63eeda02021-04-15 19:01:57 -0700648 ` (cd $ANDROID_BUILD_TOP && cp \\\n`+
649 ` "%s" \\\n`+
650 ` "%s")\n`+
Colin Cross2207f872021-03-24 12:39:08 -0700651 ` To submit the revised baseline.txt to the main Android\n`+
652 ` repository, you will need approval.\n`, updatedBaselineOutput, baselineFile.Path())
653 } else {
654 msg += fmt.Sprintf(``+
655 `2. You can add a baseline file of existing lint failures\n`+
656 ` to the build rule of %s.\n`, d.Name())
657 }
658 // Note the message ends with a ' (single quote), to close the $' ... ' .
659 msg += `************************************************************\n'`
660
661 cmd.FlagWithArg("--error-message:api-lint ", msg)
662 }
663
664 // Add "check released" options. (Detect incompatible API changes from the last public release)
665
666 if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") {
667 doCheckReleased = true
668
669 if len(d.Javadoc.properties.Out) > 0 {
670 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
671 }
672
673 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
674 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
675 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700676 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "last_released_baseline.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700677
Colin Crosscb77f752021-03-24 12:04:44 -0700678 d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_last_released_api.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700679
680 cmd.FlagWithInput("--check-compatibility:api:released ", apiFile)
681 cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile)
682
683 if baselineFile.Valid() {
684 cmd.FlagWithInput("--baseline:compatibility:released ", baselineFile.Path())
685 cmd.FlagWithOutput("--update-baseline:compatibility:released ", updatedBaselineOutput)
686 }
687
688 // Note this string includes quote ($' ... '), which decodes the "\n"s.
689 msg := `$'\n******************************\n` +
690 `You have tried to change the API from what has been previously released in\n` +
691 `an SDK. Please fix the errors listed above.\n` +
692 `******************************\n'`
693
694 cmd.FlagWithArg("--error-message:compatibility:released ", msg)
695 }
696
Paul Duffin10a23c22023-08-11 22:47:31 +0100697 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
698 // Pass the current API file into metalava so it can use it as the basis for determining how to
699 // generate the output signature files (both api and removed).
700 currentApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
701 cmd.FlagWithInput("--use-same-format-as ", currentApiFile)
702 }
703
Colin Cross2207f872021-03-24 12:39:08 -0700704 if generateStubs {
705 rule.Command().
706 BuiltTool("soong_zip").
707 Flag("-write_if_changed").
708 Flag("-jar").
709 FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
710 FlagWithArg("-C ", stubsDir.String()).
711 FlagWithArg("-D ", stubsDir.String())
712 }
713
714 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700715 d.metadataZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-metadata.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700716 rule.Command().
717 BuiltTool("soong_zip").
718 Flag("-write_if_changed").
719 Flag("-d").
720 FlagWithOutput("-o ", d.metadataZip).
721 FlagWithArg("-C ", d.metadataDir.String()).
722 FlagWithArg("-D ", d.metadataDir.String())
723 }
724
725 // TODO: We don't really need two separate API files, but this is a reminiscence of how
726 // we used to run metalava separately for API lint and the "last_released" check. Unify them.
727 if doApiLint {
728 rule.Command().Text("touch").Output(d.apiLintTimestamp)
729 }
730 if doCheckReleased {
731 rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp)
732 }
733
Colin Cross6aa5c402021-03-24 12:28:50 -0700734 // TODO(b/183630617): rewrapper doesn't support restat rules
Colin Crosse52c2ac2022-03-28 17:03:35 -0700735 if !metalavaUseRbe(ctx) {
736 rule.Restat()
737 }
Colin Cross2207f872021-03-24 12:39:08 -0700738
739 zipSyncCleanupCmd(rule, srcJarDir)
740
Paul Duffinc166b682022-05-27 12:23:08 +0000741 rule.Build("metalava", "metalava merged")
742
Paul Duffine7a86642022-08-16 15:43:20 +0000743 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
744
745 if len(d.Javadoc.properties.Out) > 0 {
746 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
747 }
748
749 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
750 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
751 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)
752
753 if baselineFile.Valid() {
754 ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
755 }
756
757 d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp")
758
759 rule := android.NewRuleBuilder(pctx, ctx)
760
761 // Diff command line.
762 // -F matches the closest "opening" line, such as "package android {"
763 // and " public class Intent {".
764 diff := `diff -u -F '{ *$'`
765
766 rule.Command().Text("( true")
767 rule.Command().
768 Text(diff).
769 Input(apiFile).Input(d.apiFile)
770
771 rule.Command().
772 Text(diff).
773 Input(removedApiFile).Input(d.removedApiFile)
774
775 msg := fmt.Sprintf(`\n******************************\n`+
776 `You have tried to change the API from what has been previously approved.\n\n`+
777 `To make these errors go away, you have two choices:\n`+
778 ` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
779 ` to the new methods, etc. shown in the above diff.\n\n`+
780 ` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+
781 ` m %s-update-current-api\n\n`+
782 ` To submit the revised current.txt to the main Android repository,\n`+
783 ` you will need approval.\n`+
784 `******************************\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
Spandan Das0b555e32022-11-28 18:48:51 +0000858var _ android.ApiProvider = (*Droidstubs)(nil)
859
860type bazelJavaApiContributionAttributes struct {
861 Api bazel.LabelAttribute
862 Api_surface *string
863}
864
865func (d *Droidstubs) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
866 props := bazel.BazelTargetModuleProperties{
867 Rule_class: "java_api_contribution",
868 Bzl_load_location: "//build/bazel/rules/apis:java_api_contribution.bzl",
869 }
870 apiFile := d.properties.Check_api.Current.Api_file
871 // Do not generate a target if check_api is not set
872 if apiFile == nil {
873 return
874 }
875 attrs := &bazelJavaApiContributionAttributes{
876 Api: *bazel.MakeLabelAttribute(
877 android.BazelLabelForModuleSrcSingle(ctx, proptools.String(apiFile)).Label,
878 ),
879 Api_surface: proptools.StringPtr(bazelApiSurfaceName(d.Name())),
880 }
881 ctx.CreateBazelTargetModule(props, android.CommonAttributes{
882 Name: android.ApiContributionTargetName(ctx.ModuleName()),
883 }, attrs)
884}
885
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000886func (d *Droidstubs) createApiContribution(ctx android.DefaultableHookContext) {
887 api_file := d.properties.Check_api.Current.Api_file
888 api_surface := d.properties.Api_surface
889
890 props := struct {
891 Name *string
892 Api_surface *string
893 Api_file *string
Jihoon Kang42b589c2023-02-03 22:56:13 +0000894 Visibility []string
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000895 }{}
896
897 props.Name = proptools.StringPtr(d.Name() + ".api.contribution")
898 props.Api_surface = api_surface
899 props.Api_file = api_file
Jihoon Kang42b589c2023-02-03 22:56:13 +0000900 props.Visibility = []string{"//visibility:override", "//visibility:public"}
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000901
902 ctx.CreateModule(ApiContributionFactory, &props)
903}
904
Spandan Das0b555e32022-11-28 18:48:51 +0000905// TODO (b/262014796): Export the API contributions of CorePlatformApi
906// A map to populate the api surface of a droidstub from a substring appearing in its name
907// This map assumes that droidstubs (either checked-in or created by java_sdk_library)
908// use a strict naming convention
909var (
910 droidstubsModuleNamingToSdkKind = map[string]android.SdkKind{
911 //public is commented out since the core libraries use public in their java_sdk_library names
912 "intracore": android.SdkIntraCore,
913 "intra.core": android.SdkIntraCore,
914 "system_server": android.SdkSystemServer,
915 "system-server": android.SdkSystemServer,
916 "system": android.SdkSystem,
917 "module_lib": android.SdkModule,
918 "module-lib": android.SdkModule,
Spandan Dasda977552023-01-26 20:45:16 +0000919 "platform.api": android.SdkCorePlatform,
Spandan Das0b555e32022-11-28 18:48:51 +0000920 "test": android.SdkTest,
Spandan Das4ac2aed2022-12-28 01:54:29 +0000921 "toolchain": android.SdkToolchain,
Spandan Das0b555e32022-11-28 18:48:51 +0000922 }
923)
924
925// A helper function that returns the api surface of the corresponding java_api_contribution Bazel target
926// The api_surface is populated using the naming convention of the droidstubs module.
927func bazelApiSurfaceName(name string) string {
928 // Sort the keys so that longer strings appear first
929 // Otherwise substrings like system will match both system and system_server
930 sortedKeys := make([]string, 0)
931 for key := range droidstubsModuleNamingToSdkKind {
932 sortedKeys = append(sortedKeys, key)
933 }
934 sort.Slice(sortedKeys, func(i, j int) bool {
935 return len(sortedKeys[i]) > len(sortedKeys[j])
936 })
937 for _, sortedKey := range sortedKeys {
938 if strings.Contains(name, sortedKey) {
939 sdkKind := droidstubsModuleNamingToSdkKind[sortedKey]
940 return sdkKind.String() + "api"
941 }
942 }
943 // Default is publicapi
944 return android.SdkPublic.String() + "api"
945}
946
Colin Cross2207f872021-03-24 12:39:08 -0700947func StubsDefaultsFactory() android.Module {
948 module := &DocDefaults{}
949
950 module.AddProperties(
951 &JavadocProperties{},
952 &DroidstubsProperties{},
953 )
954
955 android.InitDefaultsModule(module)
956
957 return module
958}
959
960var _ android.PrebuiltInterface = (*PrebuiltStubsSources)(nil)
961
962type PrebuiltStubsSourcesProperties struct {
963 Srcs []string `android:"path"`
964}
965
966type PrebuiltStubsSources struct {
967 android.ModuleBase
968 android.DefaultableModuleBase
969 prebuilt android.Prebuilt
Colin Cross2207f872021-03-24 12:39:08 -0700970
971 properties PrebuiltStubsSourcesProperties
972
kgui67007242022-01-25 13:50:25 +0800973 stubsSrcJar android.Path
Colin Cross2207f872021-03-24 12:39:08 -0700974}
975
976func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
977 switch tag {
978 case "":
979 return android.Paths{p.stubsSrcJar}, nil
980 default:
981 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
982 }
983}
984
985func (d *PrebuiltStubsSources) StubsSrcJar() android.Path {
986 return d.stubsSrcJar
987}
988
989func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Cross2207f872021-03-24 12:39:08 -0700990 if len(p.properties.Srcs) != 1 {
Anton Hansson86758ac2021-11-03 14:44:12 +0000991 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 -0700992 return
993 }
994
Anton Hansson86758ac2021-11-03 14:44:12 +0000995 src := p.properties.Srcs[0]
996 if filepath.Ext(src) == ".srcjar" {
997 // This is a srcjar. We can use it directly.
998 p.stubsSrcJar = android.PathForModuleSrc(ctx, src)
999 } else {
1000 outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
Colin Cross2207f872021-03-24 12:39:08 -07001001
Anton Hansson86758ac2021-11-03 14:44:12 +00001002 // This is a directory. Glob the contents just in case the directory does not exist.
1003 srcGlob := src + "/**/*"
1004 srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
Colin Cross2207f872021-03-24 12:39:08 -07001005
Anton Hansson86758ac2021-11-03 14:44:12 +00001006 // Although PathForModuleSrc can return nil if either the path doesn't exist or
1007 // the path components are invalid it won't in this case because no components
1008 // are specified and the module directory must exist in order to get this far.
1009 srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, src)
Colin Cross2207f872021-03-24 12:39:08 -07001010
Anton Hansson86758ac2021-11-03 14:44:12 +00001011 rule := android.NewRuleBuilder(pctx, ctx)
1012 rule.Command().
1013 BuiltTool("soong_zip").
1014 Flag("-write_if_changed").
1015 Flag("-jar").
1016 FlagWithOutput("-o ", outPath).
1017 FlagWithArg("-C ", srcDir.String()).
1018 FlagWithRspFileInputList("-r ", outPath.ReplaceExtension(ctx, "rsp"), srcPaths)
1019 rule.Restat()
1020 rule.Build("zip src", "Create srcjar from prebuilt source")
1021 p.stubsSrcJar = outPath
1022 }
Colin Cross2207f872021-03-24 12:39:08 -07001023}
1024
1025func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
1026 return &p.prebuilt
1027}
1028
1029func (p *PrebuiltStubsSources) Name() string {
1030 return p.prebuilt.Name(p.ModuleBase.Name())
1031}
1032
1033// prebuilt_stubs_sources imports a set of java source files as if they were
1034// generated by droidstubs.
1035//
1036// By default, a prebuilt_stubs_sources has a single variant that expects a
1037// set of `.java` files generated by droidstubs.
1038//
1039// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one
1040// for host modules.
1041//
1042// Intended only for use by sdk snapshots.
1043func PrebuiltStubsSourcesFactory() android.Module {
1044 module := &PrebuiltStubsSources{}
1045
1046 module.AddProperties(&module.properties)
1047
1048 android.InitPrebuiltModule(module, &module.properties.Srcs)
Colin Cross2207f872021-03-24 12:39:08 -07001049 InitDroiddocModule(module, android.HostAndDeviceSupported)
1050 return module
1051}