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)
32
33const (
34	sdkXmlFileSuffix    = ".xml"
35	permissionsTemplate = `<?xml version=\"1.0\" encoding=\"utf-8\"?>\n` +
36		`<!-- Copyright (C) 2018 The Android Open Source Project\n` +
37		`\n` +
38		`    Licensed under the Apache License, Version 2.0 (the \"License\");\n` +
39		`    you may not use this file except in compliance with the License.\n` +
40		`    You may obtain a copy of the License at\n` +
41		`\n` +
42		`        http://www.apache.org/licenses/LICENSE-2.0\n` +
43		`\n` +
44		`    Unless required by applicable law or agreed to in writing, software\n` +
45		`    distributed under the License is distributed on an \"AS IS\" BASIS,\n` +
46		`    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n` +
47		`    See the License for the specific language governing permissions and\n` +
48		`    limitations under the License.\n` +
49		`-->\n` +
50		`<permissions>\n` +
51		`    <library name=\"%s\" file=\"%s\"/>\n` +
52		`</permissions>\n`
53)
54
55// A tag to associated a dependency with a specific api scope.
56type scopeDependencyTag struct {
57	blueprint.BaseDependencyTag
58	name     string
59	apiScope *apiScope
60
61	// Function for extracting appropriate path information from the dependency.
62	depInfoExtractor func(paths *scopePaths, dep android.Module) error
63}
64
65// Extract tag specific information from the dependency.
66func (tag scopeDependencyTag) extractDepInfo(ctx android.ModuleContext, dep android.Module, paths *scopePaths) {
67	err := tag.depInfoExtractor(paths, dep)
68	if err != nil {
69		ctx.ModuleErrorf("has an invalid {scopeDependencyTag: %s} dependency on module %s: %s", tag.name, ctx.OtherModuleName(dep), err.Error())
70	}
71}
72
73var _ android.ReplaceSourceWithPrebuilt = (*scopeDependencyTag)(nil)
74
75func (tag scopeDependencyTag) ReplaceSourceWithPrebuilt() bool {
76	return false
77}
78
79// Provides information about an api scope, e.g. public, system, test.
80type apiScope struct {
81	// The name of the api scope, e.g. public, system, test
82	name string
83
84	// The api scope that this scope extends.
85	extends *apiScope
86
87	// The legacy enabled status for a specific scope can be dependent on other
88	// properties that have been specified on the library so it is provided by
89	// a function that can determine the status by examining those properties.
90	legacyEnabledStatus func(module *SdkLibrary) bool
91
92	// The default enabled status for non-legacy behavior, which is triggered by
93	// explicitly enabling at least one api scope.
94	defaultEnabledStatus bool
95
96	// Gets a pointer to the scope specific properties.
97	scopeSpecificProperties func(module *SdkLibrary) *ApiScopeProperties
98
99	// The name of the field in the dynamically created structure.
100	fieldName string
101
102	// The name of the property in the java_sdk_library_import
103	propertyName string
104
105	// The tag to use to depend on the stubs library module.
106	stubsTag scopeDependencyTag
107
108	// The tag to use to depend on the stubs source module (if separate from the API module).
109	stubsSourceTag scopeDependencyTag
110
111	// The tag to use to depend on the API file generating module (if separate from the stubs source module).
112	apiFileTag scopeDependencyTag
113
114	// The tag to use to depend on the stubs source and API module.
115	stubsSourceAndApiTag scopeDependencyTag
116
117	// The scope specific prefix to add to the api file base of "current.txt" or "removed.txt".
118	apiFilePrefix string
119
120	// The scope specific prefix to add to the sdk library module name to construct a scope specific
121	// module name.
122	moduleSuffix string
123
124	// SDK version that the stubs library is built against. Note that this is always
125	// *current. Older stubs library built with a numbered SDK version is created from
126	// the prebuilt jar.
127	sdkVersion string
128
129	// The annotation that identifies this API level, empty for the public API scope.
130	annotation string
131
132	// Extra arguments to pass to droidstubs for this scope.
133	//
134	// This is not used directly but is used to construct the droidstubsArgs.
135	extraArgs []string
136
137	// The args that must be passed to droidstubs to generate the API and stubs source
138	// for this scope, constructed dynamically by initApiScope().
139	//
140	// The API only includes the additional members that this scope adds over the scope
141	// that it extends.
142	//
143	// The stubs source must include the definitions of everything that is in this
144	// api scope and all the scopes that this one extends.
145	droidstubsArgs []string
146
147	// Whether the api scope can be treated as unstable, and should skip compat checks.
148	unstable bool
149}
150
151// Initialize a scope, creating and adding appropriate dependency tags
152func initApiScope(scope *apiScope) *apiScope {
153	name := scope.name
154	scopeByName[name] = scope
155	allScopeNames = append(allScopeNames, name)
156	scope.propertyName = strings.ReplaceAll(name, "-", "_")
157	scope.fieldName = proptools.FieldNameForProperty(scope.propertyName)
158	scope.stubsTag = scopeDependencyTag{
159		name:             name + "-stubs",
160		apiScope:         scope,
161		depInfoExtractor: (*scopePaths).extractStubsLibraryInfoFromDependency,
162	}
163	scope.stubsSourceTag = scopeDependencyTag{
164		name:             name + "-stubs-source",
165		apiScope:         scope,
166		depInfoExtractor: (*scopePaths).extractStubsSourceInfoFromDep,
167	}
168	scope.apiFileTag = scopeDependencyTag{
169		name:             name + "-api",
170		apiScope:         scope,
171		depInfoExtractor: (*scopePaths).extractApiInfoFromDep,
172	}
173	scope.stubsSourceAndApiTag = scopeDependencyTag{
174		name:             name + "-stubs-source-and-api",
175		apiScope:         scope,
176		depInfoExtractor: (*scopePaths).extractStubsSourceAndApiInfoFromApiStubsProvider,
177	}
178
179	// To get the args needed to generate the stubs source append all the args from
180	// this scope and all the scopes it extends as each set of args adds additional
181	// members to the stubs.
182	var scopeSpecificArgs []string
183	if scope.annotation != "" {
184		scopeSpecificArgs = []string{"--show-annotation", scope.annotation}
185	}
186	for s := scope; s != nil; s = s.extends {
187		scopeSpecificArgs = append(scopeSpecificArgs, s.extraArgs...)
188
189		// Ensure that the generated stubs includes all the API elements from the API scope
190		// that this scope extends.
191		if s != scope && s.annotation != "" {
192			scopeSpecificArgs = append(scopeSpecificArgs, "--show-for-stub-purposes-annotation", s.annotation)
193		}
194	}
195
196	// Escape any special characters in the arguments. This is needed because droidstubs
197	// passes these directly to the shell command.
198	scope.droidstubsArgs = proptools.ShellEscapeList(scopeSpecificArgs)
199
200	return scope
201}
202
203func (scope *apiScope) stubsLibraryModuleName(baseName string) string {
204	return baseName + ".stubs" + scope.moduleSuffix
205}
206
207func (scope *apiScope) stubsSourceModuleName(baseName string) string {
208	return baseName + ".stubs.source" + scope.moduleSuffix
209}
210
211func (scope *apiScope) apiModuleName(baseName string) string {
212	return baseName + ".api" + scope.moduleSuffix
213}
214
215func (scope *apiScope) String() string {
216	return scope.name
217}
218
219type apiScopes []*apiScope
220
221func (scopes apiScopes) Strings(accessor func(*apiScope) string) []string {
222	var list []string
223	for _, scope := range scopes {
224		list = append(list, accessor(scope))
225	}
226	return list
227}
228
229var (
230	scopeByName    = make(map[string]*apiScope)
231	allScopeNames  []string
232	apiScopePublic = initApiScope(&apiScope{
233		name: "public",
234
235		// Public scope is enabled by default for both legacy and non-legacy modes.
236		legacyEnabledStatus: func(module *SdkLibrary) bool {
237			return true
238		},
239		defaultEnabledStatus: true,
240
241		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
242			return &module.sdkLibraryProperties.Public
243		},
244		sdkVersion: "current",
245	})
246	apiScopeSystem = initApiScope(&apiScope{
247		name:                "system",
248		extends:             apiScopePublic,
249		legacyEnabledStatus: (*SdkLibrary).generateTestAndSystemScopesByDefault,
250		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
251			return &module.sdkLibraryProperties.System
252		},
253		apiFilePrefix: "system-",
254		moduleSuffix:  ".system",
255		sdkVersion:    "system_current",
256		annotation:    "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS)",
257	})
258	apiScopeTest = initApiScope(&apiScope{
259		name:                "test",
260		extends:             apiScopePublic,
261		legacyEnabledStatus: (*SdkLibrary).generateTestAndSystemScopesByDefault,
262		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
263			return &module.sdkLibraryProperties.Test
264		},
265		apiFilePrefix: "test-",
266		moduleSuffix:  ".test",
267		sdkVersion:    "test_current",
268		annotation:    "android.annotation.TestApi",
269		unstable:      true,
270	})
271	apiScopeModuleLib = initApiScope(&apiScope{
272		name:    "module-lib",
273		extends: apiScopeSystem,
274		// The module-lib scope is disabled by default in legacy mode.
275		//
276		// Enabling this would break existing usages.
277		legacyEnabledStatus: func(module *SdkLibrary) bool {
278			return false
279		},
280		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
281			return &module.sdkLibraryProperties.Module_lib
282		},
283		apiFilePrefix: "module-lib-",
284		moduleSuffix:  ".module_lib",
285		sdkVersion:    "module_current",
286		annotation:    "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES)",
287	})
288	apiScopeSystemServer = initApiScope(&apiScope{
289		name:    "system-server",
290		extends: apiScopePublic,
291		// The system-server scope is disabled by default in legacy mode.
292		//
293		// Enabling this would break existing usages.
294		legacyEnabledStatus: func(module *SdkLibrary) bool {
295			return false
296		},
297		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
298			return &module.sdkLibraryProperties.System_server
299		},
300		apiFilePrefix: "system-server-",
301		moduleSuffix:  ".system_server",
302		sdkVersion:    "system_server_current",
303		annotation:    "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.SYSTEM_SERVER)",
304		extraArgs: []string{
305			"--hide-annotation", "android.annotation.Hide",
306			// com.android.* classes are okay in this interface"
307			"--hide", "InternalClasses",
308		},
309	})
310	allApiScopes = apiScopes{
311		apiScopePublic,
312		apiScopeSystem,
313		apiScopeTest,
314		apiScopeModuleLib,
315		apiScopeSystemServer,
316	}
317)
318
319var (
320	javaSdkLibrariesLock sync.Mutex
321)
322
323// TODO: these are big features that are currently missing
324// 1) disallowing linking to the runtime shared lib
325// 2) HTML generation
326
327func init() {
328	RegisterSdkLibraryBuildComponents(android.InitRegistrationContext)
329
330	android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
331		javaSdkLibraries := javaSdkLibraries(ctx.Config())
332		sort.Strings(*javaSdkLibraries)
333		ctx.Strict("JAVA_SDK_LIBRARIES", strings.Join(*javaSdkLibraries, " "))
334	})
335
336	// Register sdk member types.
337	android.RegisterSdkMemberType(&sdkLibrarySdkMemberType{
338		android.SdkMemberTypeBase{
339			PropertyName: "java_sdk_libs",
340			SupportsSdk:  true,
341		},
342	})
343}
344
345func RegisterSdkLibraryBuildComponents(ctx android.RegistrationContext) {
346	ctx.RegisterModuleType("java_sdk_library", SdkLibraryFactory)
347	ctx.RegisterModuleType("java_sdk_library_import", sdkLibraryImportFactory)
348}
349
350// Properties associated with each api scope.
351type ApiScopeProperties struct {
352	// Indicates whether the api surface is generated.
353	//
354	// If this is set for any scope then all scopes must explicitly specify if they
355	// are enabled. This is to prevent new usages from depending on legacy behavior.
356	//
357	// Otherwise, if this is not set for any scope then the default  behavior is
358	// scope specific so please refer to the scope specific property documentation.
359	Enabled *bool
360
361	// The sdk_version to use for building the stubs.
362	//
363	// If not specified then it will use an sdk_version determined as follows:
364	// 1) If the sdk_version specified on the java_sdk_library is none then this
365	//    will be none. This is used for java_sdk_library instances that are used
366	//    to create stubs that contribute to the core_current sdk version.
367	// 2) Otherwise, it is assumed that this library extends but does not contribute
368	//    directly to a specific sdk_version and so this uses the sdk_version appropriate
369	//    for the api scope. e.g. public will use sdk_version: current, system will use
370	//    sdk_version: system_current, etc.
371	//
372	// This does not affect the sdk_version used for either generating the stubs source
373	// or the API file. They both have to use the same sdk_version as is used for
374	// compiling the implementation library.
375	Sdk_version *string
376}
377
378type sdkLibraryProperties struct {
379	// Visibility for impl library module. If not specified then defaults to the
380	// visibility property.
381	Impl_library_visibility []string
382
383	// Visibility for stubs library modules. If not specified then defaults to the
384	// visibility property.
385	Stubs_library_visibility []string
386
387	// Visibility for stubs source modules. If not specified then defaults to the
388	// visibility property.
389	Stubs_source_visibility []string
390
391	// List of Java libraries that will be in the classpath when building stubs
392	Stub_only_libs []string `android:"arch_variant"`
393
394	// list of package names that will be documented and publicized as API.
395	// This allows the API to be restricted to a subset of the source files provided.
396	// If this is unspecified then all the source files will be treated as being part
397	// of the API.
398	Api_packages []string
399
400	// list of package names that must be hidden from the API
401	Hidden_api_packages []string
402
403	// the relative path to the directory containing the api specification files.
404	// Defaults to "api".
405	Api_dir *string
406
407	// Determines whether a runtime implementation library is built; defaults to false.
408	//
409	// If true then it also prevents the module from being used as a shared module, i.e.
410	// it is as is shared_library: false, was set.
411	Api_only *bool
412
413	// local files that are used within user customized droiddoc options.
414	Droiddoc_option_files []string
415
416	// additional droiddoc options
417	// Available variables for substitution:
418	//
419	//  $(location <label>): the path to the droiddoc_option_files with name <label>
420	Droiddoc_options []string
421
422	// a list of top-level directories containing files to merge qualifier annotations
423	// (i.e. those intended to be included in the stubs written) from.
424	Merge_annotations_dirs []string
425
426	// a list of top-level directories containing Java stub files to merge show/hide annotations from.
427	Merge_inclusion_annotations_dirs []string
428
429	// If set to true, the path of dist files is apistubs/core. Defaults to false.
430	Core_lib *bool
431
432	// don't create dist rules.
433	No_dist *bool `blueprint:"mutated"`
434
435	// indicates whether system and test apis should be generated.
436	Generate_system_and_test_apis bool `blueprint:"mutated"`
437
438	// The properties specific to the public api scope
439	//
440	// Unless explicitly specified by using public.enabled the public api scope is
441	// enabled by default in both legacy and non-legacy mode.
442	Public ApiScopeProperties
443
444	// The properties specific to the system api scope
445	//
446	// In legacy mode the system api scope is enabled by default when sdk_version
447	// is set to something other than "none".
448	//
449	// In non-legacy mode the system api scope is disabled by default.
450	System ApiScopeProperties
451
452	// The properties specific to the test api scope
453	//
454	// In legacy mode the test api scope is enabled by default when sdk_version
455	// is set to something other than "none".
456	//
457	// In non-legacy mode the test api scope is disabled by default.
458	Test ApiScopeProperties
459
460	// The properties specific to the module-lib api scope
461	//
462	// Unless explicitly specified by using test.enabled the module-lib api scope is
463	// disabled by default.
464	Module_lib ApiScopeProperties
465
466	// The properties specific to the system-server api scope
467	//
468	// Unless explicitly specified by using test.enabled the module-lib api scope is
469	// disabled by default.
470	System_server ApiScopeProperties
471
472	// Determines if the stubs are preferred over the implementation library
473	// for linking, even when the client doesn't specify sdk_version. When this
474	// is set to true, such clients are provided with the widest API surface that
475	// this lib provides. Note however that this option doesn't affect the clients
476	// that are in the same APEX as this library. In that case, the clients are
477	// always linked with the implementation library. Default is false.
478	Default_to_stubs *bool
479
480	// Properties related to api linting.
481	Api_lint struct {
482		// Enable api linting.
483		Enabled *bool
484	}
485
486	// TODO: determines whether to create HTML doc or not
487	//Html_doc *bool
488}
489
490// Paths to outputs from java_sdk_library and java_sdk_library_import.
491//
492// Fields that are android.Paths are always set (during GenerateAndroidBuildActions).
493// OptionalPaths are always set by java_sdk_library but may not be set by
494// java_sdk_library_import as not all instances provide that information.
495type scopePaths struct {
496	// The path (represented as Paths for convenience when returning) to the stubs header jar.
497	//
498	// That is the jar that is created by turbine.
499	stubsHeaderPath android.Paths
500
501	// The path (represented as Paths for convenience when returning) to the stubs implementation jar.
502	//
503	// This is not the implementation jar, it still only contains stubs.
504	stubsImplPath android.Paths
505
506	// The API specification file, e.g. system_current.txt.
507	currentApiFilePath android.OptionalPath
508
509	// The specification of API elements removed since the last release.
510	removedApiFilePath android.OptionalPath
511
512	// The stubs source jar.
513	stubsSrcJar android.OptionalPath
514}
515
516func (paths *scopePaths) extractStubsLibraryInfoFromDependency(dep android.Module) error {
517	if lib, ok := dep.(Dependency); ok {
518		paths.stubsHeaderPath = lib.HeaderJars()
519		paths.stubsImplPath = lib.ImplementationJars()
520		return nil
521	} else {
522		return fmt.Errorf("expected module that implements Dependency, e.g. java_library")
523	}
524}
525
526func (paths *scopePaths) treatDepAsApiStubsProvider(dep android.Module, action func(provider ApiStubsProvider)) error {
527	if apiStubsProvider, ok := dep.(ApiStubsProvider); ok {
528		action(apiStubsProvider)
529		return nil
530	} else {
531		return fmt.Errorf("expected module that implements ApiStubsProvider, e.g. droidstubs")
532	}
533}
534
535func (paths *scopePaths) treatDepAsApiStubsSrcProvider(dep android.Module, action func(provider ApiStubsSrcProvider)) error {
536	if apiStubsProvider, ok := dep.(ApiStubsSrcProvider); ok {
537		action(apiStubsProvider)
538		return nil
539	} else {
540		return fmt.Errorf("expected module that implements ApiStubsSrcProvider, e.g. droidstubs")
541	}
542}
543
544func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsProvider) {
545	paths.currentApiFilePath = android.OptionalPathForPath(provider.ApiFilePath())
546	paths.removedApiFilePath = android.OptionalPathForPath(provider.RemovedApiFilePath())
547}
548
549func (paths *scopePaths) extractApiInfoFromDep(dep android.Module) error {
550	return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) {
551		paths.extractApiInfoFromApiStubsProvider(provider)
552	})
553}
554
555func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider ApiStubsSrcProvider) {
556	paths.stubsSrcJar = android.OptionalPathForPath(provider.StubsSrcJar())
557}
558
559func (paths *scopePaths) extractStubsSourceInfoFromDep(dep android.Module) error {
560	return paths.treatDepAsApiStubsSrcProvider(dep, func(provider ApiStubsSrcProvider) {
561		paths.extractStubsSourceInfoFromApiStubsProviders(provider)
562	})
563}
564
565func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(dep android.Module) error {
566	return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) {
567		paths.extractApiInfoFromApiStubsProvider(provider)
568		paths.extractStubsSourceInfoFromApiStubsProviders(provider)
569	})
570}
571
572type commonToSdkLibraryAndImportProperties struct {
573	// The naming scheme to use for the components that this module creates.
574	//
575	// If not specified then it defaults to "default". The other allowable value is
576	// "framework-modules" which matches the scheme currently used by framework modules
577	// for the equivalent components represented as separate Soong modules.
578	//
579	// This is a temporary mechanism to simplify conversion from separate modules for each
580	// component that follow a different naming pattern to the default one.
581	//
582	// TODO(b/155480189) - Remove once naming inconsistencies have been resolved.
583	Naming_scheme *string
584
585	// Specifies whether this module can be used as an Android shared library; defaults
586	// to true.
587	//
588	// An Android shared library is one that can be referenced in a <uses-library> element
589	// in an AndroidManifest.xml.
590	Shared_library *bool
591}
592
593// Common code between sdk library and sdk library import
594type commonToSdkLibraryAndImport struct {
595	moduleBase *android.ModuleBase
596
597	scopePaths map[*apiScope]*scopePaths
598
599	namingScheme sdkLibraryComponentNamingScheme
600
601	commonSdkLibraryProperties commonToSdkLibraryAndImportProperties
602
603	// Functionality related to this being used as a component of a java_sdk_library.
604	EmbeddableSdkLibraryComponent
605}
606
607func (c *commonToSdkLibraryAndImport) initCommon(moduleBase *android.ModuleBase) {
608	c.moduleBase = moduleBase
609
610	moduleBase.AddProperties(&c.commonSdkLibraryProperties)
611
612	// Initialize this as an sdk library component.
613	c.initSdkLibraryComponent(moduleBase)
614}
615
616func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied(ctx android.DefaultableHookContext) bool {
617	schemeProperty := proptools.StringDefault(c.commonSdkLibraryProperties.Naming_scheme, "default")
618	switch schemeProperty {
619	case "default":
620		c.namingScheme = &defaultNamingScheme{}
621	case "framework-modules":
622		c.namingScheme = &frameworkModulesNamingScheme{}
623	default:
624		ctx.PropertyErrorf("naming_scheme", "expected 'default' but was %q", schemeProperty)
625		return false
626	}
627
628	// Only track this sdk library if this can be used as a shared library.
629	if c.sharedLibrary() {
630		// Use the name specified in the module definition as the owner.
631		c.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack = proptools.StringPtr(c.moduleBase.BaseModuleName())
632	}
633
634	return true
635}
636
637// Module name of the runtime implementation library
638func (c *commonToSdkLibraryAndImport) implLibraryModuleName() string {
639	return c.moduleBase.BaseModuleName() + ".impl"
640}
641
642// Module name of the XML file for the lib
643func (c *commonToSdkLibraryAndImport) xmlPermissionsModuleName() string {
644	return c.moduleBase.BaseModuleName() + sdkXmlFileSuffix
645}
646
647// Name of the java_library module that compiles the stubs source.
648func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope) string {
649	return c.namingScheme.stubsLibraryModuleName(apiScope, c.moduleBase.BaseModuleName())
650}
651
652// Name of the droidstubs module that generates the stubs source and may also
653// generate/check the API.
654func (c *commonToSdkLibraryAndImport) stubsSourceModuleName(apiScope *apiScope) string {
655	return c.namingScheme.stubsSourceModuleName(apiScope, c.moduleBase.BaseModuleName())
656}
657
658// Name of the droidstubs module that generates/checks the API. Only used if it
659// requires different arts to the stubs source generating module.
660func (c *commonToSdkLibraryAndImport) apiModuleName(apiScope *apiScope) string {
661	return c.namingScheme.apiModuleName(apiScope, c.moduleBase.BaseModuleName())
662}
663
664// The component names for different outputs of the java_sdk_library.
665//
666// They are similar to the names used for the child modules it creates
667const (
668	stubsSourceComponentName = "stubs.source"
669
670	apiTxtComponentName = "api.txt"
671
672	removedApiTxtComponentName = "removed-api.txt"
673)
674
675// A regular expression to match tags that reference a specific stubs component.
676//
677// It will only match if given a valid scope and a valid component. It is verfy strict
678// to ensure it does not accidentally match a similar looking tag that should be processed
679// by the embedded Library.
680var tagSplitter = func() *regexp.Regexp {
681	// Given a list of literal string items returns a regular expression that will
682	// match any one of the items.
683	choice := func(items ...string) string {
684		return `\Q` + strings.Join(items, `\E|\Q`) + `\E`
685	}
686
687	// Regular expression to match one of the scopes.
688	scopesRegexp := choice(allScopeNames...)
689
690	// Regular expression to match one of the components.
691	componentsRegexp := choice(stubsSourceComponentName, apiTxtComponentName, removedApiTxtComponentName)
692
693	// Regular expression to match any combination of one scope and one component.
694	return regexp.MustCompile(fmt.Sprintf(`^\.(%s)\.(%s)$`, scopesRegexp, componentsRegexp))
695}()
696
697// For OutputFileProducer interface
698//
699// .<scope>.stubs.source
700// .<scope>.api.txt
701// .<scope>.removed-api.txt
702func (c *commonToSdkLibraryAndImport) commonOutputFiles(tag string) (android.Paths, error) {
703	if groups := tagSplitter.FindStringSubmatch(tag); groups != nil {
704		scopeName := groups[1]
705		component := groups[2]
706
707		if scope, ok := scopeByName[scopeName]; ok {
708			paths := c.findScopePaths(scope)
709			if paths == nil {
710				return nil, fmt.Errorf("%q does not provide api scope %s", c.moduleBase.BaseModuleName(), scopeName)
711			}
712
713			switch component {
714			case stubsSourceComponentName:
715				if paths.stubsSrcJar.Valid() {
716					return android.Paths{paths.stubsSrcJar.Path()}, nil
717				}
718
719			case apiTxtComponentName:
720				if paths.currentApiFilePath.Valid() {
721					return android.Paths{paths.currentApiFilePath.Path()}, nil
722				}
723
724			case removedApiTxtComponentName:
725				if paths.removedApiFilePath.Valid() {
726					return android.Paths{paths.removedApiFilePath.Path()}, nil
727				}
728			}
729
730			return nil, fmt.Errorf("%s not available for api scope %s", component, scopeName)
731		} else {
732			return nil, fmt.Errorf("unknown scope %s in %s", scope, tag)
733		}
734
735	} else {
736		return nil, nil
737	}
738}
739
740func (c *commonToSdkLibraryAndImport) getScopePathsCreateIfNeeded(scope *apiScope) *scopePaths {
741	if c.scopePaths == nil {
742		c.scopePaths = make(map[*apiScope]*scopePaths)
743	}
744	paths := c.scopePaths[scope]
745	if paths == nil {
746		paths = &scopePaths{}
747		c.scopePaths[scope] = paths
748	}
749
750	return paths
751}
752
753func (c *commonToSdkLibraryAndImport) findScopePaths(scope *apiScope) *scopePaths {
754	if c.scopePaths == nil {
755		return nil
756	}
757
758	return c.scopePaths[scope]
759}
760
761// If this does not support the requested api scope then find the closest available
762// scope it does support. Returns nil if no such scope is available.
763func (c *commonToSdkLibraryAndImport) findClosestScopePath(scope *apiScope) *scopePaths {
764	for s := scope; s != nil; s = s.extends {
765		if paths := c.findScopePaths(s); paths != nil {
766			return paths
767		}
768	}
769
770	// This should never happen outside tests as public should be the base scope for every
771	// scope and is enabled by default.
772	return nil
773}
774
775func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
776
777	// If a specific numeric version has been requested then use prebuilt versions of the sdk.
778	if sdkVersion.version.isNumbered() {
779		return PrebuiltJars(ctx, c.moduleBase.BaseModuleName(), sdkVersion)
780	}
781
782	var apiScope *apiScope
783	switch sdkVersion.kind {
784	case sdkSystem:
785		apiScope = apiScopeSystem
786	case sdkModule:
787		apiScope = apiScopeModuleLib
788	case sdkTest:
789		apiScope = apiScopeTest
790	case sdkSystemServer:
791		apiScope = apiScopeSystemServer
792	default:
793		apiScope = apiScopePublic
794	}
795
796	paths := c.findClosestScopePath(apiScope)
797	if paths == nil {
798		var scopes []string
799		for _, s := range allApiScopes {
800			if c.findScopePaths(s) != nil {
801				scopes = append(scopes, s.name)
802			}
803		}
804		ctx.ModuleErrorf("requires api scope %s from %s but it only has %q available", apiScope.name, c.moduleBase.BaseModuleName(), scopes)
805		return nil
806	}
807
808	return paths.stubsHeaderPath
809}
810
811func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() interface{} {
812	componentProps := &struct {
813		SdkLibraryToImplicitlyTrack *string
814	}{}
815
816	if c.sharedLibrary() {
817		// Mark the stubs library as being components of this java_sdk_library so that
818		// any app that includes code which depends (directly or indirectly) on the stubs
819		// library will have the appropriate <uses-library> invocation inserted into its
820		// manifest if necessary.
821		componentProps.SdkLibraryToImplicitlyTrack = proptools.StringPtr(c.moduleBase.BaseModuleName())
822	}
823
824	return componentProps
825}
826
827// Check if this can be used as a shared library.
828func (c *commonToSdkLibraryAndImport) sharedLibrary() bool {
829	return proptools.BoolDefault(c.commonSdkLibraryProperties.Shared_library, true)
830}
831
832// Properties related to the use of a module as an component of a java_sdk_library.
833type SdkLibraryComponentProperties struct {
834
835	// The name of the java_sdk_library/_import to add to a <uses-library> entry
836	// in the AndroidManifest.xml of any Android app that includes code that references
837	// this module. If not set then no java_sdk_library/_import is tracked.
838	SdkLibraryToImplicitlyTrack *string `blueprint:"mutated"`
839}
840
841// Structure to be embedded in a module struct that needs to support the
842// SdkLibraryComponentDependency interface.
843type EmbeddableSdkLibraryComponent struct {
844	sdkLibraryComponentProperties SdkLibraryComponentProperties
845}
846
847func (e *EmbeddableSdkLibraryComponent) initSdkLibraryComponent(moduleBase *android.ModuleBase) {
848	moduleBase.AddProperties(&e.sdkLibraryComponentProperties)
849}
850
851// to satisfy SdkLibraryComponentDependency
852func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() []string {
853	if e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack != nil {
854		return []string{*e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack}
855	}
856	return nil
857}
858
859// Implemented by modules that are (or possibly could be) a component of a java_sdk_library
860// (including the java_sdk_library) itself.
861type SdkLibraryComponentDependency interface {
862	// The optional name of the sdk library that should be implicitly added to the
863	// AndroidManifest of an app that contains code which references the sdk library.
864	//
865	// Returns an array containing 0 or 1 items rather than a *string to make it easier
866	// to append this to the list of exported sdk libraries.
867	OptionalImplicitSdkLibrary() []string
868}
869
870// Make sure that all the module types that are components of java_sdk_library/_import
871// and which can be referenced (directly or indirectly) from an android app implement
872// the SdkLibraryComponentDependency interface.
873var _ SdkLibraryComponentDependency = (*Library)(nil)
874var _ SdkLibraryComponentDependency = (*Import)(nil)
875var _ SdkLibraryComponentDependency = (*SdkLibrary)(nil)
876var _ SdkLibraryComponentDependency = (*SdkLibraryImport)(nil)
877
878// Provides access to sdk_version related header and implentation jars.
879type SdkLibraryDependency interface {
880	SdkLibraryComponentDependency
881
882	// Get the header jars appropriate for the supplied sdk_version.
883	//
884	// These are turbine generated jars so they only change if the externals of the
885	// class changes but it does not contain and implementation or JavaDoc.
886	SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths
887
888	// Get the implementation jars appropriate for the supplied sdk version.
889	//
890	// These are either the implementation jar for the whole sdk library or the implementation
891	// jars for the stubs. The latter should only be needed when generating JavaDoc as otherwise
892	// they are identical to the corresponding header jars.
893	SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths
894}
895
896type SdkLibrary struct {
897	Library
898
899	sdkLibraryProperties sdkLibraryProperties
900
901	// Map from api scope to the scope specific property structure.
902	scopeToProperties map[*apiScope]*ApiScopeProperties
903
904	commonToSdkLibraryAndImport
905}
906
907var _ Dependency = (*SdkLibrary)(nil)
908var _ SdkLibraryDependency = (*SdkLibrary)(nil)
909
910func (module *SdkLibrary) generateTestAndSystemScopesByDefault() bool {
911	return module.sdkLibraryProperties.Generate_system_and_test_apis
912}
913
914func (module *SdkLibrary) getGeneratedApiScopes(ctx android.EarlyModuleContext) apiScopes {
915	// Check to see if any scopes have been explicitly enabled. If any have then all
916	// must be.
917	anyScopesExplicitlyEnabled := false
918	for _, scope := range allApiScopes {
919		scopeProperties := module.scopeToProperties[scope]
920		if scopeProperties.Enabled != nil {
921			anyScopesExplicitlyEnabled = true
922			break
923		}
924	}
925
926	var generatedScopes apiScopes
927	enabledScopes := make(map[*apiScope]struct{})
928	for _, scope := range allApiScopes {
929		scopeProperties := module.scopeToProperties[scope]
930		// If any scopes are explicitly enabled then ignore the legacy enabled status.
931		// This is to ensure that any new usages of this module type do not rely on legacy
932		// behaviour.
933		defaultEnabledStatus := false
934		if anyScopesExplicitlyEnabled {
935			defaultEnabledStatus = scope.defaultEnabledStatus
936		} else {
937			defaultEnabledStatus = scope.legacyEnabledStatus(module)
938		}
939		enabled := proptools.BoolDefault(scopeProperties.Enabled, defaultEnabledStatus)
940		if enabled {
941			enabledScopes[scope] = struct{}{}
942			generatedScopes = append(generatedScopes, scope)
943		}
944	}
945
946	// Now check to make sure that any scope that is extended by an enabled scope is also
947	// enabled.
948	for _, scope := range allApiScopes {
949		if _, ok := enabledScopes[scope]; ok {
950			extends := scope.extends
951			if extends != nil {
952				if _, ok := enabledScopes[extends]; !ok {
953					ctx.ModuleErrorf("enabled api scope %q depends on disabled scope %q", scope, extends)
954				}
955			}
956		}
957	}
958
959	return generatedScopes
960}
961
962type sdkLibraryComponentTag struct {
963	blueprint.BaseDependencyTag
964	name string
965}
966
967// Mark this tag so dependencies that use it are excluded from visibility enforcement.
968func (t sdkLibraryComponentTag) ExcludeFromVisibilityEnforcement() {}
969
970var xmlPermissionsFileTag = sdkLibraryComponentTag{name: "xml-permissions-file"}
971
972func IsXmlPermissionsFileDepTag(depTag blueprint.DependencyTag) bool {
973	if dt, ok := depTag.(sdkLibraryComponentTag); ok {
974		return dt == xmlPermissionsFileTag
975	}
976	return false
977}
978
979var implLibraryTag = sdkLibraryComponentTag{name: "impl-library"}
980
981// Add the dependencies on the child modules in the component deps mutator.
982func (module *SdkLibrary) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
983	for _, apiScope := range module.getGeneratedApiScopes(ctx) {
984		// Add dependencies to the stubs library
985		ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope))
986
987		// Add a dependency on the stubs source in order to access both stubs source and api information.
988		ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceModuleName(apiScope))
989	}
990
991	if module.requiresRuntimeImplementationLibrary() {
992		// Add dependency to the rule for generating the implementation library.
993		ctx.AddDependency(module, implLibraryTag, module.implLibraryModuleName())
994
995		if module.sharedLibrary() {
996			// Add dependency to the rule for generating the xml permissions file
997			ctx.AddDependency(module, xmlPermissionsFileTag, module.xmlPermissionsModuleName())
998		}
999	}
1000}
1001
1002// Add other dependencies as normal.
1003func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
1004	if module.requiresRuntimeImplementationLibrary() {
1005		// Only add the deps for the library if it is actually going to be built.
1006		module.Library.deps(ctx)
1007	}
1008}
1009
1010func (module *SdkLibrary) OutputFiles(tag string) (android.Paths, error) {
1011	paths, err := module.commonOutputFiles(tag)
1012	if paths == nil && err == nil {
1013		return module.Library.OutputFiles(tag)
1014	} else {
1015		return paths, err
1016	}
1017}
1018
1019func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
1020	// Only build an implementation library if required.
1021	if module.requiresRuntimeImplementationLibrary() {
1022		module.Library.GenerateAndroidBuildActions(ctx)
1023	}
1024
1025	// Record the paths to the header jars of the library (stubs and impl).
1026	// When this java_sdk_library is depended upon from others via "libs" property,
1027	// the recorded paths will be returned depending on the link type of the caller.
1028	ctx.VisitDirectDeps(func(to android.Module) {
1029		tag := ctx.OtherModuleDependencyTag(to)
1030
1031		// Extract information from any of the scope specific dependencies.
1032		if scopeTag, ok := tag.(scopeDependencyTag); ok {
1033			apiScope := scopeTag.apiScope
1034			scopePaths := module.getScopePathsCreateIfNeeded(apiScope)
1035
1036			// Extract information from the dependency. The exact information extracted
1037			// is determined by the nature of the dependency which is determined by the tag.
1038			scopeTag.extractDepInfo(ctx, to, scopePaths)
1039		}
1040	})
1041}
1042
1043func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries {
1044	if !module.requiresRuntimeImplementationLibrary() {
1045		return nil
1046	}
1047	entriesList := module.Library.AndroidMkEntries()
1048	if module.sharedLibrary() {
1049		entries := &entriesList[0]
1050		entries.Required = append(entries.Required, module.xmlPermissionsModuleName())
1051	}
1052	return entriesList
1053}
1054
1055// The dist path of the stub artifacts
1056func (module *SdkLibrary) apiDistPath(apiScope *apiScope) string {
1057	if module.ModuleBase.Owner() != "" {
1058		return path.Join("apistubs", module.ModuleBase.Owner(), apiScope.name)
1059	} else if Bool(module.sdkLibraryProperties.Core_lib) {
1060		return path.Join("apistubs", "core", apiScope.name)
1061	} else {
1062		return path.Join("apistubs", "android", apiScope.name)
1063	}
1064}
1065
1066// Get the sdk version for use when compiling the stubs library.
1067func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.EarlyModuleContext, apiScope *apiScope) string {
1068	scopeProperties := module.scopeToProperties[apiScope]
1069	if scopeProperties.Sdk_version != nil {
1070		return proptools.String(scopeProperties.Sdk_version)
1071	}
1072
1073	sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
1074	if sdkDep.hasStandardLibs() {
1075		// If building against a standard sdk then use the sdk version appropriate for the scope.
1076		return apiScope.sdkVersion
1077	} else {
1078		// Otherwise, use no system module.
1079		return "none"
1080	}
1081}
1082
1083func (module *SdkLibrary) latestApiFilegroupName(apiScope *apiScope) string {
1084	return ":" + module.BaseModuleName() + ".api." + apiScope.name + ".latest"
1085}
1086
1087func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope *apiScope) string {
1088	return ":" + module.BaseModuleName() + "-removed.api." + apiScope.name + ".latest"
1089}
1090
1091// Creates the implementation java library
1092func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) {
1093
1094	moduleNamePtr := proptools.StringPtr(module.BaseModuleName())
1095
1096	props := struct {
1097		Name              *string
1098		Visibility        []string
1099		Instrument        bool
1100		ConfigurationName *string
1101	}{
1102		Name:       proptools.StringPtr(module.implLibraryModuleName()),
1103		Visibility: module.sdkLibraryProperties.Impl_library_visibility,
1104		// Set the instrument property to ensure it is instrumented when instrumentation is required.
1105		Instrument: true,
1106
1107		// Make the created library behave as if it had the same name as this module.
1108		ConfigurationName: moduleNamePtr,
1109	}
1110
1111	properties := []interface{}{
1112		&module.properties,
1113		&module.protoProperties,
1114		&module.deviceProperties,
1115		&module.dexpreoptProperties,
1116		&module.linter.properties,
1117		&props,
1118		module.sdkComponentPropertiesForChildLibrary(),
1119	}
1120	mctx.CreateModule(LibraryFactory, properties...)
1121}
1122
1123// Creates a static java library that has API stubs
1124func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
1125	props := struct {
1126		Name              *string
1127		Visibility        []string
1128		Srcs              []string
1129		Installable       *bool
1130		Sdk_version       *string
1131		System_modules    *string
1132		Patch_module      *string
1133		Libs              []string
1134		Compile_dex       *bool
1135		Java_version      *string
1136		Product_variables struct {
1137			Pdk struct {
1138				Enabled *bool
1139			}
1140		}
1141		Openjdk9 struct {
1142			Srcs       []string
1143			Javacflags []string
1144		}
1145		Dist struct {
1146			Targets []string
1147			Dest    *string
1148			Dir     *string
1149			Tag     *string
1150		}
1151	}{}
1152
1153	props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
1154
1155	// If stubs_library_visibility is not set then the created module will use the
1156	// visibility of this module.
1157	visibility := module.sdkLibraryProperties.Stubs_library_visibility
1158	props.Visibility = visibility
1159
1160	// sources are generated from the droiddoc
1161	props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)}
1162	sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
1163	props.Sdk_version = proptools.StringPtr(sdkVersion)
1164	props.System_modules = module.deviceProperties.System_modules
1165	props.Patch_module = module.properties.Patch_module
1166	props.Installable = proptools.BoolPtr(false)
1167	props.Libs = module.sdkLibraryProperties.Stub_only_libs
1168	props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false)
1169	props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs
1170	props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags
1171	// We compile the stubs for 1.8 in line with the main android.jar stubs, and potential
1172	// interop with older developer tools that don't support 1.9.
1173	props.Java_version = proptools.StringPtr("1.8")
1174	if module.deviceProperties.Compile_dex != nil {
1175		props.Compile_dex = module.deviceProperties.Compile_dex
1176	}
1177
1178	// Dist the class jar artifact for sdk builds.
1179	if !Bool(module.sdkLibraryProperties.No_dist) {
1180		props.Dist.Targets = []string{"sdk", "win_sdk"}
1181		props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.BaseModuleName()))
1182		props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
1183		props.Dist.Tag = proptools.StringPtr(".jar")
1184	}
1185
1186	mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
1187}
1188
1189// Creates a droidstubs module that creates stubs source files from the given full source
1190// files and also updates and checks the API specification files.
1191func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope, name string, scopeSpecificDroidstubsArgs []string) {
1192	props := struct {
1193		Name                             *string
1194		Visibility                       []string
1195		Srcs                             []string
1196		Installable                      *bool
1197		Sdk_version                      *string
1198		System_modules                   *string
1199		Libs                             []string
1200		Arg_files                        []string
1201		Args                             *string
1202		Java_version                     *string
1203		Merge_annotations_dirs           []string
1204		Merge_inclusion_annotations_dirs []string
1205		Generate_stubs                   *bool
1206		Check_api                        struct {
1207			Current                   ApiToCheck
1208			Last_released             ApiToCheck
1209			Ignore_missing_latest_api *bool
1210
1211			Api_lint struct {
1212				Enabled       *bool
1213				New_since     *string
1214				Baseline_file *string
1215			}
1216		}
1217		Aidl struct {
1218			Include_dirs       []string
1219			Local_include_dirs []string
1220		}
1221		Dist struct {
1222			Targets []string
1223			Dest    *string
1224			Dir     *string
1225		}
1226	}{}
1227
1228	// The stubs source processing uses the same compile time classpath when extracting the
1229	// API from the implementation library as it does when compiling it. i.e. the same
1230	// * sdk version
1231	// * system_modules
1232	// * libs (static_libs/libs)
1233
1234	props.Name = proptools.StringPtr(name)
1235
1236	// If stubs_source_visibility is not set then the created module will use the
1237	// visibility of this module.
1238	visibility := module.sdkLibraryProperties.Stubs_source_visibility
1239	props.Visibility = visibility
1240
1241	props.Srcs = append(props.Srcs, module.properties.Srcs...)
1242	props.Sdk_version = module.deviceProperties.Sdk_version
1243	props.System_modules = module.deviceProperties.System_modules
1244	props.Installable = proptools.BoolPtr(false)
1245	// A droiddoc module has only one Libs property and doesn't distinguish between
1246	// shared libs and static libs. So we need to add both of these libs to Libs property.
1247	props.Libs = module.properties.Libs
1248	props.Libs = append(props.Libs, module.properties.Static_libs...)
1249	props.Aidl.Include_dirs = module.deviceProperties.Aidl.Include_dirs
1250	props.Aidl.Local_include_dirs = module.deviceProperties.Aidl.Local_include_dirs
1251	props.Java_version = module.properties.Java_version
1252
1253	props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs
1254	props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs
1255
1256	droidstubsArgs := []string{}
1257	if len(module.sdkLibraryProperties.Api_packages) != 0 {
1258		droidstubsArgs = append(droidstubsArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":"))
1259	}
1260	if len(module.sdkLibraryProperties.Hidden_api_packages) != 0 {
1261		droidstubsArgs = append(droidstubsArgs,
1262			android.JoinWithPrefix(module.sdkLibraryProperties.Hidden_api_packages, " --hide-package "))
1263	}
1264	droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...)
1265	disabledWarnings := []string{
1266		"MissingPermission",
1267		"BroadcastBehavior",
1268		"HiddenSuperclass",
1269		"DeprecationMismatch",
1270		"UnavailableSymbol",
1271		"SdkConstant",
1272		"HiddenTypeParameter",
1273		"Todo",
1274		"Typo",
1275	}
1276	droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
1277
1278	// Add in scope specific arguments.
1279	droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...)
1280	props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
1281	props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " "))
1282
1283	// List of APIs identified from the provided source files are created. They are later
1284	// compared against to the not-yet-released (a.k.a current) list of APIs and to the
1285	// last-released (a.k.a numbered) list of API.
1286	currentApiFileName := apiScope.apiFilePrefix + "current.txt"
1287	removedApiFileName := apiScope.apiFilePrefix + "removed.txt"
1288	apiDir := module.getApiDir()
1289	currentApiFileName = path.Join(apiDir, currentApiFileName)
1290	removedApiFileName = path.Join(apiDir, removedApiFileName)
1291
1292	// check against the not-yet-release API
1293	props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
1294	props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
1295
1296	if !apiScope.unstable {
1297		// check against the latest released API
1298		latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope))
1299		props.Check_api.Last_released.Api_file = latestApiFilegroupName
1300		props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
1301			module.latestRemovedApiFilegroupName(apiScope))
1302		props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
1303
1304		if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) {
1305			// Enable api lint.
1306			props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true)
1307			props.Check_api.Api_lint.New_since = latestApiFilegroupName
1308
1309			// If it exists then pass a lint-baseline.txt through to droidstubs.
1310			baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt")
1311			baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath)
1312			paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil)
1313			if err != nil {
1314				mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err)
1315			}
1316			if len(paths) == 1 {
1317				props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath)
1318			} else if len(paths) != 0 {
1319				mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths)
1320			}
1321		}
1322	}
1323
1324	// Dist the api txt artifact for sdk builds.
1325	if !Bool(module.sdkLibraryProperties.No_dist) {
1326		props.Dist.Targets = []string{"sdk", "win_sdk"}
1327		props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.txt", module.BaseModuleName()))
1328		props.Dist.Dir = proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
1329	}
1330
1331	mctx.CreateModule(DroidstubsFactory, &props)
1332}
1333
1334func (module *SdkLibrary) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool {
1335	depTag := mctx.OtherModuleDependencyTag(dep)
1336	if depTag == xmlPermissionsFileTag {
1337		return true
1338	}
1339	return module.Library.DepIsInSameApex(mctx, dep)
1340}
1341
1342// Creates the xml file that publicizes the runtime library
1343func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) {
1344	props := struct {
1345		Name           *string
1346		Lib_name       *string
1347		Apex_available []string
1348	}{
1349		Name:           proptools.StringPtr(module.xmlPermissionsModuleName()),
1350		Lib_name:       proptools.StringPtr(module.BaseModuleName()),
1351		Apex_available: module.ApexProperties.Apex_available,
1352	}
1353
1354	mctx.CreateModule(sdkLibraryXmlFactory, &props)
1355}
1356
1357func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s sdkSpec) android.Paths {
1358	var ver sdkVersion
1359	var kind sdkKind
1360	if s.usePrebuilt(ctx) {
1361		ver = s.version
1362		kind = s.kind
1363	} else {
1364		// We don't have prebuilt SDK for the specific sdkVersion.
1365		// Instead of breaking the build, fallback to use "system_current"
1366		ver = sdkVersionCurrent
1367		kind = sdkSystem
1368	}
1369
1370	dir := filepath.Join("prebuilts", "sdk", ver.String(), kind.String())
1371	jar := filepath.Join(dir, baseName+".jar")
1372	jarPath := android.ExistentPathForSource(ctx, jar)
1373	if !jarPath.Valid() {
1374		if ctx.Config().AllowMissingDependencies() {
1375			return android.Paths{android.PathForSource(ctx, jar)}
1376		} else {
1377			ctx.PropertyErrorf("sdk_library", "invalid sdk version %q, %q does not exist", s.raw, jar)
1378		}
1379		return nil
1380	}
1381	return android.Paths{jarPath.Path()}
1382}
1383
1384// Get the apex name for module, "" if it is for platform.
1385func getApexNameForModule(module android.Module) string {
1386	if apex, ok := module.(android.ApexModule); ok {
1387		return apex.ApexName()
1388	}
1389
1390	return ""
1391}
1392
1393// Check to see if the other module is within the same named APEX as this module.
1394//
1395// If either this or the other module are on the platform then this will return
1396// false.
1397func withinSameApexAs(module android.ApexModule, other android.Module) bool {
1398	name := module.ApexName()
1399	return name != "" && getApexNameForModule(other) == name
1400}
1401
1402func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths {
1403	// If the client doesn't set sdk_version, but if this library prefers stubs over
1404	// the impl library, let's provide the widest API surface possible. To do so,
1405	// force override sdk_version to module_current so that the closest possible API
1406	// surface could be found in selectHeaderJarsForSdkVersion
1407	if module.defaultsToStubs() && !sdkVersion.specified() {
1408		sdkVersion = sdkSpecFrom("module_current")
1409	}
1410
1411	// Only provide access to the implementation library if it is actually built.
1412	if module.requiresRuntimeImplementationLibrary() {
1413		// Check any special cases for java_sdk_library.
1414		//
1415		// Only allow access to the implementation library in the following condition:
1416		// * No sdk_version specified on the referencing module.
1417		// * The referencing module is in the same apex as this.
1418		if sdkVersion.kind == sdkPrivate || withinSameApexAs(module, ctx.Module()) {
1419			if headerJars {
1420				return module.HeaderJars()
1421			} else {
1422				return module.ImplementationJars()
1423			}
1424		}
1425	}
1426
1427	return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion)
1428}
1429
1430// to satisfy SdkLibraryDependency interface
1431func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
1432	return module.sdkJars(ctx, sdkVersion, true /*headerJars*/)
1433}
1434
1435// to satisfy SdkLibraryDependency interface
1436func (module *SdkLibrary) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
1437	return module.sdkJars(ctx, sdkVersion, false /*headerJars*/)
1438}
1439
1440func (module *SdkLibrary) SetNoDist() {
1441	module.sdkLibraryProperties.No_dist = proptools.BoolPtr(true)
1442}
1443
1444var javaSdkLibrariesKey = android.NewOnceKey("javaSdkLibraries")
1445
1446func javaSdkLibraries(config android.Config) *[]string {
1447	return config.Once(javaSdkLibrariesKey, func() interface{} {
1448		return &[]string{}
1449	}).(*[]string)
1450}
1451
1452func (module *SdkLibrary) getApiDir() string {
1453	return proptools.StringDefault(module.sdkLibraryProperties.Api_dir, "api")
1454}
1455
1456// For a java_sdk_library module, create internal modules for stubs, docs,
1457// runtime libs and xml file. If requested, the stubs and docs are created twice
1458// once for public API level and once for system API level
1459func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookContext) {
1460	// If the module has been disabled then don't create any child modules.
1461	if !module.Enabled() {
1462		return
1463	}
1464
1465	if len(module.properties.Srcs) == 0 {
1466		mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs")
1467		return
1468	}
1469
1470	// If this builds against standard libraries (i.e. is not part of the core libraries)
1471	// then assume it provides both system and test apis. Otherwise, assume it does not and
1472	// also assume it does not contribute to the dist build.
1473	sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
1474	hasSystemAndTestApis := sdkDep.hasStandardLibs()
1475	module.sdkLibraryProperties.Generate_system_and_test_apis = hasSystemAndTestApis
1476	module.sdkLibraryProperties.No_dist = proptools.BoolPtr(!hasSystemAndTestApis)
1477
1478	missing_current_api := false
1479
1480	generatedScopes := module.getGeneratedApiScopes(mctx)
1481
1482	apiDir := module.getApiDir()
1483	for _, scope := range generatedScopes {
1484		for _, api := range []string{"current.txt", "removed.txt"} {
1485			path := path.Join(mctx.ModuleDir(), apiDir, scope.apiFilePrefix+api)
1486			p := android.ExistentPathForSource(mctx, path)
1487			if !p.Valid() {
1488				mctx.ModuleErrorf("Current api file %#v doesn't exist", path)
1489				missing_current_api = true
1490			}
1491		}
1492	}
1493
1494	if missing_current_api {
1495		script := "build/soong/scripts/gen-java-current-api-files.sh"
1496		p := android.ExistentPathForSource(mctx, script)
1497
1498		if !p.Valid() {
1499			panic(fmt.Sprintf("script file %s doesn't exist", script))
1500		}
1501
1502		mctx.ModuleErrorf("One or more current api files are missing. "+
1503			"You can update them by:\n"+
1504			"%s %q %s && m update-api",
1505			script, filepath.Join(mctx.ModuleDir(), apiDir),
1506			strings.Join(generatedScopes.Strings(func(s *apiScope) string { return s.apiFilePrefix }), " "))
1507		return
1508	}
1509
1510	for _, scope := range generatedScopes {
1511		// Use the stubs source name for legacy reasons.
1512		module.createStubsSourcesAndApi(mctx, scope, module.stubsSourceModuleName(scope), scope.droidstubsArgs)
1513
1514		module.createStubsLibrary(mctx, scope)
1515	}
1516
1517	if module.requiresRuntimeImplementationLibrary() {
1518		// Create child module to create an implementation library.
1519		//
1520		// This temporarily creates a second implementation library that can be explicitly
1521		// referenced.
1522		//
1523		// TODO(b/156618935) - update comment once only one implementation library is created.
1524		module.createImplLibrary(mctx)
1525
1526		// Only create an XML permissions file that declares the library as being usable
1527		// as a shared library if required.
1528		if module.sharedLibrary() {
1529			module.createXmlFile(mctx)
1530		}
1531
1532		// record java_sdk_library modules so that they are exported to make
1533		javaSdkLibraries := javaSdkLibraries(mctx.Config())
1534		javaSdkLibrariesLock.Lock()
1535		defer javaSdkLibrariesLock.Unlock()
1536		*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
1537	}
1538}
1539
1540func (module *SdkLibrary) InitSdkLibraryProperties() {
1541	module.addHostAndDeviceProperties()
1542	module.AddProperties(&module.sdkLibraryProperties)
1543
1544	module.initSdkLibraryComponent(&module.ModuleBase)
1545
1546	module.properties.Installable = proptools.BoolPtr(true)
1547	module.deviceProperties.IsSDKLibrary = true
1548}
1549
1550func (module *SdkLibrary) requiresRuntimeImplementationLibrary() bool {
1551	return !proptools.Bool(module.sdkLibraryProperties.Api_only)
1552}
1553
1554func (module *SdkLibrary) defaultsToStubs() bool {
1555	return proptools.Bool(module.sdkLibraryProperties.Default_to_stubs)
1556}
1557
1558// Defines how to name the individual component modules the sdk library creates.
1559type sdkLibraryComponentNamingScheme interface {
1560	stubsLibraryModuleName(scope *apiScope, baseName string) string
1561
1562	stubsSourceModuleName(scope *apiScope, baseName string) string
1563
1564	apiModuleName(scope *apiScope, baseName string) string
1565}
1566
1567type defaultNamingScheme struct {
1568}
1569
1570func (s *defaultNamingScheme) stubsLibraryModuleName(scope *apiScope, baseName string) string {
1571	return scope.stubsLibraryModuleName(baseName)
1572}
1573
1574func (s *defaultNamingScheme) stubsSourceModuleName(scope *apiScope, baseName string) string {
1575	return scope.stubsSourceModuleName(baseName)
1576}
1577
1578func (s *defaultNamingScheme) apiModuleName(scope *apiScope, baseName string) string {
1579	return scope.apiModuleName(baseName)
1580}
1581
1582var _ sdkLibraryComponentNamingScheme = (*defaultNamingScheme)(nil)
1583
1584type frameworkModulesNamingScheme struct {
1585}
1586
1587func (s *frameworkModulesNamingScheme) moduleSuffix(scope *apiScope) string {
1588	suffix := scope.name
1589	if scope == apiScopeModuleLib {
1590		suffix = "module_libs_"
1591	}
1592	return suffix
1593}
1594
1595func (s *frameworkModulesNamingScheme) stubsLibraryModuleName(scope *apiScope, baseName string) string {
1596	return fmt.Sprintf("%s-stubs-%sapi", baseName, s.moduleSuffix(scope))
1597}
1598
1599func (s *frameworkModulesNamingScheme) stubsSourceModuleName(scope *apiScope, baseName string) string {
1600	return fmt.Sprintf("%s-stubs-srcs-%sapi", baseName, s.moduleSuffix(scope))
1601}
1602
1603func (s *frameworkModulesNamingScheme) apiModuleName(scope *apiScope, baseName string) string {
1604	return fmt.Sprintf("%s-api-%sapi", baseName, s.moduleSuffix(scope))
1605}
1606
1607var _ sdkLibraryComponentNamingScheme = (*frameworkModulesNamingScheme)(nil)
1608
1609func moduleStubLinkType(name string) (stub bool, ret linkType) {
1610	// This suffix-based approach is fragile and could potentially mis-trigger.
1611	// TODO(b/155164730): Clean this up when modules no longer reference sdk_lib stubs directly.
1612	if strings.HasSuffix(name, ".stubs.public") || strings.HasSuffix(name, "-stubs-publicapi") {
1613		return true, javaSdk
1614	}
1615	if strings.HasSuffix(name, ".stubs.system") || strings.HasSuffix(name, "-stubs-systemapi") {
1616		return true, javaSystem
1617	}
1618	if strings.HasSuffix(name, ".stubs.module_lib") || strings.HasSuffix(name, "-stubs-module_libs_api") {
1619		return true, javaModule
1620	}
1621	if strings.HasSuffix(name, ".stubs.test") {
1622		return true, javaSystem
1623	}
1624	return false, javaPlatform
1625}
1626
1627// java_sdk_library is a special Java library that provides optional platform APIs to apps.
1628// In practice, it can be viewed as a combination of several modules: 1) stubs library that clients
1629// are linked against to, 2) droiddoc module that internally generates API stubs source files,
1630// 3) the real runtime shared library that implements the APIs, and 4) XML file for adding
1631// the runtime lib to the classpath at runtime if requested via <uses-library>.
1632func SdkLibraryFactory() android.Module {
1633	module := &SdkLibrary{}
1634
1635	// Initialize information common between source and prebuilt.
1636	module.initCommon(&module.ModuleBase)
1637
1638	module.InitSdkLibraryProperties()
1639	android.InitApexModule(module)
1640	InitJavaModule(module, android.HostAndDeviceSupported)
1641
1642	// Initialize the map from scope to scope specific properties.
1643	scopeToProperties := make(map[*apiScope]*ApiScopeProperties)
1644	for _, scope := range allApiScopes {
1645		scopeToProperties[scope] = scope.scopeSpecificProperties(module)
1646	}
1647	module.scopeToProperties = scopeToProperties
1648
1649	// Add the properties containing visibility rules so that they are checked.
1650	android.AddVisibilityProperty(module, "impl_library_visibility", &module.sdkLibraryProperties.Impl_library_visibility)
1651	android.AddVisibilityProperty(module, "stubs_library_visibility", &module.sdkLibraryProperties.Stubs_library_visibility)
1652	android.AddVisibilityProperty(module, "stubs_source_visibility", &module.sdkLibraryProperties.Stubs_source_visibility)
1653
1654	module.SetDefaultableHook(func(ctx android.DefaultableHookContext) {
1655		// If no implementation is required then it cannot be used as a shared library
1656		// either.
1657		if !module.requiresRuntimeImplementationLibrary() {
1658			// If shared_library has been explicitly set to true then it is incompatible
1659			// with api_only: true.
1660			if proptools.Bool(module.commonSdkLibraryProperties.Shared_library) {
1661				ctx.PropertyErrorf("api_only/shared_library", "inconsistent settings, shared_library and api_only cannot both be true")
1662			}
1663			// Set shared_library: false.
1664			module.commonSdkLibraryProperties.Shared_library = proptools.BoolPtr(false)
1665		}
1666
1667		if module.initCommonAfterDefaultsApplied(ctx) {
1668			module.CreateInternalModules(ctx)
1669		}
1670	})
1671	return module
1672}
1673
1674//
1675// SDK library prebuilts
1676//
1677
1678// Properties associated with each api scope.
1679type sdkLibraryScopeProperties struct {
1680	Jars []string `android:"path"`
1681
1682	Sdk_version *string
1683
1684	// List of shared java libs that this module has dependencies to
1685	Libs []string
1686
1687	// The stubs source.
1688	Stub_srcs []string `android:"path"`
1689
1690	// The current.txt
1691	Current_api *string `android:"path"`
1692
1693	// The removed.txt
1694	Removed_api *string `android:"path"`
1695}
1696
1697type sdkLibraryImportProperties struct {
1698	// List of shared java libs, common to all scopes, that this module has
1699	// dependencies to
1700	Libs []string
1701}
1702
1703type SdkLibraryImport struct {
1704	android.ModuleBase
1705	android.DefaultableModuleBase
1706	prebuilt android.Prebuilt
1707	android.ApexModuleBase
1708	android.SdkBase
1709
1710	properties sdkLibraryImportProperties
1711
1712	// Map from api scope to the scope specific property structure.
1713	scopeProperties map[*apiScope]*sdkLibraryScopeProperties
1714
1715	commonToSdkLibraryAndImport
1716
1717	// The reference to the implementation library created by the source module.
1718	// Is nil if the source module does not exist.
1719	implLibraryModule *Library
1720
1721	// The reference to the xml permissions module created by the source module.
1722	// Is nil if the source module does not exist.
1723	xmlPermissionsFileModule *sdkLibraryXml
1724}
1725
1726var _ SdkLibraryDependency = (*SdkLibraryImport)(nil)
1727
1728// The type of a structure that contains a field of type sdkLibraryScopeProperties
1729// for each apiscope in allApiScopes, e.g. something like:
1730// struct {
1731//   Public sdkLibraryScopeProperties
1732//   System sdkLibraryScopeProperties
1733//   ...
1734// }
1735var allScopeStructType = createAllScopePropertiesStructType()
1736
1737// Dynamically create a structure type for each apiscope in allApiScopes.
1738func createAllScopePropertiesStructType() reflect.Type {
1739	var fields []reflect.StructField
1740	for _, apiScope := range allApiScopes {
1741		field := reflect.StructField{
1742			Name: apiScope.fieldName,
1743			Type: reflect.TypeOf(sdkLibraryScopeProperties{}),
1744		}
1745		fields = append(fields, field)
1746	}
1747
1748	return reflect.StructOf(fields)
1749}
1750
1751// Create an instance of the scope specific structure type and return a map
1752// from apiscope to a pointer to each scope specific field.
1753func createPropertiesInstance() (interface{}, map[*apiScope]*sdkLibraryScopeProperties) {
1754	allScopePropertiesPtr := reflect.New(allScopeStructType)
1755	allScopePropertiesStruct := allScopePropertiesPtr.Elem()
1756	scopeProperties := make(map[*apiScope]*sdkLibraryScopeProperties)
1757
1758	for _, apiScope := range allApiScopes {
1759		field := allScopePropertiesStruct.FieldByName(apiScope.fieldName)
1760		scopeProperties[apiScope] = field.Addr().Interface().(*sdkLibraryScopeProperties)
1761	}
1762
1763	return allScopePropertiesPtr.Interface(), scopeProperties
1764}
1765
1766// java_sdk_library_import imports a prebuilt java_sdk_library.
1767func sdkLibraryImportFactory() android.Module {
1768	module := &SdkLibraryImport{}
1769
1770	allScopeProperties, scopeToProperties := createPropertiesInstance()
1771	module.scopeProperties = scopeToProperties
1772	module.AddProperties(&module.properties, allScopeProperties)
1773
1774	// Initialize information common between source and prebuilt.
1775	module.initCommon(&module.ModuleBase)
1776
1777	android.InitPrebuiltModule(module, &[]string{""})
1778	android.InitApexModule(module)
1779	android.InitSdkAwareModule(module)
1780	InitJavaModule(module, android.HostAndDeviceSupported)
1781
1782	module.SetDefaultableHook(func(mctx android.DefaultableHookContext) {
1783		if module.initCommonAfterDefaultsApplied(mctx) {
1784			module.createInternalModules(mctx)
1785		}
1786	})
1787	return module
1788}
1789
1790func (module *SdkLibraryImport) Prebuilt() *android.Prebuilt {
1791	return &module.prebuilt
1792}
1793
1794func (module *SdkLibraryImport) Name() string {
1795	return module.prebuilt.Name(module.ModuleBase.Name())
1796}
1797
1798func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHookContext) {
1799
1800	// If the build is configured to use prebuilts then force this to be preferred.
1801	if mctx.Config().UnbundledBuildUsePrebuiltSdks() {
1802		module.prebuilt.ForcePrefer()
1803	}
1804
1805	for apiScope, scopeProperties := range module.scopeProperties {
1806		if len(scopeProperties.Jars) == 0 {
1807			continue
1808		}
1809
1810		module.createJavaImportForStubs(mctx, apiScope, scopeProperties)
1811
1812		if len(scopeProperties.Stub_srcs) > 0 {
1813			module.createPrebuiltStubsSources(mctx, apiScope, scopeProperties)
1814		}
1815	}
1816
1817	javaSdkLibraries := javaSdkLibraries(mctx.Config())
1818	javaSdkLibrariesLock.Lock()
1819	defer javaSdkLibrariesLock.Unlock()
1820	*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
1821}
1822
1823func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
1824	// Creates a java import for the jar with ".stubs" suffix
1825	props := struct {
1826		Name        *string
1827		Sdk_version *string
1828		Libs        []string
1829		Jars        []string
1830		Prefer      *bool
1831	}{}
1832	props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
1833	props.Sdk_version = scopeProperties.Sdk_version
1834	// Prepend any of the libs from the legacy public properties to the libs for each of the
1835	// scopes to avoid having to duplicate them in each scope.
1836	props.Libs = append(module.properties.Libs, scopeProperties.Libs...)
1837	props.Jars = scopeProperties.Jars
1838
1839	// The imports are preferred if the java_sdk_library_import is preferred.
1840	props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer())
1841
1842	mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
1843}
1844
1845func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
1846	props := struct {
1847		Name   *string
1848		Srcs   []string
1849		Prefer *bool
1850	}{}
1851	props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope))
1852	props.Srcs = scopeProperties.Stub_srcs
1853	mctx.CreateModule(PrebuiltStubsSourcesFactory, &props)
1854
1855	// The stubs source is preferred if the java_sdk_library_import is preferred.
1856	props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer())
1857}
1858
1859// Add the dependencies on the child module in the component deps mutator so that it
1860// creates references to the prebuilt and not the source modules.
1861func (module *SdkLibraryImport) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
1862	for apiScope, scopeProperties := range module.scopeProperties {
1863		if len(scopeProperties.Jars) == 0 {
1864			continue
1865		}
1866
1867		// Add dependencies to the prebuilt stubs library
1868		ctx.AddVariationDependencies(nil, apiScope.stubsTag, "prebuilt_"+module.stubsLibraryModuleName(apiScope))
1869
1870		if len(scopeProperties.Stub_srcs) > 0 {
1871			// Add dependencies to the prebuilt stubs source library
1872			ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, "prebuilt_"+module.stubsSourceModuleName(apiScope))
1873		}
1874	}
1875}
1876
1877// Add other dependencies as normal.
1878func (module *SdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
1879
1880	implName := module.implLibraryModuleName()
1881	if ctx.OtherModuleExists(implName) {
1882		ctx.AddVariationDependencies(nil, implLibraryTag, implName)
1883
1884		xmlPermissionsModuleName := module.xmlPermissionsModuleName()
1885		if module.sharedLibrary() && ctx.OtherModuleExists(xmlPermissionsModuleName) {
1886			// Add dependency to the rule for generating the xml permissions file
1887			ctx.AddDependency(module, xmlPermissionsFileTag, xmlPermissionsModuleName)
1888		}
1889	}
1890}
1891
1892func (module *SdkLibraryImport) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool {
1893	depTag := mctx.OtherModuleDependencyTag(dep)
1894	if depTag == xmlPermissionsFileTag {
1895		return true
1896	}
1897
1898	// None of the other dependencies of the java_sdk_library_import are in the same apex
1899	// as the one that references this module.
1900	return false
1901}
1902
1903func (module *SdkLibraryImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
1904	// we don't check prebuilt modules for sdk_version
1905	return nil
1906}
1907
1908func (module *SdkLibraryImport) OutputFiles(tag string) (android.Paths, error) {
1909	return module.commonOutputFiles(tag)
1910}
1911
1912func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
1913	// Record the paths to the prebuilt stubs library and stubs source.
1914	ctx.VisitDirectDeps(func(to android.Module) {
1915		tag := ctx.OtherModuleDependencyTag(to)
1916
1917		// Extract information from any of the scope specific dependencies.
1918		if scopeTag, ok := tag.(scopeDependencyTag); ok {
1919			apiScope := scopeTag.apiScope
1920			scopePaths := module.getScopePathsCreateIfNeeded(apiScope)
1921
1922			// Extract information from the dependency. The exact information extracted
1923			// is determined by the nature of the dependency which is determined by the tag.
1924			scopeTag.extractDepInfo(ctx, to, scopePaths)
1925		} else if tag == implLibraryTag {
1926			if implLibrary, ok := to.(*Library); ok {
1927				module.implLibraryModule = implLibrary
1928			} else {
1929				ctx.ModuleErrorf("implementation library must be of type *java.Library but was %T", to)
1930			}
1931		} else if tag == xmlPermissionsFileTag {
1932			if xmlPermissionsFileModule, ok := to.(*sdkLibraryXml); ok {
1933				module.xmlPermissionsFileModule = xmlPermissionsFileModule
1934			} else {
1935				ctx.ModuleErrorf("xml permissions file module must be of type *sdkLibraryXml but was %T", to)
1936			}
1937		}
1938	})
1939
1940	// Populate the scope paths with information from the properties.
1941	for apiScope, scopeProperties := range module.scopeProperties {
1942		if len(scopeProperties.Jars) == 0 {
1943			continue
1944		}
1945
1946		paths := module.getScopePathsCreateIfNeeded(apiScope)
1947		paths.currentApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Current_api)
1948		paths.removedApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Removed_api)
1949	}
1950}
1951
1952func (module *SdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths {
1953
1954	// For consistency with SdkLibrary make the implementation jar available to libraries that
1955	// are within the same APEX.
1956	implLibraryModule := module.implLibraryModule
1957	if implLibraryModule != nil && withinSameApexAs(module, ctx.Module()) {
1958		if headerJars {
1959			return implLibraryModule.HeaderJars()
1960		} else {
1961			return implLibraryModule.ImplementationJars()
1962		}
1963	}
1964
1965	return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion)
1966}
1967
1968// to satisfy SdkLibraryDependency interface
1969func (module *SdkLibraryImport) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
1970	// This module is just a wrapper for the prebuilt stubs.
1971	return module.sdkJars(ctx, sdkVersion, true)
1972}
1973
1974// to satisfy SdkLibraryDependency interface
1975func (module *SdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
1976	// This module is just a wrapper for the stubs.
1977	return module.sdkJars(ctx, sdkVersion, false)
1978}
1979
1980// to satisfy apex.javaDependency interface
1981func (module *SdkLibraryImport) DexJarBuildPath() android.Path {
1982	if module.implLibraryModule == nil {
1983		return nil
1984	} else {
1985		return module.implLibraryModule.DexJarBuildPath()
1986	}
1987}
1988
1989// to satisfy apex.javaDependency interface
1990func (module *SdkLibraryImport) JacocoReportClassesFile() android.Path {
1991	if module.implLibraryModule == nil {
1992		return nil
1993	} else {
1994		return module.implLibraryModule.JacocoReportClassesFile()
1995	}
1996}
1997
1998// to satisfy apex.javaDependency interface
1999func (module *SdkLibraryImport) LintDepSets() LintDepSets {
2000	if module.implLibraryModule == nil {
2001		return LintDepSets{}
2002	} else {
2003		return module.implLibraryModule.LintDepSets()
2004	}
2005}
2006
2007// to satisfy apex.javaDependency interface
2008func (module *SdkLibraryImport) Stem() string {
2009	return module.BaseModuleName()
2010}
2011
2012var _ ApexDependency = (*SdkLibraryImport)(nil)
2013
2014// to satisfy java.ApexDependency interface
2015func (module *SdkLibraryImport) HeaderJars() android.Paths {
2016	if module.implLibraryModule == nil {
2017		return nil
2018	} else {
2019		return module.implLibraryModule.HeaderJars()
2020	}
2021}
2022
2023// to satisfy java.ApexDependency interface
2024func (module *SdkLibraryImport) ImplementationAndResourcesJars() android.Paths {
2025	if module.implLibraryModule == nil {
2026		return nil
2027	} else {
2028		return module.implLibraryModule.ImplementationAndResourcesJars()
2029	}
2030}
2031
2032//
2033// java_sdk_library_xml
2034//
2035type sdkLibraryXml struct {
2036	android.ModuleBase
2037	android.DefaultableModuleBase
2038	android.ApexModuleBase
2039
2040	properties sdkLibraryXmlProperties
2041
2042	outputFilePath android.OutputPath
2043	installDirPath android.InstallPath
2044}
2045
2046type sdkLibraryXmlProperties struct {
2047	// canonical name of the lib
2048	Lib_name *string
2049}
2050
2051// java_sdk_library_xml builds the permission xml file for a java_sdk_library.
2052// Not to be used directly by users. java_sdk_library internally uses this.
2053func sdkLibraryXmlFactory() android.Module {
2054	module := &sdkLibraryXml{}
2055
2056	module.AddProperties(&module.properties)
2057
2058	android.InitApexModule(module)
2059	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
2060
2061	return module
2062}
2063
2064// from android.PrebuiltEtcModule
2065func (module *sdkLibraryXml) SubDir() string {
2066	return "permissions"
2067}
2068
2069// from android.PrebuiltEtcModule
2070func (module *sdkLibraryXml) OutputFile() android.OutputPath {
2071	return module.outputFilePath
2072}
2073
2074// from android.ApexModule
2075func (module *sdkLibraryXml) AvailableFor(what string) bool {
2076	return true
2077}
2078
2079func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) {
2080	// do nothing
2081}
2082
2083func (module *sdkLibraryXml) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
2084	// sdkLibraryXml doesn't need to be checked separately because java_sdk_library is checked
2085	return nil
2086}
2087
2088// File path to the runtime implementation library
2089func (module *sdkLibraryXml) implPath() string {
2090	implName := proptools.String(module.properties.Lib_name)
2091	if apexName := module.ApexName(); apexName != "" {
2092		// TODO(b/146468504): ApexName() is only a soong module name, not apex name.
2093		// In most cases, this works fine. But when apex_name is set or override_apex is used
2094		// this can be wrong.
2095		return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexName, implName)
2096	}
2097	partition := "system"
2098	if module.SocSpecific() {
2099		partition = "vendor"
2100	} else if module.DeviceSpecific() {
2101		partition = "odm"
2102	} else if module.ProductSpecific() {
2103		partition = "product"
2104	} else if module.SystemExtSpecific() {
2105		partition = "system_ext"
2106	}
2107	return "/" + partition + "/framework/" + implName + ".jar"
2108}
2109
2110func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
2111	libName := proptools.String(module.properties.Lib_name)
2112	xmlContent := fmt.Sprintf(permissionsTemplate, libName, module.implPath())
2113
2114	module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath
2115	rule := android.NewRuleBuilder()
2116	rule.Command().
2117		Text("/bin/bash -c \"echo -e '" + xmlContent + "'\" > ").
2118		Output(module.outputFilePath)
2119
2120	rule.Build(pctx, ctx, "java_sdk_xml", "Permission XML")
2121
2122	module.installDirPath = android.PathForModuleInstall(ctx, "etc", module.SubDir())
2123}
2124
2125func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries {
2126	if !module.IsForPlatform() {
2127		return []android.AndroidMkEntries{android.AndroidMkEntries{
2128			Disabled: true,
2129		}}
2130	}
2131
2132	return []android.AndroidMkEntries{android.AndroidMkEntries{
2133		Class:      "ETC",
2134		OutputFile: android.OptionalPathForPath(module.outputFilePath),
2135		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
2136			func(entries *android.AndroidMkEntries) {
2137				entries.SetString("LOCAL_MODULE_TAGS", "optional")
2138				entries.SetString("LOCAL_MODULE_PATH", module.installDirPath.ToMakePath().String())
2139				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", module.outputFilePath.Base())
2140			},
2141		},
2142	}}
2143}
2144
2145type sdkLibrarySdkMemberType struct {
2146	android.SdkMemberTypeBase
2147}
2148
2149func (s *sdkLibrarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
2150	mctx.AddVariationDependencies(nil, dependencyTag, names...)
2151}
2152
2153func (s *sdkLibrarySdkMemberType) IsInstance(module android.Module) bool {
2154	_, ok := module.(*SdkLibrary)
2155	return ok
2156}
2157
2158func (s *sdkLibrarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
2159	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_sdk_library_import")
2160}
2161
2162func (s *sdkLibrarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
2163	return &sdkLibrarySdkMemberProperties{}
2164}
2165
2166type sdkLibrarySdkMemberProperties struct {
2167	android.SdkMemberPropertiesBase
2168
2169	// Scope to per scope properties.
2170	Scopes map[*apiScope]scopeProperties
2171
2172	// Additional libraries that the exported stubs libraries depend upon.
2173	Libs []string
2174
2175	// The Java stubs source files.
2176	Stub_srcs []string
2177
2178	// The naming scheme.
2179	Naming_scheme *string
2180
2181	// True if the java_sdk_library_import is for a shared library, false
2182	// otherwise.
2183	Shared_library *bool
2184}
2185
2186type scopeProperties struct {
2187	Jars           android.Paths
2188	StubsSrcJar    android.Path
2189	CurrentApiFile android.Path
2190	RemovedApiFile android.Path
2191	SdkVersion     string
2192}
2193
2194func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
2195	sdk := variant.(*SdkLibrary)
2196
2197	s.Scopes = make(map[*apiScope]scopeProperties)
2198	for _, apiScope := range allApiScopes {
2199		paths := sdk.findScopePaths(apiScope)
2200		if paths == nil {
2201			continue
2202		}
2203
2204		jars := paths.stubsImplPath
2205		if len(jars) > 0 {
2206			properties := scopeProperties{}
2207			properties.Jars = jars
2208			properties.SdkVersion = sdk.sdkVersionForStubsLibrary(ctx.SdkModuleContext(), apiScope)
2209			properties.StubsSrcJar = paths.stubsSrcJar.Path()
2210			if paths.currentApiFilePath.Valid() {
2211				properties.CurrentApiFile = paths.currentApiFilePath.Path()
2212			}
2213			if paths.removedApiFilePath.Valid() {
2214				properties.RemovedApiFile = paths.removedApiFilePath.Path()
2215			}
2216			s.Scopes[apiScope] = properties
2217		}
2218	}
2219
2220	s.Libs = sdk.properties.Libs
2221	s.Naming_scheme = sdk.commonSdkLibraryProperties.Naming_scheme
2222	s.Shared_library = proptools.BoolPtr(sdk.sharedLibrary())
2223}
2224
2225func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
2226	if s.Naming_scheme != nil {
2227		propertySet.AddProperty("naming_scheme", proptools.String(s.Naming_scheme))
2228	}
2229	if s.Shared_library != nil {
2230		propertySet.AddProperty("shared_library", *s.Shared_library)
2231	}
2232
2233	for _, apiScope := range allApiScopes {
2234		if properties, ok := s.Scopes[apiScope]; ok {
2235			scopeSet := propertySet.AddPropertySet(apiScope.propertyName)
2236
2237			scopeDir := filepath.Join("sdk_library", s.OsPrefix(), apiScope.name)
2238
2239			var jars []string
2240			for _, p := range properties.Jars {
2241				dest := filepath.Join(scopeDir, ctx.Name()+"-stubs.jar")
2242				ctx.SnapshotBuilder().CopyToSnapshot(p, dest)
2243				jars = append(jars, dest)
2244			}
2245			scopeSet.AddProperty("jars", jars)
2246
2247			// Merge the stubs source jar into the snapshot zip so that when it is unpacked
2248			// the source files are also unpacked.
2249			snapshotRelativeDir := filepath.Join(scopeDir, ctx.Name()+"_stub_sources")
2250			ctx.SnapshotBuilder().UnzipToSnapshot(properties.StubsSrcJar, snapshotRelativeDir)
2251			scopeSet.AddProperty("stub_srcs", []string{snapshotRelativeDir})
2252
2253			if properties.CurrentApiFile != nil {
2254				currentApiSnapshotPath := filepath.Join(scopeDir, ctx.Name()+".txt")
2255				ctx.SnapshotBuilder().CopyToSnapshot(properties.CurrentApiFile, currentApiSnapshotPath)
2256				scopeSet.AddProperty("current_api", currentApiSnapshotPath)
2257			}
2258
2259			if properties.RemovedApiFile != nil {
2260				removedApiSnapshotPath := filepath.Join(scopeDir, ctx.Name()+"-removed.txt")
2261				ctx.SnapshotBuilder().CopyToSnapshot(properties.RemovedApiFile, removedApiSnapshotPath)
2262				scopeSet.AddProperty("removed_api", removedApiSnapshotPath)
2263			}
2264
2265			if properties.SdkVersion != "" {
2266				scopeSet.AddProperty("sdk_version", properties.SdkVersion)
2267			}
2268		}
2269	}
2270
2271	if len(s.Libs) > 0 {
2272		propertySet.AddPropertyWithTag("libs", s.Libs, ctx.SnapshotBuilder().SdkMemberReferencePropertyTag(false))
2273	}
2274}
2275