1// Copyright (C) 2021 The Android Open Source Project
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 api
16
17import (
18	"fmt"
19	"sort"
20	"strings"
21
22	"github.com/google/blueprint/proptools"
23
24	"android/soong/android"
25	"android/soong/genrule"
26	"android/soong/java"
27)
28
29const art = "art.module.public.api"
30const conscrypt = "conscrypt.module.public.api"
31const i18n = "i18n.module.public.api"
32const virtualization = "framework-virtualization"
33const location = "framework-location"
34
35var core_libraries_modules = []string{art, conscrypt, i18n}
36
37// List of modules that are not yet updatable, and hence they can still compile
38// against hidden APIs. These modules are filtered out when building the
39// updatable-framework-module-impl (because updatable-framework-module-impl is
40// built against module_current SDK). Instead they are directly statically
41// linked into the all-framework-module-lib, which is building against hidden
42// APIs.
43// In addition, the modules in this list are allowed to contribute to test APIs
44// stubs.
45var non_updatable_modules = []string{virtualization, location}
46
47// The intention behind this soong plugin is to generate a number of "merged"
48// API-related modules that would otherwise require a large amount of very
49// similar Android.bp boilerplate to define. For example, the merged current.txt
50// API definitions (created by merging the non-updatable current.txt with all
51// the module current.txts). This simplifies the addition of new android
52// modules, by reducing the number of genrules etc a new module must be added to.
53
54// The properties of the combined_apis module type.
55type CombinedApisProperties struct {
56	// Module libraries in the bootclasspath
57	Bootclasspath []string
58	// Module libraries on the bootclasspath if include_nonpublic_framework_api is true.
59	Conditional_bootclasspath []string
60	// Module libraries in system server
61	System_server_classpath []string
62}
63
64type CombinedApis struct {
65	android.ModuleBase
66	android.DefaultableModuleBase
67
68	properties CombinedApisProperties
69}
70
71func init() {
72	registerBuildComponents(android.InitRegistrationContext)
73}
74
75func registerBuildComponents(ctx android.RegistrationContext) {
76	ctx.RegisterModuleType("combined_apis", combinedApisModuleFactory)
77	ctx.RegisterModuleType("combined_apis_defaults", CombinedApisModuleDefaultsFactory)
78}
79
80var PrepareForCombinedApisTest = android.FixtureRegisterWithContext(registerBuildComponents)
81
82func (a *CombinedApis) apiFingerprintStubDeps() []string {
83	ret := []string{}
84	ret = append(
85		ret,
86		transformArray(a.properties.Bootclasspath, "", ".stubs")...,
87	)
88	ret = append(
89		ret,
90		transformArray(a.properties.Bootclasspath, "", ".stubs.system")...,
91	)
92	ret = append(
93		ret,
94		transformArray(a.properties.Bootclasspath, "", ".stubs.module_lib")...,
95	)
96	ret = append(
97		ret,
98		transformArray(a.properties.System_server_classpath, "", ".stubs.system_server")...,
99	)
100	return ret
101}
102
103func (a *CombinedApis) DepsMutator(ctx android.BottomUpMutatorContext) {
104	ctx.AddDependency(ctx.Module(), nil, a.apiFingerprintStubDeps()...)
105}
106
107func (a *CombinedApis) GenerateAndroidBuildActions(ctx android.ModuleContext) {
108	ctx.WalkDeps(func(child, parent android.Module) bool {
109		if _, ok := child.(java.AndroidLibraryDependency); ok && child.Name() != "framework-res" {
110			// Stubs of BCP and SSCP libraries should not have any dependencies on apps
111			// This check ensures that we do not run into circular dependencies when UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT=true
112			ctx.ModuleErrorf(
113				"Module %s is not a valid dependency of the stub library %s\n."+
114					"If this dependency has been added via `libs` of java_sdk_library, please move it to `impl_only_libs`\n",
115				child.Name(), parent.Name())
116			return false // error detected
117		}
118		return true
119	})
120
121}
122
123type genruleProps struct {
124	Name       *string
125	Cmd        *string
126	Dists      []android.Dist
127	Out        []string
128	Srcs       []string
129	Tools      []string
130	Visibility []string
131}
132
133type libraryProps struct {
134	Name            *string
135	Sdk_version     *string
136	Static_libs     []string
137	Visibility      []string
138	Defaults        []string
139	Is_stubs_module *bool
140}
141
142type fgProps struct {
143	Name       *string
144	Srcs       []string
145	Visibility []string
146}
147
148type defaultsProps struct {
149	Name                *string
150	Api_surface         *string
151	Api_contributions   []string
152	Defaults_visibility []string
153	Previous_api        *string
154}
155
156// Struct to pass parameters for the various merged [current|removed].txt file modules we create.
157type MergedTxtDefinition struct {
158	// "current.txt" or "removed.txt"
159	TxtFilename string
160	// Filename in the new dist dir. "android.txt" or "android-removed.txt"
161	DistFilename string
162	// The module for the non-updatable / non-module part of the api.
163	BaseTxt string
164	// The list of modules that are relevant for this merged txt.
165	Modules []string
166	// The output tag for each module to use.e.g. {.public.api.txt} for current.txt
167	ModuleTag string
168	// public, system, module-lib or system-server
169	Scope string
170}
171
172func createMergedTxt(ctx android.LoadHookContext, txt MergedTxtDefinition, stubsTypeSuffix string, doDist bool) {
173	metalavaCmd := "$(location metalava)"
174	// Silence reflection warnings. See b/168689341
175	metalavaCmd += " -J--add-opens=java.base/java.util=ALL-UNNAMED "
176	metalavaCmd += " --quiet merge-signatures --format=v2 "
177
178	filename := txt.TxtFilename
179	if txt.Scope != "public" {
180		filename = txt.Scope + "-" + filename
181	}
182	moduleName := ctx.ModuleName() + stubsTypeSuffix + filename
183
184	props := genruleProps{}
185	props.Name = proptools.StringPtr(moduleName)
186	props.Tools = []string{"metalava"}
187	props.Out = []string{filename}
188	props.Cmd = proptools.StringPtr(metalavaCmd + "$(in) --out $(out)")
189	props.Srcs = append([]string{txt.BaseTxt}, createSrcs(txt.Modules, txt.ModuleTag)...)
190	if doDist {
191		props.Dists = []android.Dist{
192			{
193				Targets: []string{"droidcore"},
194				Dir:     proptools.StringPtr("api"),
195				Dest:    proptools.StringPtr(filename),
196			},
197			{
198				Targets: []string{"api_txt", "sdk"},
199				Dir:     proptools.StringPtr("apistubs/android/" + txt.Scope + "/api"),
200				Dest:    proptools.StringPtr(txt.DistFilename),
201			},
202		}
203	}
204	props.Visibility = []string{"//visibility:public"}
205	ctx.CreateModule(genrule.GenRuleFactory, &props)
206}
207
208func createMergedAnnotationsFilegroups(ctx android.LoadHookContext, modules, system_server_modules []string) {
209	for _, i := range []struct {
210		name    string
211		tag     string
212		modules []string
213	}{
214		{
215			name:    "all-modules-public-annotations",
216			tag:     "{.public.annotations.zip}",
217			modules: modules,
218		}, {
219			name:    "all-modules-system-annotations",
220			tag:     "{.system.annotations.zip}",
221			modules: modules,
222		}, {
223			name:    "all-modules-module-lib-annotations",
224			tag:     "{.module-lib.annotations.zip}",
225			modules: modules,
226		}, {
227			name:    "all-modules-system-server-annotations",
228			tag:     "{.system-server.annotations.zip}",
229			modules: system_server_modules,
230		},
231	} {
232		props := fgProps{}
233		props.Name = proptools.StringPtr(i.name)
234		props.Srcs = createSrcs(i.modules, i.tag)
235		ctx.CreateModule(android.FileGroupFactory, &props)
236	}
237}
238
239func createMergedPublicStubs(ctx android.LoadHookContext, modules []string) {
240	props := libraryProps{}
241	props.Name = proptools.StringPtr("all-modules-public-stubs")
242	props.Static_libs = transformArray(modules, "", ".stubs")
243	props.Sdk_version = proptools.StringPtr("module_current")
244	props.Visibility = []string{"//frameworks/base"}
245	props.Is_stubs_module = proptools.BoolPtr(true)
246	ctx.CreateModule(java.LibraryFactory, &props)
247}
248
249func createMergedPublicExportableStubs(ctx android.LoadHookContext, modules []string) {
250	props := libraryProps{}
251	props.Name = proptools.StringPtr("all-modules-public-stubs-exportable")
252	props.Static_libs = transformArray(modules, "", ".stubs.exportable")
253	props.Sdk_version = proptools.StringPtr("module_current")
254	props.Visibility = []string{"//frameworks/base"}
255	props.Is_stubs_module = proptools.BoolPtr(true)
256	ctx.CreateModule(java.LibraryFactory, &props)
257}
258
259func createMergedSystemStubs(ctx android.LoadHookContext, modules []string) {
260	// First create the all-updatable-modules-system-stubs
261	{
262		updatable_modules := removeAll(modules, non_updatable_modules)
263		props := libraryProps{}
264		props.Name = proptools.StringPtr("all-updatable-modules-system-stubs")
265		props.Static_libs = transformArray(updatable_modules, "", ".stubs.system")
266		props.Sdk_version = proptools.StringPtr("module_current")
267		props.Visibility = []string{"//frameworks/base"}
268		props.Is_stubs_module = proptools.BoolPtr(true)
269		ctx.CreateModule(java.LibraryFactory, &props)
270	}
271	// Now merge all-updatable-modules-system-stubs and stubs from non-updatable modules
272	// into all-modules-system-stubs.
273	{
274		props := libraryProps{}
275		props.Name = proptools.StringPtr("all-modules-system-stubs")
276		props.Static_libs = transformArray(non_updatable_modules, "", ".stubs.system")
277		props.Static_libs = append(props.Static_libs, "all-updatable-modules-system-stubs")
278		props.Sdk_version = proptools.StringPtr("module_current")
279		props.Visibility = []string{"//frameworks/base"}
280		props.Is_stubs_module = proptools.BoolPtr(true)
281		ctx.CreateModule(java.LibraryFactory, &props)
282	}
283}
284
285func createMergedSystemExportableStubs(ctx android.LoadHookContext, modules []string) {
286	// First create the all-updatable-modules-system-stubs
287	{
288		updatable_modules := removeAll(modules, non_updatable_modules)
289		props := libraryProps{}
290		props.Name = proptools.StringPtr("all-updatable-modules-system-stubs-exportable")
291		props.Static_libs = transformArray(updatable_modules, "", ".stubs.exportable.system")
292		props.Sdk_version = proptools.StringPtr("module_current")
293		props.Visibility = []string{"//frameworks/base"}
294		props.Is_stubs_module = proptools.BoolPtr(true)
295		ctx.CreateModule(java.LibraryFactory, &props)
296	}
297	// Now merge all-updatable-modules-system-stubs and stubs from non-updatable modules
298	// into all-modules-system-stubs.
299	{
300		props := libraryProps{}
301		props.Name = proptools.StringPtr("all-modules-system-stubs-exportable")
302		props.Static_libs = transformArray(non_updatable_modules, "", ".stubs.exportable.system")
303		props.Static_libs = append(props.Static_libs, "all-updatable-modules-system-stubs-exportable")
304		props.Sdk_version = proptools.StringPtr("module_current")
305		props.Visibility = []string{"//frameworks/base"}
306		props.Is_stubs_module = proptools.BoolPtr(true)
307		ctx.CreateModule(java.LibraryFactory, &props)
308	}
309}
310
311func createMergedTestStubsForNonUpdatableModules(ctx android.LoadHookContext) {
312	props := libraryProps{}
313	props.Name = proptools.StringPtr("all-non-updatable-modules-test-stubs")
314	props.Static_libs = transformArray(non_updatable_modules, "", ".stubs.test")
315	props.Sdk_version = proptools.StringPtr("module_current")
316	props.Visibility = []string{"//frameworks/base"}
317	props.Is_stubs_module = proptools.BoolPtr(true)
318	ctx.CreateModule(java.LibraryFactory, &props)
319}
320
321func createMergedTestExportableStubsForNonUpdatableModules(ctx android.LoadHookContext) {
322	props := libraryProps{}
323	props.Name = proptools.StringPtr("all-non-updatable-modules-test-stubs-exportable")
324	props.Static_libs = transformArray(non_updatable_modules, "", ".stubs.exportable.test")
325	props.Sdk_version = proptools.StringPtr("module_current")
326	props.Visibility = []string{"//frameworks/base"}
327	props.Is_stubs_module = proptools.BoolPtr(true)
328	ctx.CreateModule(java.LibraryFactory, &props)
329}
330
331func createMergedFrameworkImpl(ctx android.LoadHookContext, modules []string) {
332	// This module is for the "framework-all" module, which should not include the core libraries.
333	modules = removeAll(modules, core_libraries_modules)
334	// Remove the modules that belong to non-updatable APEXes since those are allowed to compile
335	// against unstable APIs.
336	modules = removeAll(modules, non_updatable_modules)
337	// First create updatable-framework-module-impl, which contains all updatable modules.
338	// This module compiles against module_lib SDK.
339	{
340		props := libraryProps{}
341		props.Name = proptools.StringPtr("updatable-framework-module-impl")
342		props.Static_libs = transformArray(modules, "", ".impl")
343		props.Sdk_version = proptools.StringPtr("module_current")
344		props.Visibility = []string{"//frameworks/base"}
345		ctx.CreateModule(java.LibraryFactory, &props)
346	}
347
348	// Now create all-framework-module-impl, which contains updatable-framework-module-impl
349	// and all non-updatable modules. This module compiles against hidden APIs.
350	{
351		props := libraryProps{}
352		props.Name = proptools.StringPtr("all-framework-module-impl")
353		props.Static_libs = transformArray(non_updatable_modules, "", ".impl")
354		props.Static_libs = append(props.Static_libs, "updatable-framework-module-impl")
355		props.Sdk_version = proptools.StringPtr("core_platform")
356		props.Visibility = []string{"//frameworks/base"}
357		ctx.CreateModule(java.LibraryFactory, &props)
358	}
359}
360
361func createMergedFrameworkModuleLibExportableStubs(ctx android.LoadHookContext, modules []string) {
362	// The user of this module compiles against the "core" SDK and against non-updatable modules,
363	// so remove to avoid dupes.
364	modules = removeAll(modules, core_libraries_modules)
365	modules = removeAll(modules, non_updatable_modules)
366	props := libraryProps{}
367	props.Name = proptools.StringPtr("framework-updatable-stubs-module_libs_api-exportable")
368	props.Static_libs = transformArray(modules, "", ".stubs.exportable.module_lib")
369	props.Sdk_version = proptools.StringPtr("module_current")
370	props.Visibility = []string{"//frameworks/base"}
371	props.Is_stubs_module = proptools.BoolPtr(true)
372	ctx.CreateModule(java.LibraryFactory, &props)
373}
374
375func createMergedFrameworkModuleLibStubs(ctx android.LoadHookContext, modules []string) {
376	// The user of this module compiles against the "core" SDK and against non-updatable modules,
377	// so remove to avoid dupes.
378	modules = removeAll(modules, core_libraries_modules)
379	modules = removeAll(modules, non_updatable_modules)
380	props := libraryProps{}
381	props.Name = proptools.StringPtr("framework-updatable-stubs-module_libs_api")
382	props.Static_libs = transformArray(modules, "", ".stubs.module_lib")
383	props.Sdk_version = proptools.StringPtr("module_current")
384	props.Visibility = []string{"//frameworks/base"}
385	props.Is_stubs_module = proptools.BoolPtr(true)
386	ctx.CreateModule(java.LibraryFactory, &props)
387}
388
389func createMergedFrameworkSystemServerExportableStubs(ctx android.LoadHookContext, bootclasspath, system_server_classpath []string) {
390	// The user of this module compiles against the "core" SDK and against non-updatable bootclasspathModules,
391	// so remove to avoid dupes.
392	bootclasspathModules := removeAll(bootclasspath, core_libraries_modules)
393	bootclasspathModules = removeAll(bootclasspath, non_updatable_modules)
394	modules := append(
395		// Include all the module-lib APIs from the bootclasspath libraries.
396		transformArray(bootclasspathModules, "", ".stubs.exportable.module_lib"),
397		// Then add all the system-server APIs from the service-* libraries.
398		transformArray(system_server_classpath, "", ".stubs.exportable.system_server")...,
399	)
400	props := libraryProps{}
401	props.Name = proptools.StringPtr("framework-updatable-stubs-system_server_api-exportable")
402	props.Static_libs = modules
403	props.Sdk_version = proptools.StringPtr("system_server_current")
404	props.Visibility = []string{"//frameworks/base"}
405	props.Is_stubs_module = proptools.BoolPtr(true)
406	ctx.CreateModule(java.LibraryFactory, &props)
407}
408
409func createPublicStubsSourceFilegroup(ctx android.LoadHookContext, modules []string) {
410	props := fgProps{}
411	props.Name = proptools.StringPtr("all-modules-public-stubs-source")
412	props.Srcs = createSrcs(modules, "{.public.stubs.source}")
413	props.Visibility = []string{"//frameworks/base"}
414	ctx.CreateModule(android.FileGroupFactory, &props)
415}
416
417func createMergedTxts(ctx android.LoadHookContext, bootclasspath, system_server_classpath []string, baseTxtModulePrefix, stubsTypeSuffix string, doDist bool) {
418	var textFiles []MergedTxtDefinition
419
420	tagSuffix := []string{".api.txt}", ".removed-api.txt}"}
421	distFilename := []string{"android.txt", "android-removed.txt"}
422	for i, f := range []string{"current.txt", "removed.txt"} {
423		textFiles = append(textFiles, MergedTxtDefinition{
424			TxtFilename:  f,
425			DistFilename: distFilename[i],
426			BaseTxt:      ":" + baseTxtModulePrefix + f,
427			Modules:      bootclasspath,
428			ModuleTag:    "{.public" + tagSuffix[i],
429			Scope:        "public",
430		})
431		textFiles = append(textFiles, MergedTxtDefinition{
432			TxtFilename:  f,
433			DistFilename: distFilename[i],
434			BaseTxt:      ":" + baseTxtModulePrefix + "system-" + f,
435			Modules:      bootclasspath,
436			ModuleTag:    "{.system" + tagSuffix[i],
437			Scope:        "system",
438		})
439		textFiles = append(textFiles, MergedTxtDefinition{
440			TxtFilename:  f,
441			DistFilename: distFilename[i],
442			BaseTxt:      ":" + baseTxtModulePrefix + "module-lib-" + f,
443			Modules:      bootclasspath,
444			ModuleTag:    "{.module-lib" + tagSuffix[i],
445			Scope:        "module-lib",
446		})
447		textFiles = append(textFiles, MergedTxtDefinition{
448			TxtFilename:  f,
449			DistFilename: distFilename[i],
450			BaseTxt:      ":" + baseTxtModulePrefix + "system-server-" + f,
451			Modules:      system_server_classpath,
452			ModuleTag:    "{.system-server" + tagSuffix[i],
453			Scope:        "system-server",
454		})
455	}
456	for _, txt := range textFiles {
457		createMergedTxt(ctx, txt, stubsTypeSuffix, doDist)
458	}
459}
460
461func createApiContributionDefaults(ctx android.LoadHookContext, modules []string) {
462	defaultsSdkKinds := []android.SdkKind{
463		android.SdkPublic, android.SdkSystem, android.SdkModule,
464	}
465	for _, sdkKind := range defaultsSdkKinds {
466		props := defaultsProps{}
467		props.Name = proptools.StringPtr(
468			sdkKind.DefaultJavaLibraryName() + "_contributions")
469		if sdkKind == android.SdkModule {
470			props.Name = proptools.StringPtr(
471				sdkKind.DefaultJavaLibraryName() + "_contributions_full")
472		}
473		props.Api_surface = proptools.StringPtr(sdkKind.String())
474		apiSuffix := ""
475		if sdkKind != android.SdkPublic {
476			apiSuffix = "." + strings.ReplaceAll(sdkKind.String(), "-", "_")
477		}
478		props.Api_contributions = transformArray(
479			modules, "", fmt.Sprintf(".stubs.source%s.api.contribution", apiSuffix))
480		props.Defaults_visibility = []string{"//visibility:public"}
481		props.Previous_api = proptools.StringPtr(":android.api.public.latest")
482		ctx.CreateModule(java.DefaultsFactory, &props)
483	}
484}
485
486func createFullApiLibraries(ctx android.LoadHookContext) {
487	javaLibraryNames := []string{
488		"android_stubs_current",
489		"android_system_stubs_current",
490		"android_test_stubs_current",
491		"android_test_frameworks_core_stubs_current",
492		"android_module_lib_stubs_current",
493		"android_system_server_stubs_current",
494	}
495
496	for _, libraryName := range javaLibraryNames {
497		props := libraryProps{}
498		props.Name = proptools.StringPtr(libraryName)
499		staticLib := libraryName + ".from-source"
500		if ctx.Config().BuildFromTextStub() {
501			staticLib = libraryName + ".from-text"
502		}
503		props.Static_libs = []string{staticLib}
504		props.Defaults = []string{"android.jar_defaults"}
505		props.Visibility = []string{"//visibility:public"}
506		props.Is_stubs_module = proptools.BoolPtr(true)
507
508		ctx.CreateModule(java.LibraryFactory, &props)
509	}
510}
511
512func createFullExportableApiLibraries(ctx android.LoadHookContext) {
513	javaLibraryNames := []string{
514		"android_stubs_current_exportable",
515		"android_system_stubs_current_exportable",
516		"android_test_stubs_current_exportable",
517		"android_module_lib_stubs_current_exportable",
518		"android_system_server_stubs_current_exportable",
519	}
520
521	for _, libraryName := range javaLibraryNames {
522		props := libraryProps{}
523		props.Name = proptools.StringPtr(libraryName)
524		staticLib := libraryName + ".from-source"
525		props.Static_libs = []string{staticLib}
526		props.Defaults = []string{"android.jar_defaults"}
527		props.Visibility = []string{"//visibility:public"}
528		props.Is_stubs_module = proptools.BoolPtr(true)
529
530		ctx.CreateModule(java.LibraryFactory, &props)
531	}
532}
533
534func (a *CombinedApis) createInternalModules(ctx android.LoadHookContext) {
535	bootclasspath := a.properties.Bootclasspath
536	system_server_classpath := a.properties.System_server_classpath
537	if ctx.Config().VendorConfig("ANDROID").Bool("include_nonpublic_framework_api") {
538		bootclasspath = append(bootclasspath, a.properties.Conditional_bootclasspath...)
539		sort.Strings(bootclasspath)
540	}
541	createMergedTxts(ctx, bootclasspath, system_server_classpath, "non-updatable-", "-", false)
542	createMergedTxts(ctx, bootclasspath, system_server_classpath, "non-updatable-exportable-", "-exportable-", true)
543
544	createMergedPublicStubs(ctx, bootclasspath)
545	createMergedSystemStubs(ctx, bootclasspath)
546	createMergedTestStubsForNonUpdatableModules(ctx)
547	createMergedFrameworkModuleLibStubs(ctx, bootclasspath)
548	createMergedFrameworkImpl(ctx, bootclasspath)
549
550	createMergedPublicExportableStubs(ctx, bootclasspath)
551	createMergedSystemExportableStubs(ctx, bootclasspath)
552	createMergedTestExportableStubsForNonUpdatableModules(ctx)
553	createMergedFrameworkModuleLibExportableStubs(ctx, bootclasspath)
554	createMergedFrameworkSystemServerExportableStubs(ctx, bootclasspath, system_server_classpath)
555
556	createMergedAnnotationsFilegroups(ctx, bootclasspath, system_server_classpath)
557
558	createPublicStubsSourceFilegroup(ctx, bootclasspath)
559
560	createApiContributionDefaults(ctx, bootclasspath)
561
562	createFullApiLibraries(ctx)
563
564	createFullExportableApiLibraries(ctx)
565}
566
567func combinedApisModuleFactory() android.Module {
568	module := &CombinedApis{}
569	module.AddProperties(&module.properties)
570	android.InitAndroidModule(module)
571	android.InitDefaultableModule(module)
572	android.AddLoadHook(module, func(ctx android.LoadHookContext) { module.createInternalModules(ctx) })
573	return module
574}
575
576// Various utility methods below.
577
578// Creates an array of ":<m><tag>" for each m in <modules>.
579func createSrcs(modules []string, tag string) []string {
580	return transformArray(modules, ":", tag)
581}
582
583// Creates an array of "<prefix><m><suffix>", for each m in <modules>.
584func transformArray(modules []string, prefix, suffix string) []string {
585	a := make([]string, 0, len(modules))
586	for _, module := range modules {
587		a = append(a, prefix+module+suffix)
588	}
589	return a
590}
591
592func removeAll(s []string, vs []string) []string {
593	for _, v := range vs {
594		s = remove(s, v)
595	}
596	return s
597}
598
599func remove(s []string, v string) []string {
600	s2 := make([]string, 0, len(s))
601	for _, sv := range s {
602		if sv != v {
603			s2 = append(s2, sv)
604		}
605	}
606	return s2
607}
608
609// Defaults
610type CombinedApisModuleDefaults struct {
611	android.ModuleBase
612	android.DefaultsModuleBase
613}
614
615func CombinedApisModuleDefaultsFactory() android.Module {
616	module := &CombinedApisModuleDefaults{}
617	module.AddProperties(&CombinedApisProperties{})
618	android.InitDefaultsModule(module)
619	return module
620}
621