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