blob: ec9c160ea9b57f177fea80649656b8aa1b6f5dd0 [file] [log] [blame]
Jihoon Kang96ce83b2024-09-23 22:09:44 +00001// Copyright 2024 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 (
Jihoon Kang96ce83b2024-09-23 22:09:44 +000018 "fmt"
19 "path"
20 "strings"
21
Yu Liub73c3a62024-12-10 00:58:06 +000022 "android/soong/android"
23 "android/soong/etc"
24
Jihoon Kang96ce83b2024-09-23 22:09:44 +000025 "github.com/google/blueprint/proptools"
26)
27
28// ---------------------------------------------------------------------------------------------
29// Naming scheme of the submodules generated by java_sdk_library and java_sdk_library_import
30// ---------------------------------------------------------------------------------------------
31
32const (
33 sdkXmlFileSuffix = ".xml"
34 implLibSuffix = ".impl"
35)
36
Jihoon Kanga6d0aa82024-09-24 00:34:49 +000037func implLibraryModuleName(sdkLibName string) string {
38 return sdkLibName + implLibSuffix
39}
40
Jihoon Kang96ce83b2024-09-23 22:09:44 +000041// Module name of the runtime implementation library
42func (c *commonToSdkLibraryAndImport) implLibraryModuleName() string {
Jihoon Kanga6d0aa82024-09-24 00:34:49 +000043 return implLibraryModuleName(c.module.RootLibraryName())
Jihoon Kang96ce83b2024-09-23 22:09:44 +000044}
45
46// Module name of the XML file for the lib
47func (c *commonToSdkLibraryAndImport) xmlPermissionsModuleName() string {
48 return c.module.RootLibraryName() + sdkXmlFileSuffix
49}
50
51// Name of the java_library module that compiles the stubs source.
52func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope) string {
53 baseName := c.module.RootLibraryName()
54 return apiScope.stubsLibraryModuleName(baseName)
55}
56
57// Name of the java_library module that compiles the exportable stubs source.
58func (c *commonToSdkLibraryAndImport) exportableStubsLibraryModuleName(apiScope *apiScope) string {
59 baseName := c.module.RootLibraryName()
60 return apiScope.exportableStubsLibraryModuleName(baseName)
61}
62
63// Name of the droidstubs module that generates the stubs source and may also
64// generate/check the API.
65func (c *commonToSdkLibraryAndImport) droidstubsModuleName(apiScope *apiScope) string {
66 baseName := c.module.RootLibraryName()
67 return apiScope.stubsSourceModuleName(baseName)
68}
69
70// Name of the java_api_library module that generates the from-text stubs source
71// and compiles to a jar file.
72func (c *commonToSdkLibraryAndImport) fromTextStubsLibraryModuleName(apiScope *apiScope) string {
73 baseName := c.module.RootLibraryName()
74 return apiScope.apiLibraryModuleName(baseName)
75}
76
77// Name of the java_library module that compiles the stubs
78// generated from source Java files.
79func (c *commonToSdkLibraryAndImport) fromSourceStubsLibraryModuleName(apiScope *apiScope) string {
80 baseName := c.module.RootLibraryName()
81 return apiScope.sourceStubsLibraryModuleName(baseName)
82}
83
84// Name of the java_library module that compiles the exportable stubs
85// generated from source Java files.
86func (c *commonToSdkLibraryAndImport) exportableFromSourceStubsLibraryModuleName(apiScope *apiScope) string {
87 baseName := c.module.RootLibraryName()
88 return apiScope.exportableSourceStubsLibraryModuleName(baseName)
89}
90
91// ---------------------------------------------------------------------------------------------
92// Build rules of the submodules generated by java_sdk_library.
93// java_sdk_library "framework-foo" generates the following submodules:
94//
95// - "framework-foo.impl" (type: [Library]): the implementation library, which generates the
96// compilation outputs that include the implementation details and the private apis
97// (i.e. class/methods that are annotated @hide).
98//
99// - "framework-foo.stubs.source.<[apiScope.name]>" (type: [Droidstubs]): droidstubs module that
100// generates the stubs and the api files for the given api scope.
101//
102// - "framework-foo.stubs.<[apiScope.name]>" (type: [Library]): stub library module that
103// provides the compilation output of the stubs to the reverse dependencies. The module
104// itself does not perform any compilation actions; the module statically depends on one of
105// the from-source stub module or the from-text stub configuration based on the build
106// configuration.
107//
108// - "framework-foo.stubs.<[apiScope.name]>.from-source" (type: [Library]): stub library module
109// that compiles the stubs generated by the droidstubs submodule. This module is a static
110// dependency of the stub library module when
111// [android/soong/android/config.BuildFromTextStub()] is false.
112//
113// - "framework-foo.stubs.<[apiScope.name]>.from-text" (type: [ApiLibrary]): api library module
114// that generates and compiles the stubs from the api files checked in the tree instead of
115// the source Java files (e.g. *-current.txt files). This module is a static dependency of
116// the stub library module when [android/soong/android/config.BuildFromTextStub()] is true.
117//
118// - "framework-foo.stubs.exportable.<[apiScope.name]>" (type: [Library]): stub library module
119// that provides the "exportable" stubs. "exportable" stubs are the stubs that do not
120// include in-development flagged apis. This module is only used for SDK builds to generate
121// the SDK artifacts, and not purposed for consumption for other modules.
122//
123// - "framework-foo.stubs.exportable.<[apiScope.name]>.from-source" (type: [Library]): stub
124// library module that compiles the "exportable" stubs generated by the droidstubs
125// submodule. This module is always a static dependency of the "exportable" stub library
126// module given that from-text stubs cannot be used for SDK builds as it does not contain
127// documentations.
128//
129// - "framework-foo.xml" (type: [sdkLibraryXml]): xml library that generates the permission xml
130// file, which allows [SdkLibrary] to be used with <uses-permission> tag in the
131// AndroidManifest.xml files.
132// ---------------------------------------------------------------------------------------------
133
134// Creates the implementation [Library] with ".impl" suffix.
135func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) {
136 visibility := childModuleVisibility(module.sdkLibraryProperties.Impl_library_visibility)
137
138 staticLibs := module.properties.Static_libs.Clone()
139 staticLibs.AppendSimpleValue(module.sdkLibraryProperties.Impl_only_static_libs)
140 props := struct {
141 Name *string
142 Enabled proptools.Configurable[bool]
143 Visibility []string
144 Libs []string
145 Static_libs proptools.Configurable[[]string]
146 Apex_available []string
147 Stem *string
148 }{
149 Name: proptools.StringPtr(module.implLibraryModuleName()),
150 Enabled: module.EnabledProperty(),
151 Visibility: visibility,
152
153 Libs: append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...),
154
155 Static_libs: staticLibs,
156 // Pass the apex_available settings down so that the impl library can be statically
157 // embedded within a library that is added to an APEX. Needed for updatable-media.
158 Apex_available: module.ApexAvailable(),
159
160 Stem: proptools.StringPtr(module.Name()),
161 }
162
163 properties := []interface{}{
164 &module.properties,
165 &module.protoProperties,
166 &module.deviceProperties,
167 &module.dexProperties,
168 &module.dexpreoptProperties,
169 &module.linter.properties,
170 &module.overridableProperties,
171 &props,
172 module.sdkComponentPropertiesForChildLibrary(),
173 }
174 mctx.CreateModule(LibraryFactory, properties...)
175}
176
177// Creates the [Droidstubs] module with ".stubs.source.<[apiScope.name]>" that creates stubs
178// source files from the given full source files and also updates and checks the API
179// specification files (i.e. "*-current.txt", "*-removed.txt" files).
180func (module *SdkLibrary) createDroidstubs(mctx android.DefaultableHookContext, apiScope *apiScope, name string, scopeSpecificDroidstubsArgs []string) {
181 props := struct {
182 Name *string
183 Enabled proptools.Configurable[bool]
184 Visibility []string
185 Srcs []string
186 Installable *bool
187 Sdk_version *string
188 Api_surface *string
189 System_modules *string
190 Libs proptools.Configurable[[]string]
191 Output_javadoc_comments *bool
192 Arg_files []string
193 Args *string
194 Java_version *string
195 Annotations_enabled *bool
196 Merge_annotations_dirs []string
197 Merge_inclusion_annotations_dirs []string
198 Generate_stubs *bool
199 Previous_api *string
200 Aconfig_declarations []string
201 Check_api struct {
202 Current ApiToCheck
203 Last_released ApiToCheck
204
205 Api_lint struct {
206 Enabled *bool
207 New_since *string
208 Baseline_file *string
209 }
210 }
211 Aidl struct {
212 Include_dirs []string
213 Local_include_dirs []string
214 }
215 Dists []android.Dist
216 }{}
217
218 // The stubs source processing uses the same compile time classpath when extracting the
219 // API from the implementation library as it does when compiling it. i.e. the same
220 // * sdk version
221 // * system_modules
222 // * libs (static_libs/libs)
223
224 props.Name = proptools.StringPtr(name)
225 props.Enabled = module.EnabledProperty()
226 props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_source_visibility)
227 props.Srcs = append(props.Srcs, module.properties.Srcs...)
228 props.Srcs = append(props.Srcs, module.sdkLibraryProperties.Api_srcs...)
229 props.Sdk_version = module.deviceProperties.Sdk_version
230 props.Api_surface = &apiScope.name
231 props.System_modules = module.deviceProperties.System_modules
232 props.Installable = proptools.BoolPtr(false)
233 // A droiddoc module has only one Libs property and doesn't distinguish between
234 // shared libs and static libs. So we need to add both of these libs to Libs property.
235 props.Libs = proptools.NewConfigurable[[]string](nil, nil)
236 props.Libs.AppendSimpleValue(module.properties.Libs)
237 props.Libs.Append(module.properties.Static_libs)
238 props.Libs.AppendSimpleValue(module.sdkLibraryProperties.Stub_only_libs)
239 props.Libs.AppendSimpleValue(module.scopeToProperties[apiScope].Libs)
240 props.Aidl.Include_dirs = module.deviceProperties.Aidl.Include_dirs
241 props.Aidl.Local_include_dirs = module.deviceProperties.Aidl.Local_include_dirs
242 props.Java_version = module.properties.Java_version
243
244 props.Annotations_enabled = module.sdkLibraryProperties.Annotations_enabled
245 props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs
246 props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs
247 props.Aconfig_declarations = module.sdkLibraryProperties.Aconfig_declarations
248
249 droidstubsArgs := []string{}
250 if len(module.sdkLibraryProperties.Api_packages) != 0 {
251 droidstubsArgs = append(droidstubsArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":"))
252 }
253 droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...)
254 disabledWarnings := []string{"HiddenSuperclass"}
255 if proptools.BoolDefault(module.sdkLibraryProperties.Api_lint.Legacy_errors_allowed, true) {
256 disabledWarnings = append(disabledWarnings,
257 "BroadcastBehavior",
258 "DeprecationMismatch",
259 "MissingPermission",
260 "SdkConstant",
261 "Todo",
262 )
263 }
264 droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
265
266 // Output Javadoc comments for public scope.
267 if apiScope == apiScopePublic {
268 props.Output_javadoc_comments = proptools.BoolPtr(true)
269 }
270
271 // Add in scope specific arguments.
272 droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...)
273 props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
274 props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " "))
275
276 // List of APIs identified from the provided source files are created. They are later
277 // compared against to the not-yet-released (a.k.a current) list of APIs and to the
278 // last-released (a.k.a numbered) list of API.
279 currentApiFileName := apiScope.apiFilePrefix + "current.txt"
280 removedApiFileName := apiScope.apiFilePrefix + "removed.txt"
281 apiDir := module.getApiDir()
282 currentApiFileName = path.Join(apiDir, currentApiFileName)
283 removedApiFileName = path.Join(apiDir, removedApiFileName)
284
285 // check against the not-yet-release API
286 props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
287 props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
288
289 if module.compareAgainstLatestApi(apiScope) {
290 // check against the latest released API
291 latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope))
292 props.Previous_api = latestApiFilegroupName
293 props.Check_api.Last_released.Api_file = latestApiFilegroupName
294 props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
295 module.latestRemovedApiFilegroupName(apiScope))
296 props.Check_api.Last_released.Baseline_file = proptools.StringPtr(
297 module.latestIncompatibilitiesFilegroupName(apiScope))
298
299 if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) {
300 // Enable api lint.
301 props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true)
302 props.Check_api.Api_lint.New_since = latestApiFilegroupName
303
304 // If it exists then pass a lint-baseline.txt through to droidstubs.
305 baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt")
306 baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath)
307 paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil)
308 if err != nil {
309 mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err)
310 }
311 if len(paths) == 1 {
312 props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath)
313 } else if len(paths) != 0 {
314 mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths)
315 }
316 }
317 }
318
319 if !Bool(module.sdkLibraryProperties.No_dist) {
320 // Dist the api txt and removed api txt artifacts for sdk builds.
321 distDir := proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
322 stubsTypeTagPrefix := ""
323 if mctx.Config().ReleaseHiddenApiExportableStubs() {
324 stubsTypeTagPrefix = ".exportable"
325 }
326 for _, p := range []struct {
327 tag string
328 pattern string
329 }{
330 // "exportable" api files are copied to the dist directory instead of the
331 // "everything" api files when "RELEASE_HIDDEN_API_EXPORTABLE_STUBS" build flag
332 // is set. Otherwise, the "everything" api files are copied to the dist directory.
333 {tag: "%s.api.txt", pattern: "%s.txt"},
334 {tag: "%s.removed-api.txt", pattern: "%s-removed.txt"},
335 } {
336 props.Dists = append(props.Dists, android.Dist{
337 Targets: []string{"sdk", "win_sdk"},
338 Dir: distDir,
339 Dest: proptools.StringPtr(fmt.Sprintf(p.pattern, module.distStem())),
340 Tag: proptools.StringPtr(fmt.Sprintf(p.tag, stubsTypeTagPrefix)),
341 })
342 }
343 }
344
345 mctx.CreateModule(DroidstubsFactory, &props, module.sdkComponentPropertiesForChildLibrary()).(*Droidstubs).CallHookIfAvailable(mctx)
346}
347
348type libraryProperties struct {
349 Name *string
350 Enabled proptools.Configurable[bool]
351 Visibility []string
352 Srcs []string
353 Installable *bool
354 Sdk_version *string
355 System_modules *string
356 Patch_module *string
357 Libs []string
358 Static_libs []string
359 Compile_dex *bool
360 Java_version *string
361 Openjdk9 struct {
362 Srcs []string
363 Javacflags []string
364 }
365 Dist struct {
366 Targets []string
367 Dest *string
368 Dir *string
369 Tag *string
370 }
371 Is_stubs_module *bool
372 Stub_contributing_api *string
373}
374
375func (module *SdkLibrary) stubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope) libraryProperties {
376 props := libraryProperties{}
377 props.Enabled = module.EnabledProperty()
378 props.Visibility = []string{"//visibility:override", "//visibility:private"}
379 // sources are generated from the droiddoc
380 sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
381 props.Sdk_version = proptools.StringPtr(sdkVersion)
382 props.System_modules = module.deviceProperties.System_modules
383 props.Patch_module = module.properties.Patch_module
384 props.Installable = proptools.BoolPtr(false)
385 props.Libs = module.sdkLibraryProperties.Stub_only_libs
386 props.Libs = append(props.Libs, module.scopeToProperties[apiScope].Libs...)
387 props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs
388 // The stub-annotations library contains special versions of the annotations
389 // with CLASS retention policy, so that they're kept.
390 if proptools.Bool(module.sdkLibraryProperties.Annotations_enabled) {
391 props.Libs = append(props.Libs, "stub-annotations")
392 }
393 props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs
394 props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags
395 // We compile the stubs for 1.8 in line with the main android.jar stubs, and potential
396 // interop with older developer tools that don't support 1.9.
397 props.Java_version = proptools.StringPtr("1.8")
398 props.Is_stubs_module = proptools.BoolPtr(true)
399 props.Stub_contributing_api = proptools.StringPtr(apiScope.kind.String())
400
401 return props
402}
403
404// Creates the from-source stub [Library] with ".stubs.<[apiScope.name]>.from-source" suffix.
405func (module *SdkLibrary) createFromSourceStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
406
407 props := module.stubsLibraryProps(mctx, apiScope)
408 props.Name = proptools.StringPtr(module.fromSourceStubsLibraryModuleName(apiScope))
409 props.Srcs = []string{":" + module.droidstubsModuleName(apiScope)}
410
411 mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
412}
413
414// Creates the "exportable" from-source stub [Library] with
415// ".stubs.exportable.<[apiScope.name]>" suffix.
416func (module *SdkLibrary) createExportableFromSourceStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
417 props := module.stubsLibraryProps(mctx, apiScope)
418 props.Name = proptools.StringPtr(module.exportableFromSourceStubsLibraryModuleName(apiScope))
419 props.Srcs = []string{":" + module.droidstubsModuleName(apiScope) + "{.exportable}"}
420
421 mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
422}
423
424// Creates the from-text stub [ApiLibrary] with ".stubs.<[apiScope.name]>.from-text" suffix.
425func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
426 props := struct {
427 Name *string
428 Enabled proptools.Configurable[bool]
429 Visibility []string
430 Api_contributions []string
431 Libs proptools.Configurable[[]string]
432 Static_libs []string
433 System_modules *string
434 Enable_validation *bool
435 Stubs_type *string
436 Sdk_version *string
437 Previous_api *string
438 }{}
439
440 props.Name = proptools.StringPtr(module.fromTextStubsLibraryModuleName(apiScope))
441 props.Enabled = module.EnabledProperty()
442 props.Visibility = []string{"//visibility:override", "//visibility:private"}
443
444 apiContributions := []string{}
445
446 // Api surfaces are not independent of each other, but have subset relationships,
447 // and so does the api files. To generate from-text stubs for api surfaces other than public,
448 // all subset api domains' api_contriubtions must be added as well.
449 scope := apiScope
450 for scope != nil {
451 apiContributions = append(apiContributions, module.droidstubsModuleName(scope)+".api.contribution")
452 scope = scope.extends
453 }
454 if apiScope == apiScopePublic {
455 additionalApiContribution := module.apiLibraryAdditionalApiContribution()
456 if additionalApiContribution != "" {
457 apiContributions = append(apiContributions, additionalApiContribution)
458 }
459 }
460
461 props.Api_contributions = apiContributions
462
463 // Ensure that stub-annotations is added to the classpath before any other libs
464 props.Libs = proptools.NewConfigurable[[]string](nil, nil)
465 props.Libs.AppendSimpleValue([]string{"stub-annotations"})
466 props.Libs.AppendSimpleValue(module.properties.Libs)
467 props.Libs.Append(module.properties.Static_libs)
468 props.Libs.AppendSimpleValue(module.sdkLibraryProperties.Stub_only_libs)
469 props.Libs.AppendSimpleValue(module.scopeToProperties[apiScope].Libs)
470 props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs
471
472 props.System_modules = module.deviceProperties.System_modules
473 props.Enable_validation = proptools.BoolPtr(true)
474 props.Stubs_type = proptools.StringPtr("everything")
475
476 if module.deviceProperties.Sdk_version != nil {
477 props.Sdk_version = module.deviceProperties.Sdk_version
478 }
479
480 if module.compareAgainstLatestApi(apiScope) {
481 // check against the latest released API
482 latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope))
483 props.Previous_api = latestApiFilegroupName
484 }
485
486 mctx.CreateModule(ApiLibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
487}
488
489func (module *SdkLibrary) topLevelStubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope, doDist bool) libraryProperties {
490 props := libraryProperties{}
491
492 props.Enabled = module.EnabledProperty()
493 props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
494 sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
495 props.Sdk_version = proptools.StringPtr(sdkVersion)
496
497 props.System_modules = module.deviceProperties.System_modules
498
499 // The imports need to be compiled to dex if the java_sdk_library requests it.
500 compileDex := module.dexProperties.Compile_dex
501 if module.stubLibrariesCompiledForDex() {
502 compileDex = proptools.BoolPtr(true)
503 }
504 props.Compile_dex = compileDex
505
506 props.Stub_contributing_api = proptools.StringPtr(apiScope.kind.String())
507
508 if !Bool(module.sdkLibraryProperties.No_dist) && doDist {
509 props.Dist.Targets = []string{"sdk", "win_sdk"}
510 props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.distStem()))
511 props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
512 props.Dist.Tag = proptools.StringPtr(".jar")
513 }
514 props.Is_stubs_module = proptools.BoolPtr(true)
515
516 return props
517}
518
519// Creates the stub [Library] with ".stubs.<[apiScope.name]>" suffix.
520func (module *SdkLibrary) createTopLevelStubsLibrary(
521 mctx android.DefaultableHookContext, apiScope *apiScope) {
522
523 // Dist the "everything" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is false
524 doDist := !mctx.Config().ReleaseHiddenApiExportableStubs()
525 props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist)
526 props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
527
528 // Add the stub compiling java_library/java_api_library as static lib based on build config
529 staticLib := module.fromSourceStubsLibraryModuleName(apiScope)
530 if mctx.Config().BuildFromTextStub() && module.ModuleBuildFromTextStubs() {
531 staticLib = module.fromTextStubsLibraryModuleName(apiScope)
532 }
533 props.Static_libs = append(props.Static_libs, staticLib)
534
535 mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
536}
537
538// Creates the "exportable" stub [Library] with ".stubs.exportable.<[apiScope.name]>" suffix.
539func (module *SdkLibrary) createTopLevelExportableStubsLibrary(
540 mctx android.DefaultableHookContext, apiScope *apiScope) {
541
542 // Dist the "exportable" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is true
543 doDist := mctx.Config().ReleaseHiddenApiExportableStubs()
544 props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist)
545 props.Name = proptools.StringPtr(module.exportableStubsLibraryModuleName(apiScope))
546
547 staticLib := module.exportableFromSourceStubsLibraryModuleName(apiScope)
548 props.Static_libs = append(props.Static_libs, staticLib)
549
550 mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
551}
552
553// Creates the [sdkLibraryXml] with ".xml" suffix.
554func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) {
555 moduleMinApiLevel := module.Library.MinSdkVersion(mctx)
556 var moduleMinApiLevelStr = moduleMinApiLevel.String()
557 if moduleMinApiLevel == android.NoneApiLevel {
558 moduleMinApiLevelStr = "current"
559 }
560 props := struct {
561 Name *string
562 Enabled proptools.Configurable[bool]
563 Lib_name *string
564 Apex_available []string
565 On_bootclasspath_since *string
566 On_bootclasspath_before *string
567 Min_device_sdk *string
568 Max_device_sdk *string
569 Sdk_library_min_api_level *string
Cole Faust64f2d842024-10-17 13:28:34 -0700570 Uses_libs_dependencies proptools.Configurable[[]string]
Jihoon Kang96ce83b2024-09-23 22:09:44 +0000571 }{
572 Name: proptools.StringPtr(module.xmlPermissionsModuleName()),
573 Enabled: module.EnabledProperty(),
574 Lib_name: proptools.StringPtr(module.BaseModuleName()),
575 Apex_available: module.ApexProperties.Apex_available,
576 On_bootclasspath_since: module.commonSdkLibraryProperties.On_bootclasspath_since,
577 On_bootclasspath_before: module.commonSdkLibraryProperties.On_bootclasspath_before,
578 Min_device_sdk: module.commonSdkLibraryProperties.Min_device_sdk,
579 Max_device_sdk: module.commonSdkLibraryProperties.Max_device_sdk,
580 Sdk_library_min_api_level: &moduleMinApiLevelStr,
Cole Faust64f2d842024-10-17 13:28:34 -0700581 Uses_libs_dependencies: module.usesLibraryProperties.Uses_libs.Clone(),
Jihoon Kang96ce83b2024-09-23 22:09:44 +0000582 }
583
584 mctx.CreateModule(sdkLibraryXmlFactory, &props)
585}
586
587// ---------------------------------------------------------------------------------------------
588// Build rules of the submodules generated by java_sdk_library_import.
589// Note that the java_sdk_library_import module does not generate the implementation library.
590// Instead, it will create a dependency to the source implemenetation library if one exists.
591// java_sdk_library_import "framework-foo" generates the following submodules:
592//
593// - "framework-foo.stubs.<[apiScope.name]>" (type: [Import]): prebuilt stub library module that
594// provides the stub jar file checked in the tree.
595//
596// - "framework-foo.stubs.source.<[apiScope.name]>" (type: [PrebuiltStubsSources]): prebuilt
597// droidstubs module that provides the stub source jar file checked in the tree.
598//
599// - "framework-foo.stubs.source.<[apiScope.name]>.api.contribution"
600// (type [JavaApiContributionImport]): prebuilt java_api_contribution module that provides
601// the prebuilt api file for previously released from-text stub generation.
602// ---------------------------------------------------------------------------------------------
603
604// Creates the prebuilt stub [Import] with ".stubs.<[apiScope.name]>" suffix.
605func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
606 // Creates a java import for the jar with ".stubs" suffix
607 props := struct {
608 Name *string
609 Source_module_name *string
610 Created_by_java_sdk_library_name *string
611 Sdk_version *string
612 Libs []string
613 Jars []string
614 Compile_dex *bool
615 Is_stubs_module *bool
616
617 android.UserSuppliedPrebuiltProperties
618 }{}
619 props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
620 props.Source_module_name = proptools.StringPtr(apiScope.stubsLibraryModuleName(module.BaseModuleName()))
621 props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName())
622 props.Sdk_version = scopeProperties.Sdk_version
623 // Prepend any of the libs from the legacy public properties to the libs for each of the
624 // scopes to avoid having to duplicate them in each scope.
625 props.Libs = append(module.properties.Libs, scopeProperties.Libs...)
626 props.Jars = scopeProperties.Jars
627
628 // The imports are preferred if the java_sdk_library_import is preferred.
629 props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt)
630
631 // The imports need to be compiled to dex if the java_sdk_library_import requests it.
632 compileDex := module.properties.Compile_dex
633 if module.stubLibrariesCompiledForDex() {
634 compileDex = proptools.BoolPtr(true)
635 }
636 props.Compile_dex = compileDex
637 props.Is_stubs_module = proptools.BoolPtr(true)
638
639 mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
640}
641
642func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
643 props := struct {
644 Name *string
645 Source_module_name *string
646 Created_by_java_sdk_library_name *string
647 Srcs []string
648
649 android.UserSuppliedPrebuiltProperties
650 }{}
651 props.Name = proptools.StringPtr(module.droidstubsModuleName(apiScope))
652 props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName()))
653 props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName())
654 props.Srcs = scopeProperties.Stub_srcs
655
656 // The stubs source is preferred if the java_sdk_library_import is preferred.
657 props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt)
658
659 mctx.CreateModule(PrebuiltStubsSourcesFactory, &props, module.sdkComponentPropertiesForChildLibrary())
660}
661
662// Creates the prebuilt api contribution [JavaApiContributionImport] with
663// ".stubs.source.<[apiScope.name]>.api.contribution" suffix.
664func (module *SdkLibraryImport) createPrebuiltApiContribution(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
665 api_file := scopeProperties.Current_api
666 api_surface := &apiScope.name
667
668 props := struct {
669 Name *string
670 Source_module_name *string
671 Created_by_java_sdk_library_name *string
672 Api_surface *string
673 Api_file *string
674 Visibility []string
675 }{}
676
677 props.Name = proptools.StringPtr(module.droidstubsModuleName(apiScope) + ".api.contribution")
678 props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName()) + ".api.contribution")
679 props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName())
680 props.Api_surface = api_surface
681 props.Api_file = api_file
682 props.Visibility = []string{"//visibility:override", "//visibility:public"}
683
684 mctx.CreateModule(ApiContributionImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
685}
686
687// ---------------------------------------------------------------------------------------------
688// End of the build rules of the submodules generated by java_sdk_library_import.
689// ---------------------------------------------------------------------------------------------
690
691// Definition of the [sdkLibraryXml] module. The module generates the permissions xml file,
692// so that the apps can specify the java_sdk_library using <uses-permission> tag in the
693// AndroidManifest.xml file.
694type sdkLibraryXml struct {
695 android.ModuleBase
696 android.DefaultableModuleBase
697 android.ApexModuleBase
698
699 properties sdkLibraryXmlProperties
700
701 outputFilePath android.OutputPath
702 installDirPath android.InstallPath
703
704 hideApexVariantFromMake bool
705}
706
707type sdkLibraryXmlProperties struct {
708 // canonical name of the lib
709 Lib_name *string
710
711 // Signals that this shared library is part of the bootclasspath starting
712 // on the version indicated in this attribute.
713 //
714 // This will make platforms at this level and above to ignore
715 // <uses-library> tags with this library name because the library is already
716 // available
717 On_bootclasspath_since *string
718
719 // Signals that this shared library was part of the bootclasspath before
720 // (but not including) the version indicated in this attribute.
721 //
722 // The system will automatically add a <uses-library> tag with this library to
723 // apps that target any SDK less than the version indicated in this attribute.
724 On_bootclasspath_before *string
725
726 // Indicates that PackageManager should ignore this shared library if the
727 // platform is below the version indicated in this attribute.
728 //
729 // This means that the device won't recognise this library as installed.
730 Min_device_sdk *string
731
732 // Indicates that PackageManager should ignore this shared library if the
733 // platform is above the version indicated in this attribute.
734 //
735 // This means that the device won't recognise this library as installed.
736 Max_device_sdk *string
737
738 // The SdkLibrary's min api level as a string
739 //
740 // This value comes from the ApiLevel of the MinSdkVersion property.
741 Sdk_library_min_api_level *string
742
743 // Uses-libs dependencies that the shared library requires to work correctly.
744 //
745 // This will add dependency="foo:bar" to the <library> section.
Cole Faust64f2d842024-10-17 13:28:34 -0700746 Uses_libs_dependencies proptools.Configurable[[]string]
Jihoon Kang96ce83b2024-09-23 22:09:44 +0000747}
748
749// java_sdk_library_xml builds the permission xml file for a java_sdk_library.
750// Not to be used directly by users. java_sdk_library internally uses this.
751func sdkLibraryXmlFactory() android.Module {
752 module := &sdkLibraryXml{}
753
754 module.AddProperties(&module.properties)
755
756 android.InitApexModule(module)
757 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
758
759 return module
760}
761
762func (module *sdkLibraryXml) UniqueApexVariations() bool {
763 // sdkLibraryXml needs a unique variation per APEX because the generated XML file contains the path to the
764 // mounted APEX, which contains the name of the APEX.
765 return true
766}
767
768// from android.PrebuiltEtcModule
769func (module *sdkLibraryXml) BaseDir() string {
770 return "etc"
771}
772
773// from android.PrebuiltEtcModule
774func (module *sdkLibraryXml) SubDir() string {
775 return "permissions"
776}
777
778var _ etc.PrebuiltEtcModule = (*sdkLibraryXml)(nil)
779
780// from android.ApexModule
781func (module *sdkLibraryXml) AvailableFor(what string) bool {
Yu Liub73c3a62024-12-10 00:58:06 +0000782 return android.CheckAvailableForApex(what, module.ApexAvailableFor())
783}
784
785func (module *sdkLibraryXml) ApexAvailableFor() []string {
786 return []string{android.AvailableToPlatform, android.AvailableToAnyApex}
Jihoon Kang96ce83b2024-09-23 22:09:44 +0000787}
788
789func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) {
790 // do nothing
791}
792
793var _ android.ApexModule = (*sdkLibraryXml)(nil)
794
795// Implements android.ApexModule
796func (module *sdkLibraryXml) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
797 sdkVersion android.ApiLevel) error {
798 // sdkLibraryXml doesn't need to be checked separately because java_sdk_library is checked
799 return nil
800}
801
802// File path to the runtime implementation library
803func (module *sdkLibraryXml) implPath(ctx android.ModuleContext) string {
804 implName := proptools.String(module.properties.Lib_name)
805 if apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider); !apexInfo.IsForPlatform() {
806 // TODO(b/146468504): ApexVariationName() is only a soong module name, not apex name.
807 // In most cases, this works fine. But when apex_name is set or override_apex is used
808 // this can be wrong.
809 return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexInfo.BaseApexName, implName)
810 }
811 partition := "system"
812 if module.SocSpecific() {
813 partition = "vendor"
814 } else if module.DeviceSpecific() {
815 partition = "odm"
816 } else if module.ProductSpecific() {
817 partition = "product"
818 } else if module.SystemExtSpecific() {
819 partition = "system_ext"
820 }
821 return "/" + partition + "/framework/" + implName + ".jar"
822}
823
824func formattedOptionalSdkLevelAttribute(ctx android.ModuleContext, attrName string, value *string) string {
825 if value == nil {
826 return ""
827 }
828 apiLevel, err := android.ApiLevelFromUser(ctx, *value)
829 if err != nil {
830 // attributes in bp files have underscores but in the xml have dashes.
831 ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"), err.Error())
832 return ""
833 }
834 if apiLevel.IsCurrent() {
835 // passing "current" would always mean a future release, never the current (or the current in
836 // progress) which means some conditions would never be triggered.
837 ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"),
838 `"current" is not an allowed value for this attribute`)
839 return ""
840 }
841 // "safeValue" is safe because it translates finalized codenames to a string
842 // with their SDK int.
843 safeValue := apiLevel.String()
844 return formattedOptionalAttribute(attrName, &safeValue)
845}
846
847// formats an attribute for the xml permissions file if the value is not null
848// returns empty string otherwise
849func formattedOptionalAttribute(attrName string, value *string) string {
850 if value == nil {
851 return ""
852 }
853 return fmt.Sprintf(" %s=\"%s\"\n", attrName, *value)
854}
855
856func formattedDependenciesAttribute(dependencies []string) string {
857 if dependencies == nil {
858 return ""
859 }
860 return fmt.Sprintf(" dependency=\"%s\"\n", strings.Join(dependencies, ":"))
861}
862
863func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) string {
864 libName := proptools.String(module.properties.Lib_name)
865 libNameAttr := formattedOptionalAttribute("name", &libName)
866 filePath := module.implPath(ctx)
867 filePathAttr := formattedOptionalAttribute("file", &filePath)
868 implicitFromAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-since", module.properties.On_bootclasspath_since)
869 implicitUntilAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-before", module.properties.On_bootclasspath_before)
870 minSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "min-device-sdk", module.properties.Min_device_sdk)
871 maxSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "max-device-sdk", module.properties.Max_device_sdk)
Cole Faust64f2d842024-10-17 13:28:34 -0700872 dependenciesAttr := formattedDependenciesAttribute(module.properties.Uses_libs_dependencies.GetOrDefault(ctx, nil))
Jihoon Kang96ce83b2024-09-23 22:09:44 +0000873 // <library> is understood in all android versions whereas <apex-library> is only understood from API T (and ignored before that).
874 // similarly, min_device_sdk is only understood from T. So if a library is using that, we need to use the apex-library to make sure this library is not loaded before T
875 var libraryTag string
876 if module.properties.Min_device_sdk != nil {
877 libraryTag = " <apex-library\n"
878 } else {
879 libraryTag = " <library\n"
880 }
881
882 return strings.Join([]string{
883 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n",
884 "<!-- Copyright (C) 2018 The Android Open Source Project\n",
885 "\n",
886 " Licensed under the Apache License, Version 2.0 (the \"License\");\n",
887 " you may not use this file except in compliance with the License.\n",
888 " You may obtain a copy of the License at\n",
889 "\n",
890 " http://www.apache.org/licenses/LICENSE-2.0\n",
891 "\n",
892 " Unless required by applicable law or agreed to in writing, software\n",
893 " distributed under the License is distributed on an \"AS IS\" BASIS,\n",
894 " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
895 " See the License for the specific language governing permissions and\n",
896 " limitations under the License.\n",
897 "-->\n",
898 "<permissions>\n",
899 libraryTag,
900 libNameAttr,
901 filePathAttr,
902 implicitFromAttr,
903 implicitUntilAttr,
904 minSdkAttr,
905 maxSdkAttr,
906 dependenciesAttr,
907 " />\n",
908 "</permissions>\n",
909 }, "")
910}
911
912func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
913 apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
914 module.hideApexVariantFromMake = !apexInfo.IsForPlatform()
915
916 libName := proptools.String(module.properties.Lib_name)
917 module.selfValidate(ctx)
918 xmlContent := module.permissionsContents(ctx)
919
920 module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath
921 android.WriteFileRuleVerbatim(ctx, module.outputFilePath, xmlContent)
922
923 module.installDirPath = android.PathForModuleInstall(ctx, "etc", module.SubDir())
924 ctx.PackageFile(module.installDirPath, libName+".xml", module.outputFilePath)
925
926 ctx.SetOutputFiles(android.OutputPaths{module.outputFilePath}.Paths(), "")
927}
928
929func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries {
930 if module.hideApexVariantFromMake {
931 return []android.AndroidMkEntries{{
932 Disabled: true,
933 }}
934 }
935
936 return []android.AndroidMkEntries{{
937 Class: "ETC",
938 OutputFile: android.OptionalPathForPath(module.outputFilePath),
939 ExtraEntries: []android.AndroidMkExtraEntriesFunc{
940 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
941 entries.SetString("LOCAL_MODULE_TAGS", "optional")
942 entries.SetString("LOCAL_MODULE_PATH", module.installDirPath.String())
943 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", module.outputFilePath.Base())
944 },
945 },
946 }}
947}
948
949func (module *sdkLibraryXml) selfValidate(ctx android.ModuleContext) {
950 module.validateAtLeastTAttributes(ctx)
951 module.validateMinAndMaxDeviceSdk(ctx)
952 module.validateMinMaxDeviceSdkAndModuleMinSdk(ctx)
953 module.validateOnBootclasspathBeforeRequirements(ctx)
954}
955
956func (module *sdkLibraryXml) validateAtLeastTAttributes(ctx android.ModuleContext) {
957 t := android.ApiLevelOrPanic(ctx, "Tiramisu")
958 module.attrAtLeastT(ctx, t, module.properties.Min_device_sdk, "min_device_sdk")
959 module.attrAtLeastT(ctx, t, module.properties.Max_device_sdk, "max_device_sdk")
960 module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_before, "on_bootclasspath_before")
961 module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_since, "on_bootclasspath_since")
962}
963
964func (module *sdkLibraryXml) attrAtLeastT(ctx android.ModuleContext, t android.ApiLevel, attr *string, attrName string) {
965 if attr != nil {
966 if level, err := android.ApiLevelFromUser(ctx, *attr); err == nil {
967 // we will inform the user of invalid inputs when we try to write the
968 // permissions xml file so we don't need to do it here
969 if t.GreaterThan(level) {
970 ctx.PropertyErrorf(attrName, "Attribute value needs to be at least T")
971 }
972 }
973 }
974}
975
976func (module *sdkLibraryXml) validateMinAndMaxDeviceSdk(ctx android.ModuleContext) {
977 if module.properties.Min_device_sdk != nil && module.properties.Max_device_sdk != nil {
978 min, minErr := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk)
979 max, maxErr := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk)
980 if minErr == nil && maxErr == nil {
981 // we will inform the user of invalid inputs when we try to write the
982 // permissions xml file so we don't need to do it here
983 if min.GreaterThan(max) {
984 ctx.ModuleErrorf("min_device_sdk can't be greater than max_device_sdk")
985 }
986 }
987 }
988}
989
990func (module *sdkLibraryXml) validateMinMaxDeviceSdkAndModuleMinSdk(ctx android.ModuleContext) {
991 moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level)
992 if module.properties.Min_device_sdk != nil {
993 api, err := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk)
994 if err == nil {
995 if moduleMinApi.GreaterThan(api) {
996 ctx.PropertyErrorf("min_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi)
997 }
998 }
999 }
1000 if module.properties.Max_device_sdk != nil {
1001 api, err := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk)
1002 if err == nil {
1003 if moduleMinApi.GreaterThan(api) {
1004 ctx.PropertyErrorf("max_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi)
1005 }
1006 }
1007 }
1008}
1009
1010func (module *sdkLibraryXml) validateOnBootclasspathBeforeRequirements(ctx android.ModuleContext) {
1011 moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level)
1012 if module.properties.On_bootclasspath_before != nil {
1013 t := android.ApiLevelOrPanic(ctx, "Tiramisu")
1014 // if we use the attribute, then we need to do this validation
1015 if moduleMinApi.LessThan(t) {
1016 // if minAPi is < T, then we need to have min_device_sdk (which only accepts T+)
1017 if module.properties.Min_device_sdk == nil {
1018 ctx.PropertyErrorf("on_bootclasspath_before", "Using this property requires that the module's min_sdk_version or the shared library's min_device_sdk is at least T")
1019 }
1020 }
1021 }
1022}