• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2018 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package java
16
17import (
18	"fmt"
19	"path"
20	"path/filepath"
21	"reflect"
22	"regexp"
23	"sort"
24	"strings"
25	"sync"
26
27	"github.com/google/blueprint"
28	"github.com/google/blueprint/proptools"
29
30	"android/soong/android"
31	"android/soong/bazel"
32	"android/soong/dexpreopt"
33)
34
35const (
36	sdkXmlFileSuffix = ".xml"
37)
38
39// A tag to associated a dependency with a specific api scope.
40type scopeDependencyTag struct {
41	blueprint.BaseDependencyTag
42	name     string
43	apiScope *apiScope
44
45	// Function for extracting appropriate path information from the dependency.
46	depInfoExtractor func(paths *scopePaths, ctx android.ModuleContext, dep android.Module) error
47}
48
49// Extract tag specific information from the dependency.
50func (tag scopeDependencyTag) extractDepInfo(ctx android.ModuleContext, dep android.Module, paths *scopePaths) {
51	err := tag.depInfoExtractor(paths, ctx, dep)
52	if err != nil {
53		ctx.ModuleErrorf("has an invalid {scopeDependencyTag: %s} dependency on module %s: %s", tag.name, ctx.OtherModuleName(dep), err.Error())
54	}
55}
56
57var _ android.ReplaceSourceWithPrebuilt = (*scopeDependencyTag)(nil)
58
59func (tag scopeDependencyTag) ReplaceSourceWithPrebuilt() bool {
60	return false
61}
62
63// Provides information about an api scope, e.g. public, system, test.
64type apiScope struct {
65	// The name of the api scope, e.g. public, system, test
66	name string
67
68	// The api scope that this scope extends.
69	//
70	// This organizes the scopes into an extension hierarchy.
71	//
72	// If set this means that the API provided by this scope includes the API provided by the scope
73	// set in this field.
74	extends *apiScope
75
76	// The next api scope that a library that uses this scope can access.
77	//
78	// This organizes the scopes into an access hierarchy.
79	//
80	// If set this means that a library that can access this API can also access the API provided by
81	// the scope set in this field.
82	//
83	// A module that sets sdk_version: "<scope>_current" should have access to the <scope> API of
84	// every java_sdk_library that it depends on. If the library does not provide an API for <scope>
85	// then it will traverse up this access hierarchy to find an API that it does provide.
86	//
87	// If this is not set then it defaults to the scope set in extends.
88	canAccess *apiScope
89
90	// The legacy enabled status for a specific scope can be dependent on other
91	// properties that have been specified on the library so it is provided by
92	// a function that can determine the status by examining those properties.
93	legacyEnabledStatus func(module *SdkLibrary) bool
94
95	// The default enabled status for non-legacy behavior, which is triggered by
96	// explicitly enabling at least one api scope.
97	defaultEnabledStatus bool
98
99	// Gets a pointer to the scope specific properties.
100	scopeSpecificProperties func(module *SdkLibrary) *ApiScopeProperties
101
102	// The name of the field in the dynamically created structure.
103	fieldName string
104
105	// The name of the property in the java_sdk_library_import
106	propertyName string
107
108	// The tag to use to depend on the stubs library module.
109	stubsTag scopeDependencyTag
110
111	// The tag to use to depend on the stubs source module (if separate from the API module).
112	stubsSourceTag scopeDependencyTag
113
114	// The tag to use to depend on the API file generating module (if separate from the stubs source module).
115	apiFileTag scopeDependencyTag
116
117	// The tag to use to depend on the stubs source and API module.
118	stubsSourceAndApiTag scopeDependencyTag
119
120	// The tag to use to depend on the module that provides the latest version of the API .txt file.
121	latestApiModuleTag scopeDependencyTag
122
123	// The tag to use to depend on the module that provides the latest version of the API removed.txt
124	// file.
125	latestRemovedApiModuleTag scopeDependencyTag
126
127	// The scope specific prefix to add to the api file base of "current.txt" or "removed.txt".
128	apiFilePrefix string
129
130	// The scope specific suffix to add to the sdk library module name to construct a scope specific
131	// module name.
132	moduleSuffix string
133
134	// SDK version that the stubs library is built against. Note that this is always
135	// *current. Older stubs library built with a numbered SDK version is created from
136	// the prebuilt jar.
137	sdkVersion string
138
139	// The annotation that identifies this API level, empty for the public API scope.
140	annotation string
141
142	// Extra arguments to pass to droidstubs for this scope.
143	//
144	// This is not used directly but is used to construct the droidstubsArgs.
145	extraArgs []string
146
147	// The args that must be passed to droidstubs to generate the API and stubs source
148	// for this scope, constructed dynamically by initApiScope().
149	//
150	// The API only includes the additional members that this scope adds over the scope
151	// that it extends.
152	//
153	// The stubs source must include the definitions of everything that is in this
154	// api scope and all the scopes that this one extends.
155	droidstubsArgs []string
156
157	// Whether the api scope can be treated as unstable, and should skip compat checks.
158	unstable bool
159}
160
161// Initialize a scope, creating and adding appropriate dependency tags
162func initApiScope(scope *apiScope) *apiScope {
163	name := scope.name
164	scopeByName[name] = scope
165	allScopeNames = append(allScopeNames, name)
166	scope.propertyName = strings.ReplaceAll(name, "-", "_")
167	scope.fieldName = proptools.FieldNameForProperty(scope.propertyName)
168	scope.stubsTag = scopeDependencyTag{
169		name:             name + "-stubs",
170		apiScope:         scope,
171		depInfoExtractor: (*scopePaths).extractStubsLibraryInfoFromDependency,
172	}
173	scope.stubsSourceTag = scopeDependencyTag{
174		name:             name + "-stubs-source",
175		apiScope:         scope,
176		depInfoExtractor: (*scopePaths).extractStubsSourceInfoFromDep,
177	}
178	scope.apiFileTag = scopeDependencyTag{
179		name:             name + "-api",
180		apiScope:         scope,
181		depInfoExtractor: (*scopePaths).extractApiInfoFromDep,
182	}
183	scope.stubsSourceAndApiTag = scopeDependencyTag{
184		name:             name + "-stubs-source-and-api",
185		apiScope:         scope,
186		depInfoExtractor: (*scopePaths).extractStubsSourceAndApiInfoFromApiStubsProvider,
187	}
188	scope.latestApiModuleTag = scopeDependencyTag{
189		name:             name + "-latest-api",
190		apiScope:         scope,
191		depInfoExtractor: (*scopePaths).extractLatestApiPath,
192	}
193	scope.latestRemovedApiModuleTag = scopeDependencyTag{
194		name:             name + "-latest-removed-api",
195		apiScope:         scope,
196		depInfoExtractor: (*scopePaths).extractLatestRemovedApiPath,
197	}
198
199	// To get the args needed to generate the stubs source append all the args from
200	// this scope and all the scopes it extends as each set of args adds additional
201	// members to the stubs.
202	var scopeSpecificArgs []string
203	if scope.annotation != "" {
204		scopeSpecificArgs = []string{"--show-annotation", scope.annotation}
205	}
206	for s := scope; s != nil; s = s.extends {
207		scopeSpecificArgs = append(scopeSpecificArgs, s.extraArgs...)
208
209		// Ensure that the generated stubs includes all the API elements from the API scope
210		// that this scope extends.
211		if s != scope && s.annotation != "" {
212			scopeSpecificArgs = append(scopeSpecificArgs, "--show-for-stub-purposes-annotation", s.annotation)
213		}
214	}
215
216	// By default, a library that can access a scope can also access the scope it extends.
217	if scope.canAccess == nil {
218		scope.canAccess = scope.extends
219	}
220
221	// Escape any special characters in the arguments. This is needed because droidstubs
222	// passes these directly to the shell command.
223	scope.droidstubsArgs = proptools.ShellEscapeList(scopeSpecificArgs)
224
225	return scope
226}
227
228func (scope *apiScope) stubsLibraryModuleNameSuffix() string {
229	return ".stubs" + scope.moduleSuffix
230}
231
232func (scope *apiScope) stubsLibraryModuleName(baseName string) string {
233	return baseName + scope.stubsLibraryModuleNameSuffix()
234}
235
236func (scope *apiScope) stubsSourceModuleName(baseName string) string {
237	return baseName + ".stubs.source" + scope.moduleSuffix
238}
239
240func (scope *apiScope) apiModuleName(baseName string) string {
241	return baseName + ".api" + scope.moduleSuffix
242}
243
244func (scope *apiScope) String() string {
245	return scope.name
246}
247
248// snapshotRelativeDir returns the snapshot directory into which the files related to scopes will
249// be stored.
250func (scope *apiScope) snapshotRelativeDir() string {
251	return filepath.Join("sdk_library", scope.name)
252}
253
254// snapshotRelativeCurrentApiTxtPath returns the snapshot path to the API .txt file for the named
255// library.
256func (scope *apiScope) snapshotRelativeCurrentApiTxtPath(name string) string {
257	return filepath.Join(scope.snapshotRelativeDir(), name+".txt")
258}
259
260// snapshotRelativeRemovedApiTxtPath returns the snapshot path to the removed API .txt file for the
261// named library.
262func (scope *apiScope) snapshotRelativeRemovedApiTxtPath(name string) string {
263	return filepath.Join(scope.snapshotRelativeDir(), name+"-removed.txt")
264}
265
266type apiScopes []*apiScope
267
268func (scopes apiScopes) Strings(accessor func(*apiScope) string) []string {
269	var list []string
270	for _, scope := range scopes {
271		list = append(list, accessor(scope))
272	}
273	return list
274}
275
276var (
277	scopeByName    = make(map[string]*apiScope)
278	allScopeNames  []string
279	apiScopePublic = initApiScope(&apiScope{
280		name: "public",
281
282		// Public scope is enabled by default for both legacy and non-legacy modes.
283		legacyEnabledStatus: func(module *SdkLibrary) bool {
284			return true
285		},
286		defaultEnabledStatus: true,
287
288		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
289			return &module.sdkLibraryProperties.Public
290		},
291		sdkVersion: "current",
292	})
293	apiScopeSystem = initApiScope(&apiScope{
294		name:                "system",
295		extends:             apiScopePublic,
296		legacyEnabledStatus: (*SdkLibrary).generateTestAndSystemScopesByDefault,
297		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
298			return &module.sdkLibraryProperties.System
299		},
300		apiFilePrefix: "system-",
301		moduleSuffix:  ".system",
302		sdkVersion:    "system_current",
303		annotation:    "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS)",
304	})
305	apiScopeTest = initApiScope(&apiScope{
306		name:                "test",
307		extends:             apiScopeSystem,
308		legacyEnabledStatus: (*SdkLibrary).generateTestAndSystemScopesByDefault,
309		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
310			return &module.sdkLibraryProperties.Test
311		},
312		apiFilePrefix: "test-",
313		moduleSuffix:  ".test",
314		sdkVersion:    "test_current",
315		annotation:    "android.annotation.TestApi",
316		unstable:      true,
317	})
318	apiScopeModuleLib = initApiScope(&apiScope{
319		name:    "module-lib",
320		extends: apiScopeSystem,
321		// The module-lib scope is disabled by default in legacy mode.
322		//
323		// Enabling this would break existing usages.
324		legacyEnabledStatus: func(module *SdkLibrary) bool {
325			return false
326		},
327		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
328			return &module.sdkLibraryProperties.Module_lib
329		},
330		apiFilePrefix: "module-lib-",
331		moduleSuffix:  ".module_lib",
332		sdkVersion:    "module_current",
333		annotation:    "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES)",
334	})
335	apiScopeSystemServer = initApiScope(&apiScope{
336		name:    "system-server",
337		extends: apiScopePublic,
338
339		// The system-server scope can access the module-lib scope.
340		//
341		// A module that provides a system-server API is appended to the standard bootclasspath that is
342		// used by the system server. So, it should be able to access module-lib APIs provided by
343		// libraries on the bootclasspath.
344		canAccess: apiScopeModuleLib,
345
346		// The system-server scope is disabled by default in legacy mode.
347		//
348		// Enabling this would break existing usages.
349		legacyEnabledStatus: func(module *SdkLibrary) bool {
350			return false
351		},
352		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
353			return &module.sdkLibraryProperties.System_server
354		},
355		apiFilePrefix: "system-server-",
356		moduleSuffix:  ".system_server",
357		sdkVersion:    "system_server_current",
358		annotation:    "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.SYSTEM_SERVER)",
359		extraArgs: []string{
360			"--hide-annotation", "android.annotation.Hide",
361			// com.android.* classes are okay in this interface"
362			"--hide", "InternalClasses",
363		},
364	})
365	allApiScopes = apiScopes{
366		apiScopePublic,
367		apiScopeSystem,
368		apiScopeTest,
369		apiScopeModuleLib,
370		apiScopeSystemServer,
371	}
372)
373
374var (
375	javaSdkLibrariesLock sync.Mutex
376)
377
378// TODO: these are big features that are currently missing
379// 1) disallowing linking to the runtime shared lib
380// 2) HTML generation
381
382func init() {
383	RegisterSdkLibraryBuildComponents(android.InitRegistrationContext)
384
385	android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
386		javaSdkLibraries := javaSdkLibraries(ctx.Config())
387		sort.Strings(*javaSdkLibraries)
388		ctx.Strict("JAVA_SDK_LIBRARIES", strings.Join(*javaSdkLibraries, " "))
389	})
390
391	// Register sdk member types.
392	android.RegisterSdkMemberType(javaSdkLibrarySdkMemberType)
393}
394
395func RegisterSdkLibraryBuildComponents(ctx android.RegistrationContext) {
396	ctx.RegisterModuleType("java_sdk_library", SdkLibraryFactory)
397	ctx.RegisterModuleType("java_sdk_library_import", sdkLibraryImportFactory)
398}
399
400// Properties associated with each api scope.
401type ApiScopeProperties struct {
402	// Indicates whether the api surface is generated.
403	//
404	// If this is set for any scope then all scopes must explicitly specify if they
405	// are enabled. This is to prevent new usages from depending on legacy behavior.
406	//
407	// Otherwise, if this is not set for any scope then the default  behavior is
408	// scope specific so please refer to the scope specific property documentation.
409	Enabled *bool
410
411	// The sdk_version to use for building the stubs.
412	//
413	// If not specified then it will use an sdk_version determined as follows:
414	//
415	// 1) If the sdk_version specified on the java_sdk_library is none then this
416	// will be none. This is used for java_sdk_library instances that are used
417	// to create stubs that contribute to the core_current sdk version.
418	// 2) Otherwise, it is assumed that this library extends but does not
419	// contribute directly to a specific sdk_version and so this uses the
420	// sdk_version appropriate for the api scope. e.g. public will use
421	// sdk_version: current, system will use sdk_version: system_current, etc.
422	//
423	// This does not affect the sdk_version used for either generating the stubs source
424	// or the API file. They both have to use the same sdk_version as is used for
425	// compiling the implementation library.
426	Sdk_version *string
427}
428
429type sdkLibraryProperties struct {
430	// List of source files that are needed to compile the API, but are not part of runtime library.
431	Api_srcs []string `android:"arch_variant"`
432
433	// Visibility for impl library module. If not specified then defaults to the
434	// visibility property.
435	Impl_library_visibility []string
436
437	// Visibility for stubs library modules. If not specified then defaults to the
438	// visibility property.
439	Stubs_library_visibility []string
440
441	// Visibility for stubs source modules. If not specified then defaults to the
442	// visibility property.
443	Stubs_source_visibility []string
444
445	// List of Java libraries that will be in the classpath when building the implementation lib
446	Impl_only_libs []string `android:"arch_variant"`
447
448	// List of Java libraries that will included in the implementation lib.
449	Impl_only_static_libs []string `android:"arch_variant"`
450
451	// List of Java libraries that will be in the classpath when building stubs
452	Stub_only_libs []string `android:"arch_variant"`
453
454	// List of Java libraries that will included in stub libraries
455	Stub_only_static_libs []string `android:"arch_variant"`
456
457	// list of package names that will be documented and publicized as API.
458	// This allows the API to be restricted to a subset of the source files provided.
459	// If this is unspecified then all the source files will be treated as being part
460	// of the API.
461	Api_packages []string
462
463	// list of package names that must be hidden from the API
464	Hidden_api_packages []string
465
466	// the relative path to the directory containing the api specification files.
467	// Defaults to "api".
468	Api_dir *string
469
470	// Determines whether a runtime implementation library is built; defaults to false.
471	//
472	// If true then it also prevents the module from being used as a shared module, i.e.
473	// it is as if shared_library: false, was set.
474	Api_only *bool
475
476	// local files that are used within user customized droiddoc options.
477	Droiddoc_option_files []string
478
479	// additional droiddoc options.
480	// Available variables for substitution:
481	//
482	//  $(location <label>): the path to the droiddoc_option_files with name <label>
483	Droiddoc_options []string
484
485	// is set to true, Metalava will allow framework SDK to contain annotations.
486	Annotations_enabled *bool
487
488	// a list of top-level directories containing files to merge qualifier annotations
489	// (i.e. those intended to be included in the stubs written) from.
490	Merge_annotations_dirs []string
491
492	// a list of top-level directories containing Java stub files to merge show/hide annotations from.
493	Merge_inclusion_annotations_dirs []string
494
495	// If set to true then don't create dist rules.
496	No_dist *bool
497
498	// The stem for the artifacts that are copied to the dist, if not specified
499	// then defaults to the base module name.
500	//
501	// For each scope the following artifacts are copied to the apistubs/<scope>
502	// directory in the dist.
503	// * stubs impl jar -> <dist-stem>.jar
504	// * API specification file -> api/<dist-stem>.txt
505	// * Removed API specification file -> api/<dist-stem>-removed.txt
506	//
507	// Also used to construct the name of the filegroup (created by prebuilt_apis)
508	// that references the latest released API and remove API specification files.
509	// * API specification filegroup -> <dist-stem>.api.<scope>.latest
510	// * Removed API specification filegroup -> <dist-stem>-removed.api.<scope>.latest
511	// * API incompatibilities baseline filegroup -> <dist-stem>-incompatibilities.api.<scope>.latest
512	Dist_stem *string
513
514	// The subdirectory for the artifacts that are copied to the dist directory.  If not specified
515	// then defaults to "unknown".  Should be set to "android" for anything that should be published
516	// in the public Android SDK.
517	Dist_group *string
518
519	// A compatibility mode that allows historical API-tracking files to not exist.
520	// Do not use.
521	Unsafe_ignore_missing_latest_api bool
522
523	// indicates whether system and test apis should be generated.
524	Generate_system_and_test_apis bool `blueprint:"mutated"`
525
526	// The properties specific to the public api scope
527	//
528	// Unless explicitly specified by using public.enabled the public api scope is
529	// enabled by default in both legacy and non-legacy mode.
530	Public ApiScopeProperties
531
532	// The properties specific to the system api scope
533	//
534	// In legacy mode the system api scope is enabled by default when sdk_version
535	// is set to something other than "none".
536	//
537	// In non-legacy mode the system api scope is disabled by default.
538	System ApiScopeProperties
539
540	// The properties specific to the test api scope
541	//
542	// In legacy mode the test api scope is enabled by default when sdk_version
543	// is set to something other than "none".
544	//
545	// In non-legacy mode the test api scope is disabled by default.
546	Test ApiScopeProperties
547
548	// The properties specific to the module-lib api scope
549	//
550	// Unless explicitly specified by using module_lib.enabled the module_lib api
551	// scope is disabled by default.
552	Module_lib ApiScopeProperties
553
554	// The properties specific to the system-server api scope
555	//
556	// Unless explicitly specified by using system_server.enabled the
557	// system_server api scope is disabled by default.
558	System_server ApiScopeProperties
559
560	// Determines if the stubs are preferred over the implementation library
561	// for linking, even when the client doesn't specify sdk_version. When this
562	// is set to true, such clients are provided with the widest API surface that
563	// this lib provides. Note however that this option doesn't affect the clients
564	// that are in the same APEX as this library. In that case, the clients are
565	// always linked with the implementation library. Default is false.
566	Default_to_stubs *bool
567
568	// Properties related to api linting.
569	Api_lint struct {
570		// Enable api linting.
571		Enabled *bool
572	}
573
574	// TODO: determines whether to create HTML doc or not
575	// Html_doc *bool
576}
577
578// Paths to outputs from java_sdk_library and java_sdk_library_import.
579//
580// Fields that are android.Paths are always set (during GenerateAndroidBuildActions).
581// OptionalPaths are always set by java_sdk_library but may not be set by
582// java_sdk_library_import as not all instances provide that information.
583type scopePaths struct {
584	// The path (represented as Paths for convenience when returning) to the stubs header jar.
585	//
586	// That is the jar that is created by turbine.
587	stubsHeaderPath android.Paths
588
589	// The path (represented as Paths for convenience when returning) to the stubs implementation jar.
590	//
591	// This is not the implementation jar, it still only contains stubs.
592	stubsImplPath android.Paths
593
594	// The dex jar for the stubs.
595	//
596	// This is not the implementation jar, it still only contains stubs.
597	stubsDexJarPath OptionalDexJarPath
598
599	// The API specification file, e.g. system_current.txt.
600	currentApiFilePath android.OptionalPath
601
602	// The specification of API elements removed since the last release.
603	removedApiFilePath android.OptionalPath
604
605	// The stubs source jar.
606	stubsSrcJar android.OptionalPath
607
608	// Extracted annotations.
609	annotationsZip android.OptionalPath
610
611	// The path to the latest API file.
612	latestApiPath android.OptionalPath
613
614	// The path to the latest removed API file.
615	latestRemovedApiPath android.OptionalPath
616}
617
618func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error {
619	if ctx.OtherModuleHasProvider(dep, JavaInfoProvider) {
620		lib := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
621		paths.stubsHeaderPath = lib.HeaderJars
622		paths.stubsImplPath = lib.ImplementationJars
623
624		libDep := dep.(UsesLibraryDependency)
625		paths.stubsDexJarPath = libDep.DexJarBuildPath()
626		return nil
627	} else {
628		return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library")
629	}
630}
631
632func (paths *scopePaths) treatDepAsApiStubsProvider(dep android.Module, action func(provider ApiStubsProvider)) error {
633	if apiStubsProvider, ok := dep.(ApiStubsProvider); ok {
634		action(apiStubsProvider)
635		return nil
636	} else {
637		return fmt.Errorf("expected module that implements ApiStubsProvider, e.g. droidstubs")
638	}
639}
640
641func (paths *scopePaths) treatDepAsApiStubsSrcProvider(dep android.Module, action func(provider ApiStubsSrcProvider)) error {
642	if apiStubsProvider, ok := dep.(ApiStubsSrcProvider); ok {
643		action(apiStubsProvider)
644		return nil
645	} else {
646		return fmt.Errorf("expected module that implements ApiStubsSrcProvider, e.g. droidstubs")
647	}
648}
649
650func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsProvider) {
651	paths.annotationsZip = android.OptionalPathForPath(provider.AnnotationsZip())
652	paths.currentApiFilePath = android.OptionalPathForPath(provider.ApiFilePath())
653	paths.removedApiFilePath = android.OptionalPathForPath(provider.RemovedApiFilePath())
654}
655
656func (paths *scopePaths) extractApiInfoFromDep(ctx android.ModuleContext, dep android.Module) error {
657	return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) {
658		paths.extractApiInfoFromApiStubsProvider(provider)
659	})
660}
661
662func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider ApiStubsSrcProvider) {
663	paths.stubsSrcJar = android.OptionalPathForPath(provider.StubsSrcJar())
664}
665
666func (paths *scopePaths) extractStubsSourceInfoFromDep(ctx android.ModuleContext, dep android.Module) error {
667	return paths.treatDepAsApiStubsSrcProvider(dep, func(provider ApiStubsSrcProvider) {
668		paths.extractStubsSourceInfoFromApiStubsProviders(provider)
669	})
670}
671
672func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(ctx android.ModuleContext, dep android.Module) error {
673	return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) {
674		paths.extractApiInfoFromApiStubsProvider(provider)
675		paths.extractStubsSourceInfoFromApiStubsProviders(provider)
676	})
677}
678
679func extractSingleOptionalOutputPath(dep android.Module) (android.OptionalPath, error) {
680	var paths android.Paths
681	if sourceFileProducer, ok := dep.(android.SourceFileProducer); ok {
682		paths = sourceFileProducer.Srcs()
683	} else {
684		return android.OptionalPath{}, fmt.Errorf("module %q does not produce source files", dep)
685	}
686	if len(paths) != 1 {
687		return android.OptionalPath{}, fmt.Errorf("expected one path from %q, got %q", dep, paths)
688	}
689	return android.OptionalPathForPath(paths[0]), nil
690}
691
692func (paths *scopePaths) extractLatestApiPath(ctx android.ModuleContext, dep android.Module) error {
693	outputPath, err := extractSingleOptionalOutputPath(dep)
694	paths.latestApiPath = outputPath
695	return err
696}
697
698func (paths *scopePaths) extractLatestRemovedApiPath(ctx android.ModuleContext, dep android.Module) error {
699	outputPath, err := extractSingleOptionalOutputPath(dep)
700	paths.latestRemovedApiPath = outputPath
701	return err
702}
703
704type commonToSdkLibraryAndImportProperties struct {
705	// The naming scheme to use for the components that this module creates.
706	//
707	// If not specified then it defaults to "default".
708	//
709	// This is a temporary mechanism to simplify conversion from separate modules for each
710	// component that follow a different naming pattern to the default one.
711	//
712	// TODO(b/155480189) - Remove once naming inconsistencies have been resolved.
713	Naming_scheme *string
714
715	// Specifies whether this module can be used as an Android shared library; defaults
716	// to true.
717	//
718	// An Android shared library is one that can be referenced in a <uses-library> element
719	// in an AndroidManifest.xml.
720	Shared_library *bool
721
722	// Files containing information about supported java doc tags.
723	Doctag_files []string `android:"path"`
724
725	// Signals that this shared library is part of the bootclasspath starting
726	// on the version indicated in this attribute.
727	//
728	// This will make platforms at this level and above to ignore
729	// <uses-library> tags with this library name because the library is already
730	// available
731	On_bootclasspath_since *string
732
733	// Signals that this shared library was part of the bootclasspath before
734	// (but not including) the version indicated in this attribute.
735	//
736	// The system will automatically add a <uses-library> tag with this library to
737	// apps that target any SDK less than the version indicated in this attribute.
738	On_bootclasspath_before *string
739
740	// Indicates that PackageManager should ignore this shared library if the
741	// platform is below the version indicated in this attribute.
742	//
743	// This means that the device won't recognise this library as installed.
744	Min_device_sdk *string
745
746	// Indicates that PackageManager should ignore this shared library if the
747	// platform is above the version indicated in this attribute.
748	//
749	// This means that the device won't recognise this library as installed.
750	Max_device_sdk *string
751}
752
753// commonSdkLibraryAndImportModule defines the interface that must be provided by a module that
754// embeds the commonToSdkLibraryAndImport struct.
755type commonSdkLibraryAndImportModule interface {
756	android.Module
757
758	BaseModuleName() string
759}
760
761// Common code between sdk library and sdk library import
762type commonToSdkLibraryAndImport struct {
763	module commonSdkLibraryAndImportModule
764
765	scopePaths map[*apiScope]*scopePaths
766
767	namingScheme sdkLibraryComponentNamingScheme
768
769	commonSdkLibraryProperties commonToSdkLibraryAndImportProperties
770
771	// Paths to commonSdkLibraryProperties.Doctag_files
772	doctagPaths android.Paths
773
774	// Functionality related to this being used as a component of a java_sdk_library.
775	EmbeddableSdkLibraryComponent
776}
777
778func (c *commonToSdkLibraryAndImport) initCommon(module commonSdkLibraryAndImportModule) {
779	c.module = module
780
781	module.AddProperties(&c.commonSdkLibraryProperties)
782
783	// Initialize this as an sdk library component.
784	c.initSdkLibraryComponent(module)
785}
786
787func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied(ctx android.DefaultableHookContext) bool {
788	schemeProperty := proptools.StringDefault(c.commonSdkLibraryProperties.Naming_scheme, "default")
789	switch schemeProperty {
790	case "default":
791		c.namingScheme = &defaultNamingScheme{}
792	default:
793		ctx.PropertyErrorf("naming_scheme", "expected 'default' but was %q", schemeProperty)
794		return false
795	}
796
797	namePtr := proptools.StringPtr(c.module.BaseModuleName())
798	c.sdkLibraryComponentProperties.SdkLibraryName = namePtr
799
800	// Only track this sdk library if this can be used as a shared library.
801	if c.sharedLibrary() {
802		// Use the name specified in the module definition as the owner.
803		c.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack = namePtr
804	}
805
806	return true
807}
808
809// uniqueApexVariations provides common implementation of the ApexModule.UniqueApexVariations
810// method.
811func (c *commonToSdkLibraryAndImport) uniqueApexVariations() bool {
812	// A java_sdk_library that is a shared library produces an XML file that makes the shared library
813	// usable from an AndroidManifest.xml's <uses-library> entry. That XML file contains the name of
814	// the APEX and so it needs a unique variation per APEX.
815	return c.sharedLibrary()
816}
817
818func (c *commonToSdkLibraryAndImport) generateCommonBuildActions(ctx android.ModuleContext) {
819	c.doctagPaths = android.PathsForModuleSrc(ctx, c.commonSdkLibraryProperties.Doctag_files)
820}
821
822// Module name of the runtime implementation library
823func (c *commonToSdkLibraryAndImport) implLibraryModuleName() string {
824	return c.module.BaseModuleName() + ".impl"
825}
826
827// Module name of the XML file for the lib
828func (c *commonToSdkLibraryAndImport) xmlPermissionsModuleName() string {
829	return c.module.BaseModuleName() + sdkXmlFileSuffix
830}
831
832// Name of the java_library module that compiles the stubs source.
833func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope) string {
834	baseName := c.module.BaseModuleName()
835	return c.namingScheme.stubsLibraryModuleName(apiScope, baseName)
836}
837
838// Name of the droidstubs module that generates the stubs source and may also
839// generate/check the API.
840func (c *commonToSdkLibraryAndImport) stubsSourceModuleName(apiScope *apiScope) string {
841	baseName := c.module.BaseModuleName()
842	return c.namingScheme.stubsSourceModuleName(apiScope, baseName)
843}
844
845// The component names for different outputs of the java_sdk_library.
846//
847// They are similar to the names used for the child modules it creates
848const (
849	stubsSourceComponentName = "stubs.source"
850
851	apiTxtComponentName = "api.txt"
852
853	removedApiTxtComponentName = "removed-api.txt"
854
855	annotationsComponentName = "annotations.zip"
856)
857
858// A regular expression to match tags that reference a specific stubs component.
859//
860// It will only match if given a valid scope and a valid component. It is verfy strict
861// to ensure it does not accidentally match a similar looking tag that should be processed
862// by the embedded Library.
863var tagSplitter = func() *regexp.Regexp {
864	// Given a list of literal string items returns a regular expression that will
865	// match any one of the items.
866	choice := func(items ...string) string {
867		return `\Q` + strings.Join(items, `\E|\Q`) + `\E`
868	}
869
870	// Regular expression to match one of the scopes.
871	scopesRegexp := choice(allScopeNames...)
872
873	// Regular expression to match one of the components.
874	componentsRegexp := choice(stubsSourceComponentName, apiTxtComponentName, removedApiTxtComponentName, annotationsComponentName)
875
876	// Regular expression to match any combination of one scope and one component.
877	return regexp.MustCompile(fmt.Sprintf(`^\.(%s)\.(%s)$`, scopesRegexp, componentsRegexp))
878}()
879
880// For OutputFileProducer interface
881//
882// .<scope>.<component name>, for all ComponentNames (for example: .public.removed-api.txt)
883func (c *commonToSdkLibraryAndImport) commonOutputFiles(tag string) (android.Paths, error) {
884	if groups := tagSplitter.FindStringSubmatch(tag); groups != nil {
885		scopeName := groups[1]
886		component := groups[2]
887
888		if scope, ok := scopeByName[scopeName]; ok {
889			paths := c.findScopePaths(scope)
890			if paths == nil {
891				return nil, fmt.Errorf("%q does not provide api scope %s", c.module.BaseModuleName(), scopeName)
892			}
893
894			switch component {
895			case stubsSourceComponentName:
896				if paths.stubsSrcJar.Valid() {
897					return android.Paths{paths.stubsSrcJar.Path()}, nil
898				}
899
900			case apiTxtComponentName:
901				if paths.currentApiFilePath.Valid() {
902					return android.Paths{paths.currentApiFilePath.Path()}, nil
903				}
904
905			case removedApiTxtComponentName:
906				if paths.removedApiFilePath.Valid() {
907					return android.Paths{paths.removedApiFilePath.Path()}, nil
908				}
909
910			case annotationsComponentName:
911				if paths.annotationsZip.Valid() {
912					return android.Paths{paths.annotationsZip.Path()}, nil
913				}
914			}
915
916			return nil, fmt.Errorf("%s not available for api scope %s", component, scopeName)
917		} else {
918			return nil, fmt.Errorf("unknown scope %s in %s", scope, tag)
919		}
920
921	} else {
922		switch tag {
923		case ".doctags":
924			if c.doctagPaths != nil {
925				return c.doctagPaths, nil
926			} else {
927				return nil, fmt.Errorf("no doctag_files specified on %s", c.module.BaseModuleName())
928			}
929		}
930		return nil, nil
931	}
932}
933
934func (c *commonToSdkLibraryAndImport) getScopePathsCreateIfNeeded(scope *apiScope) *scopePaths {
935	if c.scopePaths == nil {
936		c.scopePaths = make(map[*apiScope]*scopePaths)
937	}
938	paths := c.scopePaths[scope]
939	if paths == nil {
940		paths = &scopePaths{}
941		c.scopePaths[scope] = paths
942	}
943
944	return paths
945}
946
947func (c *commonToSdkLibraryAndImport) findScopePaths(scope *apiScope) *scopePaths {
948	if c.scopePaths == nil {
949		return nil
950	}
951
952	return c.scopePaths[scope]
953}
954
955// If this does not support the requested api scope then find the closest available
956// scope it does support. Returns nil if no such scope is available.
957func (c *commonToSdkLibraryAndImport) findClosestScopePath(scope *apiScope) *scopePaths {
958	for s := scope; s != nil; s = s.canAccess {
959		if paths := c.findScopePaths(s); paths != nil {
960			return paths
961		}
962	}
963
964	// This should never happen outside tests as public should be the base scope for every
965	// scope and is enabled by default.
966	return nil
967}
968
969func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
970
971	// If a specific numeric version has been requested then use prebuilt versions of the sdk.
972	if !sdkVersion.ApiLevel.IsPreview() {
973		return PrebuiltJars(ctx, c.module.BaseModuleName(), sdkVersion)
974	}
975
976	paths := c.selectScopePaths(ctx, sdkVersion.Kind)
977	if paths == nil {
978		return nil
979	}
980
981	return paths.stubsHeaderPath
982}
983
984// selectScopePaths returns the *scopePaths appropriate for the specific kind.
985//
986// If the module does not support the specific kind then it will return the *scopePaths for the
987// closest kind which is a subset of the requested kind. e.g. if requesting android.SdkModule then
988// it will return *scopePaths for android.SdkSystem if available or android.SdkPublic of not.
989func (c *commonToSdkLibraryAndImport) selectScopePaths(ctx android.BaseModuleContext, kind android.SdkKind) *scopePaths {
990	apiScope := sdkKindToApiScope(kind)
991
992	paths := c.findClosestScopePath(apiScope)
993	if paths == nil {
994		var scopes []string
995		for _, s := range allApiScopes {
996			if c.findScopePaths(s) != nil {
997				scopes = append(scopes, s.name)
998			}
999		}
1000		ctx.ModuleErrorf("requires api scope %s from %s but it only has %q available", apiScope.name, c.module.BaseModuleName(), scopes)
1001		return nil
1002	}
1003
1004	return paths
1005}
1006
1007// sdkKindToApiScope maps from android.SdkKind to apiScope.
1008func sdkKindToApiScope(kind android.SdkKind) *apiScope {
1009	var apiScope *apiScope
1010	switch kind {
1011	case android.SdkSystem:
1012		apiScope = apiScopeSystem
1013	case android.SdkModule:
1014		apiScope = apiScopeModuleLib
1015	case android.SdkTest:
1016		apiScope = apiScopeTest
1017	case android.SdkSystemServer:
1018		apiScope = apiScopeSystemServer
1019	default:
1020		apiScope = apiScopePublic
1021	}
1022	return apiScope
1023}
1024
1025// to satisfy SdkLibraryDependency interface
1026func (c *commonToSdkLibraryAndImport) SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath {
1027	paths := c.selectScopePaths(ctx, kind)
1028	if paths == nil {
1029		return makeUnsetDexJarPath()
1030	}
1031
1032	return paths.stubsDexJarPath
1033}
1034
1035// to satisfy SdkLibraryDependency interface
1036func (c *commonToSdkLibraryAndImport) SdkRemovedTxtFile(ctx android.BaseModuleContext, kind android.SdkKind) android.OptionalPath {
1037	apiScope := sdkKindToApiScope(kind)
1038	paths := c.findScopePaths(apiScope)
1039	if paths == nil {
1040		return android.OptionalPath{}
1041	}
1042
1043	return paths.removedApiFilePath
1044}
1045
1046func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() interface{} {
1047	componentProps := &struct {
1048		SdkLibraryName              *string
1049		SdkLibraryToImplicitlyTrack *string
1050	}{}
1051
1052	namePtr := proptools.StringPtr(c.module.BaseModuleName())
1053	componentProps.SdkLibraryName = namePtr
1054
1055	if c.sharedLibrary() {
1056		// Mark the stubs library as being components of this java_sdk_library so that
1057		// any app that includes code which depends (directly or indirectly) on the stubs
1058		// library will have the appropriate <uses-library> invocation inserted into its
1059		// manifest if necessary.
1060		componentProps.SdkLibraryToImplicitlyTrack = namePtr
1061	}
1062
1063	return componentProps
1064}
1065
1066func (c *commonToSdkLibraryAndImport) sharedLibrary() bool {
1067	return proptools.BoolDefault(c.commonSdkLibraryProperties.Shared_library, true)
1068}
1069
1070// Check if the stub libraries should be compiled for dex
1071func (c *commonToSdkLibraryAndImport) stubLibrariesCompiledForDex() bool {
1072	// Always compile the dex file files for the stub libraries if they will be used on the
1073	// bootclasspath.
1074	return !c.sharedLibrary()
1075}
1076
1077// Properties related to the use of a module as an component of a java_sdk_library.
1078type SdkLibraryComponentProperties struct {
1079	// The name of the java_sdk_library/_import module.
1080	SdkLibraryName *string `blueprint:"mutated"`
1081
1082	// The name of the java_sdk_library/_import to add to a <uses-library> entry
1083	// in the AndroidManifest.xml of any Android app that includes code that references
1084	// this module. If not set then no java_sdk_library/_import is tracked.
1085	SdkLibraryToImplicitlyTrack *string `blueprint:"mutated"`
1086}
1087
1088// Structure to be embedded in a module struct that needs to support the
1089// SdkLibraryComponentDependency interface.
1090type EmbeddableSdkLibraryComponent struct {
1091	sdkLibraryComponentProperties SdkLibraryComponentProperties
1092}
1093
1094func (e *EmbeddableSdkLibraryComponent) initSdkLibraryComponent(module android.Module) {
1095	module.AddProperties(&e.sdkLibraryComponentProperties)
1096}
1097
1098// to satisfy SdkLibraryComponentDependency
1099func (e *EmbeddableSdkLibraryComponent) SdkLibraryName() *string {
1100	return e.sdkLibraryComponentProperties.SdkLibraryName
1101}
1102
1103// to satisfy SdkLibraryComponentDependency
1104func (e *EmbeddableSdkLibraryComponent) OptionalSdkLibraryImplementation() *string {
1105	// For shared libraries, this is the same as the SDK library name. If a Java library or app
1106	// depends on a component library (e.g. a stub library) it still needs to know the name of the
1107	// run-time library and the corresponding module that provides the implementation. This name is
1108	// passed to manifest_fixer (to be added to AndroidManifest.xml) and added to CLC (to be used
1109	// in dexpreopt).
1110	//
1111	// For non-shared SDK (component or not) libraries this returns `nil`, as they are not
1112	// <uses-library> and should not be added to the manifest or to CLC.
1113	return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack
1114}
1115
1116// Implemented by modules that are (or possibly could be) a component of a java_sdk_library
1117// (including the java_sdk_library) itself.
1118type SdkLibraryComponentDependency interface {
1119	UsesLibraryDependency
1120
1121	// SdkLibraryName returns the name of the java_sdk_library/_import module.
1122	SdkLibraryName() *string
1123
1124	// The name of the implementation library for the optional SDK library or nil, if there isn't one.
1125	OptionalSdkLibraryImplementation() *string
1126}
1127
1128// Make sure that all the module types that are components of java_sdk_library/_import
1129// and which can be referenced (directly or indirectly) from an android app implement
1130// the SdkLibraryComponentDependency interface.
1131var _ SdkLibraryComponentDependency = (*Library)(nil)
1132var _ SdkLibraryComponentDependency = (*Import)(nil)
1133var _ SdkLibraryComponentDependency = (*SdkLibrary)(nil)
1134var _ SdkLibraryComponentDependency = (*SdkLibraryImport)(nil)
1135
1136// Provides access to sdk_version related files, e.g. header and implementation jars.
1137type SdkLibraryDependency interface {
1138	SdkLibraryComponentDependency
1139
1140	// Get the header jars appropriate for the supplied sdk_version.
1141	//
1142	// These are turbine generated jars so they only change if the externals of the
1143	// class changes but it does not contain and implementation or JavaDoc.
1144	SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths
1145
1146	// Get the implementation jars appropriate for the supplied sdk version.
1147	//
1148	// These are either the implementation jar for the whole sdk library or the implementation
1149	// jars for the stubs. The latter should only be needed when generating JavaDoc as otherwise
1150	// they are identical to the corresponding header jars.
1151	SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths
1152
1153	// SdkApiStubDexJar returns the dex jar for the stubs. It is needed by the hiddenapi processing
1154	// tool which processes dex files.
1155	SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath
1156
1157	// SdkRemovedTxtFile returns the optional path to the removed.txt file for the specified sdk kind.
1158	SdkRemovedTxtFile(ctx android.BaseModuleContext, kind android.SdkKind) android.OptionalPath
1159
1160	// sharedLibrary returns true if this can be used as a shared library.
1161	sharedLibrary() bool
1162}
1163
1164type SdkLibrary struct {
1165	Library
1166
1167	android.BazelModuleBase
1168
1169	sdkLibraryProperties sdkLibraryProperties
1170
1171	// Map from api scope to the scope specific property structure.
1172	scopeToProperties map[*apiScope]*ApiScopeProperties
1173
1174	commonToSdkLibraryAndImport
1175}
1176
1177var _ SdkLibraryDependency = (*SdkLibrary)(nil)
1178
1179func (module *SdkLibrary) generateTestAndSystemScopesByDefault() bool {
1180	return module.sdkLibraryProperties.Generate_system_and_test_apis
1181}
1182
1183func (module *SdkLibrary) getGeneratedApiScopes(ctx android.EarlyModuleContext) apiScopes {
1184	// Check to see if any scopes have been explicitly enabled. If any have then all
1185	// must be.
1186	anyScopesExplicitlyEnabled := false
1187	for _, scope := range allApiScopes {
1188		scopeProperties := module.scopeToProperties[scope]
1189		if scopeProperties.Enabled != nil {
1190			anyScopesExplicitlyEnabled = true
1191			break
1192		}
1193	}
1194
1195	var generatedScopes apiScopes
1196	enabledScopes := make(map[*apiScope]struct{})
1197	for _, scope := range allApiScopes {
1198		scopeProperties := module.scopeToProperties[scope]
1199		// If any scopes are explicitly enabled then ignore the legacy enabled status.
1200		// This is to ensure that any new usages of this module type do not rely on legacy
1201		// behaviour.
1202		defaultEnabledStatus := false
1203		if anyScopesExplicitlyEnabled {
1204			defaultEnabledStatus = scope.defaultEnabledStatus
1205		} else {
1206			defaultEnabledStatus = scope.legacyEnabledStatus(module)
1207		}
1208		enabled := proptools.BoolDefault(scopeProperties.Enabled, defaultEnabledStatus)
1209		if enabled {
1210			enabledScopes[scope] = struct{}{}
1211			generatedScopes = append(generatedScopes, scope)
1212		}
1213	}
1214
1215	// Now check to make sure that any scope that is extended by an enabled scope is also
1216	// enabled.
1217	for _, scope := range allApiScopes {
1218		if _, ok := enabledScopes[scope]; ok {
1219			extends := scope.extends
1220			if extends != nil {
1221				if _, ok := enabledScopes[extends]; !ok {
1222					ctx.ModuleErrorf("enabled api scope %q depends on disabled scope %q", scope, extends)
1223				}
1224			}
1225		}
1226	}
1227
1228	return generatedScopes
1229}
1230
1231var _ android.ModuleWithMinSdkVersionCheck = (*SdkLibrary)(nil)
1232
1233func (module *SdkLibrary) CheckMinSdkVersion(ctx android.ModuleContext) {
1234	android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx), func(c android.ModuleContext, do android.PayloadDepsCallback) {
1235		ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
1236			isExternal := !module.depIsInSameApex(ctx, child)
1237			if am, ok := child.(android.ApexModule); ok {
1238				if !do(ctx, parent, am, isExternal) {
1239					return false
1240				}
1241			}
1242			return !isExternal
1243		})
1244	})
1245}
1246
1247type sdkLibraryComponentTag struct {
1248	blueprint.BaseDependencyTag
1249	name string
1250}
1251
1252// Mark this tag so dependencies that use it are excluded from visibility enforcement.
1253func (t sdkLibraryComponentTag) ExcludeFromVisibilityEnforcement() {}
1254
1255var xmlPermissionsFileTag = sdkLibraryComponentTag{name: "xml-permissions-file"}
1256
1257func IsXmlPermissionsFileDepTag(depTag blueprint.DependencyTag) bool {
1258	if dt, ok := depTag.(sdkLibraryComponentTag); ok {
1259		return dt == xmlPermissionsFileTag
1260	}
1261	return false
1262}
1263
1264var implLibraryTag = sdkLibraryComponentTag{name: "impl-library"}
1265
1266// Add the dependencies on the child modules in the component deps mutator.
1267func (module *SdkLibrary) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
1268	for _, apiScope := range module.getGeneratedApiScopes(ctx) {
1269		// Add dependencies to the stubs library
1270		stubModuleName := module.stubsLibraryModuleName(apiScope)
1271		// Use JavaApiLibraryName function to be redirected to stubs generated from .txt if applicable
1272		stubModuleName = android.JavaApiLibraryName(ctx.Config(), stubModuleName)
1273		ctx.AddVariationDependencies(nil, apiScope.stubsTag, stubModuleName)
1274
1275		// Add a dependency on the stubs source in order to access both stubs source and api information.
1276		ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceModuleName(apiScope))
1277
1278		if module.compareAgainstLatestApi(apiScope) {
1279			// Add dependencies on the latest finalized version of the API .txt file.
1280			latestApiModuleName := module.latestApiModuleName(apiScope)
1281			ctx.AddDependency(module, apiScope.latestApiModuleTag, latestApiModuleName)
1282
1283			// Add dependencies on the latest finalized version of the remove API .txt file.
1284			latestRemovedApiModuleName := module.latestRemovedApiModuleName(apiScope)
1285			ctx.AddDependency(module, apiScope.latestRemovedApiModuleTag, latestRemovedApiModuleName)
1286		}
1287	}
1288
1289	if module.requiresRuntimeImplementationLibrary() {
1290		// Add dependency to the rule for generating the implementation library.
1291		ctx.AddDependency(module, implLibraryTag, module.implLibraryModuleName())
1292
1293		if module.sharedLibrary() {
1294			// Add dependency to the rule for generating the xml permissions file
1295			ctx.AddDependency(module, xmlPermissionsFileTag, module.xmlPermissionsModuleName())
1296		}
1297	}
1298}
1299
1300// Add other dependencies as normal.
1301func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
1302	var missingApiModules []string
1303	for _, apiScope := range module.getGeneratedApiScopes(ctx) {
1304		if apiScope.unstable {
1305			continue
1306		}
1307		if m := module.latestApiModuleName(apiScope); !ctx.OtherModuleExists(m) {
1308			missingApiModules = append(missingApiModules, m)
1309		}
1310		if m := module.latestRemovedApiModuleName(apiScope); !ctx.OtherModuleExists(m) {
1311			missingApiModules = append(missingApiModules, m)
1312		}
1313		if m := module.latestIncompatibilitiesModuleName(apiScope); !ctx.OtherModuleExists(m) {
1314			missingApiModules = append(missingApiModules, m)
1315		}
1316	}
1317	if len(missingApiModules) != 0 && !module.sdkLibraryProperties.Unsafe_ignore_missing_latest_api {
1318		m := module.Name() + " is missing tracking files for previously released library versions.\n"
1319		m += "You need to do one of the following:\n"
1320		m += "- Add `unsafe_ignore_missing_latest_api: true` to your blueprint (to disable compat tracking)\n"
1321		m += "- Add a set of prebuilt txt files representing the last released version of this library for compat checking.\n"
1322		m += "  (the current set of API files can be used as a seed for this compatibility tracking\n"
1323		m += "\n"
1324		m += "The following filegroup modules are missing:\n  "
1325		m += strings.Join(missingApiModules, "\n  ") + "\n"
1326		m += "Please see the documentation of the prebuilt_apis module type (and a usage example in prebuilts/sdk) for a convenient way to generate these."
1327		ctx.ModuleErrorf(m)
1328	}
1329	if module.requiresRuntimeImplementationLibrary() {
1330		// Only add the deps for the library if it is actually going to be built.
1331		module.Library.deps(ctx)
1332	}
1333}
1334
1335func (module *SdkLibrary) OutputFiles(tag string) (android.Paths, error) {
1336	paths, err := module.commonOutputFiles(tag)
1337	if paths != nil || err != nil {
1338		return paths, err
1339	}
1340	if module.requiresRuntimeImplementationLibrary() {
1341		return module.Library.OutputFiles(tag)
1342	}
1343	if tag == "" {
1344		return nil, nil
1345	}
1346	return nil, fmt.Errorf("unsupported module reference tag %q", tag)
1347}
1348
1349func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
1350	if proptools.String(module.deviceProperties.Min_sdk_version) != "" {
1351		module.CheckMinSdkVersion(ctx)
1352	}
1353
1354	module.generateCommonBuildActions(ctx)
1355
1356	// Only build an implementation library if required.
1357	if module.requiresRuntimeImplementationLibrary() {
1358		module.Library.GenerateAndroidBuildActions(ctx)
1359	}
1360
1361	// Collate the components exported by this module. All scope specific modules are exported but
1362	// the impl and xml component modules are not.
1363	exportedComponents := map[string]struct{}{}
1364
1365	// Record the paths to the header jars of the library (stubs and impl).
1366	// When this java_sdk_library is depended upon from others via "libs" property,
1367	// the recorded paths will be returned depending on the link type of the caller.
1368	ctx.VisitDirectDeps(func(to android.Module) {
1369		tag := ctx.OtherModuleDependencyTag(to)
1370
1371		// Extract information from any of the scope specific dependencies.
1372		if scopeTag, ok := tag.(scopeDependencyTag); ok {
1373			apiScope := scopeTag.apiScope
1374			scopePaths := module.getScopePathsCreateIfNeeded(apiScope)
1375
1376			// Extract information from the dependency. The exact information extracted
1377			// is determined by the nature of the dependency which is determined by the tag.
1378			scopeTag.extractDepInfo(ctx, to, scopePaths)
1379
1380			exportedComponents[ctx.OtherModuleName(to)] = struct{}{}
1381		}
1382	})
1383
1384	// Make the set of components exported by this module available for use elsewhere.
1385	exportedComponentInfo := android.ExportedComponentsInfo{Components: android.SortedKeys(exportedComponents)}
1386	ctx.SetProvider(android.ExportedComponentsInfoProvider, exportedComponentInfo)
1387
1388	// Provide additional information for inclusion in an sdk's generated .info file.
1389	additionalSdkInfo := map[string]interface{}{}
1390	additionalSdkInfo["dist_stem"] = module.distStem()
1391	baseModuleName := module.distStem()
1392	scopes := map[string]interface{}{}
1393	additionalSdkInfo["scopes"] = scopes
1394	for scope, scopePaths := range module.scopePaths {
1395		scopeInfo := map[string]interface{}{}
1396		scopes[scope.name] = scopeInfo
1397		scopeInfo["current_api"] = scope.snapshotRelativeCurrentApiTxtPath(baseModuleName)
1398		scopeInfo["removed_api"] = scope.snapshotRelativeRemovedApiTxtPath(baseModuleName)
1399		if p := scopePaths.latestApiPath; p.Valid() {
1400			scopeInfo["latest_api"] = p.Path().String()
1401		}
1402		if p := scopePaths.latestRemovedApiPath; p.Valid() {
1403			scopeInfo["latest_removed_api"] = p.Path().String()
1404		}
1405	}
1406	ctx.SetProvider(android.AdditionalSdkInfoProvider, android.AdditionalSdkInfo{additionalSdkInfo})
1407}
1408
1409func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries {
1410	if !module.requiresRuntimeImplementationLibrary() {
1411		return nil
1412	}
1413	entriesList := module.Library.AndroidMkEntries()
1414	if module.sharedLibrary() {
1415		entries := &entriesList[0]
1416		entries.Required = append(entries.Required, module.xmlPermissionsModuleName())
1417	}
1418	return entriesList
1419}
1420
1421// The dist path of the stub artifacts
1422func (module *SdkLibrary) apiDistPath(apiScope *apiScope) string {
1423	return path.Join("apistubs", module.distGroup(), apiScope.name)
1424}
1425
1426// Get the sdk version for use when compiling the stubs library.
1427func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.EarlyModuleContext, apiScope *apiScope) string {
1428	scopeProperties := module.scopeToProperties[apiScope]
1429	if scopeProperties.Sdk_version != nil {
1430		return proptools.String(scopeProperties.Sdk_version)
1431	}
1432
1433	sdkDep := decodeSdkDep(mctx, android.SdkContext(&module.Library))
1434	if sdkDep.hasStandardLibs() {
1435		// If building against a standard sdk then use the sdk version appropriate for the scope.
1436		return apiScope.sdkVersion
1437	} else {
1438		// Otherwise, use no system module.
1439		return "none"
1440	}
1441}
1442
1443func (module *SdkLibrary) distStem() string {
1444	return proptools.StringDefault(module.sdkLibraryProperties.Dist_stem, module.BaseModuleName())
1445}
1446
1447// distGroup returns the subdirectory of the dist path of the stub artifacts.
1448func (module *SdkLibrary) distGroup() string {
1449	return proptools.StringDefault(module.sdkLibraryProperties.Dist_group, "unknown")
1450}
1451
1452func latestPrebuiltApiModuleName(name string, apiScope *apiScope) string {
1453	return PrebuiltApiModuleName(name, apiScope.name, "latest")
1454}
1455
1456func (module *SdkLibrary) latestApiFilegroupName(apiScope *apiScope) string {
1457	return ":" + module.latestApiModuleName(apiScope)
1458}
1459
1460func (module *SdkLibrary) latestApiModuleName(apiScope *apiScope) string {
1461	return latestPrebuiltApiModuleName(module.distStem(), apiScope)
1462}
1463
1464func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope *apiScope) string {
1465	return ":" + module.latestRemovedApiModuleName(apiScope)
1466}
1467
1468func (module *SdkLibrary) latestRemovedApiModuleName(apiScope *apiScope) string {
1469	return latestPrebuiltApiModuleName(module.distStem()+"-removed", apiScope)
1470}
1471
1472func (module *SdkLibrary) latestIncompatibilitiesFilegroupName(apiScope *apiScope) string {
1473	return ":" + module.latestIncompatibilitiesModuleName(apiScope)
1474}
1475
1476func (module *SdkLibrary) latestIncompatibilitiesModuleName(apiScope *apiScope) string {
1477	return latestPrebuiltApiModuleName(module.distStem()+"-incompatibilities", apiScope)
1478}
1479
1480func childModuleVisibility(childVisibility []string) []string {
1481	if childVisibility == nil {
1482		// No child visibility set. The child will use the visibility of the sdk_library.
1483		return nil
1484	}
1485
1486	// Prepend an override to ignore the sdk_library's visibility, and rely on the child visibility.
1487	var visibility []string
1488	visibility = append(visibility, "//visibility:override")
1489	visibility = append(visibility, childVisibility...)
1490	return visibility
1491}
1492
1493// Creates the implementation java library
1494func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) {
1495	visibility := childModuleVisibility(module.sdkLibraryProperties.Impl_library_visibility)
1496
1497	props := struct {
1498		Name           *string
1499		Visibility     []string
1500		Instrument     bool
1501		Libs           []string
1502		Static_libs    []string
1503		Apex_available []string
1504	}{
1505		Name:       proptools.StringPtr(module.implLibraryModuleName()),
1506		Visibility: visibility,
1507		// Set the instrument property to ensure it is instrumented when instrumentation is required.
1508		Instrument: true,
1509		// Set the impl_only libs. Note that the module's "Libs" get appended as well, via the
1510		// addition of &module.properties below.
1511		Libs: module.sdkLibraryProperties.Impl_only_libs,
1512		// Set the impl_only static libs. Note that the module's "static_libs" get appended as well, via the
1513		// addition of &module.properties below.
1514		Static_libs: module.sdkLibraryProperties.Impl_only_static_libs,
1515		// Pass the apex_available settings down so that the impl library can be statically
1516		// embedded within a library that is added to an APEX. Needed for updatable-media.
1517		Apex_available: module.ApexAvailable(),
1518	}
1519
1520	properties := []interface{}{
1521		&module.properties,
1522		&module.protoProperties,
1523		&module.deviceProperties,
1524		&module.dexProperties,
1525		&module.dexpreoptProperties,
1526		&module.linter.properties,
1527		&props,
1528		module.sdkComponentPropertiesForChildLibrary(),
1529	}
1530	mctx.CreateModule(LibraryFactory, properties...)
1531}
1532
1533// Creates a static java library that has API stubs
1534func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
1535	props := struct {
1536		Name           *string
1537		Visibility     []string
1538		Srcs           []string
1539		Installable    *bool
1540		Sdk_version    *string
1541		System_modules *string
1542		Patch_module   *string
1543		Libs           []string
1544		Static_libs    []string
1545		Compile_dex    *bool
1546		Java_version   *string
1547		Openjdk9       struct {
1548			Srcs       []string
1549			Javacflags []string
1550		}
1551		Dist struct {
1552			Targets []string
1553			Dest    *string
1554			Dir     *string
1555			Tag     *string
1556		}
1557	}{}
1558
1559	props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
1560	props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
1561	// sources are generated from the droiddoc
1562	props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)}
1563	sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
1564	props.Sdk_version = proptools.StringPtr(sdkVersion)
1565	props.System_modules = module.deviceProperties.System_modules
1566	props.Patch_module = module.properties.Patch_module
1567	props.Installable = proptools.BoolPtr(false)
1568	props.Libs = module.sdkLibraryProperties.Stub_only_libs
1569	props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs
1570	// The stub-annotations library contains special versions of the annotations
1571	// with CLASS retention policy, so that they're kept.
1572	if proptools.Bool(module.sdkLibraryProperties.Annotations_enabled) {
1573		props.Libs = append(props.Libs, "stub-annotations")
1574	}
1575	props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs
1576	props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags
1577	// We compile the stubs for 1.8 in line with the main android.jar stubs, and potential
1578	// interop with older developer tools that don't support 1.9.
1579	props.Java_version = proptools.StringPtr("1.8")
1580
1581	// The imports need to be compiled to dex if the java_sdk_library requests it.
1582	compileDex := module.dexProperties.Compile_dex
1583	if module.stubLibrariesCompiledForDex() {
1584		compileDex = proptools.BoolPtr(true)
1585	}
1586	props.Compile_dex = compileDex
1587
1588	// Dist the class jar artifact for sdk builds.
1589	if !Bool(module.sdkLibraryProperties.No_dist) {
1590		props.Dist.Targets = []string{"sdk", "win_sdk"}
1591		props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.distStem()))
1592		props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
1593		props.Dist.Tag = proptools.StringPtr(".jar")
1594	}
1595
1596	mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
1597}
1598
1599// Creates a droidstubs module that creates stubs source files from the given full source
1600// files and also updates and checks the API specification files.
1601func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope, name string, scopeSpecificDroidstubsArgs []string) {
1602	props := struct {
1603		Name                             *string
1604		Visibility                       []string
1605		Srcs                             []string
1606		Installable                      *bool
1607		Sdk_version                      *string
1608		Api_surface                      *string
1609		System_modules                   *string
1610		Libs                             []string
1611		Output_javadoc_comments          *bool
1612		Arg_files                        []string
1613		Args                             *string
1614		Java_version                     *string
1615		Annotations_enabled              *bool
1616		Merge_annotations_dirs           []string
1617		Merge_inclusion_annotations_dirs []string
1618		Generate_stubs                   *bool
1619		Previous_api                     *string
1620		Check_api                        struct {
1621			Current       ApiToCheck
1622			Last_released ApiToCheck
1623
1624			Api_lint struct {
1625				Enabled       *bool
1626				New_since     *string
1627				Baseline_file *string
1628			}
1629		}
1630		Aidl struct {
1631			Include_dirs       []string
1632			Local_include_dirs []string
1633		}
1634		Dists []android.Dist
1635	}{}
1636
1637	// The stubs source processing uses the same compile time classpath when extracting the
1638	// API from the implementation library as it does when compiling it. i.e. the same
1639	// * sdk version
1640	// * system_modules
1641	// * libs (static_libs/libs)
1642
1643	props.Name = proptools.StringPtr(name)
1644	props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_source_visibility)
1645	props.Srcs = append(props.Srcs, module.properties.Srcs...)
1646	props.Srcs = append(props.Srcs, module.sdkLibraryProperties.Api_srcs...)
1647	props.Sdk_version = module.deviceProperties.Sdk_version
1648	props.Api_surface = &apiScope.name
1649	props.System_modules = module.deviceProperties.System_modules
1650	props.Installable = proptools.BoolPtr(false)
1651	// A droiddoc module has only one Libs property and doesn't distinguish between
1652	// shared libs and static libs. So we need to add both of these libs to Libs property.
1653	props.Libs = module.properties.Libs
1654	props.Libs = append(props.Libs, module.properties.Static_libs...)
1655	props.Libs = append(props.Libs, module.sdkLibraryProperties.Stub_only_libs...)
1656	props.Aidl.Include_dirs = module.deviceProperties.Aidl.Include_dirs
1657	props.Aidl.Local_include_dirs = module.deviceProperties.Aidl.Local_include_dirs
1658	props.Java_version = module.properties.Java_version
1659
1660	props.Annotations_enabled = module.sdkLibraryProperties.Annotations_enabled
1661	props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs
1662	props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs
1663
1664	droidstubsArgs := []string{}
1665	if len(module.sdkLibraryProperties.Api_packages) != 0 {
1666		droidstubsArgs = append(droidstubsArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":"))
1667	}
1668	if len(module.sdkLibraryProperties.Hidden_api_packages) != 0 {
1669		droidstubsArgs = append(droidstubsArgs,
1670			android.JoinWithPrefix(module.sdkLibraryProperties.Hidden_api_packages, " --hide-package "))
1671	}
1672	droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...)
1673	disabledWarnings := []string{
1674		"BroadcastBehavior",
1675		"DeprecationMismatch",
1676		"HiddenSuperclass",
1677		"HiddenTypeParameter",
1678		"MissingPermission",
1679		"SdkConstant",
1680		"Todo",
1681		"Typo",
1682		"UnavailableSymbol",
1683	}
1684	droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
1685
1686	// Output Javadoc comments for public scope.
1687	if apiScope == apiScopePublic {
1688		props.Output_javadoc_comments = proptools.BoolPtr(true)
1689	}
1690
1691	// Add in scope specific arguments.
1692	droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...)
1693	props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
1694	props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " "))
1695
1696	// List of APIs identified from the provided source files are created. They are later
1697	// compared against to the not-yet-released (a.k.a current) list of APIs and to the
1698	// last-released (a.k.a numbered) list of API.
1699	currentApiFileName := apiScope.apiFilePrefix + "current.txt"
1700	removedApiFileName := apiScope.apiFilePrefix + "removed.txt"
1701	apiDir := module.getApiDir()
1702	currentApiFileName = path.Join(apiDir, currentApiFileName)
1703	removedApiFileName = path.Join(apiDir, removedApiFileName)
1704
1705	// check against the not-yet-release API
1706	props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
1707	props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
1708
1709	if module.compareAgainstLatestApi(apiScope) {
1710		// check against the latest released API
1711		latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope))
1712		props.Previous_api = latestApiFilegroupName
1713		props.Check_api.Last_released.Api_file = latestApiFilegroupName
1714		props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
1715			module.latestRemovedApiFilegroupName(apiScope))
1716		props.Check_api.Last_released.Baseline_file = proptools.StringPtr(
1717			module.latestIncompatibilitiesFilegroupName(apiScope))
1718
1719		if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) {
1720			// Enable api lint.
1721			props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true)
1722			props.Check_api.Api_lint.New_since = latestApiFilegroupName
1723
1724			// If it exists then pass a lint-baseline.txt through to droidstubs.
1725			baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt")
1726			baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath)
1727			paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil)
1728			if err != nil {
1729				mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err)
1730			}
1731			if len(paths) == 1 {
1732				props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath)
1733			} else if len(paths) != 0 {
1734				mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths)
1735			}
1736		}
1737	}
1738
1739	if !Bool(module.sdkLibraryProperties.No_dist) {
1740		// Dist the api txt and removed api txt artifacts for sdk builds.
1741		distDir := proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
1742		for _, p := range []struct {
1743			tag     string
1744			pattern string
1745		}{
1746			{tag: ".api.txt", pattern: "%s.txt"},
1747			{tag: ".removed-api.txt", pattern: "%s-removed.txt"},
1748		} {
1749			props.Dists = append(props.Dists, android.Dist{
1750				Targets: []string{"sdk", "win_sdk"},
1751				Dir:     distDir,
1752				Dest:    proptools.StringPtr(fmt.Sprintf(p.pattern, module.distStem())),
1753				Tag:     proptools.StringPtr(p.tag),
1754			})
1755		}
1756	}
1757
1758	mctx.CreateModule(DroidstubsFactory, &props).(*Droidstubs).CallHookIfAvailable(mctx)
1759}
1760
1761func (module *SdkLibrary) compareAgainstLatestApi(apiScope *apiScope) bool {
1762	return !(apiScope.unstable || module.sdkLibraryProperties.Unsafe_ignore_missing_latest_api)
1763}
1764
1765// Implements android.ApexModule
1766func (module *SdkLibrary) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool {
1767	depTag := mctx.OtherModuleDependencyTag(dep)
1768	if depTag == xmlPermissionsFileTag {
1769		return true
1770	}
1771	return module.Library.DepIsInSameApex(mctx, dep)
1772}
1773
1774// Implements android.ApexModule
1775func (module *SdkLibrary) UniqueApexVariations() bool {
1776	return module.uniqueApexVariations()
1777}
1778
1779// Creates the xml file that publicizes the runtime library
1780func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) {
1781	moduleMinApiLevel := module.Library.MinSdkVersion(mctx)
1782	var moduleMinApiLevelStr = moduleMinApiLevel.String()
1783	if moduleMinApiLevel == android.NoneApiLevel {
1784		moduleMinApiLevelStr = "current"
1785	}
1786	props := struct {
1787		Name                      *string
1788		Lib_name                  *string
1789		Apex_available            []string
1790		On_bootclasspath_since    *string
1791		On_bootclasspath_before   *string
1792		Min_device_sdk            *string
1793		Max_device_sdk            *string
1794		Sdk_library_min_api_level *string
1795	}{
1796		Name:                      proptools.StringPtr(module.xmlPermissionsModuleName()),
1797		Lib_name:                  proptools.StringPtr(module.BaseModuleName()),
1798		Apex_available:            module.ApexProperties.Apex_available,
1799		On_bootclasspath_since:    module.commonSdkLibraryProperties.On_bootclasspath_since,
1800		On_bootclasspath_before:   module.commonSdkLibraryProperties.On_bootclasspath_before,
1801		Min_device_sdk:            module.commonSdkLibraryProperties.Min_device_sdk,
1802		Max_device_sdk:            module.commonSdkLibraryProperties.Max_device_sdk,
1803		Sdk_library_min_api_level: &moduleMinApiLevelStr,
1804	}
1805
1806	mctx.CreateModule(sdkLibraryXmlFactory, &props)
1807}
1808
1809func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s android.SdkSpec) android.Paths {
1810	var ver android.ApiLevel
1811	var kind android.SdkKind
1812	if s.UsePrebuilt(ctx) {
1813		ver = s.ApiLevel
1814		kind = s.Kind
1815	} else {
1816		// We don't have prebuilt SDK for the specific sdkVersion.
1817		// Instead of breaking the build, fallback to use "system_current"
1818		ver = android.FutureApiLevel
1819		kind = android.SdkSystem
1820	}
1821
1822	dir := filepath.Join("prebuilts", "sdk", ver.String(), kind.String())
1823	jar := filepath.Join(dir, baseName+".jar")
1824	jarPath := android.ExistentPathForSource(ctx, jar)
1825	if !jarPath.Valid() {
1826		if ctx.Config().AllowMissingDependencies() {
1827			return android.Paths{android.PathForSource(ctx, jar)}
1828		} else {
1829			ctx.PropertyErrorf("sdk_library", "invalid sdk version %q, %q does not exist", s.Raw, jar)
1830		}
1831		return nil
1832	}
1833	return android.Paths{jarPath.Path()}
1834}
1835
1836// Check to see if the other module is within the same set of named APEXes as this module.
1837//
1838// If either this or the other module are on the platform then this will return
1839// false.
1840func withinSameApexesAs(ctx android.BaseModuleContext, other android.Module) bool {
1841	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
1842	otherApexInfo := ctx.OtherModuleProvider(other, android.ApexInfoProvider).(android.ApexInfo)
1843	return len(otherApexInfo.InApexVariants) > 0 && reflect.DeepEqual(apexInfo.InApexVariants, otherApexInfo.InApexVariants)
1844}
1845
1846func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec, headerJars bool) android.Paths {
1847	// If the client doesn't set sdk_version, but if this library prefers stubs over
1848	// the impl library, let's provide the widest API surface possible. To do so,
1849	// force override sdk_version to module_current so that the closest possible API
1850	// surface could be found in selectHeaderJarsForSdkVersion
1851	if module.defaultsToStubs() && !sdkVersion.Specified() {
1852		sdkVersion = android.SdkSpecFrom(ctx, "module_current")
1853	}
1854
1855	// Only provide access to the implementation library if it is actually built.
1856	if module.requiresRuntimeImplementationLibrary() {
1857		// Check any special cases for java_sdk_library.
1858		//
1859		// Only allow access to the implementation library in the following condition:
1860		// * No sdk_version specified on the referencing module.
1861		// * The referencing module is in the same apex as this.
1862		if sdkVersion.Kind == android.SdkPrivate || withinSameApexesAs(ctx, module) {
1863			if headerJars {
1864				return module.HeaderJars()
1865			} else {
1866				return module.ImplementationJars()
1867			}
1868		}
1869	}
1870
1871	return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion)
1872}
1873
1874// to satisfy SdkLibraryDependency interface
1875func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
1876	return module.sdkJars(ctx, sdkVersion, true /*headerJars*/)
1877}
1878
1879// to satisfy SdkLibraryDependency interface
1880func (module *SdkLibrary) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
1881	return module.sdkJars(ctx, sdkVersion, false /*headerJars*/)
1882}
1883
1884var javaSdkLibrariesKey = android.NewOnceKey("javaSdkLibraries")
1885
1886func javaSdkLibraries(config android.Config) *[]string {
1887	return config.Once(javaSdkLibrariesKey, func() interface{} {
1888		return &[]string{}
1889	}).(*[]string)
1890}
1891
1892func (module *SdkLibrary) getApiDir() string {
1893	return proptools.StringDefault(module.sdkLibraryProperties.Api_dir, "api")
1894}
1895
1896// For a java_sdk_library module, create internal modules for stubs, docs,
1897// runtime libs and xml file. If requested, the stubs and docs are created twice
1898// once for public API level and once for system API level
1899func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookContext) {
1900	// If the module has been disabled then don't create any child modules.
1901	if !module.Enabled() {
1902		return
1903	}
1904
1905	if len(module.properties.Srcs) == 0 {
1906		mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs")
1907		return
1908	}
1909
1910	// If this builds against standard libraries (i.e. is not part of the core libraries)
1911	// then assume it provides both system and test apis.
1912	sdkDep := decodeSdkDep(mctx, android.SdkContext(&module.Library))
1913	hasSystemAndTestApis := sdkDep.hasStandardLibs()
1914	module.sdkLibraryProperties.Generate_system_and_test_apis = hasSystemAndTestApis
1915
1916	missingCurrentApi := false
1917
1918	generatedScopes := module.getGeneratedApiScopes(mctx)
1919
1920	apiDir := module.getApiDir()
1921	for _, scope := range generatedScopes {
1922		for _, api := range []string{"current.txt", "removed.txt"} {
1923			path := path.Join(mctx.ModuleDir(), apiDir, scope.apiFilePrefix+api)
1924			p := android.ExistentPathForSource(mctx, path)
1925			if !p.Valid() {
1926				if mctx.Config().AllowMissingDependencies() {
1927					mctx.AddMissingDependencies([]string{path})
1928				} else {
1929					mctx.ModuleErrorf("Current api file %#v doesn't exist", path)
1930					missingCurrentApi = true
1931				}
1932			}
1933		}
1934	}
1935
1936	if missingCurrentApi {
1937		script := "build/soong/scripts/gen-java-current-api-files.sh"
1938		p := android.ExistentPathForSource(mctx, script)
1939
1940		if !p.Valid() {
1941			panic(fmt.Sprintf("script file %s doesn't exist", script))
1942		}
1943
1944		mctx.ModuleErrorf("One or more current api files are missing. "+
1945			"You can update them by:\n"+
1946			"%s %q %s && m update-api",
1947			script, filepath.Join(mctx.ModuleDir(), apiDir),
1948			strings.Join(generatedScopes.Strings(func(s *apiScope) string { return s.apiFilePrefix }), " "))
1949		return
1950	}
1951
1952	for _, scope := range generatedScopes {
1953		// Use the stubs source name for legacy reasons.
1954		module.createStubsSourcesAndApi(mctx, scope, module.stubsSourceModuleName(scope), scope.droidstubsArgs)
1955
1956		module.createStubsLibrary(mctx, scope)
1957	}
1958
1959	if module.requiresRuntimeImplementationLibrary() {
1960		// Create child module to create an implementation library.
1961		//
1962		// This temporarily creates a second implementation library that can be explicitly
1963		// referenced.
1964		//
1965		// TODO(b/156618935) - update comment once only one implementation library is created.
1966		module.createImplLibrary(mctx)
1967
1968		// Only create an XML permissions file that declares the library as being usable
1969		// as a shared library if required.
1970		if module.sharedLibrary() {
1971			module.createXmlFile(mctx)
1972		}
1973
1974		// record java_sdk_library modules so that they are exported to make
1975		javaSdkLibraries := javaSdkLibraries(mctx.Config())
1976		javaSdkLibrariesLock.Lock()
1977		defer javaSdkLibrariesLock.Unlock()
1978		*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
1979	}
1980
1981	// Add the impl_only_libs and impl_only_static_libs *after* we're done using them in submodules.
1982	module.properties.Libs = append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...)
1983	module.properties.Static_libs = append(module.properties.Static_libs, module.sdkLibraryProperties.Impl_only_static_libs...)
1984}
1985
1986func (module *SdkLibrary) InitSdkLibraryProperties() {
1987	module.addHostAndDeviceProperties()
1988	module.AddProperties(&module.sdkLibraryProperties)
1989
1990	module.initSdkLibraryComponent(module)
1991
1992	module.properties.Installable = proptools.BoolPtr(true)
1993	module.deviceProperties.IsSDKLibrary = true
1994}
1995
1996func (module *SdkLibrary) requiresRuntimeImplementationLibrary() bool {
1997	return !proptools.Bool(module.sdkLibraryProperties.Api_only)
1998}
1999
2000func (module *SdkLibrary) defaultsToStubs() bool {
2001	return proptools.Bool(module.sdkLibraryProperties.Default_to_stubs)
2002}
2003
2004// Defines how to name the individual component modules the sdk library creates.
2005type sdkLibraryComponentNamingScheme interface {
2006	stubsLibraryModuleName(scope *apiScope, baseName string) string
2007
2008	stubsSourceModuleName(scope *apiScope, baseName string) string
2009}
2010
2011type defaultNamingScheme struct {
2012}
2013
2014func (s *defaultNamingScheme) stubsLibraryModuleName(scope *apiScope, baseName string) string {
2015	return scope.stubsLibraryModuleName(baseName)
2016}
2017
2018func (s *defaultNamingScheme) stubsSourceModuleName(scope *apiScope, baseName string) string {
2019	return scope.stubsSourceModuleName(baseName)
2020}
2021
2022var _ sdkLibraryComponentNamingScheme = (*defaultNamingScheme)(nil)
2023
2024func moduleStubLinkType(name string) (stub bool, ret sdkLinkType) {
2025	// This suffix-based approach is fragile and could potentially mis-trigger.
2026	// TODO(b/155164730): Clean this up when modules no longer reference sdk_lib stubs directly.
2027	if strings.HasSuffix(name, apiScopePublic.stubsLibraryModuleNameSuffix()) {
2028		if name == "hwbinder.stubs" || name == "libcore_private.stubs" {
2029			// Due to a previous bug, these modules were not considered stubs, so we retain that.
2030			return false, javaPlatform
2031		}
2032		return true, javaSdk
2033	}
2034	if strings.HasSuffix(name, apiScopeSystem.stubsLibraryModuleNameSuffix()) {
2035		return true, javaSystem
2036	}
2037	if strings.HasSuffix(name, apiScopeModuleLib.stubsLibraryModuleNameSuffix()) {
2038		return true, javaModule
2039	}
2040	if strings.HasSuffix(name, apiScopeTest.stubsLibraryModuleNameSuffix()) {
2041		return true, javaSystem
2042	}
2043	return false, javaPlatform
2044}
2045
2046// java_sdk_library is a special Java library that provides optional platform APIs to apps.
2047// In practice, it can be viewed as a combination of several modules: 1) stubs library that clients
2048// are linked against to, 2) droiddoc module that internally generates API stubs source files,
2049// 3) the real runtime shared library that implements the APIs, and 4) XML file for adding
2050// the runtime lib to the classpath at runtime if requested via <uses-library>.
2051func SdkLibraryFactory() android.Module {
2052	module := &SdkLibrary{}
2053
2054	// Initialize information common between source and prebuilt.
2055	module.initCommon(module)
2056
2057	module.InitSdkLibraryProperties()
2058	android.InitApexModule(module)
2059	InitJavaModule(module, android.HostAndDeviceSupported)
2060
2061	// Initialize the map from scope to scope specific properties.
2062	scopeToProperties := make(map[*apiScope]*ApiScopeProperties)
2063	for _, scope := range allApiScopes {
2064		scopeToProperties[scope] = scope.scopeSpecificProperties(module)
2065	}
2066	module.scopeToProperties = scopeToProperties
2067
2068	// Add the properties containing visibility rules so that they are checked.
2069	android.AddVisibilityProperty(module, "impl_library_visibility", &module.sdkLibraryProperties.Impl_library_visibility)
2070	android.AddVisibilityProperty(module, "stubs_library_visibility", &module.sdkLibraryProperties.Stubs_library_visibility)
2071	android.AddVisibilityProperty(module, "stubs_source_visibility", &module.sdkLibraryProperties.Stubs_source_visibility)
2072
2073	module.SetDefaultableHook(func(ctx android.DefaultableHookContext) {
2074		// If no implementation is required then it cannot be used as a shared library
2075		// either.
2076		if !module.requiresRuntimeImplementationLibrary() {
2077			// If shared_library has been explicitly set to true then it is incompatible
2078			// with api_only: true.
2079			if proptools.Bool(module.commonSdkLibraryProperties.Shared_library) {
2080				ctx.PropertyErrorf("api_only/shared_library", "inconsistent settings, shared_library and api_only cannot both be true")
2081			}
2082			// Set shared_library: false.
2083			module.commonSdkLibraryProperties.Shared_library = proptools.BoolPtr(false)
2084		}
2085
2086		if module.initCommonAfterDefaultsApplied(ctx) {
2087			module.CreateInternalModules(ctx)
2088		}
2089	})
2090	android.InitBazelModule(module)
2091	return module
2092}
2093
2094type bazelSdkLibraryAttributes struct {
2095	Public        bazel.StringAttribute
2096	System        bazel.StringAttribute
2097	Test          bazel.StringAttribute
2098	Module_lib    bazel.StringAttribute
2099	System_server bazel.StringAttribute
2100}
2101
2102// java_sdk_library bp2build converter
2103func (module *SdkLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
2104	if ctx.ModuleType() != "java_sdk_library" {
2105		return
2106	}
2107
2108	nameToAttr := make(map[string]bazel.StringAttribute)
2109
2110	for _, scope := range module.getGeneratedApiScopes(ctx) {
2111		apiSurfaceFile := path.Join(module.getApiDir(), scope.apiFilePrefix+"current.txt")
2112		var scopeStringAttribute bazel.StringAttribute
2113		scopeStringAttribute.SetValue(apiSurfaceFile)
2114		nameToAttr[scope.name] = scopeStringAttribute
2115	}
2116
2117	attrs := bazelSdkLibraryAttributes{
2118		Public:        nameToAttr["public"],
2119		System:        nameToAttr["system"],
2120		Test:          nameToAttr["test"],
2121		Module_lib:    nameToAttr["module-lib"],
2122		System_server: nameToAttr["system-server"],
2123	}
2124	props := bazel.BazelTargetModuleProperties{
2125		Rule_class:        "java_sdk_library",
2126		Bzl_load_location: "//build/bazel/rules/java:sdk_library.bzl",
2127	}
2128
2129	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, &attrs)
2130}
2131
2132//
2133// SDK library prebuilts
2134//
2135
2136// Properties associated with each api scope.
2137type sdkLibraryScopeProperties struct {
2138	Jars []string `android:"path"`
2139
2140	Sdk_version *string
2141
2142	// List of shared java libs that this module has dependencies to
2143	Libs []string
2144
2145	// The stubs source.
2146	Stub_srcs []string `android:"path"`
2147
2148	// The current.txt
2149	Current_api *string `android:"path"`
2150
2151	// The removed.txt
2152	Removed_api *string `android:"path"`
2153
2154	// Annotation zip
2155	Annotations *string `android:"path"`
2156}
2157
2158type sdkLibraryImportProperties struct {
2159	// List of shared java libs, common to all scopes, that this module has
2160	// dependencies to
2161	Libs []string
2162
2163	// If set to true, compile dex files for the stubs. Defaults to false.
2164	Compile_dex *bool
2165
2166	// If not empty, classes are restricted to the specified packages and their sub-packages.
2167	Permitted_packages []string
2168}
2169
2170type SdkLibraryImport struct {
2171	android.ModuleBase
2172	android.DefaultableModuleBase
2173	prebuilt android.Prebuilt
2174	android.ApexModuleBase
2175
2176	hiddenAPI
2177	dexpreopter
2178
2179	properties sdkLibraryImportProperties
2180
2181	// Map from api scope to the scope specific property structure.
2182	scopeProperties map[*apiScope]*sdkLibraryScopeProperties
2183
2184	commonToSdkLibraryAndImport
2185
2186	// The reference to the implementation library created by the source module.
2187	// Is nil if the source module does not exist.
2188	implLibraryModule *Library
2189
2190	// The reference to the xml permissions module created by the source module.
2191	// Is nil if the source module does not exist.
2192	xmlPermissionsFileModule *sdkLibraryXml
2193
2194	// Build path to the dex implementation jar obtained from the prebuilt_apex, if any.
2195	dexJarFile OptionalDexJarPath
2196
2197	// Expected install file path of the source module(sdk_library)
2198	// or dex implementation jar obtained from the prebuilt_apex, if any.
2199	installFile android.Path
2200}
2201
2202var _ SdkLibraryDependency = (*SdkLibraryImport)(nil)
2203
2204// The type of a structure that contains a field of type sdkLibraryScopeProperties
2205// for each apiscope in allApiScopes, e.g. something like:
2206//
2207//	struct {
2208//	  Public sdkLibraryScopeProperties
2209//	  System sdkLibraryScopeProperties
2210//	  ...
2211//	}
2212var allScopeStructType = createAllScopePropertiesStructType()
2213
2214// Dynamically create a structure type for each apiscope in allApiScopes.
2215func createAllScopePropertiesStructType() reflect.Type {
2216	var fields []reflect.StructField
2217	for _, apiScope := range allApiScopes {
2218		field := reflect.StructField{
2219			Name: apiScope.fieldName,
2220			Type: reflect.TypeOf(sdkLibraryScopeProperties{}),
2221		}
2222		fields = append(fields, field)
2223	}
2224
2225	return reflect.StructOf(fields)
2226}
2227
2228// Create an instance of the scope specific structure type and return a map
2229// from apiscope to a pointer to each scope specific field.
2230func createPropertiesInstance() (interface{}, map[*apiScope]*sdkLibraryScopeProperties) {
2231	allScopePropertiesPtr := reflect.New(allScopeStructType)
2232	allScopePropertiesStruct := allScopePropertiesPtr.Elem()
2233	scopeProperties := make(map[*apiScope]*sdkLibraryScopeProperties)
2234
2235	for _, apiScope := range allApiScopes {
2236		field := allScopePropertiesStruct.FieldByName(apiScope.fieldName)
2237		scopeProperties[apiScope] = field.Addr().Interface().(*sdkLibraryScopeProperties)
2238	}
2239
2240	return allScopePropertiesPtr.Interface(), scopeProperties
2241}
2242
2243// java_sdk_library_import imports a prebuilt java_sdk_library.
2244func sdkLibraryImportFactory() android.Module {
2245	module := &SdkLibraryImport{}
2246
2247	allScopeProperties, scopeToProperties := createPropertiesInstance()
2248	module.scopeProperties = scopeToProperties
2249	module.AddProperties(&module.properties, allScopeProperties, &module.importDexpreoptProperties)
2250
2251	// Initialize information common between source and prebuilt.
2252	module.initCommon(module)
2253
2254	android.InitPrebuiltModule(module, &[]string{""})
2255	android.InitApexModule(module)
2256	InitJavaModule(module, android.HostAndDeviceSupported)
2257
2258	module.SetDefaultableHook(func(mctx android.DefaultableHookContext) {
2259		if module.initCommonAfterDefaultsApplied(mctx) {
2260			module.createInternalModules(mctx)
2261		}
2262	})
2263	return module
2264}
2265
2266var _ PermittedPackagesForUpdatableBootJars = (*SdkLibraryImport)(nil)
2267
2268func (module *SdkLibraryImport) PermittedPackagesForUpdatableBootJars() []string {
2269	return module.properties.Permitted_packages
2270}
2271
2272func (module *SdkLibraryImport) Prebuilt() *android.Prebuilt {
2273	return &module.prebuilt
2274}
2275
2276func (module *SdkLibraryImport) Name() string {
2277	return module.prebuilt.Name(module.ModuleBase.Name())
2278}
2279
2280func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHookContext) {
2281
2282	// If the build is configured to use prebuilts then force this to be preferred.
2283	if mctx.Config().AlwaysUsePrebuiltSdks() {
2284		module.prebuilt.ForcePrefer()
2285	}
2286
2287	for apiScope, scopeProperties := range module.scopeProperties {
2288		if len(scopeProperties.Jars) == 0 {
2289			continue
2290		}
2291
2292		module.createJavaImportForStubs(mctx, apiScope, scopeProperties)
2293
2294		if len(scopeProperties.Stub_srcs) > 0 {
2295			module.createPrebuiltStubsSources(mctx, apiScope, scopeProperties)
2296		}
2297	}
2298
2299	javaSdkLibraries := javaSdkLibraries(mctx.Config())
2300	javaSdkLibrariesLock.Lock()
2301	defer javaSdkLibrariesLock.Unlock()
2302	*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
2303}
2304
2305func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
2306	// Creates a java import for the jar with ".stubs" suffix
2307	props := struct {
2308		Name        *string
2309		Sdk_version *string
2310		Libs        []string
2311		Jars        []string
2312		Compile_dex *bool
2313
2314		android.UserSuppliedPrebuiltProperties
2315	}{}
2316	props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
2317	props.Sdk_version = scopeProperties.Sdk_version
2318	// Prepend any of the libs from the legacy public properties to the libs for each of the
2319	// scopes to avoid having to duplicate them in each scope.
2320	props.Libs = append(module.properties.Libs, scopeProperties.Libs...)
2321	props.Jars = scopeProperties.Jars
2322
2323	// The imports are preferred if the java_sdk_library_import is preferred.
2324	props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt)
2325
2326	// The imports need to be compiled to dex if the java_sdk_library_import requests it.
2327	compileDex := module.properties.Compile_dex
2328	if module.stubLibrariesCompiledForDex() {
2329		compileDex = proptools.BoolPtr(true)
2330	}
2331	props.Compile_dex = compileDex
2332
2333	mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
2334}
2335
2336func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
2337	props := struct {
2338		Name *string
2339		Srcs []string
2340
2341		android.UserSuppliedPrebuiltProperties
2342	}{}
2343	props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope))
2344	props.Srcs = scopeProperties.Stub_srcs
2345
2346	// The stubs source is preferred if the java_sdk_library_import is preferred.
2347	props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt)
2348
2349	mctx.CreateModule(PrebuiltStubsSourcesFactory, &props)
2350}
2351
2352// Add the dependencies on the child module in the component deps mutator so that it
2353// creates references to the prebuilt and not the source modules.
2354func (module *SdkLibraryImport) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
2355	for apiScope, scopeProperties := range module.scopeProperties {
2356		if len(scopeProperties.Jars) == 0 {
2357			continue
2358		}
2359
2360		// Add dependencies to the prebuilt stubs library
2361		ctx.AddVariationDependencies(nil, apiScope.stubsTag, android.PrebuiltNameFromSource(module.stubsLibraryModuleName(apiScope)))
2362
2363		if len(scopeProperties.Stub_srcs) > 0 {
2364			// Add dependencies to the prebuilt stubs source library
2365			ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, android.PrebuiltNameFromSource(module.stubsSourceModuleName(apiScope)))
2366		}
2367	}
2368}
2369
2370// Add other dependencies as normal.
2371func (module *SdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
2372
2373	implName := module.implLibraryModuleName()
2374	if ctx.OtherModuleExists(implName) {
2375		ctx.AddVariationDependencies(nil, implLibraryTag, implName)
2376
2377		xmlPermissionsModuleName := module.xmlPermissionsModuleName()
2378		if module.sharedLibrary() && ctx.OtherModuleExists(xmlPermissionsModuleName) {
2379			// Add dependency to the rule for generating the xml permissions file
2380			ctx.AddDependency(module, xmlPermissionsFileTag, xmlPermissionsModuleName)
2381		}
2382	}
2383}
2384
2385func (module *SdkLibraryImport) AndroidMkEntries() []android.AndroidMkEntries {
2386	// For an SDK library imported from a prebuilt APEX, we don't need a Make module for itself, as we
2387	// don't need to install it. However, we need to add its dexpreopt outputs as sub-modules, if it
2388	// is preopted.
2389	dexpreoptEntries := module.dexpreopter.AndroidMkEntriesForApex()
2390	return append(dexpreoptEntries, android.AndroidMkEntries{Disabled: true})
2391}
2392
2393var _ android.ApexModule = (*SdkLibraryImport)(nil)
2394
2395// Implements android.ApexModule
2396func (module *SdkLibraryImport) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool {
2397	depTag := mctx.OtherModuleDependencyTag(dep)
2398	if depTag == xmlPermissionsFileTag {
2399		return true
2400	}
2401
2402	// None of the other dependencies of the java_sdk_library_import are in the same apex
2403	// as the one that references this module.
2404	return false
2405}
2406
2407// Implements android.ApexModule
2408func (module *SdkLibraryImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
2409	sdkVersion android.ApiLevel) error {
2410	// we don't check prebuilt modules for sdk_version
2411	return nil
2412}
2413
2414// Implements android.ApexModule
2415func (module *SdkLibraryImport) UniqueApexVariations() bool {
2416	return module.uniqueApexVariations()
2417}
2418
2419// MinSdkVersion - Implements hiddenAPIModule
2420func (module *SdkLibraryImport) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
2421	return android.NoneApiLevel
2422}
2423
2424var _ hiddenAPIModule = (*SdkLibraryImport)(nil)
2425
2426func (module *SdkLibraryImport) OutputFiles(tag string) (android.Paths, error) {
2427	paths, err := module.commonOutputFiles(tag)
2428	if paths != nil || err != nil {
2429		return paths, err
2430	}
2431	if module.implLibraryModule != nil {
2432		return module.implLibraryModule.OutputFiles(tag)
2433	} else {
2434		return nil, nil
2435	}
2436}
2437
2438func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
2439	module.generateCommonBuildActions(ctx)
2440
2441	// Assume that source module(sdk_library) is installed in /<sdk_library partition>/framework
2442	module.installFile = android.PathForModuleInstall(ctx, "framework", module.Stem()+".jar")
2443
2444	// Record the paths to the prebuilt stubs library and stubs source.
2445	ctx.VisitDirectDeps(func(to android.Module) {
2446		tag := ctx.OtherModuleDependencyTag(to)
2447
2448		// Extract information from any of the scope specific dependencies.
2449		if scopeTag, ok := tag.(scopeDependencyTag); ok {
2450			apiScope := scopeTag.apiScope
2451			scopePaths := module.getScopePathsCreateIfNeeded(apiScope)
2452
2453			// Extract information from the dependency. The exact information extracted
2454			// is determined by the nature of the dependency which is determined by the tag.
2455			scopeTag.extractDepInfo(ctx, to, scopePaths)
2456		} else if tag == implLibraryTag {
2457			if implLibrary, ok := to.(*Library); ok {
2458				module.implLibraryModule = implLibrary
2459			} else {
2460				ctx.ModuleErrorf("implementation library must be of type *java.Library but was %T", to)
2461			}
2462		} else if tag == xmlPermissionsFileTag {
2463			if xmlPermissionsFileModule, ok := to.(*sdkLibraryXml); ok {
2464				module.xmlPermissionsFileModule = xmlPermissionsFileModule
2465			} else {
2466				ctx.ModuleErrorf("xml permissions file module must be of type *sdkLibraryXml but was %T", to)
2467			}
2468		}
2469	})
2470
2471	// Populate the scope paths with information from the properties.
2472	for apiScope, scopeProperties := range module.scopeProperties {
2473		if len(scopeProperties.Jars) == 0 {
2474			continue
2475		}
2476
2477		paths := module.getScopePathsCreateIfNeeded(apiScope)
2478		paths.annotationsZip = android.OptionalPathForModuleSrc(ctx, scopeProperties.Annotations)
2479		paths.currentApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Current_api)
2480		paths.removedApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Removed_api)
2481	}
2482
2483	if ctx.Device() {
2484		// If this is a variant created for a prebuilt_apex then use the dex implementation jar
2485		// obtained from the associated deapexer module.
2486		ai := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
2487		if ai.ForPrebuiltApex {
2488			// Get the path of the dex implementation jar from the `deapexer` module.
2489			di := android.FindDeapexerProviderForModule(ctx)
2490			if di == nil {
2491				return // An error has been reported by FindDeapexerProviderForModule.
2492			}
2493			dexJarFileApexRootRelative := apexRootRelativePathToJavaLib(module.BaseModuleName())
2494			if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil {
2495				dexJarFile := makeDexJarPathFromPath(dexOutputPath)
2496				module.dexJarFile = dexJarFile
2497				installPath := android.PathForModuleInPartitionInstall(
2498					ctx, "apex", ai.ApexVariationName, dexJarFileApexRootRelative)
2499				module.installFile = installPath
2500				module.initHiddenAPI(ctx, dexJarFile, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil)
2501
2502				module.dexpreopter.installPath = module.dexpreopter.getInstallPath(ctx, installPath)
2503				module.dexpreopter.isSDKLibrary = true
2504				module.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &module.dexpreopter)
2505
2506				if profilePath := di.PrebuiltExportPath(dexJarFileApexRootRelative + ".prof"); profilePath != nil {
2507					module.dexpreopter.inputProfilePathOnHost = profilePath
2508				}
2509
2510				// Dexpreopting.
2511				module.dexpreopt(ctx, dexOutputPath)
2512			} else {
2513				// This should never happen as a variant for a prebuilt_apex is only created if the
2514				// prebuilt_apex has been configured to export the java library dex file.
2515				ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt APEX %s", di.ApexModuleName())
2516			}
2517		}
2518	}
2519}
2520
2521func (module *SdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec, headerJars bool) android.Paths {
2522
2523	// For consistency with SdkLibrary make the implementation jar available to libraries that
2524	// are within the same APEX.
2525	implLibraryModule := module.implLibraryModule
2526	if implLibraryModule != nil && withinSameApexesAs(ctx, module) {
2527		if headerJars {
2528			return implLibraryModule.HeaderJars()
2529		} else {
2530			return implLibraryModule.ImplementationJars()
2531		}
2532	}
2533
2534	return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion)
2535}
2536
2537// to satisfy SdkLibraryDependency interface
2538func (module *SdkLibraryImport) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
2539	// This module is just a wrapper for the prebuilt stubs.
2540	return module.sdkJars(ctx, sdkVersion, true)
2541}
2542
2543// to satisfy SdkLibraryDependency interface
2544func (module *SdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
2545	// This module is just a wrapper for the stubs.
2546	return module.sdkJars(ctx, sdkVersion, false)
2547}
2548
2549// to satisfy UsesLibraryDependency interface
2550func (module *SdkLibraryImport) DexJarBuildPath() OptionalDexJarPath {
2551	// The dex implementation jar extracted from the .apex file should be used in preference to the
2552	// source.
2553	if module.dexJarFile.IsSet() {
2554		return module.dexJarFile
2555	}
2556	if module.implLibraryModule == nil {
2557		return makeUnsetDexJarPath()
2558	} else {
2559		return module.implLibraryModule.DexJarBuildPath()
2560	}
2561}
2562
2563// to satisfy UsesLibraryDependency interface
2564func (module *SdkLibraryImport) DexJarInstallPath() android.Path {
2565	return module.installFile
2566}
2567
2568// to satisfy UsesLibraryDependency interface
2569func (module *SdkLibraryImport) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap {
2570	return nil
2571}
2572
2573// to satisfy apex.javaDependency interface
2574func (module *SdkLibraryImport) JacocoReportClassesFile() android.Path {
2575	if module.implLibraryModule == nil {
2576		return nil
2577	} else {
2578		return module.implLibraryModule.JacocoReportClassesFile()
2579	}
2580}
2581
2582// to satisfy apex.javaDependency interface
2583func (module *SdkLibraryImport) LintDepSets() LintDepSets {
2584	if module.implLibraryModule == nil {
2585		return LintDepSets{}
2586	} else {
2587		return module.implLibraryModule.LintDepSets()
2588	}
2589}
2590
2591func (module *SdkLibraryImport) GetStrictUpdatabilityLinting() bool {
2592	if module.implLibraryModule == nil {
2593		return false
2594	} else {
2595		return module.implLibraryModule.GetStrictUpdatabilityLinting()
2596	}
2597}
2598
2599func (module *SdkLibraryImport) SetStrictUpdatabilityLinting(strictLinting bool) {
2600	if module.implLibraryModule != nil {
2601		module.implLibraryModule.SetStrictUpdatabilityLinting(strictLinting)
2602	}
2603}
2604
2605// to satisfy apex.javaDependency interface
2606func (module *SdkLibraryImport) Stem() string {
2607	return module.BaseModuleName()
2608}
2609
2610var _ ApexDependency = (*SdkLibraryImport)(nil)
2611
2612// to satisfy java.ApexDependency interface
2613func (module *SdkLibraryImport) HeaderJars() android.Paths {
2614	if module.implLibraryModule == nil {
2615		return nil
2616	} else {
2617		return module.implLibraryModule.HeaderJars()
2618	}
2619}
2620
2621// to satisfy java.ApexDependency interface
2622func (module *SdkLibraryImport) ImplementationAndResourcesJars() android.Paths {
2623	if module.implLibraryModule == nil {
2624		return nil
2625	} else {
2626		return module.implLibraryModule.ImplementationAndResourcesJars()
2627	}
2628}
2629
2630// to satisfy java.DexpreopterInterface interface
2631func (module *SdkLibraryImport) IsInstallable() bool {
2632	return true
2633}
2634
2635var _ android.RequiredFilesFromPrebuiltApex = (*SdkLibraryImport)(nil)
2636
2637func (module *SdkLibraryImport) RequiredFilesFromPrebuiltApex(ctx android.BaseModuleContext) []string {
2638	name := module.BaseModuleName()
2639	return requiredFilesFromPrebuiltApexForImport(name, &module.dexpreopter)
2640}
2641
2642// java_sdk_library_xml
2643type sdkLibraryXml struct {
2644	android.ModuleBase
2645	android.DefaultableModuleBase
2646	android.ApexModuleBase
2647
2648	properties sdkLibraryXmlProperties
2649
2650	outputFilePath android.OutputPath
2651	installDirPath android.InstallPath
2652
2653	hideApexVariantFromMake bool
2654}
2655
2656type sdkLibraryXmlProperties struct {
2657	// canonical name of the lib
2658	Lib_name *string
2659
2660	// Signals that this shared library is part of the bootclasspath starting
2661	// on the version indicated in this attribute.
2662	//
2663	// This will make platforms at this level and above to ignore
2664	// <uses-library> tags with this library name because the library is already
2665	// available
2666	On_bootclasspath_since *string
2667
2668	// Signals that this shared library was part of the bootclasspath before
2669	// (but not including) the version indicated in this attribute.
2670	//
2671	// The system will automatically add a <uses-library> tag with this library to
2672	// apps that target any SDK less than the version indicated in this attribute.
2673	On_bootclasspath_before *string
2674
2675	// Indicates that PackageManager should ignore this shared library if the
2676	// platform is below the version indicated in this attribute.
2677	//
2678	// This means that the device won't recognise this library as installed.
2679	Min_device_sdk *string
2680
2681	// Indicates that PackageManager should ignore this shared library if the
2682	// platform is above the version indicated in this attribute.
2683	//
2684	// This means that the device won't recognise this library as installed.
2685	Max_device_sdk *string
2686
2687	// The SdkLibrary's min api level as a string
2688	//
2689	// This value comes from the ApiLevel of the MinSdkVersion property.
2690	Sdk_library_min_api_level *string
2691}
2692
2693// java_sdk_library_xml builds the permission xml file for a java_sdk_library.
2694// Not to be used directly by users. java_sdk_library internally uses this.
2695func sdkLibraryXmlFactory() android.Module {
2696	module := &sdkLibraryXml{}
2697
2698	module.AddProperties(&module.properties)
2699
2700	android.InitApexModule(module)
2701	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
2702
2703	return module
2704}
2705
2706func (module *sdkLibraryXml) UniqueApexVariations() bool {
2707	// sdkLibraryXml needs a unique variation per APEX because the generated XML file contains the path to the
2708	// mounted APEX, which contains the name of the APEX.
2709	return true
2710}
2711
2712// from android.PrebuiltEtcModule
2713func (module *sdkLibraryXml) BaseDir() string {
2714	return "etc"
2715}
2716
2717// from android.PrebuiltEtcModule
2718func (module *sdkLibraryXml) SubDir() string {
2719	return "permissions"
2720}
2721
2722// from android.PrebuiltEtcModule
2723func (module *sdkLibraryXml) OutputFile() android.OutputPath {
2724	return module.outputFilePath
2725}
2726
2727// from android.ApexModule
2728func (module *sdkLibraryXml) AvailableFor(what string) bool {
2729	return true
2730}
2731
2732func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) {
2733	// do nothing
2734}
2735
2736var _ android.ApexModule = (*sdkLibraryXml)(nil)
2737
2738// Implements android.ApexModule
2739func (module *sdkLibraryXml) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
2740	sdkVersion android.ApiLevel) error {
2741	// sdkLibraryXml doesn't need to be checked separately because java_sdk_library is checked
2742	return nil
2743}
2744
2745// File path to the runtime implementation library
2746func (module *sdkLibraryXml) implPath(ctx android.ModuleContext) string {
2747	implName := proptools.String(module.properties.Lib_name)
2748	if apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo); !apexInfo.IsForPlatform() {
2749		// TODO(b/146468504): ApexVariationName() is only a soong module name, not apex name.
2750		// In most cases, this works fine. But when apex_name is set or override_apex is used
2751		// this can be wrong.
2752		return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexInfo.ApexVariationName, implName)
2753	}
2754	partition := "system"
2755	if module.SocSpecific() {
2756		partition = "vendor"
2757	} else if module.DeviceSpecific() {
2758		partition = "odm"
2759	} else if module.ProductSpecific() {
2760		partition = "product"
2761	} else if module.SystemExtSpecific() {
2762		partition = "system_ext"
2763	}
2764	return "/" + partition + "/framework/" + implName + ".jar"
2765}
2766
2767func formattedOptionalSdkLevelAttribute(ctx android.ModuleContext, attrName string, value *string) string {
2768	if value == nil {
2769		return ""
2770	}
2771	apiLevel, err := android.ApiLevelFromUser(ctx, *value)
2772	if err != nil {
2773		// attributes in bp files have underscores but in the xml have dashes.
2774		ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"), err.Error())
2775		return ""
2776	}
2777	if apiLevel.IsCurrent() {
2778		// passing "current" would always mean a future release, never the current (or the current in
2779		// progress) which means some conditions would never be triggered.
2780		ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"),
2781			`"current" is not an allowed value for this attribute`)
2782		return ""
2783	}
2784	// "safeValue" is safe because it translates finalized codenames to a string
2785	// with their SDK int.
2786	safeValue := apiLevel.String()
2787	return formattedOptionalAttribute(attrName, &safeValue)
2788}
2789
2790// formats an attribute for the xml permissions file if the value is not null
2791// returns empty string otherwise
2792func formattedOptionalAttribute(attrName string, value *string) string {
2793	if value == nil {
2794		return ""
2795	}
2796	return fmt.Sprintf(`        %s=\"%s\"\n`, attrName, *value)
2797}
2798
2799func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) string {
2800	libName := proptools.String(module.properties.Lib_name)
2801	libNameAttr := formattedOptionalAttribute("name", &libName)
2802	filePath := module.implPath(ctx)
2803	filePathAttr := formattedOptionalAttribute("file", &filePath)
2804	implicitFromAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-since", module.properties.On_bootclasspath_since)
2805	implicitUntilAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-before", module.properties.On_bootclasspath_before)
2806	minSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "min-device-sdk", module.properties.Min_device_sdk)
2807	maxSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "max-device-sdk", module.properties.Max_device_sdk)
2808	// <library> is understood in all android versions whereas <apex-library> is only understood from API T (and ignored before that).
2809	// 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
2810	var libraryTag string
2811	if module.properties.Min_device_sdk != nil {
2812		libraryTag = `    <apex-library\n`
2813	} else {
2814		libraryTag = `    <library\n`
2815	}
2816
2817	return strings.Join([]string{
2818		`<?xml version=\"1.0\" encoding=\"utf-8\"?>\n`,
2819		`<!-- Copyright (C) 2018 The Android Open Source Project\n`,
2820		`\n`,
2821		`    Licensed under the Apache License, Version 2.0 (the \"License\");\n`,
2822		`    you may not use this file except in compliance with the License.\n`,
2823		`    You may obtain a copy of the License at\n`,
2824		`\n`,
2825		`        http://www.apache.org/licenses/LICENSE-2.0\n`,
2826		`\n`,
2827		`    Unless required by applicable law or agreed to in writing, software\n`,
2828		`    distributed under the License is distributed on an \"AS IS\" BASIS,\n`,
2829		`    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n`,
2830		`    See the License for the specific language governing permissions and\n`,
2831		`    limitations under the License.\n`,
2832		`-->\n`,
2833		`<permissions>\n`,
2834		libraryTag,
2835		libNameAttr,
2836		filePathAttr,
2837		implicitFromAttr,
2838		implicitUntilAttr,
2839		minSdkAttr,
2840		maxSdkAttr,
2841		`    />\n`,
2842		`</permissions>\n`}, "")
2843}
2844
2845func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
2846	module.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
2847
2848	libName := proptools.String(module.properties.Lib_name)
2849	module.selfValidate(ctx)
2850	xmlContent := module.permissionsContents(ctx)
2851
2852	module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath
2853	rule := android.NewRuleBuilder(pctx, ctx)
2854	rule.Command().
2855		Text("/bin/bash -c \"echo -e '" + xmlContent + "'\" > ").
2856		Output(module.outputFilePath)
2857
2858	rule.Build("java_sdk_xml", "Permission XML")
2859
2860	module.installDirPath = android.PathForModuleInstall(ctx, "etc", module.SubDir())
2861}
2862
2863func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries {
2864	if module.hideApexVariantFromMake {
2865		return []android.AndroidMkEntries{{
2866			Disabled: true,
2867		}}
2868	}
2869
2870	return []android.AndroidMkEntries{{
2871		Class:      "ETC",
2872		OutputFile: android.OptionalPathForPath(module.outputFilePath),
2873		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
2874			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
2875				entries.SetString("LOCAL_MODULE_TAGS", "optional")
2876				entries.SetString("LOCAL_MODULE_PATH", module.installDirPath.String())
2877				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", module.outputFilePath.Base())
2878			},
2879		},
2880	}}
2881}
2882
2883func (module *sdkLibraryXml) selfValidate(ctx android.ModuleContext) {
2884	module.validateAtLeastTAttributes(ctx)
2885	module.validateMinAndMaxDeviceSdk(ctx)
2886	module.validateMinMaxDeviceSdkAndModuleMinSdk(ctx)
2887	module.validateOnBootclasspathBeforeRequirements(ctx)
2888}
2889
2890func (module *sdkLibraryXml) validateAtLeastTAttributes(ctx android.ModuleContext) {
2891	t := android.ApiLevelOrPanic(ctx, "Tiramisu")
2892	module.attrAtLeastT(ctx, t, module.properties.Min_device_sdk, "min_device_sdk")
2893	module.attrAtLeastT(ctx, t, module.properties.Max_device_sdk, "max_device_sdk")
2894	module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_before, "on_bootclasspath_before")
2895	module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_since, "on_bootclasspath_since")
2896}
2897
2898func (module *sdkLibraryXml) attrAtLeastT(ctx android.ModuleContext, t android.ApiLevel, attr *string, attrName string) {
2899	if attr != nil {
2900		if level, err := android.ApiLevelFromUser(ctx, *attr); err == nil {
2901			// we will inform the user of invalid inputs when we try to write the
2902			// permissions xml file so we don't need to do it here
2903			if t.GreaterThan(level) {
2904				ctx.PropertyErrorf(attrName, "Attribute value needs to be at least T")
2905			}
2906		}
2907	}
2908}
2909
2910func (module *sdkLibraryXml) validateMinAndMaxDeviceSdk(ctx android.ModuleContext) {
2911	if module.properties.Min_device_sdk != nil && module.properties.Max_device_sdk != nil {
2912		min, minErr := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk)
2913		max, maxErr := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk)
2914		if minErr == nil && maxErr == nil {
2915			// we will inform the user of invalid inputs when we try to write the
2916			// permissions xml file so we don't need to do it here
2917			if min.GreaterThan(max) {
2918				ctx.ModuleErrorf("min_device_sdk can't be greater than max_device_sdk")
2919			}
2920		}
2921	}
2922}
2923
2924func (module *sdkLibraryXml) validateMinMaxDeviceSdkAndModuleMinSdk(ctx android.ModuleContext) {
2925	moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level)
2926	if module.properties.Min_device_sdk != nil {
2927		api, err := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk)
2928		if err == nil {
2929			if moduleMinApi.GreaterThan(api) {
2930				ctx.PropertyErrorf("min_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi)
2931			}
2932		}
2933	}
2934	if module.properties.Max_device_sdk != nil {
2935		api, err := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk)
2936		if err == nil {
2937			if moduleMinApi.GreaterThan(api) {
2938				ctx.PropertyErrorf("max_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi)
2939			}
2940		}
2941	}
2942}
2943
2944func (module *sdkLibraryXml) validateOnBootclasspathBeforeRequirements(ctx android.ModuleContext) {
2945	moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level)
2946	if module.properties.On_bootclasspath_before != nil {
2947		t := android.ApiLevelOrPanic(ctx, "Tiramisu")
2948		// if we use the attribute, then we need to do this validation
2949		if moduleMinApi.LessThan(t) {
2950			// if minAPi is < T, then we need to have min_device_sdk (which only accepts T+)
2951			if module.properties.Min_device_sdk == nil {
2952				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")
2953			}
2954		}
2955	}
2956}
2957
2958type sdkLibrarySdkMemberType struct {
2959	android.SdkMemberTypeBase
2960}
2961
2962func (s *sdkLibrarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
2963	ctx.AddVariationDependencies(nil, dependencyTag, names...)
2964}
2965
2966func (s *sdkLibrarySdkMemberType) IsInstance(module android.Module) bool {
2967	_, ok := module.(*SdkLibrary)
2968	return ok
2969}
2970
2971func (s *sdkLibrarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
2972	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_sdk_library_import")
2973}
2974
2975func (s *sdkLibrarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
2976	return &sdkLibrarySdkMemberProperties{}
2977}
2978
2979var javaSdkLibrarySdkMemberType = &sdkLibrarySdkMemberType{
2980	android.SdkMemberTypeBase{
2981		PropertyName: "java_sdk_libs",
2982		SupportsSdk:  true,
2983	},
2984}
2985
2986type sdkLibrarySdkMemberProperties struct {
2987	android.SdkMemberPropertiesBase
2988
2989	// Stem name for files in the sdk snapshot.
2990	//
2991	// This is used to construct the path names of various sdk library files in the sdk snapshot to
2992	// make sure that they match the finalized versions of those files in prebuilts/sdk.
2993	//
2994	// This property is marked as keep so that it will be kept in all instances of this struct, will
2995	// not be cleared but will be copied to common structs. That is needed because this field is used
2996	// to construct many file names for other parts of this struct and so it needs to be present in
2997	// all structs. If it was not marked as keep then it would be cleared in some structs and so would
2998	// be unavailable for generating file names if there were other properties that were still set.
2999	Stem string `sdk:"keep"`
3000
3001	// Scope to per scope properties.
3002	Scopes map[*apiScope]*scopeProperties
3003
3004	// The Java stubs source files.
3005	Stub_srcs []string
3006
3007	// The naming scheme.
3008	Naming_scheme *string
3009
3010	// True if the java_sdk_library_import is for a shared library, false
3011	// otherwise.
3012	Shared_library *bool
3013
3014	// True if the stub imports should produce dex jars.
3015	Compile_dex *bool
3016
3017	// The paths to the doctag files to add to the prebuilt.
3018	Doctag_paths android.Paths
3019
3020	Permitted_packages []string
3021
3022	// Signals that this shared library is part of the bootclasspath starting
3023	// on the version indicated in this attribute.
3024	//
3025	// This will make platforms at this level and above to ignore
3026	// <uses-library> tags with this library name because the library is already
3027	// available
3028	On_bootclasspath_since *string
3029
3030	// Signals that this shared library was part of the bootclasspath before
3031	// (but not including) the version indicated in this attribute.
3032	//
3033	// The system will automatically add a <uses-library> tag with this library to
3034	// apps that target any SDK less than the version indicated in this attribute.
3035	On_bootclasspath_before *string
3036
3037	// Indicates that PackageManager should ignore this shared library if the
3038	// platform is below the version indicated in this attribute.
3039	//
3040	// This means that the device won't recognise this library as installed.
3041	Min_device_sdk *string
3042
3043	// Indicates that PackageManager should ignore this shared library if the
3044	// platform is above the version indicated in this attribute.
3045	//
3046	// This means that the device won't recognise this library as installed.
3047	Max_device_sdk *string
3048
3049	DexPreoptProfileGuided *bool `supported_build_releases:"UpsideDownCake+"`
3050}
3051
3052type scopeProperties struct {
3053	Jars           android.Paths
3054	StubsSrcJar    android.Path
3055	CurrentApiFile android.Path
3056	RemovedApiFile android.Path
3057	AnnotationsZip android.Path `supported_build_releases:"Tiramisu+"`
3058	SdkVersion     string
3059}
3060
3061func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
3062	sdk := variant.(*SdkLibrary)
3063
3064	// Copy the stem name for files in the sdk snapshot.
3065	s.Stem = sdk.distStem()
3066
3067	s.Scopes = make(map[*apiScope]*scopeProperties)
3068	for _, apiScope := range allApiScopes {
3069		paths := sdk.findScopePaths(apiScope)
3070		if paths == nil {
3071			continue
3072		}
3073
3074		jars := paths.stubsImplPath
3075		if len(jars) > 0 {
3076			properties := scopeProperties{}
3077			properties.Jars = jars
3078			properties.SdkVersion = sdk.sdkVersionForStubsLibrary(ctx.SdkModuleContext(), apiScope)
3079			properties.StubsSrcJar = paths.stubsSrcJar.Path()
3080			if paths.currentApiFilePath.Valid() {
3081				properties.CurrentApiFile = paths.currentApiFilePath.Path()
3082			}
3083			if paths.removedApiFilePath.Valid() {
3084				properties.RemovedApiFile = paths.removedApiFilePath.Path()
3085			}
3086			// The annotations zip is only available for modules that set annotations_enabled: true.
3087			if paths.annotationsZip.Valid() {
3088				properties.AnnotationsZip = paths.annotationsZip.Path()
3089			}
3090			s.Scopes[apiScope] = &properties
3091		}
3092	}
3093
3094	s.Naming_scheme = sdk.commonSdkLibraryProperties.Naming_scheme
3095	s.Shared_library = proptools.BoolPtr(sdk.sharedLibrary())
3096	s.Compile_dex = sdk.dexProperties.Compile_dex
3097	s.Doctag_paths = sdk.doctagPaths
3098	s.Permitted_packages = sdk.PermittedPackagesForUpdatableBootJars()
3099	s.On_bootclasspath_since = sdk.commonSdkLibraryProperties.On_bootclasspath_since
3100	s.On_bootclasspath_before = sdk.commonSdkLibraryProperties.On_bootclasspath_before
3101	s.Min_device_sdk = sdk.commonSdkLibraryProperties.Min_device_sdk
3102	s.Max_device_sdk = sdk.commonSdkLibraryProperties.Max_device_sdk
3103
3104	if sdk.dexpreopter.dexpreoptProperties.Dex_preopt_result.Profile_guided {
3105		s.DexPreoptProfileGuided = proptools.BoolPtr(true)
3106	}
3107}
3108
3109func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
3110	if s.Naming_scheme != nil {
3111		propertySet.AddProperty("naming_scheme", proptools.String(s.Naming_scheme))
3112	}
3113	if s.Shared_library != nil {
3114		propertySet.AddProperty("shared_library", *s.Shared_library)
3115	}
3116	if s.Compile_dex != nil {
3117		propertySet.AddProperty("compile_dex", *s.Compile_dex)
3118	}
3119	if len(s.Permitted_packages) > 0 {
3120		propertySet.AddProperty("permitted_packages", s.Permitted_packages)
3121	}
3122	dexPreoptSet := propertySet.AddPropertySet("dex_preopt")
3123	if s.DexPreoptProfileGuided != nil {
3124		dexPreoptSet.AddProperty("profile_guided", proptools.Bool(s.DexPreoptProfileGuided))
3125	}
3126
3127	stem := s.Stem
3128
3129	for _, apiScope := range allApiScopes {
3130		if properties, ok := s.Scopes[apiScope]; ok {
3131			scopeSet := propertySet.AddPropertySet(apiScope.propertyName)
3132
3133			scopeDir := apiScope.snapshotRelativeDir()
3134
3135			var jars []string
3136			for _, p := range properties.Jars {
3137				dest := filepath.Join(scopeDir, stem+"-stubs.jar")
3138				ctx.SnapshotBuilder().CopyToSnapshot(p, dest)
3139				jars = append(jars, dest)
3140			}
3141			scopeSet.AddProperty("jars", jars)
3142
3143			if ctx.SdkModuleContext().Config().IsEnvTrue("SOONG_SDK_SNAPSHOT_USE_SRCJAR") {
3144				// Copy the stubs source jar into the snapshot zip as is.
3145				srcJarSnapshotPath := filepath.Join(scopeDir, stem+".srcjar")
3146				ctx.SnapshotBuilder().CopyToSnapshot(properties.StubsSrcJar, srcJarSnapshotPath)
3147				scopeSet.AddProperty("stub_srcs", []string{srcJarSnapshotPath})
3148			} else {
3149				// Merge the stubs source jar into the snapshot zip so that when it is unpacked
3150				// the source files are also unpacked.
3151				snapshotRelativeDir := filepath.Join(scopeDir, stem+"_stub_sources")
3152				ctx.SnapshotBuilder().UnzipToSnapshot(properties.StubsSrcJar, snapshotRelativeDir)
3153				scopeSet.AddProperty("stub_srcs", []string{snapshotRelativeDir})
3154			}
3155
3156			if properties.CurrentApiFile != nil {
3157				currentApiSnapshotPath := apiScope.snapshotRelativeCurrentApiTxtPath(stem)
3158				ctx.SnapshotBuilder().CopyToSnapshot(properties.CurrentApiFile, currentApiSnapshotPath)
3159				scopeSet.AddProperty("current_api", currentApiSnapshotPath)
3160			}
3161
3162			if properties.RemovedApiFile != nil {
3163				removedApiSnapshotPath := apiScope.snapshotRelativeRemovedApiTxtPath(stem)
3164				ctx.SnapshotBuilder().CopyToSnapshot(properties.RemovedApiFile, removedApiSnapshotPath)
3165				scopeSet.AddProperty("removed_api", removedApiSnapshotPath)
3166			}
3167
3168			if properties.AnnotationsZip != nil {
3169				annotationsSnapshotPath := filepath.Join(scopeDir, stem+"_annotations.zip")
3170				ctx.SnapshotBuilder().CopyToSnapshot(properties.AnnotationsZip, annotationsSnapshotPath)
3171				scopeSet.AddProperty("annotations", annotationsSnapshotPath)
3172			}
3173
3174			if properties.SdkVersion != "" {
3175				scopeSet.AddProperty("sdk_version", properties.SdkVersion)
3176			}
3177		}
3178	}
3179
3180	if len(s.Doctag_paths) > 0 {
3181		dests := []string{}
3182		for _, p := range s.Doctag_paths {
3183			dest := filepath.Join("doctags", p.Rel())
3184			ctx.SnapshotBuilder().CopyToSnapshot(p, dest)
3185			dests = append(dests, dest)
3186		}
3187		propertySet.AddProperty("doctag_files", dests)
3188	}
3189}
3190