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