blob: a7e8eb659bb51cd087c7db4fb044db77311aba03 [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
Colin Cross2207f872021-03-24 12:39:08 -070051
52 properties DroidstubsProperties
Paul Duffinc71d2b72022-08-16 15:24:01 +000053 apiFile android.Path
54 removedApiFile android.Path
Colin Cross2207f872021-03-24 12:39:08 -070055 nullabilityWarningsFile android.WritablePath
56
57 checkCurrentApiTimestamp android.WritablePath
58 updateCurrentApiTimestamp android.WritablePath
59 checkLastReleasedApiTimestamp android.WritablePath
60 apiLintTimestamp android.WritablePath
61 apiLintReport android.WritablePath
62
63 checkNullabilityWarningsTimestamp android.WritablePath
64
65 annotationsZip android.WritablePath
66 apiVersionsXml android.WritablePath
67
Colin Cross2207f872021-03-24 12:39:08 -070068 metadataZip android.WritablePath
69 metadataDir android.WritablePath
70}
71
72type DroidstubsProperties struct {
73 // The generated public API filename by Metalava, defaults to <module>_api.txt
74 Api_filename *string
75
76 // the generated removed API filename by Metalava, defaults to <module>_removed.txt
77 Removed_api_filename *string
78
Colin Cross2207f872021-03-24 12:39:08 -070079 Check_api struct {
80 Last_released ApiToCheck
81
82 Current ApiToCheck
83
84 Api_lint struct {
85 Enabled *bool
86
87 // If set, performs api_lint on any new APIs not found in the given signature file
88 New_since *string `android:"path"`
89
90 // If not blank, path to the baseline txt file for approved API lint violations.
91 Baseline_file *string `android:"path"`
92 }
93 }
94
95 // user can specify the version of previous released API file in order to do compatibility check.
96 Previous_api *string `android:"path"`
97
98 // is set to true, Metalava will allow framework SDK to contain annotations.
99 Annotations_enabled *bool
100
101 // a list of top-level directories containing files to merge qualifier annotations (i.e. those intended to be included in the stubs written) from.
102 Merge_annotations_dirs []string
103
104 // a list of top-level directories containing Java stub files to merge show/hide annotations from.
105 Merge_inclusion_annotations_dirs []string
106
107 // a file containing a list of classes to do nullability validation for.
108 Validate_nullability_from_list *string
109
110 // a file containing expected warnings produced by validation of nullability annotations.
111 Check_nullability_warnings *string
112
113 // if set to true, allow Metalava to generate doc_stubs source files. Defaults to false.
114 Create_doc_stubs *bool
115
116 // if set to true, cause Metalava to output Javadoc comments in the stubs source files. Defaults to false.
117 // Has no effect if create_doc_stubs: true.
118 Output_javadoc_comments *bool
119
120 // if set to false then do not write out stubs. Defaults to true.
121 //
122 // TODO(b/146727827): Remove capability when we do not need to generate stubs and API separately.
123 Generate_stubs *bool
124
125 // if set to true, provides a hint to the build system that this rule uses a lot of memory,
Liz Kammer170dd722023-10-16 15:08:39 -0400126 // which can be used for scheduling purposes
Colin Cross2207f872021-03-24 12:39:08 -0700127 High_mem *bool
128
satayev783195c2021-06-23 21:49:57 +0100129 // if set to true, Metalava will allow framework SDK to contain API levels annotations.
Colin Cross2207f872021-03-24 12:39:08 -0700130 Api_levels_annotations_enabled *bool
131
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000132 // Apply the api levels database created by this module rather than generating one in this droidstubs.
133 Api_levels_module *string
134
Colin Cross2207f872021-03-24 12:39:08 -0700135 // the dirs which Metalava extracts API levels annotations from.
136 Api_levels_annotations_dirs []string
137
Cole Faust051fa912022-10-05 12:45:42 -0700138 // the sdk kind which Metalava extracts API levels annotations from. Supports 'public', 'system', 'module-lib' and 'system-server'; defaults to public.
satayev783195c2021-06-23 21:49:57 +0100139 Api_levels_sdk_type *string
140
Colin Cross2207f872021-03-24 12:39:08 -0700141 // the filename which Metalava extracts API levels annotations from. Defaults to android.jar.
142 Api_levels_jar_filename *string
143
144 // if set to true, collect the values used by the Dev tools and
145 // write them in files packaged with the SDK. Defaults to false.
146 Write_sdk_values *bool
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200147
148 // path or filegroup to file defining extension an SDK name <-> numerical ID mapping and
149 // what APIs exist in which SDKs; passed to metalava via --sdk-extensions-info
150 Extensions_info_file *string `android:"path"`
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000151
152 // API surface of this module. If set, the module contributes to an API surface.
153 // For the full list of available API surfaces, refer to soong/android/sdk_version.go
154 Api_surface *string
Colin Cross2207f872021-03-24 12:39:08 -0700155}
156
Anton Hansson52609322021-05-05 10:36:05 +0100157// Used by xsd_config
158type ApiFilePath interface {
159 ApiFilePath() android.Path
160}
161
162type ApiStubsSrcProvider interface {
163 StubsSrcJar() android.Path
164}
165
166// Provider of information about API stubs, used by java_sdk_library.
167type ApiStubsProvider interface {
Anton Hanssond78eb762021-09-21 15:25:12 +0100168 AnnotationsZip() android.Path
Anton Hansson52609322021-05-05 10:36:05 +0100169 ApiFilePath
170 RemovedApiFilePath() android.Path
171
172 ApiStubsSrcProvider
173}
174
Jihoon Kang063ec002023-06-28 01:16:23 +0000175type currentApiTimestampProvider interface {
176 CurrentApiTimestamp() android.Path
177}
178
Colin Cross2207f872021-03-24 12:39:08 -0700179// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
180// documented, filtering out hidden classes and methods. The resulting .java files are intended to be passed to
181// a droiddoc module to generate documentation.
182func DroidstubsFactory() android.Module {
183 module := &Droidstubs{}
184
185 module.AddProperties(&module.properties,
186 &module.Javadoc.properties)
187
188 InitDroiddocModule(module, android.HostAndDeviceSupported)
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000189
190 module.SetDefaultableHook(func(ctx android.DefaultableHookContext) {
191 module.createApiContribution(ctx)
192 })
Colin Cross2207f872021-03-24 12:39:08 -0700193 return module
194}
195
196// droidstubs_host passes sources files through Metalava to generate stub .java files that only contain the API
197// to be documented, filtering out hidden classes and methods. The resulting .java files are intended to be
198// passed to a droiddoc_host module to generate documentation. Use a droidstubs_host instead of a droidstubs
199// module when symbols needed by the source files are provided by java_library_host modules.
200func DroidstubsHostFactory() android.Module {
201 module := &Droidstubs{}
202
203 module.AddProperties(&module.properties,
204 &module.Javadoc.properties)
205
206 InitDroiddocModule(module, android.HostSupported)
207 return module
208}
209
210func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) {
211 switch tag {
212 case "":
213 return android.Paths{d.stubsSrcJar}, nil
214 case ".docs.zip":
215 return android.Paths{d.docZip}, nil
216 case ".api.txt", android.DefaultDistTag:
217 // This is the default dist path for dist properties that have no tag property.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000218 return android.Paths{d.apiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700219 case ".removed-api.txt":
Paul Duffinc71d2b72022-08-16 15:24:01 +0000220 return android.Paths{d.removedApiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700221 case ".annotations.zip":
222 return android.Paths{d.annotationsZip}, nil
223 case ".api_versions.xml":
224 return android.Paths{d.apiVersionsXml}, nil
225 default:
226 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
227 }
228}
229
Anton Hanssond78eb762021-09-21 15:25:12 +0100230func (d *Droidstubs) AnnotationsZip() android.Path {
231 return d.annotationsZip
232}
233
Colin Cross2207f872021-03-24 12:39:08 -0700234func (d *Droidstubs) ApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000235 return d.apiFile
Colin Cross2207f872021-03-24 12:39:08 -0700236}
237
238func (d *Droidstubs) RemovedApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000239 return d.removedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700240}
241
242func (d *Droidstubs) StubsSrcJar() android.Path {
243 return d.stubsSrcJar
244}
245
Jihoon Kang063ec002023-06-28 01:16:23 +0000246func (d *Droidstubs) CurrentApiTimestamp() android.Path {
247 return d.checkCurrentApiTimestamp
248}
249
Colin Cross2207f872021-03-24 12:39:08 -0700250var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"}
251var metalavaMergeInclusionAnnotationsDirTag = dependencyTag{name: "metalava-merge-inclusion-annotations-dir"}
252var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"}
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000253var metalavaAPILevelsModuleTag = dependencyTag{name: "metalava-api-levels-module-tag"}
Jihoon Kang063ec002023-06-28 01:16:23 +0000254var metalavaCurrentApiTimestampTag = dependencyTag{name: "metalava-current-api-timestamp-tag"}
Colin Cross2207f872021-03-24 12:39:08 -0700255
256func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) {
257 d.Javadoc.addDeps(ctx)
258
259 if len(d.properties.Merge_annotations_dirs) != 0 {
260 for _, mergeAnnotationsDir := range d.properties.Merge_annotations_dirs {
261 ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir)
262 }
263 }
264
265 if len(d.properties.Merge_inclusion_annotations_dirs) != 0 {
266 for _, mergeInclusionAnnotationsDir := range d.properties.Merge_inclusion_annotations_dirs {
267 ctx.AddDependency(ctx.Module(), metalavaMergeInclusionAnnotationsDirTag, mergeInclusionAnnotationsDir)
268 }
269 }
270
271 if len(d.properties.Api_levels_annotations_dirs) != 0 {
272 for _, apiLevelsAnnotationsDir := range d.properties.Api_levels_annotations_dirs {
273 ctx.AddDependency(ctx.Module(), metalavaAPILevelsAnnotationsDirTag, apiLevelsAnnotationsDir)
274 }
275 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000276
277 if d.properties.Api_levels_module != nil {
278 ctx.AddDependency(ctx.Module(), metalavaAPILevelsModuleTag, proptools.String(d.properties.Api_levels_module))
279 }
Colin Cross2207f872021-03-24 12:39:08 -0700280}
281
282func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) {
283 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
284 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
285 String(d.properties.Api_filename) != "" {
286 filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000287 uncheckedApiFile := android.PathForModuleOut(ctx, "metalava", filename)
288 cmd.FlagWithOutput("--api ", uncheckedApiFile)
289 d.apiFile = uncheckedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700290 } else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" {
291 // If check api is disabled then make the source file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000292 d.apiFile = android.PathForModuleSrc(ctx, sourceApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700293 }
294
295 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
296 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
297 String(d.properties.Removed_api_filename) != "" {
298 filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000299 uncheckedRemovedFile := android.PathForModuleOut(ctx, "metalava", filename)
300 cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile)
301 d.removedApiFile = uncheckedRemovedFile
Colin Cross2207f872021-03-24 12:39:08 -0700302 } else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" {
303 // If check api is disabled then make the source removed api file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000304 d.removedApiFile = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700305 }
306
Colin Cross2207f872021-03-24 12:39:08 -0700307 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700308 d.metadataDir = android.PathForModuleOut(ctx, "metalava", "metadata")
Colin Cross2207f872021-03-24 12:39:08 -0700309 cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
310 }
311
312 if stubsDir.Valid() {
313 if Bool(d.properties.Create_doc_stubs) {
314 cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
315 } else {
316 cmd.FlagWithArg("--stubs ", stubsDir.String())
317 if !Bool(d.properties.Output_javadoc_comments) {
318 cmd.Flag("--exclude-documentation-from-stubs")
319 }
320 }
321 }
322}
323
324func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
325 if Bool(d.properties.Annotations_enabled) {
Liz Kammere09e20e2023-10-16 15:07:54 -0400326 cmd.Flag(config.MetalavaAnnotationsFlags)
Andrei Onea4985e512021-04-29 16:29:34 +0100327
Colin Cross2207f872021-03-24 12:39:08 -0700328 validatingNullability :=
Colin Crossbc139922021-03-25 18:33:16 -0700329 strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") ||
Colin Cross2207f872021-03-24 12:39:08 -0700330 String(d.properties.Validate_nullability_from_list) != ""
331
332 migratingNullability := String(d.properties.Previous_api) != ""
333 if migratingNullability {
334 previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
335 cmd.FlagWithInput("--migrate-nullness ", previousApi)
336 }
337
338 if s := String(d.properties.Validate_nullability_from_list); s != "" {
339 cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
340 }
341
342 if validatingNullability {
Colin Crosscb77f752021-03-24 12:04:44 -0700343 d.nullabilityWarningsFile = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_nullability_warnings.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700344 cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile)
345 }
346
Colin Crosscb77f752021-03-24 12:04:44 -0700347 d.annotationsZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_annotations.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700348 cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip)
349
350 if len(d.properties.Merge_annotations_dirs) != 0 {
351 d.mergeAnnoDirFlags(ctx, cmd)
352 }
353
Liz Kammere09e20e2023-10-16 15:07:54 -0400354 cmd.Flag(config.MetalavaAnnotationsWarningsFlags)
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)
Anas Sulaiman9c493642023-10-18 16:34:37 +0000501 compare, _ := strconv.ParseBool(ctx.Config().GetenvWithDefault("RBE_METALAVA_COMPARE", "false"))
Colin Cross8095c292021-03-30 16:40:48 -0700502 labels := map[string]string{"type": "tool", "name": "metalava"}
503 // TODO: metalava pool rejects these jobs
504 pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
505 rule.Rewrapper(&remoteexec.REParams{
506 Labels: labels,
507 ExecStrategy: execStrategy,
508 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
509 Platform: map[string]string{remoteexec.PoolKey: pool},
Anas Sulaiman9c493642023-10-18 16:34:37 +0000510 Compare: compare,
511 NumLocalRuns: 1,
512 NumRemoteRuns: 1,
Colin Cross8095c292021-03-30 16:40:48 -0700513 })
Colin Cross2207f872021-03-24 12:39:08 -0700514 }
515
Colin Cross6aa5c402021-03-24 12:28:50 -0700516 cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
Colin Cross2207f872021-03-24 12:39:08 -0700517 Flag(config.JavacVmFlags).
Liz Kammere09e20e2023-10-16 15:07:54 -0400518 Flag(config.MetalavaAddOpens).
Paul Duffin808211e2023-08-09 12:36:08 +0100519 FlagWithArg("--java-source ", javaVersion.String()).
Colin Cross2207f872021-03-24 12:39:08 -0700520 FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs).
521 FlagWithInput("@", srcJarList)
522
Paul Duffinf8aaaa12023-08-10 15:16:35 +0100523 // Metalava does not differentiate between bootclasspath and classpath and has not done so for
524 // years, so it is unlikely to change any time soon.
525 combinedPaths := append(([]android.Path)(nil), bootclasspath.Paths()...)
526 combinedPaths = append(combinedPaths, classpath.Paths()...)
527 if len(combinedPaths) > 0 {
528 cmd.FlagWithInputList("--classpath ", combinedPaths, ":")
Colin Cross2207f872021-03-24 12:39:08 -0700529 }
530
Liz Kammere09e20e2023-10-16 15:07:54 -0400531 cmd.Flag(config.MetalavaFlags)
Jihoon Kangc8313892023-09-20 00:54:47 +0000532 if ctx.DeviceConfig().HideFlaggedApis() {
Liz Kammere09e20e2023-10-16 15:07:54 -0400533 cmd.Flag(config.MetalavaHideFlaggedApis)
Jihoon Kangc8313892023-09-20 00:54:47 +0000534 }
535
Colin Cross2207f872021-03-24 12:39:08 -0700536 return cmd
537}
538
539func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
540 deps := d.Javadoc.collectDeps(ctx)
541
Jiyong Parkf1691d22021-03-29 20:11:58 +0900542 javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d))
Colin Cross2207f872021-03-24 12:39:08 -0700543
544 // Create rule for metalava
545
Colin Crosscb77f752021-03-24 12:04:44 -0700546 srcJarDir := android.PathForModuleOut(ctx, "metalava", "srcjars")
Colin Cross2207f872021-03-24 12:39:08 -0700547
548 rule := android.NewRuleBuilder(pctx, ctx)
549
Colin Cross8095c292021-03-30 16:40:48 -0700550 rule.Sbox(android.PathForModuleOut(ctx, "metalava"),
551 android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
552 SandboxInputs()
Colin Cross6aa5c402021-03-24 12:28:50 -0700553
Colin Cross2207f872021-03-24 12:39:08 -0700554 if BoolDefault(d.properties.High_mem, false) {
555 // This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel.
556 rule.HighMem()
557 }
558
559 generateStubs := BoolDefault(d.properties.Generate_stubs, true)
560 var stubsDir android.OptionalPath
561 if generateStubs {
Colin Crosscb77f752021-03-24 12:04:44 -0700562 d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
563 stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "metalava", "stubsDir"))
Colin Cross2207f872021-03-24 12:39:08 -0700564 rule.Command().Text("rm -rf").Text(stubsDir.String())
565 rule.Command().Text("mkdir -p").Text(stubsDir.String())
566 }
567
568 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
569
Colin Crosscb77f752021-03-24 12:04:44 -0700570 homeDir := android.PathForModuleOut(ctx, "metalava", "home")
Colin Cross2207f872021-03-24 12:39:08 -0700571 cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
Anton Hansson556e8142021-06-04 16:20:25 +0100572 deps.bootClasspath, deps.classpath, homeDir)
Colin Cross2207f872021-03-24 12:39:08 -0700573 cmd.Implicits(d.Javadoc.implicits)
574
575 d.stubsFlags(ctx, cmd, stubsDir)
576
577 d.annotationsFlags(ctx, cmd)
578 d.inclusionAnnotationsFlags(ctx, cmd)
579 d.apiLevelsAnnotationsFlags(ctx, cmd)
580
Colin Crossbc139922021-03-25 18:33:16 -0700581 d.expandArgs(ctx, cmd)
Colin Cross2207f872021-03-24 12:39:08 -0700582
Colin Cross2207f872021-03-24 12:39:08 -0700583 for _, o := range d.Javadoc.properties.Out {
584 cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
585 }
586
587 // Add options for the other optional tasks: API-lint and check-released.
588 // We generate separate timestamp files for them.
589
590 doApiLint := false
591 doCheckReleased := false
592
593 // Add API lint options.
594
595 if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) {
596 doApiLint = true
597
598 newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since)
599 if newSince.Valid() {
600 cmd.FlagWithInput("--api-lint ", newSince.Path())
601 } else {
602 cmd.Flag("--api-lint")
603 }
Colin Crosscb77f752021-03-24 12:04:44 -0700604 d.apiLintReport = android.PathForModuleOut(ctx, "metalava", "api_lint_report.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700605 cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO: Change to ":api-lint"
606
Colin Cross0d532412021-03-25 09:38:45 -0700607 // TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released.
Colin Cross2207f872021-03-24 12:39:08 -0700608 if d.Name() != "android.car-system-stubs-docs" &&
609 d.Name() != "android.car-stubs-docs" {
610 cmd.Flag("--lints-as-errors")
611 cmd.Flag("--warnings-as-errors") // Most lints are actually warnings.
612 }
613
614 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700615 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "api_lint_baseline.txt")
616 d.apiLintTimestamp = android.PathForModuleOut(ctx, "metalava", "api_lint.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700617
618 // Note this string includes a special shell quote $' ... ', which decodes the "\n"s.
Colin Cross2207f872021-03-24 12:39:08 -0700619 //
620 // TODO: metalava also has a slightly different message hardcoded. Should we unify this
621 // message and metalava's one?
622 msg := `$'` + // Enclose with $' ... '
623 `************************************************************\n` +
624 `Your API changes are triggering API Lint warnings or errors.\n` +
625 `To make these errors go away, fix the code according to the\n` +
626 `error and/or warning messages above.\n` +
627 `\n` +
628 `If it is not possible to do so, there are workarounds:\n` +
629 `\n` +
Aurimas Liutikasb23b7452021-05-24 18:00:37 +0000630 `1. You can suppress the errors with @SuppressLint("<id>")\n` +
631 ` where the <id> is given in brackets in the error message above.\n`
Colin Cross2207f872021-03-24 12:39:08 -0700632
633 if baselineFile.Valid() {
634 cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path())
635 cmd.FlagWithOutput("--update-baseline:api-lint ", updatedBaselineOutput)
636
637 msg += fmt.Sprintf(``+
638 `2. You can update the baseline by executing the following\n`+
639 ` command:\n`+
Colin Cross63eeda02021-04-15 19:01:57 -0700640 ` (cd $ANDROID_BUILD_TOP && cp \\\n`+
641 ` "%s" \\\n`+
642 ` "%s")\n`+
Colin Cross2207f872021-03-24 12:39:08 -0700643 ` To submit the revised baseline.txt to the main Android\n`+
644 ` repository, you will need approval.\n`, updatedBaselineOutput, baselineFile.Path())
645 } else {
646 msg += fmt.Sprintf(``+
647 `2. You can add a baseline file of existing lint failures\n`+
648 ` to the build rule of %s.\n`, d.Name())
649 }
650 // Note the message ends with a ' (single quote), to close the $' ... ' .
651 msg += `************************************************************\n'`
652
653 cmd.FlagWithArg("--error-message:api-lint ", msg)
654 }
655
656 // Add "check released" options. (Detect incompatible API changes from the last public release)
657
658 if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") {
659 doCheckReleased = true
660
661 if len(d.Javadoc.properties.Out) > 0 {
662 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
663 }
664
665 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
666 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
667 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file)
Colin Crosscb77f752021-03-24 12:04:44 -0700668 updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "last_released_baseline.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700669
Colin Crosscb77f752021-03-24 12:04:44 -0700670 d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_last_released_api.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700671
672 cmd.FlagWithInput("--check-compatibility:api:released ", apiFile)
673 cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile)
674
675 if baselineFile.Valid() {
676 cmd.FlagWithInput("--baseline:compatibility:released ", baselineFile.Path())
677 cmd.FlagWithOutput("--update-baseline:compatibility:released ", updatedBaselineOutput)
678 }
679
680 // Note this string includes quote ($' ... '), which decodes the "\n"s.
681 msg := `$'\n******************************\n` +
682 `You have tried to change the API from what has been previously released in\n` +
683 `an SDK. Please fix the errors listed above.\n` +
684 `******************************\n'`
685
686 cmd.FlagWithArg("--error-message:compatibility:released ", msg)
687 }
688
Paul Duffin10a23c22023-08-11 22:47:31 +0100689 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
690 // Pass the current API file into metalava so it can use it as the basis for determining how to
691 // generate the output signature files (both api and removed).
692 currentApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
693 cmd.FlagWithInput("--use-same-format-as ", currentApiFile)
694 }
695
Colin Cross2207f872021-03-24 12:39:08 -0700696 if generateStubs {
697 rule.Command().
698 BuiltTool("soong_zip").
699 Flag("-write_if_changed").
700 Flag("-jar").
701 FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
702 FlagWithArg("-C ", stubsDir.String()).
703 FlagWithArg("-D ", stubsDir.String())
704 }
705
706 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700707 d.metadataZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-metadata.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700708 rule.Command().
709 BuiltTool("soong_zip").
710 Flag("-write_if_changed").
711 Flag("-d").
712 FlagWithOutput("-o ", d.metadataZip).
713 FlagWithArg("-C ", d.metadataDir.String()).
714 FlagWithArg("-D ", d.metadataDir.String())
715 }
716
717 // TODO: We don't really need two separate API files, but this is a reminiscence of how
718 // we used to run metalava separately for API lint and the "last_released" check. Unify them.
719 if doApiLint {
720 rule.Command().Text("touch").Output(d.apiLintTimestamp)
721 }
722 if doCheckReleased {
723 rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp)
724 }
725
Colin Cross6aa5c402021-03-24 12:28:50 -0700726 // TODO(b/183630617): rewrapper doesn't support restat rules
Colin Crosse52c2ac2022-03-28 17:03:35 -0700727 if !metalavaUseRbe(ctx) {
728 rule.Restat()
729 }
Colin Cross2207f872021-03-24 12:39:08 -0700730
731 zipSyncCleanupCmd(rule, srcJarDir)
732
Paul Duffinc166b682022-05-27 12:23:08 +0000733 rule.Build("metalava", "metalava merged")
734
Paul Duffine7a86642022-08-16 15:43:20 +0000735 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
736
737 if len(d.Javadoc.properties.Out) > 0 {
738 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
739 }
740
741 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
742 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
743 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)
744
745 if baselineFile.Valid() {
746 ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
747 }
748
749 d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp")
750
751 rule := android.NewRuleBuilder(pctx, ctx)
752
753 // Diff command line.
754 // -F matches the closest "opening" line, such as "package android {"
755 // and " public class Intent {".
756 diff := `diff -u -F '{ *$'`
757
758 rule.Command().Text("( true")
759 rule.Command().
760 Text(diff).
761 Input(apiFile).Input(d.apiFile)
762
763 rule.Command().
764 Text(diff).
765 Input(removedApiFile).Input(d.removedApiFile)
766
767 msg := fmt.Sprintf(`\n******************************\n`+
768 `You have tried to change the API from what has been previously approved.\n\n`+
769 `To make these errors go away, you have two choices:\n`+
770 ` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
771 ` to the new methods, etc. shown in the above diff.\n\n`+
772 ` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+
773 ` m %s-update-current-api\n\n`+
774 ` To submit the revised current.txt to the main Android repository,\n`+
775 ` you will need approval.\n`+
776 `******************************\n`, ctx.ModuleName())
777
778 rule.Command().
779 Text("touch").Output(d.checkCurrentApiTimestamp).
780 Text(") || (").
781 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
782 Text("; exit 38").
783 Text(")")
784
785 rule.Build("metalavaCurrentApiCheck", "check current API")
786
787 d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "update_current_api.timestamp")
788
789 // update API rule
790 rule = android.NewRuleBuilder(pctx, ctx)
791
792 rule.Command().Text("( true")
793
794 rule.Command().
795 Text("cp").Flag("-f").
796 Input(d.apiFile).Flag(apiFile.String())
797
798 rule.Command().
799 Text("cp").Flag("-f").
800 Input(d.removedApiFile).Flag(removedApiFile.String())
801
802 msg = "failed to update public API"
803
804 rule.Command().
805 Text("touch").Output(d.updateCurrentApiTimestamp).
806 Text(") || (").
807 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
808 Text("; exit 38").
809 Text(")")
810
811 rule.Build("metalavaCurrentApiUpdate", "update current API")
812 }
813
Colin Cross2207f872021-03-24 12:39:08 -0700814 if String(d.properties.Check_nullability_warnings) != "" {
815 if d.nullabilityWarningsFile == nil {
816 ctx.PropertyErrorf("check_nullability_warnings",
817 "Cannot specify check_nullability_warnings unless validating nullability")
818 }
819
820 checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings))
821
Colin Crosscb77f752021-03-24 12:04:44 -0700822 d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "metalava", "check_nullability_warnings.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700823
824 msg := fmt.Sprintf(`\n******************************\n`+
825 `The warnings encountered during nullability annotation validation did\n`+
826 `not match the checked in file of expected warnings. The diffs are shown\n`+
827 `above. You have two options:\n`+
828 ` 1. Resolve the differences by editing the nullability annotations.\n`+
829 ` 2. Update the file of expected warnings by running:\n`+
830 ` cp %s %s\n`+
831 ` and submitting the updated file as part of your change.`,
832 d.nullabilityWarningsFile, checkNullabilityWarnings)
833
834 rule := android.NewRuleBuilder(pctx, ctx)
835
836 rule.Command().
837 Text("(").
838 Text("diff").Input(checkNullabilityWarnings).Input(d.nullabilityWarningsFile).
839 Text("&&").
840 Text("touch").Output(d.checkNullabilityWarningsTimestamp).
841 Text(") || (").
842 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
843 Text("; exit 38").
844 Text(")")
845
846 rule.Build("nullabilityWarningsCheck", "nullability warnings check")
847 }
848}
849
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000850func (d *Droidstubs) createApiContribution(ctx android.DefaultableHookContext) {
851 api_file := d.properties.Check_api.Current.Api_file
852 api_surface := d.properties.Api_surface
853
854 props := struct {
855 Name *string
856 Api_surface *string
857 Api_file *string
Jihoon Kang42b589c2023-02-03 22:56:13 +0000858 Visibility []string
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000859 }{}
860
861 props.Name = proptools.StringPtr(d.Name() + ".api.contribution")
862 props.Api_surface = api_surface
863 props.Api_file = api_file
Jihoon Kang42b589c2023-02-03 22:56:13 +0000864 props.Visibility = []string{"//visibility:override", "//visibility:public"}
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000865
866 ctx.CreateModule(ApiContributionFactory, &props)
867}
868
Spandan Das0b555e32022-11-28 18:48:51 +0000869// TODO (b/262014796): Export the API contributions of CorePlatformApi
870// A map to populate the api surface of a droidstub from a substring appearing in its name
871// This map assumes that droidstubs (either checked-in or created by java_sdk_library)
872// use a strict naming convention
873var (
874 droidstubsModuleNamingToSdkKind = map[string]android.SdkKind{
875 //public is commented out since the core libraries use public in their java_sdk_library names
876 "intracore": android.SdkIntraCore,
877 "intra.core": android.SdkIntraCore,
878 "system_server": android.SdkSystemServer,
879 "system-server": android.SdkSystemServer,
880 "system": android.SdkSystem,
881 "module_lib": android.SdkModule,
882 "module-lib": android.SdkModule,
Spandan Dasda977552023-01-26 20:45:16 +0000883 "platform.api": android.SdkCorePlatform,
Spandan Das0b555e32022-11-28 18:48:51 +0000884 "test": android.SdkTest,
Spandan Das4ac2aed2022-12-28 01:54:29 +0000885 "toolchain": android.SdkToolchain,
Spandan Das0b555e32022-11-28 18:48:51 +0000886 }
887)
888
889// A helper function that returns the api surface of the corresponding java_api_contribution Bazel target
890// The api_surface is populated using the naming convention of the droidstubs module.
891func bazelApiSurfaceName(name string) string {
892 // Sort the keys so that longer strings appear first
893 // Otherwise substrings like system will match both system and system_server
894 sortedKeys := make([]string, 0)
895 for key := range droidstubsModuleNamingToSdkKind {
896 sortedKeys = append(sortedKeys, key)
897 }
898 sort.Slice(sortedKeys, func(i, j int) bool {
899 return len(sortedKeys[i]) > len(sortedKeys[j])
900 })
901 for _, sortedKey := range sortedKeys {
902 if strings.Contains(name, sortedKey) {
903 sdkKind := droidstubsModuleNamingToSdkKind[sortedKey]
904 return sdkKind.String() + "api"
905 }
906 }
907 // Default is publicapi
908 return android.SdkPublic.String() + "api"
909}
910
Colin Cross2207f872021-03-24 12:39:08 -0700911func StubsDefaultsFactory() android.Module {
912 module := &DocDefaults{}
913
914 module.AddProperties(
915 &JavadocProperties{},
916 &DroidstubsProperties{},
917 )
918
919 android.InitDefaultsModule(module)
920
921 return module
922}
923
924var _ android.PrebuiltInterface = (*PrebuiltStubsSources)(nil)
925
926type PrebuiltStubsSourcesProperties struct {
927 Srcs []string `android:"path"`
928}
929
930type PrebuiltStubsSources struct {
931 android.ModuleBase
932 android.DefaultableModuleBase
933 prebuilt android.Prebuilt
Colin Cross2207f872021-03-24 12:39:08 -0700934
935 properties PrebuiltStubsSourcesProperties
936
kgui67007242022-01-25 13:50:25 +0800937 stubsSrcJar android.Path
Colin Cross2207f872021-03-24 12:39:08 -0700938}
939
940func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
941 switch tag {
942 case "":
943 return android.Paths{p.stubsSrcJar}, nil
944 default:
945 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
946 }
947}
948
949func (d *PrebuiltStubsSources) StubsSrcJar() android.Path {
950 return d.stubsSrcJar
951}
952
953func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Cross2207f872021-03-24 12:39:08 -0700954 if len(p.properties.Srcs) != 1 {
Anton Hansson86758ac2021-11-03 14:44:12 +0000955 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 -0700956 return
957 }
958
Anton Hansson86758ac2021-11-03 14:44:12 +0000959 src := p.properties.Srcs[0]
960 if filepath.Ext(src) == ".srcjar" {
961 // This is a srcjar. We can use it directly.
962 p.stubsSrcJar = android.PathForModuleSrc(ctx, src)
963 } else {
964 outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
Colin Cross2207f872021-03-24 12:39:08 -0700965
Anton Hansson86758ac2021-11-03 14:44:12 +0000966 // This is a directory. Glob the contents just in case the directory does not exist.
967 srcGlob := src + "/**/*"
968 srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
Colin Cross2207f872021-03-24 12:39:08 -0700969
Anton Hansson86758ac2021-11-03 14:44:12 +0000970 // Although PathForModuleSrc can return nil if either the path doesn't exist or
971 // the path components are invalid it won't in this case because no components
972 // are specified and the module directory must exist in order to get this far.
973 srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, src)
Colin Cross2207f872021-03-24 12:39:08 -0700974
Anton Hansson86758ac2021-11-03 14:44:12 +0000975 rule := android.NewRuleBuilder(pctx, ctx)
976 rule.Command().
977 BuiltTool("soong_zip").
978 Flag("-write_if_changed").
979 Flag("-jar").
980 FlagWithOutput("-o ", outPath).
981 FlagWithArg("-C ", srcDir.String()).
982 FlagWithRspFileInputList("-r ", outPath.ReplaceExtension(ctx, "rsp"), srcPaths)
983 rule.Restat()
984 rule.Build("zip src", "Create srcjar from prebuilt source")
985 p.stubsSrcJar = outPath
986 }
Colin Cross2207f872021-03-24 12:39:08 -0700987}
988
989func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
990 return &p.prebuilt
991}
992
993func (p *PrebuiltStubsSources) Name() string {
994 return p.prebuilt.Name(p.ModuleBase.Name())
995}
996
997// prebuilt_stubs_sources imports a set of java source files as if they were
998// generated by droidstubs.
999//
1000// By default, a prebuilt_stubs_sources has a single variant that expects a
1001// set of `.java` files generated by droidstubs.
1002//
1003// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one
1004// for host modules.
1005//
1006// Intended only for use by sdk snapshots.
1007func PrebuiltStubsSourcesFactory() android.Module {
1008 module := &PrebuiltStubsSources{}
1009
1010 module.AddProperties(&module.properties)
1011
1012 android.InitPrebuiltModule(module, &module.properties.Srcs)
Colin Cross2207f872021-03-24 12:39:08 -07001013 InitDroiddocModule(module, android.HostAndDeviceSupported)
1014 return module
1015}