• 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	"android/soong/android"
19	"android/soong/genrule"
20	"fmt"
21	"io"
22	"path"
23	"path/filepath"
24	"sort"
25	"strings"
26	"sync"
27
28	"github.com/google/blueprint"
29	"github.com/google/blueprint/proptools"
30)
31
32var (
33	sdkStubsLibrarySuffix = ".stubs"
34	sdkSystemApiSuffix    = ".system"
35	sdkTestApiSuffix      = ".test"
36	sdkDocsSuffix         = ".docs"
37	sdkXmlFileSuffix      = ".xml"
38)
39
40type stubsLibraryDependencyTag struct {
41	blueprint.BaseDependencyTag
42	name string
43}
44
45type syspropLibraryInterface interface {
46	SyspropJavaModule() *SdkLibrary
47}
48
49var (
50	publicApiStubsTag = dependencyTag{name: "public"}
51	systemApiStubsTag = dependencyTag{name: "system"}
52	testApiStubsTag   = dependencyTag{name: "test"}
53	publicApiFileTag  = dependencyTag{name: "publicApi"}
54	systemApiFileTag  = dependencyTag{name: "systemApi"}
55	testApiFileTag    = dependencyTag{name: "testApi"}
56)
57
58type apiScope int
59
60const (
61	apiScopePublic apiScope = iota
62	apiScopeSystem
63	apiScopeTest
64)
65
66var (
67	javaSdkLibrariesLock sync.Mutex
68)
69
70// java_sdk_library is to make a Java library that implements optional platform APIs to apps.
71// It is actually a wrapper of several modules: 1) stubs library that clients are linked against
72// to, 2) droiddoc module that internally generates API stubs source files, 3) the real runtime
73// shared library that implements the APIs, and 4) XML file for adding the runtime lib to the
74// classpath at runtime if requested via <uses-library>.
75//
76// TODO: these are big features that are currently missing
77// 1) disallowing linking to the runtime shared lib
78// 2) HTML generation
79
80func init() {
81	android.RegisterModuleType("java_sdk_library", SdkLibraryFactory)
82
83	android.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
84		ctx.TopDown("java_sdk_library", SdkLibraryMutator).Parallel()
85	})
86
87	android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
88		javaSdkLibraries := javaSdkLibraries(ctx.Config())
89		sort.Strings(*javaSdkLibraries)
90		ctx.Strict("JAVA_SDK_LIBRARIES", strings.Join(*javaSdkLibraries, " "))
91	})
92}
93
94type sdkLibraryProperties struct {
95	// list of optional source files that are part of API but not part of runtime library.
96	Api_srcs []string `android:"arch_variant"`
97
98	// List of Java libraries that will be in the classpath when building stubs
99	Stub_only_libs []string `android:"arch_variant"`
100
101	// list of package names that will be documented and publicized as API
102	Api_packages []string
103
104	// list of package names that must be hidden from the API
105	Hidden_api_packages []string
106
107	// local files that are used within user customized droiddoc options.
108	Droiddoc_option_files []string
109
110	// additional droiddoc options
111	// Available variables for substitution:
112	//
113	//  $(location <label>): the path to the droiddoc_option_files with name <label>
114	Droiddoc_options []string
115
116	// the java library (in classpath) for documentation that provides java srcs and srcjars.
117	Srcs_lib *string
118
119	// the base dirs under srcs_lib will be scanned for java srcs.
120	Srcs_lib_whitelist_dirs []string
121
122	// the sub dirs under srcs_lib_whitelist_dirs will be scanned for java srcs.
123	// Defaults to "android.annotation".
124	Srcs_lib_whitelist_pkgs []string
125
126	// a list of top-level directories containing files to merge qualifier annotations
127	// (i.e. those intended to be included in the stubs written) from.
128	Merge_annotations_dirs []string
129
130	// a list of top-level directories containing Java stub files to merge show/hide annotations from.
131	Merge_inclusion_annotations_dirs []string
132
133	// If set to true, the path of dist files is apistubs/core. Defaults to false.
134	Core_lib *bool
135
136	// don't create dist rules.
137	No_dist *bool `blueprint:"mutated"`
138
139	// TODO: determines whether to create HTML doc or not
140	//Html_doc *bool
141}
142
143type SdkLibrary struct {
144	Library
145
146	sdkLibraryProperties sdkLibraryProperties
147
148	publicApiStubsPath android.Paths
149	systemApiStubsPath android.Paths
150	testApiStubsPath   android.Paths
151
152	publicApiStubsImplPath android.Paths
153	systemApiStubsImplPath android.Paths
154	testApiStubsImplPath   android.Paths
155
156	publicApiFilePath android.Path
157	systemApiFilePath android.Path
158	testApiFilePath   android.Path
159}
160
161var _ Dependency = (*SdkLibrary)(nil)
162var _ SdkLibraryDependency = (*SdkLibrary)(nil)
163
164func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
165	useBuiltStubs := !ctx.Config().UnbundledBuildUsePrebuiltSdks()
166	// Add dependencies to the stubs library
167	if useBuiltStubs {
168		ctx.AddVariationDependencies(nil, publicApiStubsTag, module.stubsName(apiScopePublic))
169	}
170	ctx.AddVariationDependencies(nil, publicApiFileTag, module.docsName(apiScopePublic))
171
172	if !Bool(module.properties.No_standard_libs) {
173		if useBuiltStubs {
174			ctx.AddVariationDependencies(nil, systemApiStubsTag, module.stubsName(apiScopeSystem))
175			ctx.AddVariationDependencies(nil, testApiStubsTag, module.stubsName(apiScopeTest))
176		}
177		ctx.AddVariationDependencies(nil, systemApiFileTag, module.docsName(apiScopeSystem))
178		ctx.AddVariationDependencies(nil, testApiFileTag, module.docsName(apiScopeTest))
179	}
180
181	module.Library.deps(ctx)
182}
183
184func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
185	module.Library.GenerateAndroidBuildActions(ctx)
186
187	// Record the paths to the header jars of the library (stubs and impl).
188	// When this java_sdk_library is dependened from others via "libs" property,
189	// the recorded paths will be returned depending on the link type of the caller.
190	ctx.VisitDirectDeps(func(to android.Module) {
191		otherName := ctx.OtherModuleName(to)
192		tag := ctx.OtherModuleDependencyTag(to)
193
194		if lib, ok := to.(Dependency); ok {
195			switch tag {
196			case publicApiStubsTag:
197				module.publicApiStubsPath = lib.HeaderJars()
198				module.publicApiStubsImplPath = lib.ImplementationJars()
199			case systemApiStubsTag:
200				module.systemApiStubsPath = lib.HeaderJars()
201				module.systemApiStubsImplPath = lib.ImplementationJars()
202			case testApiStubsTag:
203				module.testApiStubsPath = lib.HeaderJars()
204				module.testApiStubsImplPath = lib.ImplementationJars()
205			}
206		}
207		if doc, ok := to.(ApiFilePath); ok {
208			switch tag {
209			case publicApiFileTag:
210				module.publicApiFilePath = doc.ApiFilePath()
211			case systemApiFileTag:
212				module.systemApiFilePath = doc.ApiFilePath()
213			case testApiFileTag:
214				module.testApiFilePath = doc.ApiFilePath()
215			default:
216				ctx.ModuleErrorf("depends on module %q of unknown tag %q", otherName, tag)
217			}
218		}
219	})
220}
221
222func (module *SdkLibrary) AndroidMk() android.AndroidMkData {
223	data := module.Library.AndroidMk()
224	data.Required = append(data.Required, module.xmlFileName())
225
226	data.Custom = func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
227		android.WriteAndroidMkData(w, data)
228
229		module.Library.AndroidMkHostDex(w, name, data)
230		if !Bool(module.sdkLibraryProperties.No_dist) {
231			// Create a phony module that installs the impl library, for the case when this lib is
232			// in PRODUCT_PACKAGES.
233			owner := module.ModuleBase.Owner()
234			if owner == "" {
235				if Bool(module.sdkLibraryProperties.Core_lib) {
236					owner = "core"
237				} else {
238					owner = "android"
239				}
240			}
241			// Create dist rules to install the stubs libs to the dist dir
242			if len(module.publicApiStubsPath) == 1 {
243				fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
244					module.publicApiStubsImplPath.Strings()[0]+
245					":"+path.Join("apistubs", owner, "public",
246					module.BaseModuleName()+".jar")+")")
247			}
248			if len(module.systemApiStubsPath) == 1 {
249				fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
250					module.systemApiStubsImplPath.Strings()[0]+
251					":"+path.Join("apistubs", owner, "system",
252					module.BaseModuleName()+".jar")+")")
253			}
254			if len(module.testApiStubsPath) == 1 {
255				fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
256					module.testApiStubsImplPath.Strings()[0]+
257					":"+path.Join("apistubs", owner, "test",
258					module.BaseModuleName()+".jar")+")")
259			}
260			if module.publicApiFilePath != nil {
261				fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
262					module.publicApiFilePath.String()+
263					":"+path.Join("apistubs", owner, "public", "api",
264					module.BaseModuleName()+".txt")+")")
265			}
266			if module.systemApiFilePath != nil {
267				fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
268					module.systemApiFilePath.String()+
269					":"+path.Join("apistubs", owner, "system", "api",
270					module.BaseModuleName()+".txt")+")")
271			}
272			if module.testApiFilePath != nil {
273				fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
274					module.testApiFilePath.String()+
275					":"+path.Join("apistubs", owner, "test", "api",
276					module.BaseModuleName()+".txt")+")")
277			}
278		}
279	}
280	return data
281}
282
283// Module name of the stubs library
284func (module *SdkLibrary) stubsName(apiScope apiScope) string {
285	stubsName := module.BaseModuleName() + sdkStubsLibrarySuffix
286	switch apiScope {
287	case apiScopeSystem:
288		stubsName = stubsName + sdkSystemApiSuffix
289	case apiScopeTest:
290		stubsName = stubsName + sdkTestApiSuffix
291	}
292	return stubsName
293}
294
295// Module name of the docs
296func (module *SdkLibrary) docsName(apiScope apiScope) string {
297	docsName := module.BaseModuleName() + sdkDocsSuffix
298	switch apiScope {
299	case apiScopeSystem:
300		docsName = docsName + sdkSystemApiSuffix
301	case apiScopeTest:
302		docsName = docsName + sdkTestApiSuffix
303	}
304	return docsName
305}
306
307// Module name of the runtime implementation library
308func (module *SdkLibrary) implName() string {
309	return module.BaseModuleName()
310}
311
312// File path to the runtime implementation library
313func (module *SdkLibrary) implPath() string {
314	partition := "system"
315	if module.SocSpecific() {
316		partition = "vendor"
317	} else if module.DeviceSpecific() {
318		partition = "odm"
319	} else if module.ProductSpecific() {
320		partition = "product"
321	}
322	return "/" + partition + "/framework/" + module.implName() + ".jar"
323}
324
325// Module name of the XML file for the lib
326func (module *SdkLibrary) xmlFileName() string {
327	return module.BaseModuleName() + sdkXmlFileSuffix
328}
329
330// SDK version that the stubs library is built against. Note that this is always
331// *current. Older stubs library built with a numberd SDK version is created from
332// the prebuilt jar.
333func (module *SdkLibrary) sdkVersion(apiScope apiScope) string {
334	switch apiScope {
335	case apiScopePublic:
336		return "current"
337	case apiScopeSystem:
338		return "system_current"
339	case apiScopeTest:
340		return "test_current"
341	default:
342		return "current"
343	}
344}
345
346// $(INTERNAL_PLATFORM_<apiTagName>_API_FILE) points to the generated
347// api file for the current source
348// TODO: remove this when apicheck is done in soong
349func (module *SdkLibrary) apiTagName(apiScope apiScope) string {
350	apiTagName := strings.Replace(strings.ToUpper(module.BaseModuleName()), ".", "_", -1)
351	switch apiScope {
352	case apiScopeSystem:
353		apiTagName = apiTagName + "_SYSTEM"
354	case apiScopeTest:
355		apiTagName = apiTagName + "_TEST"
356	}
357	return apiTagName
358}
359
360func (module *SdkLibrary) latestApiFilegroupName(apiScope apiScope) string {
361	name := ":" + module.BaseModuleName() + ".api."
362	switch apiScope {
363	case apiScopePublic:
364		name = name + "public"
365	case apiScopeSystem:
366		name = name + "system"
367	case apiScopeTest:
368		name = name + "test"
369	}
370	name = name + ".latest"
371	return name
372}
373
374func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope apiScope) string {
375	name := ":" + module.BaseModuleName() + "-removed.api."
376	switch apiScope {
377	case apiScopePublic:
378		name = name + "public"
379	case apiScopeSystem:
380		name = name + "system"
381	case apiScopeTest:
382		name = name + "test"
383	}
384	name = name + ".latest"
385	return name
386}
387
388// Creates a static java library that has API stubs
389func (module *SdkLibrary) createStubsLibrary(mctx android.TopDownMutatorContext, apiScope apiScope) {
390	props := struct {
391		Name              *string
392		Srcs              []string
393		Sdk_version       *string
394		Libs              []string
395		Soc_specific      *bool
396		Device_specific   *bool
397		Product_specific  *bool
398		Compile_dex       *bool
399		No_standard_libs  *bool
400		System_modules    *string
401		Java_version      *string
402		Product_variables struct {
403			Unbundled_build struct {
404				Enabled *bool
405			}
406			Pdk struct {
407				Enabled *bool
408			}
409		}
410		Openjdk9 struct {
411			Srcs       []string
412			Javacflags []string
413		}
414	}{}
415
416	props.Name = proptools.StringPtr(module.stubsName(apiScope))
417	// sources are generated from the droiddoc
418	props.Srcs = []string{":" + module.docsName(apiScope)}
419	props.Sdk_version = proptools.StringPtr(module.sdkVersion(apiScope))
420	props.Libs = module.sdkLibraryProperties.Stub_only_libs
421	// Unbundled apps will use the prebult one from /prebuilts/sdk
422	if mctx.Config().UnbundledBuildUsePrebuiltSdks() {
423		props.Product_variables.Unbundled_build.Enabled = proptools.BoolPtr(false)
424	}
425	props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false)
426	props.No_standard_libs = module.Library.Module.properties.No_standard_libs
427	props.System_modules = module.Library.Module.deviceProperties.System_modules
428	props.Openjdk9.Srcs = module.Library.Module.properties.Openjdk9.Srcs
429	props.Openjdk9.Javacflags = module.Library.Module.properties.Openjdk9.Javacflags
430	props.Java_version = module.Library.Module.properties.Java_version
431	if module.Library.Module.deviceProperties.Compile_dex != nil {
432		props.Compile_dex = module.Library.Module.deviceProperties.Compile_dex
433	}
434
435	if module.SocSpecific() {
436		props.Soc_specific = proptools.BoolPtr(true)
437	} else if module.DeviceSpecific() {
438		props.Device_specific = proptools.BoolPtr(true)
439	} else if module.ProductSpecific() {
440		props.Product_specific = proptools.BoolPtr(true)
441	}
442
443	mctx.CreateModule(android.ModuleFactoryAdaptor(LibraryFactory), &props)
444}
445
446// Creates a droiddoc module that creates stubs source files from the given full source
447// files
448func (module *SdkLibrary) createDocs(mctx android.TopDownMutatorContext, apiScope apiScope) {
449	props := struct {
450		Name                             *string
451		Srcs                             []string
452		Installable                      *bool
453		Srcs_lib                         *string
454		Srcs_lib_whitelist_dirs          []string
455		Srcs_lib_whitelist_pkgs          []string
456		Libs                             []string
457		Arg_files                        []string
458		Args                             *string
459		Api_tag_name                     *string
460		Api_filename                     *string
461		Removed_api_filename             *string
462		No_standard_libs                 *bool
463		Java_version                     *string
464		Merge_annotations_dirs           []string
465		Merge_inclusion_annotations_dirs []string
466		Check_api                        struct {
467			Current                   ApiToCheck
468			Last_released             ApiToCheck
469			Ignore_missing_latest_api *bool
470		}
471		Aidl struct {
472			Include_dirs       []string
473			Local_include_dirs []string
474		}
475	}{}
476
477	props.Name = proptools.StringPtr(module.docsName(apiScope))
478	props.Srcs = append(props.Srcs, module.Library.Module.properties.Srcs...)
479	props.Srcs = append(props.Srcs, module.sdkLibraryProperties.Api_srcs...)
480	props.Installable = proptools.BoolPtr(false)
481	// A droiddoc module has only one Libs property and doesn't distinguish between
482	// shared libs and static libs. So we need to add both of these libs to Libs property.
483	props.Libs = module.Library.Module.properties.Libs
484	props.Libs = append(props.Libs, module.Library.Module.properties.Static_libs...)
485	props.Aidl.Include_dirs = module.Library.Module.deviceProperties.Aidl.Include_dirs
486	props.Aidl.Local_include_dirs = module.Library.Module.deviceProperties.Aidl.Local_include_dirs
487	props.No_standard_libs = module.Library.Module.properties.No_standard_libs
488	props.Java_version = module.Library.Module.properties.Java_version
489
490	props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs
491	props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs
492
493	droiddocArgs := " --stub-packages " + strings.Join(module.sdkLibraryProperties.Api_packages, ":") +
494		" " + android.JoinWithPrefix(module.sdkLibraryProperties.Hidden_api_packages, " --hide-package ") +
495		" " + android.JoinWithPrefix(module.sdkLibraryProperties.Droiddoc_options, " ") +
496		" --hide MissingPermission --hide BroadcastBehavior " +
497		"--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
498		"--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo"
499
500	switch apiScope {
501	case apiScopeSystem:
502		droiddocArgs = droiddocArgs + " -showAnnotation android.annotation.SystemApi"
503	case apiScopeTest:
504		droiddocArgs = droiddocArgs + " -showAnnotation android.annotation.TestApi"
505	}
506	props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
507	props.Args = proptools.StringPtr(droiddocArgs)
508
509	// List of APIs identified from the provided source files are created. They are later
510	// compared against to the not-yet-released (a.k.a current) list of APIs and to the
511	// last-released (a.k.a numbered) list of API.
512	currentApiFileName := "current.txt"
513	removedApiFileName := "removed.txt"
514	switch apiScope {
515	case apiScopeSystem:
516		currentApiFileName = "system-" + currentApiFileName
517		removedApiFileName = "system-" + removedApiFileName
518	case apiScopeTest:
519		currentApiFileName = "test-" + currentApiFileName
520		removedApiFileName = "test-" + removedApiFileName
521	}
522	currentApiFileName = path.Join("api", currentApiFileName)
523	removedApiFileName = path.Join("api", removedApiFileName)
524	// TODO(jiyong): remove these three props
525	props.Api_tag_name = proptools.StringPtr(module.apiTagName(apiScope))
526	props.Api_filename = proptools.StringPtr(currentApiFileName)
527	props.Removed_api_filename = proptools.StringPtr(removedApiFileName)
528
529	// check against the not-yet-release API
530	props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
531	props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
532
533	// check against the latest released API
534	props.Check_api.Last_released.Api_file = proptools.StringPtr(
535		module.latestApiFilegroupName(apiScope))
536	props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
537		module.latestRemovedApiFilegroupName(apiScope))
538	props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
539	props.Srcs_lib = module.sdkLibraryProperties.Srcs_lib
540	props.Srcs_lib_whitelist_dirs = module.sdkLibraryProperties.Srcs_lib_whitelist_dirs
541	props.Srcs_lib_whitelist_pkgs = module.sdkLibraryProperties.Srcs_lib_whitelist_pkgs
542
543	mctx.CreateModule(android.ModuleFactoryAdaptor(DroidstubsFactory), &props)
544}
545
546// Creates the xml file that publicizes the runtime library
547func (module *SdkLibrary) createXmlFile(mctx android.TopDownMutatorContext) {
548	template := `
549<?xml version="1.0" encoding="utf-8"?>
550<!-- Copyright (C) 2018 The Android Open Source Project
551
552     Licensed under the Apache License, Version 2.0 (the "License");
553     you may not use this file except in compliance with the License.
554     You may obtain a copy of the License at
555
556          http://www.apache.org/licenses/LICENSE-2.0
557
558     Unless required by applicable law or agreed to in writing, software
559     distributed under the License is distributed on an "AS IS" BASIS,
560     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
561     See the License for the specific language governing permissions and
562     limitations under the License.
563-->
564
565<permissions>
566    <library name="%s" file="%s"/>
567</permissions>
568`
569	// genrule to generate the xml file content from the template above
570	// TODO: preserve newlines in the generate xml file. Newlines are being squashed
571	// in the ninja file. Do we need to have an external tool for this?
572	xmlContent := fmt.Sprintf(template, module.BaseModuleName(), module.implPath())
573	genruleProps := struct {
574		Name *string
575		Cmd  *string
576		Out  []string
577	}{}
578	genruleProps.Name = proptools.StringPtr(module.xmlFileName() + "-gen")
579	genruleProps.Cmd = proptools.StringPtr("echo '" + xmlContent + "' > $(out)")
580	genruleProps.Out = []string{module.xmlFileName()}
581	mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProps)
582
583	// creates a prebuilt_etc module to actually place the xml file under
584	// <partition>/etc/permissions
585	etcProps := struct {
586		Name             *string
587		Src              *string
588		Sub_dir          *string
589		Soc_specific     *bool
590		Device_specific  *bool
591		Product_specific *bool
592	}{}
593	etcProps.Name = proptools.StringPtr(module.xmlFileName())
594	etcProps.Src = proptools.StringPtr(":" + module.xmlFileName() + "-gen")
595	etcProps.Sub_dir = proptools.StringPtr("permissions")
596	if module.SocSpecific() {
597		etcProps.Soc_specific = proptools.BoolPtr(true)
598	} else if module.DeviceSpecific() {
599		etcProps.Device_specific = proptools.BoolPtr(true)
600	} else if module.ProductSpecific() {
601		etcProps.Product_specific = proptools.BoolPtr(true)
602	}
603	mctx.CreateModule(android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory), &etcProps)
604}
605
606func (module *SdkLibrary) PrebuiltJars(ctx android.BaseContext, sdkVersion string) android.Paths {
607	var api, v string
608	if sdkVersion == "" {
609		api = "system"
610		v = "current"
611	} else if strings.Contains(sdkVersion, "_") {
612		t := strings.Split(sdkVersion, "_")
613		api = t[0]
614		v = t[1]
615	} else {
616		api = "public"
617		v = sdkVersion
618	}
619	dir := filepath.Join("prebuilts", "sdk", v, api)
620	jar := filepath.Join(dir, module.BaseModuleName()+".jar")
621	jarPath := android.ExistentPathForSource(ctx, jar)
622	if !jarPath.Valid() {
623		ctx.PropertyErrorf("sdk_library", "invalid sdk version %q, %q does not exist", v, jar)
624		return nil
625	}
626	return android.Paths{jarPath.Path()}
627}
628
629// to satisfy SdkLibraryDependency interface
630func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseContext, sdkVersion string) android.Paths {
631	// This module is just a wrapper for the stubs.
632	if ctx.Config().UnbundledBuildUsePrebuiltSdks() {
633		return module.PrebuiltJars(ctx, sdkVersion)
634	} else {
635		if strings.HasPrefix(sdkVersion, "system_") {
636			return module.systemApiStubsPath
637		} else if sdkVersion == "" {
638			return module.Library.HeaderJars()
639		} else {
640			return module.publicApiStubsPath
641		}
642	}
643}
644
645// to satisfy SdkLibraryDependency interface
646func (module *SdkLibrary) SdkImplementationJars(ctx android.BaseContext, sdkVersion string) android.Paths {
647	// This module is just a wrapper for the stubs.
648	if ctx.Config().UnbundledBuildUsePrebuiltSdks() {
649		return module.PrebuiltJars(ctx, sdkVersion)
650	} else {
651		if strings.HasPrefix(sdkVersion, "system_") {
652			return module.systemApiStubsImplPath
653		} else if sdkVersion == "" {
654			return module.Library.ImplementationJars()
655		} else {
656			return module.publicApiStubsImplPath
657		}
658	}
659}
660
661func (module *SdkLibrary) SetNoDist() {
662	module.sdkLibraryProperties.No_dist = proptools.BoolPtr(true)
663}
664
665var javaSdkLibrariesKey = android.NewOnceKey("javaSdkLibraries")
666
667func javaSdkLibraries(config android.Config) *[]string {
668	return config.Once(javaSdkLibrariesKey, func() interface{} {
669		return &[]string{}
670	}).(*[]string)
671}
672
673// For a java_sdk_library module, create internal modules for stubs, docs,
674// runtime libs and xml file. If requested, the stubs and docs are created twice
675// once for public API level and once for system API level
676func SdkLibraryMutator(mctx android.TopDownMutatorContext) {
677	if module, ok := mctx.Module().(*SdkLibrary); ok {
678		module.createInternalModules(mctx)
679	} else if module, ok := mctx.Module().(syspropLibraryInterface); ok {
680		module.SyspropJavaModule().createInternalModules(mctx)
681	}
682}
683
684func (module *SdkLibrary) createInternalModules(mctx android.TopDownMutatorContext) {
685	if len(module.Library.Module.properties.Srcs) == 0 {
686		mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs")
687	}
688
689	if len(module.sdkLibraryProperties.Api_packages) == 0 {
690		mctx.PropertyErrorf("api_packages", "java_sdk_library must specify api_packages")
691	}
692
693	missing_current_api := false
694
695	for _, scope := range []string{"", "system-", "test-"} {
696		for _, api := range []string{"current.txt", "removed.txt"} {
697			path := path.Join(mctx.ModuleDir(), "api", scope+api)
698			p := android.ExistentPathForSource(mctx, path)
699			if !p.Valid() {
700				mctx.ModuleErrorf("Current api file %#v doesn't exist", path)
701				missing_current_api = true
702			}
703		}
704	}
705
706	if missing_current_api {
707		script := "build/soong/scripts/gen-java-current-api-files.sh"
708		p := android.ExistentPathForSource(mctx, script)
709
710		if !p.Valid() {
711			panic(fmt.Sprintf("script file %s doesn't exist", script))
712		}
713
714		mctx.ModuleErrorf("One or more current api files are missing. "+
715			"You can update them by:\n"+
716			"%s %q && m update-api", script, mctx.ModuleDir())
717		return
718	}
719
720	// for public API stubs
721	module.createStubsLibrary(mctx, apiScopePublic)
722	module.createDocs(mctx, apiScopePublic)
723
724	if !Bool(module.properties.No_standard_libs) {
725		// for system API stubs
726		module.createStubsLibrary(mctx, apiScopeSystem)
727		module.createDocs(mctx, apiScopeSystem)
728
729		// for test API stubs
730		module.createStubsLibrary(mctx, apiScopeTest)
731		module.createDocs(mctx, apiScopeTest)
732
733		// for runtime
734		module.createXmlFile(mctx)
735	}
736
737	// record java_sdk_library modules so that they are exported to make
738	javaSdkLibraries := javaSdkLibraries(mctx.Config())
739	javaSdkLibrariesLock.Lock()
740	defer javaSdkLibrariesLock.Unlock()
741	*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
742}
743
744func (module *SdkLibrary) InitSdkLibraryProperties() {
745	module.AddProperties(
746		&module.sdkLibraryProperties,
747		&module.Library.Module.properties,
748		&module.Library.Module.dexpreoptProperties,
749		&module.Library.Module.deviceProperties,
750		&module.Library.Module.protoProperties,
751	)
752
753	module.Library.Module.properties.Installable = proptools.BoolPtr(true)
754	module.Library.Module.deviceProperties.IsSDKLibrary = true
755}
756
757func SdkLibraryFactory() android.Module {
758	module := &SdkLibrary{}
759	module.InitSdkLibraryProperties()
760	InitJavaModule(module, android.HostAndDeviceSupported)
761	return module
762}
763