blob: 180ba92cf221eecc9455865030b3c135e152137b [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"
Anas Sulaiman9c493642023-10-18 16:34:37 +000022 "strconv"
Colin Cross2207f872021-03-24 12:39:08 -070023 "strings"
24
25 "github.com/google/blueprint/proptools"
26
27 "android/soong/android"
28 "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
Spandan Das2cc80ba2023-10-27 17:21:52 +000051 embeddableInModuleAndImport
Colin Cross2207f872021-03-24 12:39:08 -070052
53 properties DroidstubsProperties
Paul Duffinc71d2b72022-08-16 15:24:01 +000054 apiFile android.Path
55 removedApiFile android.Path
Colin Cross2207f872021-03-24 12:39:08 -070056 nullabilityWarningsFile android.WritablePath
57
58 checkCurrentApiTimestamp android.WritablePath
59 updateCurrentApiTimestamp android.WritablePath
60 checkLastReleasedApiTimestamp android.WritablePath
61 apiLintTimestamp android.WritablePath
62 apiLintReport android.WritablePath
63
64 checkNullabilityWarningsTimestamp android.WritablePath
65
66 annotationsZip android.WritablePath
67 apiVersionsXml android.WritablePath
68
Colin Cross2207f872021-03-24 12:39:08 -070069 metadataZip android.WritablePath
70 metadataDir android.WritablePath
71}
72
73type DroidstubsProperties struct {
74 // The generated public API filename by Metalava, defaults to <module>_api.txt
75 Api_filename *string
76
77 // the generated removed API filename by Metalava, defaults to <module>_removed.txt
78 Removed_api_filename *string
79
Colin Cross2207f872021-03-24 12:39:08 -070080 Check_api struct {
81 Last_released ApiToCheck
82
83 Current ApiToCheck
84
85 Api_lint struct {
86 Enabled *bool
87
88 // If set, performs api_lint on any new APIs not found in the given signature file
89 New_since *string `android:"path"`
90
91 // If not blank, path to the baseline txt file for approved API lint violations.
92 Baseline_file *string `android:"path"`
93 }
94 }
95
96 // user can specify the version of previous released API file in order to do compatibility check.
97 Previous_api *string `android:"path"`
98
99 // is set to true, Metalava will allow framework SDK to contain annotations.
100 Annotations_enabled *bool
101
102 // a list of top-level directories containing files to merge qualifier annotations (i.e. those intended to be included in the stubs written) from.
103 Merge_annotations_dirs []string
104
105 // a list of top-level directories containing Java stub files to merge show/hide annotations from.
106 Merge_inclusion_annotations_dirs []string
107
108 // a file containing a list of classes to do nullability validation for.
109 Validate_nullability_from_list *string
110
111 // a file containing expected warnings produced by validation of nullability annotations.
112 Check_nullability_warnings *string
113
114 // if set to true, allow Metalava to generate doc_stubs source files. Defaults to false.
115 Create_doc_stubs *bool
116
117 // if set to true, cause Metalava to output Javadoc comments in the stubs source files. Defaults to false.
118 // Has no effect if create_doc_stubs: true.
119 Output_javadoc_comments *bool
120
121 // if set to false then do not write out stubs. Defaults to true.
122 //
123 // TODO(b/146727827): Remove capability when we do not need to generate stubs and API separately.
124 Generate_stubs *bool
125
126 // if set to true, provides a hint to the build system that this rule uses a lot of memory,
Liz Kammer170dd722023-10-16 15:08:39 -0400127 // which can be used for scheduling purposes
Colin Cross2207f872021-03-24 12:39:08 -0700128 High_mem *bool
129
satayev783195c2021-06-23 21:49:57 +0100130 // if set to true, Metalava will allow framework SDK to contain API levels annotations.
Colin Cross2207f872021-03-24 12:39:08 -0700131 Api_levels_annotations_enabled *bool
132
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000133 // Apply the api levels database created by this module rather than generating one in this droidstubs.
134 Api_levels_module *string
135
Colin Cross2207f872021-03-24 12:39:08 -0700136 // the dirs which Metalava extracts API levels annotations from.
137 Api_levels_annotations_dirs []string
138
Cole Faust051fa912022-10-05 12:45:42 -0700139 // the sdk kind which Metalava extracts API levels annotations from. Supports 'public', 'system', 'module-lib' and 'system-server'; defaults to public.
satayev783195c2021-06-23 21:49:57 +0100140 Api_levels_sdk_type *string
141
Colin Cross2207f872021-03-24 12:39:08 -0700142 // the filename which Metalava extracts API levels annotations from. Defaults to android.jar.
143 Api_levels_jar_filename *string
144
145 // if set to true, collect the values used by the Dev tools and
146 // write them in files packaged with the SDK. Defaults to false.
147 Write_sdk_values *bool
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200148
149 // path or filegroup to file defining extension an SDK name <-> numerical ID mapping and
150 // what APIs exist in which SDKs; passed to metalava via --sdk-extensions-info
151 Extensions_info_file *string `android:"path"`
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000152
153 // API surface of this module. If set, the module contributes to an API surface.
154 // For the full list of available API surfaces, refer to soong/android/sdk_version.go
155 Api_surface *string
Colin Cross2207f872021-03-24 12:39:08 -0700156}
157
Anton Hansson52609322021-05-05 10:36:05 +0100158// Used by xsd_config
159type ApiFilePath interface {
160 ApiFilePath() android.Path
161}
162
163type ApiStubsSrcProvider interface {
164 StubsSrcJar() android.Path
165}
166
167// Provider of information about API stubs, used by java_sdk_library.
168type ApiStubsProvider interface {
Anton Hanssond78eb762021-09-21 15:25:12 +0100169 AnnotationsZip() android.Path
Anton Hansson52609322021-05-05 10:36:05 +0100170 ApiFilePath
171 RemovedApiFilePath() android.Path
172
173 ApiStubsSrcProvider
174}
175
Jihoon Kang063ec002023-06-28 01:16:23 +0000176type currentApiTimestampProvider interface {
177 CurrentApiTimestamp() android.Path
178}
179
Colin Cross2207f872021-03-24 12:39:08 -0700180// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
181// documented, filtering out hidden classes and methods. The resulting .java files are intended to be passed to
182// a droiddoc module to generate documentation.
183func DroidstubsFactory() android.Module {
184 module := &Droidstubs{}
185
186 module.AddProperties(&module.properties,
187 &module.Javadoc.properties)
Spandan Das2cc80ba2023-10-27 17:21:52 +0000188 module.initModuleAndImport(module)
Colin Cross2207f872021-03-24 12:39:08 -0700189
190 InitDroiddocModule(module, android.HostAndDeviceSupported)
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000191
192 module.SetDefaultableHook(func(ctx android.DefaultableHookContext) {
193 module.createApiContribution(ctx)
194 })
Colin Cross2207f872021-03-24 12:39:08 -0700195 return module
196}
197
198// droidstubs_host passes sources files through Metalava to generate stub .java files that only contain the API
199// to be documented, filtering out hidden classes and methods. The resulting .java files are intended to be
200// passed to a droiddoc_host module to generate documentation. Use a droidstubs_host instead of a droidstubs
201// module when symbols needed by the source files are provided by java_library_host modules.
202func DroidstubsHostFactory() android.Module {
203 module := &Droidstubs{}
204
205 module.AddProperties(&module.properties,
206 &module.Javadoc.properties)
207
208 InitDroiddocModule(module, android.HostSupported)
209 return module
210}
211
212func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) {
213 switch tag {
214 case "":
215 return android.Paths{d.stubsSrcJar}, nil
216 case ".docs.zip":
217 return android.Paths{d.docZip}, nil
218 case ".api.txt", android.DefaultDistTag:
219 // This is the default dist path for dist properties that have no tag property.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000220 return android.Paths{d.apiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700221 case ".removed-api.txt":
Paul Duffinc71d2b72022-08-16 15:24:01 +0000222 return android.Paths{d.removedApiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700223 case ".annotations.zip":
224 return android.Paths{d.annotationsZip}, nil
225 case ".api_versions.xml":
226 return android.Paths{d.apiVersionsXml}, nil
227 default:
228 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
229 }
230}
231
Anton Hanssond78eb762021-09-21 15:25:12 +0100232func (d *Droidstubs) AnnotationsZip() android.Path {
233 return d.annotationsZip
234}
235
Colin Cross2207f872021-03-24 12:39:08 -0700236func (d *Droidstubs) ApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000237 return d.apiFile
Colin Cross2207f872021-03-24 12:39:08 -0700238}
239
240func (d *Droidstubs) RemovedApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000241 return d.removedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700242}
243
244func (d *Droidstubs) StubsSrcJar() android.Path {
245 return d.stubsSrcJar
246}
247
Jihoon Kang063ec002023-06-28 01:16:23 +0000248func (d *Droidstubs) CurrentApiTimestamp() android.Path {
249 return d.checkCurrentApiTimestamp
250}
251
Colin Cross2207f872021-03-24 12:39:08 -0700252var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"}
253var metalavaMergeInclusionAnnotationsDirTag = dependencyTag{name: "metalava-merge-inclusion-annotations-dir"}
254var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"}
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000255var metalavaAPILevelsModuleTag = dependencyTag{name: "metalava-api-levels-module-tag"}
Jihoon Kang063ec002023-06-28 01:16:23 +0000256var metalavaCurrentApiTimestampTag = dependencyTag{name: "metalava-current-api-timestamp-tag"}
Colin Cross2207f872021-03-24 12:39:08 -0700257
258func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) {
259 d.Javadoc.addDeps(ctx)
260
261 if len(d.properties.Merge_annotations_dirs) != 0 {
262 for _, mergeAnnotationsDir := range d.properties.Merge_annotations_dirs {
263 ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir)
264 }
265 }
266
267 if len(d.properties.Merge_inclusion_annotations_dirs) != 0 {
268 for _, mergeInclusionAnnotationsDir := range d.properties.Merge_inclusion_annotations_dirs {
269 ctx.AddDependency(ctx.Module(), metalavaMergeInclusionAnnotationsDirTag, mergeInclusionAnnotationsDir)
270 }
271 }
272
273 if len(d.properties.Api_levels_annotations_dirs) != 0 {
274 for _, apiLevelsAnnotationsDir := range d.properties.Api_levels_annotations_dirs {
275 ctx.AddDependency(ctx.Module(), metalavaAPILevelsAnnotationsDirTag, apiLevelsAnnotationsDir)
276 }
277 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000278
279 if d.properties.Api_levels_module != nil {
280 ctx.AddDependency(ctx.Module(), metalavaAPILevelsModuleTag, proptools.String(d.properties.Api_levels_module))
281 }
Colin Cross2207f872021-03-24 12:39:08 -0700282}
283
284func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) {
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.Api_filename) != "" {
288 filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000289 uncheckedApiFile := android.PathForModuleOut(ctx, "metalava", filename)
290 cmd.FlagWithOutput("--api ", uncheckedApiFile)
291 d.apiFile = uncheckedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700292 } else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" {
293 // If check api is disabled then make the source file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000294 d.apiFile = android.PathForModuleSrc(ctx, sourceApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700295 }
296
297 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
298 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
299 String(d.properties.Removed_api_filename) != "" {
300 filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000301 uncheckedRemovedFile := android.PathForModuleOut(ctx, "metalava", filename)
302 cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile)
303 d.removedApiFile = uncheckedRemovedFile
Colin Cross2207f872021-03-24 12:39:08 -0700304 } else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" {
305 // If check api is disabled then make the source removed api file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000306 d.removedApiFile = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700307 }
308
Colin Cross2207f872021-03-24 12:39:08 -0700309 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700310 d.metadataDir = android.PathForModuleOut(ctx, "metalava", "metadata")
Colin Cross2207f872021-03-24 12:39:08 -0700311 cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
312 }
313
314 if stubsDir.Valid() {
315 if Bool(d.properties.Create_doc_stubs) {
316 cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
317 } else {
318 cmd.FlagWithArg("--stubs ", stubsDir.String())
319 if !Bool(d.properties.Output_javadoc_comments) {
320 cmd.Flag("--exclude-documentation-from-stubs")
321 }
322 }
323 }
324}
325
326func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
327 if Bool(d.properties.Annotations_enabled) {
Liz Kammere09e20e2023-10-16 15:07:54 -0400328 cmd.Flag(config.MetalavaAnnotationsFlags)
Andrei Onea4985e512021-04-29 16:29:34 +0100329
Colin Cross2207f872021-03-24 12:39:08 -0700330 validatingNullability :=
Colin Crossbc139922021-03-25 18:33:16 -0700331 strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") ||
Colin Cross2207f872021-03-24 12:39:08 -0700332 String(d.properties.Validate_nullability_from_list) != ""
333
334 migratingNullability := String(d.properties.Previous_api) != ""
335 if migratingNullability {
336 previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
337 cmd.FlagWithInput("--migrate-nullness ", previousApi)
338 }
339
340 if s := String(d.properties.Validate_nullability_from_list); s != "" {
341 cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
342 }
343
344 if validatingNullability {
Colin Crosscb77f752021-03-24 12:04:44 -0700345 d.nullabilityWarningsFile = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_nullability_warnings.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700346 cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile)
347 }
348
Colin Crosscb77f752021-03-24 12:04:44 -0700349 d.annotationsZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_annotations.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700350 cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip)
351
352 if len(d.properties.Merge_annotations_dirs) != 0 {
353 d.mergeAnnoDirFlags(ctx, cmd)
354 }
355
Liz Kammere09e20e2023-10-16 15:07:54 -0400356 cmd.Flag(config.MetalavaAnnotationsWarningsFlags)
Colin Cross2207f872021-03-24 12:39:08 -0700357 }
358}
359
360func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
361 ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
362 if t, ok := m.(*ExportedDroiddocDir); ok {
363 cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps)
364 } else {
365 ctx.PropertyErrorf("merge_annotations_dirs",
366 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
367 }
368 })
369}
370
371func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
372 ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) {
373 if t, ok := m.(*ExportedDroiddocDir); ok {
374 cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps)
375 } else {
376 ctx.PropertyErrorf("merge_inclusion_annotations_dirs",
377 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
378 }
379 })
380}
381
382func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000383 var apiVersions android.Path
384 if proptools.Bool(d.properties.Api_levels_annotations_enabled) {
385 d.apiLevelsGenerationFlags(ctx, cmd)
386 apiVersions = d.apiVersionsXml
387 } else {
388 ctx.VisitDirectDepsWithTag(metalavaAPILevelsModuleTag, func(m android.Module) {
389 if s, ok := m.(*Droidstubs); ok {
390 apiVersions = s.apiVersionsXml
391 } else {
392 ctx.PropertyErrorf("api_levels_module",
393 "module %q is not a droidstubs module", ctx.OtherModuleName(m))
394 }
395 })
Colin Cross2207f872021-03-24 12:39:08 -0700396 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000397 if apiVersions != nil {
398 cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion().String())
399 cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename())
400 cmd.FlagWithInput("--apply-api-levels ", apiVersions)
401 }
402}
Colin Cross2207f872021-03-24 12:39:08 -0700403
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000404func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Colin Cross2207f872021-03-24 12:39:08 -0700405 if len(d.properties.Api_levels_annotations_dirs) == 0 {
406 ctx.PropertyErrorf("api_levels_annotations_dirs",
407 "has to be non-empty if api levels annotations was enabled!")
408 }
409
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000410 d.apiVersionsXml = android.PathForModuleOut(ctx, "metalava", "api-versions.xml")
Colin Cross2207f872021-03-24 12:39:08 -0700411 cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml)
Colin Cross2207f872021-03-24 12:39:08 -0700412
413 filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar")
414
satayev783195c2021-06-23 21:49:57 +0100415 var dirs []string
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200416 var extensions_dir string
Colin Cross2207f872021-03-24 12:39:08 -0700417 ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
418 if t, ok := m.(*ExportedDroiddocDir); ok {
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200419 extRegex := regexp.MustCompile(t.dir.String() + `/extensions/[0-9]+/public/.*\.jar`)
420
421 // Grab the first extensions_dir and we find while scanning ExportedDroiddocDir.deps;
422 // ideally this should be read from prebuiltApis.properties.Extensions_*
Colin Cross2207f872021-03-24 12:39:08 -0700423 for _, dep := range t.deps {
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200424 if extRegex.MatchString(dep.String()) && d.properties.Extensions_info_file != nil {
425 if extensions_dir == "" {
426 extensions_dir = t.dir.String() + "/extensions"
427 }
428 cmd.Implicit(dep)
429 }
Colin Cross5f6ffc72021-03-29 21:54:45 -0700430 if dep.Base() == filename {
431 cmd.Implicit(dep)
432 }
433 if filename != "android.jar" && dep.Base() == "android.jar" {
434 // Metalava implicitly searches these patterns:
435 // prebuilts/tools/common/api-versions/android-%/android.jar
436 // prebuilts/sdk/%/public/android.jar
437 // Add android.jar files from the api_levels_annotations_dirs directories to try
438 // to satisfy these patterns. If Metalava can't find a match for an API level
439 // between 1 and 28 in at least one pattern it will fail.
Colin Cross2207f872021-03-24 12:39:08 -0700440 cmd.Implicit(dep)
441 }
442 }
satayev783195c2021-06-23 21:49:57 +0100443
444 dirs = append(dirs, t.dir.String())
Colin Cross2207f872021-03-24 12:39:08 -0700445 } else {
446 ctx.PropertyErrorf("api_levels_annotations_dirs",
447 "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
448 }
449 })
satayev783195c2021-06-23 21:49:57 +0100450
451 // Add all relevant --android-jar-pattern patterns for Metalava.
452 // When parsing a stub jar for a specific version, Metalava picks the first pattern that defines
453 // an actual file present on disk (in the order the patterns were passed). For system APIs for
454 // privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs
Pedro Loureirocc203502021-10-04 17:24:00 +0000455 // for older releases. Similarly, module-lib falls back to system API.
456 var sdkDirs []string
457 switch proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") {
Cole Faust051fa912022-10-05 12:45:42 -0700458 case "system-server":
459 sdkDirs = []string{"system-server", "module-lib", "system", "public"}
Pedro Loureirocc203502021-10-04 17:24:00 +0000460 case "module-lib":
461 sdkDirs = []string{"module-lib", "system", "public"}
462 case "system":
463 sdkDirs = []string{"system", "public"}
464 case "public":
465 sdkDirs = []string{"public"}
466 default:
467 ctx.PropertyErrorf("api_levels_sdk_type", "needs to be one of %v", allowedApiLevelSdkTypes)
468 return
satayev783195c2021-06-23 21:49:57 +0100469 }
Pedro Loureirocc203502021-10-04 17:24:00 +0000470
471 for _, sdkDir := range sdkDirs {
472 for _, dir := range dirs {
473 cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, filename))
474 }
satayev783195c2021-06-23 21:49:57 +0100475 }
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200476
477 if d.properties.Extensions_info_file != nil {
478 if extensions_dir == "" {
479 ctx.ModuleErrorf("extensions_info_file set, but no SDK extension dirs found")
480 }
481 info_file := android.PathForModuleSrc(ctx, *d.properties.Extensions_info_file)
482 cmd.Implicit(info_file)
483 cmd.FlagWithArg("--sdk-extensions-root ", extensions_dir)
484 cmd.FlagWithArg("--sdk-extensions-info ", info_file.String())
485 }
Colin Cross2207f872021-03-24 12:39:08 -0700486}
487
Colin Crosse52c2ac2022-03-28 17:03:35 -0700488func metalavaUseRbe(ctx android.ModuleContext) bool {
489 return ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA")
490}
491
Colin Cross2207f872021-03-24 12:39:08 -0700492func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
Anton Hansson556e8142021-06-04 16:20:25 +0100493 srcJarList android.Path, bootclasspath, classpath classpath, homeDir android.WritablePath) *android.RuleBuilderCommand {
Colin Cross2207f872021-03-24 12:39:08 -0700494 rule.Command().Text("rm -rf").Flag(homeDir.String())
495 rule.Command().Text("mkdir -p").Flag(homeDir.String())
496
Anton Hansson556e8142021-06-04 16:20:25 +0100497 cmd := rule.Command()
Colin Cross2207f872021-03-24 12:39:08 -0700498 cmd.FlagWithArg("ANDROID_PREFS_ROOT=", homeDir.String())
499
Colin Crosse52c2ac2022-03-28 17:03:35 -0700500 if metalavaUseRbe(ctx) {
Colin Cross2207f872021-03-24 12:39:08 -0700501 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
Colin Cross8095c292021-03-30 16:40:48 -0700502 execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
Anas Sulaiman9c493642023-10-18 16:34:37 +0000503 compare, _ := strconv.ParseBool(ctx.Config().GetenvWithDefault("RBE_METALAVA_COMPARE", "false"))
Colin Cross8095c292021-03-30 16:40:48 -0700504 labels := map[string]string{"type": "tool", "name": "metalava"}
505 // TODO: metalava pool rejects these jobs
506 pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
507 rule.Rewrapper(&remoteexec.REParams{
508 Labels: labels,
509 ExecStrategy: execStrategy,
510 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
511 Platform: map[string]string{remoteexec.PoolKey: pool},
Anas Sulaiman9c493642023-10-18 16:34:37 +0000512 Compare: compare,
513 NumLocalRuns: 1,
514 NumRemoteRuns: 1,
Colin Cross8095c292021-03-30 16:40:48 -0700515 })
Colin Cross2207f872021-03-24 12:39:08 -0700516 }
517
Colin Cross6aa5c402021-03-24 12:28:50 -0700518 cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
Colin Cross2207f872021-03-24 12:39:08 -0700519 Flag(config.JavacVmFlags).
Liz Kammere09e20e2023-10-16 15:07:54 -0400520 Flag(config.MetalavaAddOpens).
Paul Duffin808211e2023-08-09 12:36:08 +0100521 FlagWithArg("--java-source ", javaVersion.String()).
Colin Cross2207f872021-03-24 12:39:08 -0700522 FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs).
523 FlagWithInput("@", srcJarList)
524
Paul Duffinf8aaaa12023-08-10 15:16:35 +0100525 // Metalava does not differentiate between bootclasspath and classpath and has not done so for
526 // years, so it is unlikely to change any time soon.
527 combinedPaths := append(([]android.Path)(nil), bootclasspath.Paths()...)
528 combinedPaths = append(combinedPaths, classpath.Paths()...)
529 if len(combinedPaths) > 0 {
530 cmd.FlagWithInputList("--classpath ", combinedPaths, ":")
Colin Cross2207f872021-03-24 12:39:08 -0700531 }
532
Liz Kammere09e20e2023-10-16 15:07:54 -0400533 cmd.Flag(config.MetalavaFlags)
Jihoon Kangc8313892023-09-20 00:54:47 +0000534 if ctx.DeviceConfig().HideFlaggedApis() {
Liz Kammere09e20e2023-10-16 15:07:54 -0400535 cmd.Flag(config.MetalavaHideFlaggedApis)
Jihoon Kangc8313892023-09-20 00:54:47 +0000536 }
537
Colin Cross2207f872021-03-24 12:39:08 -0700538 return cmd
539}
540
541func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
542 deps := d.Javadoc.collectDeps(ctx)
543
Jiyong Parkf1691d22021-03-29 20:11:58 +0900544 javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d))
Colin Cross2207f872021-03-24 12:39:08 -0700545
546 // Create rule for metalava
547
Colin Crosscb77f752021-03-24 12:04:44 -0700548 srcJarDir := android.PathForModuleOut(ctx, "metalava", "srcjars")
Colin Cross2207f872021-03-24 12:39:08 -0700549
550 rule := android.NewRuleBuilder(pctx, ctx)
551
Colin Cross8095c292021-03-30 16:40:48 -0700552 rule.Sbox(android.PathForModuleOut(ctx, "metalava"),
553 android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
554 SandboxInputs()
Colin Cross6aa5c402021-03-24 12:28:50 -0700555
Colin Cross2207f872021-03-24 12:39:08 -0700556 if BoolDefault(d.properties.High_mem, false) {
557 // This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel.
558 rule.HighMem()
559 }
560
561 generateStubs := BoolDefault(d.properties.Generate_stubs, true)
562 var stubsDir android.OptionalPath
563 if generateStubs {
Colin Crosscb77f752021-03-24 12:04:44 -0700564 d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
565 stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "metalava", "stubsDir"))
Colin Cross2207f872021-03-24 12:39:08 -0700566 rule.Command().Text("rm -rf").Text(stubsDir.String())
567 rule.Command().Text("mkdir -p").Text(stubsDir.String())
568 }
569
570 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
571
Colin Crosscb77f752021-03-24 12:04:44 -0700572 homeDir := android.PathForModuleOut(ctx, "metalava", "home")
Colin Cross2207f872021-03-24 12:39:08 -0700573 cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
Anton Hansson556e8142021-06-04 16:20:25 +0100574 deps.bootClasspath, deps.classpath, homeDir)
Colin Cross2207f872021-03-24 12:39:08 -0700575 cmd.Implicits(d.Javadoc.implicits)
576
577 d.stubsFlags(ctx, cmd, stubsDir)
578
579 d.annotationsFlags(ctx, cmd)
580 d.inclusionAnnotationsFlags(ctx, cmd)
581 d.apiLevelsAnnotationsFlags(ctx, cmd)
582
Colin Crossbc139922021-03-25 18:33:16 -0700583 d.expandArgs(ctx, cmd)
Colin Cross2207f872021-03-24 12:39:08 -0700584
Colin Cross2207f872021-03-24 12:39:08 -0700585 for _, o := range d.Javadoc.properties.Out {
586 cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
587 }
588
589 // Add options for the other optional tasks: API-lint and check-released.
590 // We generate separate timestamp files for them.
591
592 doApiLint := false
593 doCheckReleased := false
594
595 // Add API lint options.
596
597 if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) {
598 doApiLint = true
599
600 newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since)
601 if newSince.Valid() {
602 cmd.FlagWithInput("--api-lint ", newSince.Path())
603 } else {
604 cmd.Flag("--api-lint")
605 }
Colin Crosscb77f752021-03-24 12:04:44 -0700606 d.apiLintReport = android.PathForModuleOut(ctx, "metalava", "api_lint_report.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700607 cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO: Change to ":api-lint"
608
Colin Cross0d532412021-03-25 09:38:45 -0700609 // TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released.
Colin Cross2207f872021-03-24 12:39:08 -0700610 if d.Name() != "android.car-system-stubs-docs" &&
611 d.Name() != "android.car-stubs-docs" {
612 cmd.Flag("--lints-as-errors")
613 cmd.Flag("--warnings-as-errors") // Most lints are actually warnings.
614 }
615
616 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700617 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "api_lint_baseline.txt")
618 d.apiLintTimestamp = android.PathForModuleOut(ctx, "metalava", "api_lint.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700619
620 // Note this string includes a special shell quote $' ... ', which decodes the "\n"s.
Colin Cross2207f872021-03-24 12:39:08 -0700621 //
622 // TODO: metalava also has a slightly different message hardcoded. Should we unify this
623 // message and metalava's one?
624 msg := `$'` + // Enclose with $' ... '
625 `************************************************************\n` +
626 `Your API changes are triggering API Lint warnings or errors.\n` +
627 `To make these errors go away, fix the code according to the\n` +
628 `error and/or warning messages above.\n` +
629 `\n` +
630 `If it is not possible to do so, there are workarounds:\n` +
631 `\n` +
Aurimas Liutikasb23b7452021-05-24 18:00:37 +0000632 `1. You can suppress the errors with @SuppressLint("<id>")\n` +
633 ` where the <id> is given in brackets in the error message above.\n`
Colin Cross2207f872021-03-24 12:39:08 -0700634
635 if baselineFile.Valid() {
636 cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path())
637 cmd.FlagWithOutput("--update-baseline:api-lint ", updatedBaselineOutput)
638
639 msg += fmt.Sprintf(``+
640 `2. You can update the baseline by executing the following\n`+
641 ` command:\n`+
Colin Cross63eeda02021-04-15 19:01:57 -0700642 ` (cd $ANDROID_BUILD_TOP && cp \\\n`+
643 ` "%s" \\\n`+
644 ` "%s")\n`+
Colin Cross2207f872021-03-24 12:39:08 -0700645 ` To submit the revised baseline.txt to the main Android\n`+
646 ` repository, you will need approval.\n`, updatedBaselineOutput, baselineFile.Path())
647 } else {
648 msg += fmt.Sprintf(``+
649 `2. You can add a baseline file of existing lint failures\n`+
650 ` to the build rule of %s.\n`, d.Name())
651 }
652 // Note the message ends with a ' (single quote), to close the $' ... ' .
653 msg += `************************************************************\n'`
654
655 cmd.FlagWithArg("--error-message:api-lint ", msg)
656 }
657
658 // Add "check released" options. (Detect incompatible API changes from the last public release)
659
660 if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") {
661 doCheckReleased = true
662
663 if len(d.Javadoc.properties.Out) > 0 {
664 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
665 }
666
667 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
668 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
669 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700670 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "last_released_baseline.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700671
Colin Crosscb77f752021-03-24 12:04:44 -0700672 d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_last_released_api.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700673
674 cmd.FlagWithInput("--check-compatibility:api:released ", apiFile)
675 cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile)
676
677 if baselineFile.Valid() {
678 cmd.FlagWithInput("--baseline:compatibility:released ", baselineFile.Path())
679 cmd.FlagWithOutput("--update-baseline:compatibility:released ", updatedBaselineOutput)
680 }
681
682 // Note this string includes quote ($' ... '), which decodes the "\n"s.
683 msg := `$'\n******************************\n` +
684 `You have tried to change the API from what has been previously released in\n` +
685 `an SDK. Please fix the errors listed above.\n` +
686 `******************************\n'`
687
688 cmd.FlagWithArg("--error-message:compatibility:released ", msg)
689 }
690
Paul Duffin10a23c22023-08-11 22:47:31 +0100691 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
692 // Pass the current API file into metalava so it can use it as the basis for determining how to
693 // generate the output signature files (both api and removed).
694 currentApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
695 cmd.FlagWithInput("--use-same-format-as ", currentApiFile)
696 }
697
Colin Cross2207f872021-03-24 12:39:08 -0700698 if generateStubs {
699 rule.Command().
700 BuiltTool("soong_zip").
701 Flag("-write_if_changed").
702 Flag("-jar").
703 FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
704 FlagWithArg("-C ", stubsDir.String()).
705 FlagWithArg("-D ", stubsDir.String())
706 }
707
708 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700709 d.metadataZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-metadata.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700710 rule.Command().
711 BuiltTool("soong_zip").
712 Flag("-write_if_changed").
713 Flag("-d").
714 FlagWithOutput("-o ", d.metadataZip).
715 FlagWithArg("-C ", d.metadataDir.String()).
716 FlagWithArg("-D ", d.metadataDir.String())
717 }
718
719 // TODO: We don't really need two separate API files, but this is a reminiscence of how
720 // we used to run metalava separately for API lint and the "last_released" check. Unify them.
721 if doApiLint {
722 rule.Command().Text("touch").Output(d.apiLintTimestamp)
723 }
724 if doCheckReleased {
725 rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp)
726 }
727
Colin Cross6aa5c402021-03-24 12:28:50 -0700728 // TODO(b/183630617): rewrapper doesn't support restat rules
Colin Crosse52c2ac2022-03-28 17:03:35 -0700729 if !metalavaUseRbe(ctx) {
730 rule.Restat()
731 }
Colin Cross2207f872021-03-24 12:39:08 -0700732
733 zipSyncCleanupCmd(rule, srcJarDir)
734
Paul Duffinc166b682022-05-27 12:23:08 +0000735 rule.Build("metalava", "metalava merged")
736
Paul Duffine7a86642022-08-16 15:43:20 +0000737 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
738
739 if len(d.Javadoc.properties.Out) > 0 {
740 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
741 }
742
743 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
744 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
745 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)
746
747 if baselineFile.Valid() {
748 ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
749 }
750
751 d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp")
752
753 rule := android.NewRuleBuilder(pctx, ctx)
754
755 // Diff command line.
756 // -F matches the closest "opening" line, such as "package android {"
757 // and " public class Intent {".
758 diff := `diff -u -F '{ *$'`
759
760 rule.Command().Text("( true")
761 rule.Command().
762 Text(diff).
763 Input(apiFile).Input(d.apiFile)
764
765 rule.Command().
766 Text(diff).
767 Input(removedApiFile).Input(d.removedApiFile)
768
769 msg := fmt.Sprintf(`\n******************************\n`+
770 `You have tried to change the API from what has been previously approved.\n\n`+
771 `To make these errors go away, you have two choices:\n`+
772 ` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
773 ` to the new methods, etc. shown in the above diff.\n\n`+
774 ` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+
775 ` m %s-update-current-api\n\n`+
776 ` To submit the revised current.txt to the main Android repository,\n`+
777 ` you will need approval.\n`+
Jihoon Kang3ea64672023-11-03 00:40:26 +0000778 `If your build failed due to stub validation, you can resolve the errors with\n`+
779 `either of the two choices above and try re-building the target.\n`+
780 `If the mismatch between the stubs and the current.txt is intended,\n`+
781 `you can try re-building the target by executing the following command:\n`+
782 `m DISABLE_STUB_VALIDATION=true <your build target>\n`+
Paul Duffine7a86642022-08-16 15:43:20 +0000783 `******************************\n`, ctx.ModuleName())
784
785 rule.Command().
786 Text("touch").Output(d.checkCurrentApiTimestamp).
787 Text(") || (").
788 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
789 Text("; exit 38").
790 Text(")")
791
792 rule.Build("metalavaCurrentApiCheck", "check current API")
793
794 d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "update_current_api.timestamp")
795
796 // update API rule
797 rule = android.NewRuleBuilder(pctx, ctx)
798
799 rule.Command().Text("( true")
800
801 rule.Command().
802 Text("cp").Flag("-f").
803 Input(d.apiFile).Flag(apiFile.String())
804
805 rule.Command().
806 Text("cp").Flag("-f").
807 Input(d.removedApiFile).Flag(removedApiFile.String())
808
809 msg = "failed to update public API"
810
811 rule.Command().
812 Text("touch").Output(d.updateCurrentApiTimestamp).
813 Text(") || (").
814 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
815 Text("; exit 38").
816 Text(")")
817
818 rule.Build("metalavaCurrentApiUpdate", "update current API")
819 }
820
Colin Cross2207f872021-03-24 12:39:08 -0700821 if String(d.properties.Check_nullability_warnings) != "" {
822 if d.nullabilityWarningsFile == nil {
823 ctx.PropertyErrorf("check_nullability_warnings",
824 "Cannot specify check_nullability_warnings unless validating nullability")
825 }
826
827 checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings))
828
Colin Crosscb77f752021-03-24 12:04:44 -0700829 d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "metalava", "check_nullability_warnings.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700830
831 msg := fmt.Sprintf(`\n******************************\n`+
832 `The warnings encountered during nullability annotation validation did\n`+
833 `not match the checked in file of expected warnings. The diffs are shown\n`+
834 `above. You have two options:\n`+
835 ` 1. Resolve the differences by editing the nullability annotations.\n`+
836 ` 2. Update the file of expected warnings by running:\n`+
837 ` cp %s %s\n`+
838 ` and submitting the updated file as part of your change.`,
839 d.nullabilityWarningsFile, checkNullabilityWarnings)
840
841 rule := android.NewRuleBuilder(pctx, ctx)
842
843 rule.Command().
844 Text("(").
845 Text("diff").Input(checkNullabilityWarnings).Input(d.nullabilityWarningsFile).
846 Text("&&").
847 Text("touch").Output(d.checkNullabilityWarningsTimestamp).
848 Text(") || (").
849 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
850 Text("; exit 38").
851 Text(")")
852
853 rule.Build("nullabilityWarningsCheck", "nullability warnings check")
854 }
855}
856
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000857func (d *Droidstubs) createApiContribution(ctx android.DefaultableHookContext) {
858 api_file := d.properties.Check_api.Current.Api_file
859 api_surface := d.properties.Api_surface
860
861 props := struct {
862 Name *string
863 Api_surface *string
864 Api_file *string
Jihoon Kang42b589c2023-02-03 22:56:13 +0000865 Visibility []string
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000866 }{}
867
868 props.Name = proptools.StringPtr(d.Name() + ".api.contribution")
869 props.Api_surface = api_surface
870 props.Api_file = api_file
Jihoon Kang42b589c2023-02-03 22:56:13 +0000871 props.Visibility = []string{"//visibility:override", "//visibility:public"}
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000872
873 ctx.CreateModule(ApiContributionFactory, &props)
874}
875
Spandan Das0b555e32022-11-28 18:48:51 +0000876// TODO (b/262014796): Export the API contributions of CorePlatformApi
877// A map to populate the api surface of a droidstub from a substring appearing in its name
878// This map assumes that droidstubs (either checked-in or created by java_sdk_library)
879// use a strict naming convention
880var (
881 droidstubsModuleNamingToSdkKind = map[string]android.SdkKind{
882 //public is commented out since the core libraries use public in their java_sdk_library names
883 "intracore": android.SdkIntraCore,
884 "intra.core": android.SdkIntraCore,
885 "system_server": android.SdkSystemServer,
886 "system-server": android.SdkSystemServer,
887 "system": android.SdkSystem,
888 "module_lib": android.SdkModule,
889 "module-lib": android.SdkModule,
Spandan Dasda977552023-01-26 20:45:16 +0000890 "platform.api": android.SdkCorePlatform,
Spandan Das0b555e32022-11-28 18:48:51 +0000891 "test": android.SdkTest,
Spandan Das4ac2aed2022-12-28 01:54:29 +0000892 "toolchain": android.SdkToolchain,
Spandan Das0b555e32022-11-28 18:48:51 +0000893 }
894)
895
896// A helper function that returns the api surface of the corresponding java_api_contribution Bazel target
897// The api_surface is populated using the naming convention of the droidstubs module.
898func bazelApiSurfaceName(name string) string {
899 // Sort the keys so that longer strings appear first
900 // Otherwise substrings like system will match both system and system_server
901 sortedKeys := make([]string, 0)
902 for key := range droidstubsModuleNamingToSdkKind {
903 sortedKeys = append(sortedKeys, key)
904 }
905 sort.Slice(sortedKeys, func(i, j int) bool {
906 return len(sortedKeys[i]) > len(sortedKeys[j])
907 })
908 for _, sortedKey := range sortedKeys {
909 if strings.Contains(name, sortedKey) {
910 sdkKind := droidstubsModuleNamingToSdkKind[sortedKey]
911 return sdkKind.String() + "api"
912 }
913 }
914 // Default is publicapi
915 return android.SdkPublic.String() + "api"
916}
917
Colin Cross2207f872021-03-24 12:39:08 -0700918func StubsDefaultsFactory() android.Module {
919 module := &DocDefaults{}
920
921 module.AddProperties(
922 &JavadocProperties{},
923 &DroidstubsProperties{},
924 )
925
926 android.InitDefaultsModule(module)
927
928 return module
929}
930
931var _ android.PrebuiltInterface = (*PrebuiltStubsSources)(nil)
932
933type PrebuiltStubsSourcesProperties struct {
934 Srcs []string `android:"path"`
935}
936
937type PrebuiltStubsSources struct {
938 android.ModuleBase
939 android.DefaultableModuleBase
Spandan Das2cc80ba2023-10-27 17:21:52 +0000940 embeddableInModuleAndImport
941
Colin Cross2207f872021-03-24 12:39:08 -0700942 prebuilt android.Prebuilt
Colin Cross2207f872021-03-24 12:39:08 -0700943
944 properties PrebuiltStubsSourcesProperties
945
kgui67007242022-01-25 13:50:25 +0800946 stubsSrcJar android.Path
Colin Cross2207f872021-03-24 12:39:08 -0700947}
948
949func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
950 switch tag {
951 case "":
952 return android.Paths{p.stubsSrcJar}, nil
953 default:
954 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
955 }
956}
957
958func (d *PrebuiltStubsSources) StubsSrcJar() android.Path {
959 return d.stubsSrcJar
960}
961
962func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Cross2207f872021-03-24 12:39:08 -0700963 if len(p.properties.Srcs) != 1 {
Anton Hansson86758ac2021-11-03 14:44:12 +0000964 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 -0700965 return
966 }
967
Anton Hansson86758ac2021-11-03 14:44:12 +0000968 src := p.properties.Srcs[0]
969 if filepath.Ext(src) == ".srcjar" {
970 // This is a srcjar. We can use it directly.
971 p.stubsSrcJar = android.PathForModuleSrc(ctx, src)
972 } else {
973 outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
Colin Cross2207f872021-03-24 12:39:08 -0700974
Anton Hansson86758ac2021-11-03 14:44:12 +0000975 // This is a directory. Glob the contents just in case the directory does not exist.
976 srcGlob := src + "/**/*"
977 srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
Colin Cross2207f872021-03-24 12:39:08 -0700978
Anton Hansson86758ac2021-11-03 14:44:12 +0000979 // Although PathForModuleSrc can return nil if either the path doesn't exist or
980 // the path components are invalid it won't in this case because no components
981 // are specified and the module directory must exist in order to get this far.
982 srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, src)
Colin Cross2207f872021-03-24 12:39:08 -0700983
Anton Hansson86758ac2021-11-03 14:44:12 +0000984 rule := android.NewRuleBuilder(pctx, ctx)
985 rule.Command().
986 BuiltTool("soong_zip").
987 Flag("-write_if_changed").
988 Flag("-jar").
989 FlagWithOutput("-o ", outPath).
990 FlagWithArg("-C ", srcDir.String()).
991 FlagWithRspFileInputList("-r ", outPath.ReplaceExtension(ctx, "rsp"), srcPaths)
992 rule.Restat()
993 rule.Build("zip src", "Create srcjar from prebuilt source")
994 p.stubsSrcJar = outPath
995 }
Colin Cross2207f872021-03-24 12:39:08 -0700996}
997
998func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
999 return &p.prebuilt
1000}
1001
1002func (p *PrebuiltStubsSources) Name() string {
1003 return p.prebuilt.Name(p.ModuleBase.Name())
1004}
1005
1006// prebuilt_stubs_sources imports a set of java source files as if they were
1007// generated by droidstubs.
1008//
1009// By default, a prebuilt_stubs_sources has a single variant that expects a
1010// set of `.java` files generated by droidstubs.
1011//
1012// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one
1013// for host modules.
1014//
1015// Intended only for use by sdk snapshots.
1016func PrebuiltStubsSourcesFactory() android.Module {
1017 module := &PrebuiltStubsSources{}
1018
1019 module.AddProperties(&module.properties)
Spandan Das2cc80ba2023-10-27 17:21:52 +00001020 module.initModuleAndImport(module)
Colin Cross2207f872021-03-24 12:39:08 -07001021
1022 android.InitPrebuiltModule(module, &module.properties.Srcs)
Colin Cross2207f872021-03-24 12:39:08 -07001023 InitDroiddocModule(module, android.HostAndDeviceSupported)
1024 return module
1025}