blob: 7ea8d305a193d2159867724a5cffb175748daf51 [file] [log] [blame]
Colin Cross2207f872021-03-24 12:39:08 -07001// Copyright 2021 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package java
16
17import (
18 "fmt"
Anton Hansson86758ac2021-11-03 14:44:12 +000019 "path/filepath"
Mårten Kongstad802ae0f2022-07-27 13:47:32 +020020 "regexp"
Spandan Das0b555e32022-11-28 18:48:51 +000021 "sort"
Colin Cross2207f872021-03-24 12:39:08 -070022 "strings"
23
24 "github.com/google/blueprint/proptools"
25
26 "android/soong/android"
Spandan Das0b555e32022-11-28 18:48:51 +000027 "android/soong/bazel"
Colin Cross2207f872021-03-24 12:39:08 -070028 "android/soong/java/config"
29 "android/soong/remoteexec"
30)
31
Pedro Loureirocc203502021-10-04 17:24:00 +000032// The values allowed for Droidstubs' Api_levels_sdk_type
Cole Faust051fa912022-10-05 12:45:42 -070033var allowedApiLevelSdkTypes = []string{"public", "system", "module-lib", "system-server"}
Pedro Loureirocc203502021-10-04 17:24:00 +000034
Colin Cross2207f872021-03-24 12:39:08 -070035func init() {
36 RegisterStubsBuildComponents(android.InitRegistrationContext)
37}
38
39func RegisterStubsBuildComponents(ctx android.RegistrationContext) {
40 ctx.RegisterModuleType("stubs_defaults", StubsDefaultsFactory)
41
42 ctx.RegisterModuleType("droidstubs", DroidstubsFactory)
43 ctx.RegisterModuleType("droidstubs_host", DroidstubsHostFactory)
44
45 ctx.RegisterModuleType("prebuilt_stubs_sources", PrebuiltStubsSourcesFactory)
46}
47
Colin Cross2207f872021-03-24 12:39:08 -070048// Droidstubs
Colin Cross2207f872021-03-24 12:39:08 -070049type Droidstubs struct {
50 Javadoc
Colin Cross2207f872021-03-24 12:39:08 -070051
52 properties DroidstubsProperties
Paul Duffinc71d2b72022-08-16 15:24:01 +000053 apiFile android.Path
54 removedApiFile android.Path
Colin Cross2207f872021-03-24 12:39:08 -070055 nullabilityWarningsFile android.WritablePath
56
57 checkCurrentApiTimestamp android.WritablePath
58 updateCurrentApiTimestamp android.WritablePath
59 checkLastReleasedApiTimestamp android.WritablePath
60 apiLintTimestamp android.WritablePath
61 apiLintReport android.WritablePath
62
63 checkNullabilityWarningsTimestamp android.WritablePath
64
65 annotationsZip android.WritablePath
66 apiVersionsXml android.WritablePath
67
Colin Cross2207f872021-03-24 12:39:08 -070068 metadataZip android.WritablePath
69 metadataDir android.WritablePath
70}
71
72type DroidstubsProperties struct {
73 // The generated public API filename by Metalava, defaults to <module>_api.txt
74 Api_filename *string
75
76 // the generated removed API filename by Metalava, defaults to <module>_removed.txt
77 Removed_api_filename *string
78
Colin Cross2207f872021-03-24 12:39:08 -070079 Check_api struct {
80 Last_released ApiToCheck
81
82 Current ApiToCheck
83
84 Api_lint struct {
85 Enabled *bool
86
87 // If set, performs api_lint on any new APIs not found in the given signature file
88 New_since *string `android:"path"`
89
90 // If not blank, path to the baseline txt file for approved API lint violations.
91 Baseline_file *string `android:"path"`
92 }
93 }
94
95 // user can specify the version of previous released API file in order to do compatibility check.
96 Previous_api *string `android:"path"`
97
98 // is set to true, Metalava will allow framework SDK to contain annotations.
99 Annotations_enabled *bool
100
101 // a list of top-level directories containing files to merge qualifier annotations (i.e. those intended to be included in the stubs written) from.
102 Merge_annotations_dirs []string
103
104 // a list of top-level directories containing Java stub files to merge show/hide annotations from.
105 Merge_inclusion_annotations_dirs []string
106
107 // a file containing a list of classes to do nullability validation for.
108 Validate_nullability_from_list *string
109
110 // a file containing expected warnings produced by validation of nullability annotations.
111 Check_nullability_warnings *string
112
113 // if set to true, allow Metalava to generate doc_stubs source files. Defaults to false.
114 Create_doc_stubs *bool
115
116 // if set to true, cause Metalava to output Javadoc comments in the stubs source files. Defaults to false.
117 // Has no effect if create_doc_stubs: true.
118 Output_javadoc_comments *bool
119
120 // if set to false then do not write out stubs. Defaults to true.
121 //
122 // TODO(b/146727827): Remove capability when we do not need to generate stubs and API separately.
123 Generate_stubs *bool
124
125 // if set to true, provides a hint to the build system that this rule uses a lot of memory,
126 // whicih can be used for scheduling purposes
127 High_mem *bool
128
satayev783195c2021-06-23 21:49:57 +0100129 // if set to true, Metalava will allow framework SDK to contain API levels annotations.
Colin Cross2207f872021-03-24 12:39:08 -0700130 Api_levels_annotations_enabled *bool
131
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000132 // Apply the api levels database created by this module rather than generating one in this droidstubs.
133 Api_levels_module *string
134
Colin Cross2207f872021-03-24 12:39:08 -0700135 // the dirs which Metalava extracts API levels annotations from.
136 Api_levels_annotations_dirs []string
137
Cole Faust051fa912022-10-05 12:45:42 -0700138 // the sdk kind which Metalava extracts API levels annotations from. Supports 'public', 'system', 'module-lib' and 'system-server'; defaults to public.
satayev783195c2021-06-23 21:49:57 +0100139 Api_levels_sdk_type *string
140
Colin Cross2207f872021-03-24 12:39:08 -0700141 // the filename which Metalava extracts API levels annotations from. Defaults to android.jar.
142 Api_levels_jar_filename *string
143
144 // if set to true, collect the values used by the Dev tools and
145 // write them in files packaged with the SDK. Defaults to false.
146 Write_sdk_values *bool
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200147
148 // path or filegroup to file defining extension an SDK name <-> numerical ID mapping and
149 // what APIs exist in which SDKs; passed to metalava via --sdk-extensions-info
150 Extensions_info_file *string `android:"path"`
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000151
152 // API surface of this module. If set, the module contributes to an API surface.
153 // For the full list of available API surfaces, refer to soong/android/sdk_version.go
154 Api_surface *string
Colin Cross2207f872021-03-24 12:39:08 -0700155}
156
Anton Hansson52609322021-05-05 10:36:05 +0100157// Used by xsd_config
158type ApiFilePath interface {
159 ApiFilePath() android.Path
160}
161
162type ApiStubsSrcProvider interface {
163 StubsSrcJar() android.Path
164}
165
166// Provider of information about API stubs, used by java_sdk_library.
167type ApiStubsProvider interface {
Anton Hanssond78eb762021-09-21 15:25:12 +0100168 AnnotationsZip() android.Path
Anton Hansson52609322021-05-05 10:36:05 +0100169 ApiFilePath
170 RemovedApiFilePath() android.Path
171
172 ApiStubsSrcProvider
173}
174
Colin Cross2207f872021-03-24 12:39:08 -0700175// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
176// documented, filtering out hidden classes and methods. The resulting .java files are intended to be passed to
177// a droiddoc module to generate documentation.
178func DroidstubsFactory() android.Module {
179 module := &Droidstubs{}
180
181 module.AddProperties(&module.properties,
182 &module.Javadoc.properties)
183
184 InitDroiddocModule(module, android.HostAndDeviceSupported)
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000185
186 module.SetDefaultableHook(func(ctx android.DefaultableHookContext) {
187 module.createApiContribution(ctx)
188 })
Colin Cross2207f872021-03-24 12:39:08 -0700189 return module
190}
191
192// droidstubs_host passes sources files through Metalava to generate stub .java files that only contain the API
193// to be documented, filtering out hidden classes and methods. The resulting .java files are intended to be
194// passed to a droiddoc_host module to generate documentation. Use a droidstubs_host instead of a droidstubs
195// module when symbols needed by the source files are provided by java_library_host modules.
196func DroidstubsHostFactory() android.Module {
197 module := &Droidstubs{}
198
199 module.AddProperties(&module.properties,
200 &module.Javadoc.properties)
201
202 InitDroiddocModule(module, android.HostSupported)
203 return module
204}
205
206func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) {
207 switch tag {
208 case "":
209 return android.Paths{d.stubsSrcJar}, nil
210 case ".docs.zip":
211 return android.Paths{d.docZip}, nil
212 case ".api.txt", android.DefaultDistTag:
213 // This is the default dist path for dist properties that have no tag property.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000214 return android.Paths{d.apiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700215 case ".removed-api.txt":
Paul Duffinc71d2b72022-08-16 15:24:01 +0000216 return android.Paths{d.removedApiFile}, nil
Colin Cross2207f872021-03-24 12:39:08 -0700217 case ".annotations.zip":
218 return android.Paths{d.annotationsZip}, nil
219 case ".api_versions.xml":
220 return android.Paths{d.apiVersionsXml}, nil
221 default:
222 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
223 }
224}
225
Anton Hanssond78eb762021-09-21 15:25:12 +0100226func (d *Droidstubs) AnnotationsZip() android.Path {
227 return d.annotationsZip
228}
229
Colin Cross2207f872021-03-24 12:39:08 -0700230func (d *Droidstubs) ApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000231 return d.apiFile
Colin Cross2207f872021-03-24 12:39:08 -0700232}
233
234func (d *Droidstubs) RemovedApiFilePath() android.Path {
Paul Duffinc71d2b72022-08-16 15:24:01 +0000235 return d.removedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700236}
237
238func (d *Droidstubs) StubsSrcJar() android.Path {
239 return d.stubsSrcJar
240}
241
242var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"}
243var metalavaMergeInclusionAnnotationsDirTag = dependencyTag{name: "metalava-merge-inclusion-annotations-dir"}
244var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"}
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000245var metalavaAPILevelsModuleTag = dependencyTag{name: "metalava-api-levels-module-tag"}
Colin Cross2207f872021-03-24 12:39:08 -0700246
247func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) {
248 d.Javadoc.addDeps(ctx)
249
250 if len(d.properties.Merge_annotations_dirs) != 0 {
251 for _, mergeAnnotationsDir := range d.properties.Merge_annotations_dirs {
252 ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir)
253 }
254 }
255
256 if len(d.properties.Merge_inclusion_annotations_dirs) != 0 {
257 for _, mergeInclusionAnnotationsDir := range d.properties.Merge_inclusion_annotations_dirs {
258 ctx.AddDependency(ctx.Module(), metalavaMergeInclusionAnnotationsDirTag, mergeInclusionAnnotationsDir)
259 }
260 }
261
262 if len(d.properties.Api_levels_annotations_dirs) != 0 {
263 for _, apiLevelsAnnotationsDir := range d.properties.Api_levels_annotations_dirs {
264 ctx.AddDependency(ctx.Module(), metalavaAPILevelsAnnotationsDirTag, apiLevelsAnnotationsDir)
265 }
266 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000267
268 if d.properties.Api_levels_module != nil {
269 ctx.AddDependency(ctx.Module(), metalavaAPILevelsModuleTag, proptools.String(d.properties.Api_levels_module))
270 }
Colin Cross2207f872021-03-24 12:39:08 -0700271}
272
273func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) {
274 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
275 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
276 String(d.properties.Api_filename) != "" {
277 filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000278 uncheckedApiFile := android.PathForModuleOut(ctx, "metalava", filename)
279 cmd.FlagWithOutput("--api ", uncheckedApiFile)
280 d.apiFile = uncheckedApiFile
Colin Cross2207f872021-03-24 12:39:08 -0700281 } else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" {
282 // If check api is disabled then make the source file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000283 d.apiFile = android.PathForModuleSrc(ctx, sourceApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700284 }
285
286 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
287 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
288 String(d.properties.Removed_api_filename) != "" {
289 filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
Paul Duffinc71d2b72022-08-16 15:24:01 +0000290 uncheckedRemovedFile := android.PathForModuleOut(ctx, "metalava", filename)
291 cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile)
292 d.removedApiFile = uncheckedRemovedFile
Colin Cross2207f872021-03-24 12:39:08 -0700293 } else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" {
294 // If check api is disabled then make the source removed api file available for export.
Paul Duffinc71d2b72022-08-16 15:24:01 +0000295 d.removedApiFile = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
Colin Cross2207f872021-03-24 12:39:08 -0700296 }
297
Colin Cross2207f872021-03-24 12:39:08 -0700298 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700299 d.metadataDir = android.PathForModuleOut(ctx, "metalava", "metadata")
Colin Cross2207f872021-03-24 12:39:08 -0700300 cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
301 }
302
303 if stubsDir.Valid() {
304 if Bool(d.properties.Create_doc_stubs) {
305 cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
306 } else {
307 cmd.FlagWithArg("--stubs ", stubsDir.String())
308 if !Bool(d.properties.Output_javadoc_comments) {
309 cmd.Flag("--exclude-documentation-from-stubs")
310 }
311 }
312 }
313}
314
315func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
316 if Bool(d.properties.Annotations_enabled) {
317 cmd.Flag("--include-annotations")
318
Andrei Onea4985e512021-04-29 16:29:34 +0100319 cmd.FlagWithArg("--exclude-annotation ", "androidx.annotation.RequiresApi")
320
Colin Cross2207f872021-03-24 12:39:08 -0700321 validatingNullability :=
Colin Crossbc139922021-03-25 18:33:16 -0700322 strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") ||
Colin Cross2207f872021-03-24 12:39:08 -0700323 String(d.properties.Validate_nullability_from_list) != ""
324
325 migratingNullability := String(d.properties.Previous_api) != ""
326 if migratingNullability {
327 previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
328 cmd.FlagWithInput("--migrate-nullness ", previousApi)
329 }
330
331 if s := String(d.properties.Validate_nullability_from_list); s != "" {
332 cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
333 }
334
335 if validatingNullability {
Colin Crosscb77f752021-03-24 12:04:44 -0700336 d.nullabilityWarningsFile = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_nullability_warnings.txt")
Colin Cross2207f872021-03-24 12:39:08 -0700337 cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile)
338 }
339
Colin Crosscb77f752021-03-24 12:04:44 -0700340 d.annotationsZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_annotations.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700341 cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip)
342
343 if len(d.properties.Merge_annotations_dirs) != 0 {
344 d.mergeAnnoDirFlags(ctx, cmd)
345 }
346
347 // TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
348 cmd.FlagWithArg("--hide ", "HiddenTypedefConstant").
349 FlagWithArg("--hide ", "SuperfluousPrefix").
Sam Gilbert049af112022-03-04 16:03:53 -0500350 FlagWithArg("--hide ", "AnnotationExtraction").
351 // b/222738070
Sam Gilbert675f0b42022-03-08 11:24:44 -0500352 FlagWithArg("--hide ", "BannedThrow").
353 // b/223382732
354 FlagWithArg("--hide ", "ChangedDefault")
Colin Cross2207f872021-03-24 12:39:08 -0700355 }
356}
357
358func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
359 ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
360 if t, ok := m.(*ExportedDroiddocDir); ok {
361 cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps)
362 } else {
363 ctx.PropertyErrorf("merge_annotations_dirs",
364 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
365 }
366 })
367}
368
369func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
370 ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) {
371 if t, ok := m.(*ExportedDroiddocDir); ok {
372 cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps)
373 } else {
374 ctx.PropertyErrorf("merge_inclusion_annotations_dirs",
375 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
376 }
377 })
378}
379
380func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000381 var apiVersions android.Path
382 if proptools.Bool(d.properties.Api_levels_annotations_enabled) {
383 d.apiLevelsGenerationFlags(ctx, cmd)
384 apiVersions = d.apiVersionsXml
385 } else {
386 ctx.VisitDirectDepsWithTag(metalavaAPILevelsModuleTag, func(m android.Module) {
387 if s, ok := m.(*Droidstubs); ok {
388 apiVersions = s.apiVersionsXml
389 } else {
390 ctx.PropertyErrorf("api_levels_module",
391 "module %q is not a droidstubs module", ctx.OtherModuleName(m))
392 }
393 })
Colin Cross2207f872021-03-24 12:39:08 -0700394 }
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000395 if apiVersions != nil {
396 cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion().String())
397 cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename())
398 cmd.FlagWithInput("--apply-api-levels ", apiVersions)
399 }
400}
Colin Cross2207f872021-03-24 12:39:08 -0700401
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000402func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
Colin Cross2207f872021-03-24 12:39:08 -0700403 if len(d.properties.Api_levels_annotations_dirs) == 0 {
404 ctx.PropertyErrorf("api_levels_annotations_dirs",
405 "has to be non-empty if api levels annotations was enabled!")
406 }
407
Anton Hanssonc04a16e2022-05-09 09:30:26 +0000408 d.apiVersionsXml = android.PathForModuleOut(ctx, "metalava", "api-versions.xml")
Colin Cross2207f872021-03-24 12:39:08 -0700409 cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml)
Colin Cross2207f872021-03-24 12:39:08 -0700410
411 filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar")
412
satayev783195c2021-06-23 21:49:57 +0100413 var dirs []string
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200414 var extensions_dir string
Colin Cross2207f872021-03-24 12:39:08 -0700415 ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
416 if t, ok := m.(*ExportedDroiddocDir); ok {
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200417 extRegex := regexp.MustCompile(t.dir.String() + `/extensions/[0-9]+/public/.*\.jar`)
418
419 // Grab the first extensions_dir and we find while scanning ExportedDroiddocDir.deps;
420 // ideally this should be read from prebuiltApis.properties.Extensions_*
Colin Cross2207f872021-03-24 12:39:08 -0700421 for _, dep := range t.deps {
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200422 if extRegex.MatchString(dep.String()) && d.properties.Extensions_info_file != nil {
423 if extensions_dir == "" {
424 extensions_dir = t.dir.String() + "/extensions"
425 }
426 cmd.Implicit(dep)
427 }
Colin Cross5f6ffc72021-03-29 21:54:45 -0700428 if dep.Base() == filename {
429 cmd.Implicit(dep)
430 }
431 if filename != "android.jar" && dep.Base() == "android.jar" {
432 // Metalava implicitly searches these patterns:
433 // prebuilts/tools/common/api-versions/android-%/android.jar
434 // prebuilts/sdk/%/public/android.jar
435 // Add android.jar files from the api_levels_annotations_dirs directories to try
436 // to satisfy these patterns. If Metalava can't find a match for an API level
437 // between 1 and 28 in at least one pattern it will fail.
Colin Cross2207f872021-03-24 12:39:08 -0700438 cmd.Implicit(dep)
439 }
440 }
satayev783195c2021-06-23 21:49:57 +0100441
442 dirs = append(dirs, t.dir.String())
Colin Cross2207f872021-03-24 12:39:08 -0700443 } else {
444 ctx.PropertyErrorf("api_levels_annotations_dirs",
445 "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
446 }
447 })
satayev783195c2021-06-23 21:49:57 +0100448
449 // Add all relevant --android-jar-pattern patterns for Metalava.
450 // When parsing a stub jar for a specific version, Metalava picks the first pattern that defines
451 // an actual file present on disk (in the order the patterns were passed). For system APIs for
452 // privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs
Pedro Loureirocc203502021-10-04 17:24:00 +0000453 // for older releases. Similarly, module-lib falls back to system API.
454 var sdkDirs []string
455 switch proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") {
Cole Faust051fa912022-10-05 12:45:42 -0700456 case "system-server":
457 sdkDirs = []string{"system-server", "module-lib", "system", "public"}
Pedro Loureirocc203502021-10-04 17:24:00 +0000458 case "module-lib":
459 sdkDirs = []string{"module-lib", "system", "public"}
460 case "system":
461 sdkDirs = []string{"system", "public"}
462 case "public":
463 sdkDirs = []string{"public"}
464 default:
465 ctx.PropertyErrorf("api_levels_sdk_type", "needs to be one of %v", allowedApiLevelSdkTypes)
466 return
satayev783195c2021-06-23 21:49:57 +0100467 }
Pedro Loureirocc203502021-10-04 17:24:00 +0000468
469 for _, sdkDir := range sdkDirs {
470 for _, dir := range dirs {
471 cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, filename))
472 }
satayev783195c2021-06-23 21:49:57 +0100473 }
Mårten Kongstad802ae0f2022-07-27 13:47:32 +0200474
475 if d.properties.Extensions_info_file != nil {
476 if extensions_dir == "" {
477 ctx.ModuleErrorf("extensions_info_file set, but no SDK extension dirs found")
478 }
479 info_file := android.PathForModuleSrc(ctx, *d.properties.Extensions_info_file)
480 cmd.Implicit(info_file)
481 cmd.FlagWithArg("--sdk-extensions-root ", extensions_dir)
482 cmd.FlagWithArg("--sdk-extensions-info ", info_file.String())
483 }
Colin Cross2207f872021-03-24 12:39:08 -0700484}
485
Colin Crosse52c2ac2022-03-28 17:03:35 -0700486func metalavaUseRbe(ctx android.ModuleContext) bool {
487 return ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA")
488}
489
Colin Cross2207f872021-03-24 12:39:08 -0700490func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
Anton Hansson556e8142021-06-04 16:20:25 +0100491 srcJarList android.Path, bootclasspath, classpath classpath, homeDir android.WritablePath) *android.RuleBuilderCommand {
Colin Cross2207f872021-03-24 12:39:08 -0700492 rule.Command().Text("rm -rf").Flag(homeDir.String())
493 rule.Command().Text("mkdir -p").Flag(homeDir.String())
494
Anton Hansson556e8142021-06-04 16:20:25 +0100495 cmd := rule.Command()
Colin Cross2207f872021-03-24 12:39:08 -0700496 cmd.FlagWithArg("ANDROID_PREFS_ROOT=", homeDir.String())
497
Colin Crosse52c2ac2022-03-28 17:03:35 -0700498 if metalavaUseRbe(ctx) {
Colin Cross2207f872021-03-24 12:39:08 -0700499 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
Colin Cross8095c292021-03-30 16:40:48 -0700500 execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
501 labels := map[string]string{"type": "tool", "name": "metalava"}
502 // TODO: metalava pool rejects these jobs
503 pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
504 rule.Rewrapper(&remoteexec.REParams{
505 Labels: labels,
506 ExecStrategy: execStrategy,
507 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
508 Platform: map[string]string{remoteexec.PoolKey: pool},
509 })
Colin Cross2207f872021-03-24 12:39:08 -0700510 }
511
Colin Cross6aa5c402021-03-24 12:28:50 -0700512 cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
Colin Cross2207f872021-03-24 12:39:08 -0700513 Flag(config.JavacVmFlags).
514 Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED").
515 FlagWithArg("-encoding ", "UTF-8").
516 FlagWithArg("-source ", javaVersion.String()).
517 FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs).
518 FlagWithInput("@", srcJarList)
519
Colin Cross2207f872021-03-24 12:39:08 -0700520 if len(bootclasspath) > 0 {
521 cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":")
522 }
523
524 if len(classpath) > 0 {
525 cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
526 }
527
Colin Cross2207f872021-03-24 12:39:08 -0700528 cmd.Flag("--no-banner").
529 Flag("--color").
530 Flag("--quiet").
531 Flag("--format=v2").
532 FlagWithArg("--repeat-errors-max ", "10").
Sam Gilbert09cb5db2021-10-06 11:28:28 -0400533 FlagWithArg("--hide ", "UnresolvedImport").
Ember Rose7c57af32022-04-01 10:34:44 -0400534 FlagWithArg("--hide ", "InvalidNullabilityOverride").
Sam Gilbert28e41282022-03-09 15:24:48 +0000535 // b/223382732
536 FlagWithArg("--hide ", "ChangedDefault")
Colin Cross2207f872021-03-24 12:39:08 -0700537
538 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
Colin Cross2207f872021-03-24 12:39:08 -0700691 if generateStubs {
692 rule.Command().
693 BuiltTool("soong_zip").
694 Flag("-write_if_changed").
695 Flag("-jar").
696 FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
697 FlagWithArg("-C ", stubsDir.String()).
698 FlagWithArg("-D ", stubsDir.String())
699 }
700
701 if Bool(d.properties.Write_sdk_values) {
Colin Crosscb77f752021-03-24 12:04:44 -0700702 d.metadataZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-metadata.zip")
Colin Cross2207f872021-03-24 12:39:08 -0700703 rule.Command().
704 BuiltTool("soong_zip").
705 Flag("-write_if_changed").
706 Flag("-d").
707 FlagWithOutput("-o ", d.metadataZip).
708 FlagWithArg("-C ", d.metadataDir.String()).
709 FlagWithArg("-D ", d.metadataDir.String())
710 }
711
712 // TODO: We don't really need two separate API files, but this is a reminiscence of how
713 // we used to run metalava separately for API lint and the "last_released" check. Unify them.
714 if doApiLint {
715 rule.Command().Text("touch").Output(d.apiLintTimestamp)
716 }
717 if doCheckReleased {
718 rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp)
719 }
720
Colin Cross6aa5c402021-03-24 12:28:50 -0700721 // TODO(b/183630617): rewrapper doesn't support restat rules
Colin Crosse52c2ac2022-03-28 17:03:35 -0700722 if !metalavaUseRbe(ctx) {
723 rule.Restat()
724 }
Colin Cross2207f872021-03-24 12:39:08 -0700725
726 zipSyncCleanupCmd(rule, srcJarDir)
727
Paul Duffinc166b682022-05-27 12:23:08 +0000728 rule.Build("metalava", "metalava merged")
729
Paul Duffine7a86642022-08-16 15:43:20 +0000730 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
731
732 if len(d.Javadoc.properties.Out) > 0 {
733 ctx.PropertyErrorf("out", "out property may not be combined with check_api")
734 }
735
736 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
737 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
738 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)
739
740 if baselineFile.Valid() {
741 ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
742 }
743
744 d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp")
745
746 rule := android.NewRuleBuilder(pctx, ctx)
747
748 // Diff command line.
749 // -F matches the closest "opening" line, such as "package android {"
750 // and " public class Intent {".
751 diff := `diff -u -F '{ *$'`
752
753 rule.Command().Text("( true")
754 rule.Command().
755 Text(diff).
756 Input(apiFile).Input(d.apiFile)
757
758 rule.Command().
759 Text(diff).
760 Input(removedApiFile).Input(d.removedApiFile)
761
762 msg := fmt.Sprintf(`\n******************************\n`+
763 `You have tried to change the API from what has been previously approved.\n\n`+
764 `To make these errors go away, you have two choices:\n`+
765 ` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
766 ` to the new methods, etc. shown in the above diff.\n\n`+
767 ` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+
768 ` m %s-update-current-api\n\n`+
769 ` To submit the revised current.txt to the main Android repository,\n`+
770 ` you will need approval.\n`+
771 `******************************\n`, ctx.ModuleName())
772
773 rule.Command().
774 Text("touch").Output(d.checkCurrentApiTimestamp).
775 Text(") || (").
776 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
777 Text("; exit 38").
778 Text(")")
779
780 rule.Build("metalavaCurrentApiCheck", "check current API")
781
782 d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "update_current_api.timestamp")
783
784 // update API rule
785 rule = android.NewRuleBuilder(pctx, ctx)
786
787 rule.Command().Text("( true")
788
789 rule.Command().
790 Text("cp").Flag("-f").
791 Input(d.apiFile).Flag(apiFile.String())
792
793 rule.Command().
794 Text("cp").Flag("-f").
795 Input(d.removedApiFile).Flag(removedApiFile.String())
796
797 msg = "failed to update public API"
798
799 rule.Command().
800 Text("touch").Output(d.updateCurrentApiTimestamp).
801 Text(") || (").
802 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
803 Text("; exit 38").
804 Text(")")
805
806 rule.Build("metalavaCurrentApiUpdate", "update current API")
807 }
808
Colin Cross2207f872021-03-24 12:39:08 -0700809 if String(d.properties.Check_nullability_warnings) != "" {
810 if d.nullabilityWarningsFile == nil {
811 ctx.PropertyErrorf("check_nullability_warnings",
812 "Cannot specify check_nullability_warnings unless validating nullability")
813 }
814
815 checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings))
816
Colin Crosscb77f752021-03-24 12:04:44 -0700817 d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "metalava", "check_nullability_warnings.timestamp")
Colin Cross2207f872021-03-24 12:39:08 -0700818
819 msg := fmt.Sprintf(`\n******************************\n`+
820 `The warnings encountered during nullability annotation validation did\n`+
821 `not match the checked in file of expected warnings. The diffs are shown\n`+
822 `above. You have two options:\n`+
823 ` 1. Resolve the differences by editing the nullability annotations.\n`+
824 ` 2. Update the file of expected warnings by running:\n`+
825 ` cp %s %s\n`+
826 ` and submitting the updated file as part of your change.`,
827 d.nullabilityWarningsFile, checkNullabilityWarnings)
828
829 rule := android.NewRuleBuilder(pctx, ctx)
830
831 rule.Command().
832 Text("(").
833 Text("diff").Input(checkNullabilityWarnings).Input(d.nullabilityWarningsFile).
834 Text("&&").
835 Text("touch").Output(d.checkNullabilityWarningsTimestamp).
836 Text(") || (").
837 Text("echo").Flag("-e").Flag(`"` + msg + `"`).
838 Text("; exit 38").
839 Text(")")
840
841 rule.Build("nullabilityWarningsCheck", "nullability warnings check")
842 }
843}
844
Spandan Das0b555e32022-11-28 18:48:51 +0000845var _ android.ApiProvider = (*Droidstubs)(nil)
846
847type bazelJavaApiContributionAttributes struct {
848 Api bazel.LabelAttribute
849 Api_surface *string
850}
851
852func (d *Droidstubs) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
853 props := bazel.BazelTargetModuleProperties{
854 Rule_class: "java_api_contribution",
855 Bzl_load_location: "//build/bazel/rules/apis:java_api_contribution.bzl",
856 }
857 apiFile := d.properties.Check_api.Current.Api_file
858 // Do not generate a target if check_api is not set
859 if apiFile == nil {
860 return
861 }
862 attrs := &bazelJavaApiContributionAttributes{
863 Api: *bazel.MakeLabelAttribute(
864 android.BazelLabelForModuleSrcSingle(ctx, proptools.String(apiFile)).Label,
865 ),
866 Api_surface: proptools.StringPtr(bazelApiSurfaceName(d.Name())),
867 }
868 ctx.CreateBazelTargetModule(props, android.CommonAttributes{
869 Name: android.ApiContributionTargetName(ctx.ModuleName()),
870 }, attrs)
871}
872
Jihoon Kang3198f3c2023-01-26 08:08:52 +0000873func (d *Droidstubs) createApiContribution(ctx android.DefaultableHookContext) {
874 api_file := d.properties.Check_api.Current.Api_file
875 api_surface := d.properties.Api_surface
876
877 props := struct {
878 Name *string
879 Api_surface *string
880 Api_file *string
881 }{}
882
883 props.Name = proptools.StringPtr(d.Name() + ".api.contribution")
884 props.Api_surface = api_surface
885 props.Api_file = api_file
886
887 ctx.CreateModule(ApiContributionFactory, &props)
888}
889
Spandan Das0b555e32022-11-28 18:48:51 +0000890// TODO (b/262014796): Export the API contributions of CorePlatformApi
891// A map to populate the api surface of a droidstub from a substring appearing in its name
892// This map assumes that droidstubs (either checked-in or created by java_sdk_library)
893// use a strict naming convention
894var (
895 droidstubsModuleNamingToSdkKind = map[string]android.SdkKind{
896 //public is commented out since the core libraries use public in their java_sdk_library names
897 "intracore": android.SdkIntraCore,
898 "intra.core": android.SdkIntraCore,
899 "system_server": android.SdkSystemServer,
900 "system-server": android.SdkSystemServer,
901 "system": android.SdkSystem,
902 "module_lib": android.SdkModule,
903 "module-lib": android.SdkModule,
904 "test": android.SdkTest,
Spandan Das4ac2aed2022-12-28 01:54:29 +0000905 "toolchain": android.SdkToolchain,
Spandan Das0b555e32022-11-28 18:48:51 +0000906 }
907)
908
909// A helper function that returns the api surface of the corresponding java_api_contribution Bazel target
910// The api_surface is populated using the naming convention of the droidstubs module.
911func bazelApiSurfaceName(name string) string {
912 // Sort the keys so that longer strings appear first
913 // Otherwise substrings like system will match both system and system_server
914 sortedKeys := make([]string, 0)
915 for key := range droidstubsModuleNamingToSdkKind {
916 sortedKeys = append(sortedKeys, key)
917 }
918 sort.Slice(sortedKeys, func(i, j int) bool {
919 return len(sortedKeys[i]) > len(sortedKeys[j])
920 })
921 for _, sortedKey := range sortedKeys {
922 if strings.Contains(name, sortedKey) {
923 sdkKind := droidstubsModuleNamingToSdkKind[sortedKey]
924 return sdkKind.String() + "api"
925 }
926 }
927 // Default is publicapi
928 return android.SdkPublic.String() + "api"
929}
930
Colin Cross2207f872021-03-24 12:39:08 -0700931func StubsDefaultsFactory() android.Module {
932 module := &DocDefaults{}
933
934 module.AddProperties(
935 &JavadocProperties{},
936 &DroidstubsProperties{},
937 )
938
939 android.InitDefaultsModule(module)
940
941 return module
942}
943
944var _ android.PrebuiltInterface = (*PrebuiltStubsSources)(nil)
945
946type PrebuiltStubsSourcesProperties struct {
947 Srcs []string `android:"path"`
948}
949
950type PrebuiltStubsSources struct {
951 android.ModuleBase
952 android.DefaultableModuleBase
953 prebuilt android.Prebuilt
Colin Cross2207f872021-03-24 12:39:08 -0700954
955 properties PrebuiltStubsSourcesProperties
956
kgui67007242022-01-25 13:50:25 +0800957 stubsSrcJar android.Path
Colin Cross2207f872021-03-24 12:39:08 -0700958}
959
960func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
961 switch tag {
962 case "":
963 return android.Paths{p.stubsSrcJar}, nil
964 default:
965 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
966 }
967}
968
969func (d *PrebuiltStubsSources) StubsSrcJar() android.Path {
970 return d.stubsSrcJar
971}
972
973func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Cross2207f872021-03-24 12:39:08 -0700974 if len(p.properties.Srcs) != 1 {
Anton Hansson86758ac2021-11-03 14:44:12 +0000975 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 -0700976 return
977 }
978
Anton Hansson86758ac2021-11-03 14:44:12 +0000979 src := p.properties.Srcs[0]
980 if filepath.Ext(src) == ".srcjar" {
981 // This is a srcjar. We can use it directly.
982 p.stubsSrcJar = android.PathForModuleSrc(ctx, src)
983 } else {
984 outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
Colin Cross2207f872021-03-24 12:39:08 -0700985
Anton Hansson86758ac2021-11-03 14:44:12 +0000986 // This is a directory. Glob the contents just in case the directory does not exist.
987 srcGlob := src + "/**/*"
988 srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
Colin Cross2207f872021-03-24 12:39:08 -0700989
Anton Hansson86758ac2021-11-03 14:44:12 +0000990 // Although PathForModuleSrc can return nil if either the path doesn't exist or
991 // the path components are invalid it won't in this case because no components
992 // are specified and the module directory must exist in order to get this far.
993 srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, src)
Colin Cross2207f872021-03-24 12:39:08 -0700994
Anton Hansson86758ac2021-11-03 14:44:12 +0000995 rule := android.NewRuleBuilder(pctx, ctx)
996 rule.Command().
997 BuiltTool("soong_zip").
998 Flag("-write_if_changed").
999 Flag("-jar").
1000 FlagWithOutput("-o ", outPath).
1001 FlagWithArg("-C ", srcDir.String()).
1002 FlagWithRspFileInputList("-r ", outPath.ReplaceExtension(ctx, "rsp"), srcPaths)
1003 rule.Restat()
1004 rule.Build("zip src", "Create srcjar from prebuilt source")
1005 p.stubsSrcJar = outPath
1006 }
Colin Cross2207f872021-03-24 12:39:08 -07001007}
1008
1009func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
1010 return &p.prebuilt
1011}
1012
1013func (p *PrebuiltStubsSources) Name() string {
1014 return p.prebuilt.Name(p.ModuleBase.Name())
1015}
1016
1017// prebuilt_stubs_sources imports a set of java source files as if they were
1018// generated by droidstubs.
1019//
1020// By default, a prebuilt_stubs_sources has a single variant that expects a
1021// set of `.java` files generated by droidstubs.
1022//
1023// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one
1024// for host modules.
1025//
1026// Intended only for use by sdk snapshots.
1027func PrebuiltStubsSourcesFactory() android.Module {
1028 module := &PrebuiltStubsSources{}
1029
1030 module.AddProperties(&module.properties)
1031
1032 android.InitPrebuiltModule(module, &module.properties.Srcs)
Colin Cross2207f872021-03-24 12:39:08 -07001033 InitDroiddocModule(module, android.HostAndDeviceSupported)
1034 return module
1035}