• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 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	"reflect"
20	"regexp"
21	"sort"
22	"strings"
23	"testing"
24
25	"android/soong/android"
26	"android/soong/cc"
27	"android/soong/dexpreopt"
28
29	"github.com/google/blueprint"
30)
31
32const defaultJavaDir = "default/java"
33
34// Test fixture preparer that will register most java build components.
35//
36// Singletons and mutators should only be added here if they are needed for a majority of java
37// module types, otherwise they should be added under a separate preparer to allow them to be
38// selected only when needed to reduce test execution time.
39//
40// Module types do not have much of an overhead unless they are used so this should include as many
41// module types as possible. The exceptions are those module types that require mutators and/or
42// singletons in order to function in which case they should be kept together in a separate
43// preparer.
44var PrepareForTestWithJavaBuildComponents = android.GroupFixturePreparers(
45	// Make sure that mutators and module types, e.g. prebuilt mutators available.
46	android.PrepareForTestWithAndroidBuildComponents,
47	// Make java build components available to the test.
48	android.FixtureRegisterWithContext(registerRequiredBuildComponentsForTest),
49	android.FixtureRegisterWithContext(registerJavaPluginBuildComponents),
50	// Additional files needed in tests that disallow non-existent source files.
51	// This includes files that are needed by all, or at least most, instances of a java module type.
52	android.MockFS{
53		// Needed for linter used by java_library.
54		"build/soong/java/lint_defaults.txt": nil,
55		// Needed for apps that do not provide their own.
56		"build/make/target/product/security": nil,
57		// Required to generate Java used-by API coverage
58		"build/soong/scripts/gen_java_usedby_apex.sh": nil,
59		// Needed for the global lint checks provided from frameworks/base
60		"prebuilts/cmdline-tools/AndroidGlobalLintChecker.jar": nil,
61	}.AddToFixture(),
62)
63
64var prepareForTestWithFrameworkDeps = android.GroupFixturePreparers(
65	// The java default module definitions.
66	android.FixtureAddTextFile(defaultJavaDir+"/Android.bp", gatherRequiredDepsForTest()),
67	// Additional files needed when test disallows non-existent source.
68	android.MockFS{
69		// Needed for framework-res
70		defaultJavaDir + "/AndroidManifest.xml": nil,
71		// Needed for framework
72		defaultJavaDir + "/framework/aidl": nil,
73		// Needed for various deps defined in GatherRequiredDepsForTest()
74		defaultJavaDir + "/a.java": nil,
75
76		// Needed for R8 rules on apps
77		"build/make/core/proguard.flags":             nil,
78		"build/make/core/proguard_basic_keeps.flags": nil,
79		"prebuilts/cmdline-tools/shrinker.xml":       nil,
80	}.AddToFixture(),
81)
82
83var prepareForTestWithJavaDefaultModulesBase = android.GroupFixturePreparers(
84	// Make sure that all the module types used in the defaults are registered.
85	PrepareForTestWithJavaBuildComponents,
86	prepareForTestWithFrameworkDeps,
87	// Add dexpreopt compat libs (android.test.base, etc.) and a fake dex2oatd module.
88	dexpreopt.PrepareForTestWithDexpreoptCompatLibs,
89)
90
91// Test fixture preparer that will define default java modules, e.g. standard prebuilt modules.
92var PrepareForTestWithJavaDefaultModules = android.GroupFixturePreparers(
93	prepareForTestWithJavaDefaultModulesBase,
94	dexpreopt.FixtureDisableDexpreoptBootImages(true),
95	dexpreopt.FixtureDisableDexpreopt(true),
96)
97
98// Provides everything needed by dexpreopt.
99var PrepareForTestWithDexpreopt = android.GroupFixturePreparers(
100	prepareForTestWithJavaDefaultModulesBase,
101	dexpreopt.PrepareForTestWithFakeDex2oatd,
102	dexpreopt.PrepareForTestByEnablingDexpreopt,
103)
104
105// Provides everything needed by dexpreopt except the fake_tool_binary for dex2oatd.
106var PrepareForTestWithDexpreoptWithoutFakeDex2oatd = android.GroupFixturePreparers(
107	prepareForTestWithJavaDefaultModulesBase,
108	dexpreopt.PrepareForTestByEnablingDexpreopt,
109)
110
111var PrepareForTestWithOverlayBuildComponents = android.FixtureRegisterWithContext(registerOverlayBuildComponents)
112
113// Prepare a fixture to use all java module types, mutators and singletons fully.
114//
115// This should only be used by tests that want to run with as much of the build enabled as possible.
116var PrepareForIntegrationTestWithJava = android.GroupFixturePreparers(
117	cc.PrepareForIntegrationTestWithCc,
118	PrepareForTestWithJavaDefaultModules,
119)
120
121// Prepare a fixture with the standard files required by a java_sdk_library module.
122var PrepareForTestWithJavaSdkLibraryFiles = android.FixtureMergeMockFs(android.MockFS{
123	"api/current.txt":               nil,
124	"api/removed.txt":               nil,
125	"api/system-current.txt":        nil,
126	"api/system-removed.txt":        nil,
127	"api/test-current.txt":          nil,
128	"api/test-removed.txt":          nil,
129	"api/module-lib-current.txt":    nil,
130	"api/module-lib-removed.txt":    nil,
131	"api/system-server-current.txt": nil,
132	"api/system-server-removed.txt": nil,
133})
134
135// FixtureWithLastReleaseApis creates a preparer that creates prebuilt versions of the specified
136// modules for the `last` API release. By `last` it just means last in the list of supplied versions
137// and as this only provides one version it can be any value.
138//
139// This uses FixtureWithPrebuiltApis under the covers so the limitations of that apply to this.
140func FixtureWithLastReleaseApis(moduleNames ...string) android.FixturePreparer {
141	return FixtureWithPrebuiltApis(map[string][]string{
142		"30": moduleNames,
143	})
144}
145
146// PrepareForTestWithPrebuiltsOfCurrentApi is a preparer that creates prebuilt versions of the
147// standard modules for the current version.
148//
149// This uses FixtureWithPrebuiltApis under the covers so the limitations of that apply to this.
150var PrepareForTestWithPrebuiltsOfCurrentApi = FixtureWithPrebuiltApis(map[string][]string{
151	"current": {},
152	// Can't have current on its own as it adds a prebuilt_apis module but doesn't add any
153	// .txt files which causes the prebuilt_apis module to fail.
154	"30": {},
155})
156
157var prepareForTestWithFrameworkJacocoInstrumentation = android.GroupFixturePreparers(
158	android.FixtureMergeEnv(map[string]string{
159		"EMMA_INSTRUMENT_FRAMEWORK": "true",
160	}),
161	PrepareForTestWithJacocoInstrumentation,
162)
163
164// PrepareForTestWithJacocoInstrumentation creates a mock jacocoagent library that can be
165// depended on as part of the build process for instrumented Java modules.
166var PrepareForTestWithJacocoInstrumentation = android.GroupFixturePreparers(
167	android.FixtureMergeEnv(map[string]string{
168		"EMMA_INSTRUMENT": "true",
169	}),
170	android.FixtureAddFile("jacocoagent/Test.java", nil),
171	android.FixtureAddFile("jacocoagent/Android.bp", []byte(`
172		java_library {
173			name: "jacocoagent",
174			host_supported: true,
175			srcs: ["Test.java"],
176			sdk_version: "current",
177		}
178	`)),
179)
180
181// FixtureWithPrebuiltApis creates a preparer that will define prebuilt api modules for the
182// specified releases and modules.
183//
184// The supplied map keys are the releases, e.g. current, 29, 30, etc. The values are a list of
185// modules for that release. Due to limitations in the prebuilt_apis module which this preparer
186// uses the set of releases must include at least one numbered release, i.e. it cannot just include
187// "current".
188//
189// This defines a file in the mock file system in a predefined location (prebuilts/sdk/Android.bp)
190// and so only one instance of this can be used in each fixture.
191func FixtureWithPrebuiltApis(release2Modules map[string][]string) android.FixturePreparer {
192	return FixtureWithPrebuiltApisAndExtensions(release2Modules, nil)
193}
194
195func FixtureWithPrebuiltApisAndExtensions(apiLevel2Modules map[string][]string, extensionLevel2Modules map[string][]string) android.FixturePreparer {
196	mockFS := android.MockFS{}
197	path := "prebuilts/sdk/Android.bp"
198
199	bp := fmt.Sprintf(`
200			prebuilt_apis {
201				name: "sdk",
202				api_dirs: ["%s"],
203				extensions_dir: "extensions",
204				imports_sdk_version: "none",
205				imports_compile_dex: true,
206			}
207		`, strings.Join(android.SortedKeys(apiLevel2Modules), `", "`))
208
209	for release, modules := range apiLevel2Modules {
210		mockFS.Merge(prebuiltApisFilesForModules([]string{release}, modules))
211	}
212	if extensionLevel2Modules != nil {
213		for release, modules := range extensionLevel2Modules {
214			mockFS.Merge(prebuiltExtensionApiFiles([]string{release}, modules))
215		}
216	}
217	return android.GroupFixturePreparers(
218		android.FixtureAddTextFile(path, bp),
219		android.FixtureMergeMockFs(mockFS),
220	)
221}
222
223func prebuiltApisFilesForModules(apiLevels []string, modules []string) map[string][]byte {
224	libs := append([]string{"android"}, modules...)
225
226	fs := make(map[string][]byte)
227	for _, level := range apiLevels {
228		apiLevel := android.ApiLevelForTest(level)
229		for _, sdkKind := range []android.SdkKind{android.SdkPublic, android.SdkSystem, android.SdkModule, android.SdkSystemServer, android.SdkTest} {
230			// A core-for-system-modules file must only be created for the sdk kind that supports it.
231			if sdkKind == systemModuleKind(sdkKind, apiLevel) {
232				fs[fmt.Sprintf("prebuilts/sdk/%s/%s/core-for-system-modules.jar", level, sdkKind)] = nil
233			}
234
235			for _, lib := range libs {
236				// Create a jar file for every library.
237				fs[fmt.Sprintf("prebuilts/sdk/%s/%s/%s.jar", level, sdkKind, lib)] = nil
238
239				// No finalized API files for "current"
240				if level != "current" {
241					fs[fmt.Sprintf("prebuilts/sdk/%s/%s/api/%s.txt", level, sdkKind, lib)] = nil
242					fs[fmt.Sprintf("prebuilts/sdk/%s/%s/api/%s-removed.txt", level, sdkKind, lib)] = nil
243				}
244			}
245		}
246		if level == "current" {
247			fs["prebuilts/sdk/current/core/android.jar"] = nil
248		}
249		fs[fmt.Sprintf("prebuilts/sdk/%s/public/framework.aidl", level)] = nil
250	}
251	return fs
252}
253
254func prebuiltExtensionApiFiles(extensionLevels []string, modules []string) map[string][]byte {
255	fs := make(map[string][]byte)
256	for _, level := range extensionLevels {
257		for _, sdkKind := range []android.SdkKind{android.SdkPublic, android.SdkSystem, android.SdkModule, android.SdkSystemServer} {
258			for _, lib := range modules {
259				fs[fmt.Sprintf("prebuilts/sdk/extensions/%s/%s/api/%s.txt", level, sdkKind, lib)] = nil
260				fs[fmt.Sprintf("prebuilts/sdk/extensions/%s/%s/api/%s-removed.txt", level, sdkKind, lib)] = nil
261			}
262		}
263	}
264	return fs
265}
266
267// FixtureConfigureBootJars configures the boot jars in both the dexpreopt.GlobalConfig and
268// Config.productVariables structs. As a side effect that enables dexpreopt.
269func FixtureConfigureBootJars(bootJars ...string) android.FixturePreparer {
270	artBootJars := []string{}
271	for _, j := range bootJars {
272		artApex := false
273		for _, artApexName := range artApexNames {
274			if strings.HasPrefix(j, artApexName+":") {
275				artApex = true
276				break
277			}
278		}
279		if artApex {
280			artBootJars = append(artBootJars, j)
281		}
282	}
283	return android.GroupFixturePreparers(
284		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
285			variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
286		}),
287		dexpreopt.FixtureSetBootJars(bootJars...),
288		dexpreopt.FixtureSetArtBootJars(artBootJars...),
289
290		// Add a fake dex2oatd module.
291		dexpreopt.PrepareForTestWithFakeDex2oatd,
292	)
293}
294
295// FixtureConfigureApexBootJars configures the apex boot jars in both the
296// dexpreopt.GlobalConfig and Config.productVariables structs. As a side effect that enables
297// dexpreopt.
298func FixtureConfigureApexBootJars(bootJars ...string) android.FixturePreparer {
299	return android.GroupFixturePreparers(
300		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
301			variables.ApexBootJars = android.CreateTestConfiguredJarList(bootJars)
302		}),
303		dexpreopt.FixtureSetApexBootJars(bootJars...),
304
305		// Add a fake dex2oatd module.
306		dexpreopt.PrepareForTestWithFakeDex2oatd,
307	)
308}
309
310// FixtureUseLegacyCorePlatformApi prepares the fixture by setting the exception list of those
311// modules that are allowed to use the legacy core platform API to be the ones supplied.
312func FixtureUseLegacyCorePlatformApi(moduleNames ...string) android.FixturePreparer {
313	lookup := make(map[string]struct{})
314	for _, moduleName := range moduleNames {
315		lookup[moduleName] = struct{}{}
316	}
317	return android.FixtureModifyConfig(func(config android.Config) {
318		// Try and set the legacyCorePlatformApiLookup in the config, the returned value will be the
319		// actual value that is set.
320		cached := config.Once(legacyCorePlatformApiLookupKey, func() interface{} {
321			return lookup
322		})
323		// Make sure that the cached value is the one we need.
324		if !reflect.DeepEqual(cached, lookup) {
325			panic(fmt.Errorf("attempting to set legacyCorePlatformApiLookupKey to %q but it has already been set to %q", lookup, cached))
326		}
327	})
328}
329
330// registerRequiredBuildComponentsForTest registers the build components used by
331// PrepareForTestWithJavaDefaultModules.
332//
333// As functionality is moved out of here into separate FixturePreparer instances they should also
334// be moved into GatherRequiredDepsForTest for use by tests that have not yet switched to use test
335// fixtures.
336func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) {
337	RegisterAARBuildComponents(ctx)
338	RegisterAppBuildComponents(ctx)
339	RegisterAppImportBuildComponents(ctx)
340	RegisterAppSetBuildComponents(ctx)
341	registerBootclasspathBuildComponents(ctx)
342	registerBootclasspathFragmentBuildComponents(ctx)
343	RegisterDexpreoptBootJarsComponents(ctx)
344	RegisterDocsBuildComponents(ctx)
345	RegisterGenRuleBuildComponents(ctx)
346	registerJavaBuildComponents(ctx)
347	registerPlatformBootclasspathBuildComponents(ctx)
348	RegisterPrebuiltApisBuildComponents(ctx)
349	RegisterRuntimeResourceOverlayBuildComponents(ctx)
350	RegisterSdkLibraryBuildComponents(ctx)
351	RegisterStubsBuildComponents(ctx)
352	RegisterSystemModulesBuildComponents(ctx)
353	registerSystemserverClasspathBuildComponents(ctx)
354	registerLintBuildComponents(ctx)
355}
356
357// gatherRequiredDepsForTest gathers the module definitions used by
358// PrepareForTestWithJavaDefaultModules.
359//
360// As functionality is moved out of here into separate FixturePreparer instances they should also
361// be moved into GatherRequiredDepsForTest for use by tests that have not yet switched to use test
362// fixtures.
363func gatherRequiredDepsForTest() string {
364	var bp string
365
366	extraModules := []string{
367		"core-lambda-stubs",
368		"ext",
369		"android_stubs_current",
370		"android_system_stubs_current",
371		"android_test_stubs_current",
372		"android_module_lib_stubs_current",
373		"android_system_server_stubs_current",
374		"core.current.stubs",
375		"legacy.core.platform.api.stubs",
376		"stable.core.platform.api.stubs",
377
378		"kotlin-stdlib",
379		"kotlin-stdlib-jdk7",
380		"kotlin-stdlib-jdk8",
381		"kotlin-annotations",
382		"stub-annotations",
383	}
384
385	for _, extra := range extraModules {
386		bp += fmt.Sprintf(`
387			java_library {
388				name: "%s",
389				srcs: ["a.java"],
390				sdk_version: "none",
391				system_modules: "stable-core-platform-api-stubs-system-modules",
392				compile_dex: true,
393			}
394		`, extra)
395	}
396
397	extraApiLibraryModules := map[string]string{
398		"android_stubs_current.from-text":                 "api/current.txt",
399		"android_system_stubs_current.from-text":          "api/system-current.txt",
400		"android_test_stubs_current.from-text":            "api/test-current.txt",
401		"android_module_lib_stubs_current.from-text":      "api/module-lib-current.txt",
402		"android_module_lib_stubs_current_full.from-text": "api/module-lib-current.txt",
403		"android_system_server_stubs_current.from-text":   "api/system-server-current.txt",
404		"core.current.stubs.from-text":                    "api/current.txt",
405		"legacy.core.platform.api.stubs.from-text":        "api/current.txt",
406		"stable.core.platform.api.stubs.from-text":        "api/current.txt",
407		"core-lambda-stubs.from-text":                     "api/current.txt",
408	}
409
410	for libName, apiFile := range extraApiLibraryModules {
411		bp += fmt.Sprintf(`
412            java_api_library {
413                name: "%s",
414                api_files: ["%s"],
415            }
416        `, libName, apiFile)
417	}
418
419	bp += `
420		java_library {
421			name: "framework",
422			srcs: ["a.java"],
423			sdk_version: "none",
424			system_modules: "stable-core-platform-api-stubs-system-modules",
425			aidl: {
426				export_include_dirs: ["framework/aidl"],
427			},
428			compile_dex: true,
429		}
430
431		android_app {
432			name: "framework-res",
433			sdk_version: "core_platform",
434		}`
435
436	systemModules := []string{
437		"core-public-stubs-system-modules",
438		"core-module-lib-stubs-system-modules",
439		"legacy-core-platform-api-stubs-system-modules",
440		"stable-core-platform-api-stubs-system-modules",
441		"core-public-stubs-system-modules.from-text",
442		"core-module-lib-stubs-system-modules.from-text",
443		"legacy-core-platform-api-stubs-system-modules.from-text",
444		"stable-core-platform-api-stubs-system-modules.from-text",
445	}
446
447	for _, extra := range systemModules {
448		bp += fmt.Sprintf(`
449			java_system_modules {
450				name: "%[1]s",
451				libs: ["%[1]s-lib"],
452			}
453			java_library {
454				name: "%[1]s-lib",
455				sdk_version: "none",
456				system_modules: "none",
457			}
458		`, extra)
459	}
460
461	// Make sure that the dex_bootjars singleton module is instantiated for the tests.
462	bp += `
463		dex_bootjars {
464			name: "dex_bootjars",
465		}
466`
467
468	return bp
469}
470
471func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
472	t.Helper()
473	module := ctx.ModuleForTests(name, variant).Module()
474	deps := []string{}
475	ctx.VisitDirectDeps(module, func(m blueprint.Module) {
476		deps = append(deps, m.Name())
477	})
478	sort.Strings(deps)
479
480	if actual := deps; !reflect.DeepEqual(expected, actual) {
481		t.Errorf("expected %#q, found %#q", expected, actual)
482	}
483}
484
485// CheckPlatformBootclasspathModules returns the apex:module pair for the modules depended upon by
486// the platform-bootclasspath module.
487func CheckPlatformBootclasspathModules(t *testing.T, result *android.TestResult, name string, expected []string) {
488	t.Helper()
489	platformBootclasspath := result.Module(name, "android_common").(*platformBootclasspathModule)
490	pairs := ApexNamePairsFromModules(result.TestContext, platformBootclasspath.configuredModules)
491	android.AssertDeepEquals(t, fmt.Sprintf("%s modules", "platform-bootclasspath"), expected, pairs)
492}
493
494func CheckClasspathFragmentProtoContentInfoProvider(t *testing.T, result *android.TestResult, generated bool, contents, outputFilename, installDir string) {
495	t.Helper()
496	p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
497	info := result.ModuleProvider(p, ClasspathFragmentProtoContentInfoProvider).(ClasspathFragmentProtoContentInfo)
498
499	android.AssertBoolEquals(t, "classpath proto generated", generated, info.ClasspathFragmentProtoGenerated)
500	android.AssertStringEquals(t, "classpath proto contents", contents, info.ClasspathFragmentProtoContents.String())
501	android.AssertStringEquals(t, "output filepath", outputFilename, info.ClasspathFragmentProtoOutput.Base())
502	android.AssertPathRelativeToTopEquals(t, "install filepath", installDir, info.ClasspathFragmentProtoInstallDir)
503}
504
505// ApexNamePairsFromModules returns the apex:module pair for the supplied modules.
506func ApexNamePairsFromModules(ctx *android.TestContext, modules []android.Module) []string {
507	pairs := []string{}
508	for _, module := range modules {
509		pairs = append(pairs, apexNamePairFromModule(ctx, module))
510	}
511	return pairs
512}
513
514func apexNamePairFromModule(ctx *android.TestContext, module android.Module) string {
515	name := module.Name()
516	var apex string
517	apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
518	if apexInfo.IsForPlatform() {
519		apex = "platform"
520	} else {
521		apex = apexInfo.InApexVariants[0]
522	}
523
524	return fmt.Sprintf("%s:%s", apex, name)
525}
526
527// CheckPlatformBootclasspathFragments returns the apex:module pair for the fragments depended upon
528// by the platform-bootclasspath module.
529func CheckPlatformBootclasspathFragments(t *testing.T, result *android.TestResult, name string, expected []string) {
530	t.Helper()
531	platformBootclasspath := result.Module(name, "android_common").(*platformBootclasspathModule)
532	pairs := ApexNamePairsFromModules(result.TestContext, platformBootclasspath.fragments)
533	android.AssertDeepEquals(t, fmt.Sprintf("%s fragments", "platform-bootclasspath"), expected, pairs)
534}
535
536func CheckHiddenAPIRuleInputs(t *testing.T, message string, expected string, hiddenAPIRule android.TestingBuildParams) {
537	t.Helper()
538	inputs := android.Paths{}
539	if hiddenAPIRule.Input != nil {
540		inputs = append(inputs, hiddenAPIRule.Input)
541	}
542	inputs = append(inputs, hiddenAPIRule.Inputs...)
543	inputs = append(inputs, hiddenAPIRule.Implicits...)
544	inputs = android.SortedUniquePaths(inputs)
545	actual := strings.TrimSpace(strings.Join(inputs.RelativeToTop().Strings(), "\n"))
546	re := regexp.MustCompile(`\n\s+`)
547	expected = strings.TrimSpace(re.ReplaceAllString(expected, "\n"))
548	if actual != expected {
549		t.Errorf("Expected hiddenapi rule inputs - %s:\n%s\nactual inputs:\n%s", message, expected, actual)
550	}
551}
552
553// Check that the merged file create by platform_compat_config_singleton has the correct inputs.
554func CheckMergedCompatConfigInputs(t *testing.T, result *android.TestResult, message string, expectedPaths ...string) {
555	sourceGlobalCompatConfig := result.SingletonForTests("platform_compat_config_singleton")
556	allOutputs := sourceGlobalCompatConfig.AllOutputs()
557	android.AssertIntEquals(t, message+": output len", 1, len(allOutputs))
558	output := sourceGlobalCompatConfig.Output(allOutputs[0])
559	android.AssertPathsRelativeToTopEquals(t, message+": inputs", expectedPaths, output.Implicits)
560}
561
562// Register the fake APEX mutator to `android.InitRegistrationContext` as if the real mutator exists
563// at runtime. This must be called in `init()` of a test if the test is going to use the fake APEX
564// mutator. Otherwise, we will be missing the runtime mutator because "soong-apex" is not a
565// dependency, which will cause an inconsistency between testing and runtime mutators.
566func RegisterFakeRuntimeApexMutator() {
567	registerFakeApexMutator(android.InitRegistrationContext)
568}
569
570var PrepareForTestWithFakeApexMutator = android.GroupFixturePreparers(
571	android.FixtureRegisterWithContext(registerFakeApexMutator),
572)
573
574func registerFakeApexMutator(ctx android.RegistrationContext) {
575	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
576		ctx.BottomUp("apex", fakeApexMutator).Parallel()
577	})
578}
579
580type apexModuleBase interface {
581	ApexAvailable() []string
582}
583
584var _ apexModuleBase = (*Library)(nil)
585var _ apexModuleBase = (*SdkLibrary)(nil)
586
587// A fake APEX mutator that creates a platform variant and an APEX variant for modules with
588// `apex_available`. It helps us avoid a dependency on the real mutator defined in "soong-apex",
589// which will cause a cyclic dependency, and it provides an easy way to create an APEX variant for
590// testing without dealing with all the complexities in the real mutator.
591func fakeApexMutator(mctx android.BottomUpMutatorContext) {
592	switch mctx.Module().(type) {
593	case *Library, *SdkLibrary:
594		if len(mctx.Module().(apexModuleBase).ApexAvailable()) > 0 {
595			modules := mctx.CreateVariations("", "apex1000")
596			apexInfo := android.ApexInfo{
597				ApexVariationName: "apex1000",
598			}
599			mctx.SetVariationProvider(modules[1], android.ApexInfoProvider, apexInfo)
600		}
601	}
602}
603
604// Applies the given modifier on the boot image config with the given name.
605func FixtureModifyBootImageConfig(name string, configModifier func(*bootImageConfig)) android.FixturePreparer {
606	return android.FixtureModifyConfig(func(androidConfig android.Config) {
607		pathCtx := android.PathContextForTesting(androidConfig)
608		config := genBootImageConfigRaw(pathCtx)
609		configModifier(config[name])
610	})
611}
612
613// Sets the value of `installDir` of the boot image config with the given name.
614func FixtureSetBootImageInstallDirOnDevice(name string, installDir string) android.FixturePreparer {
615	return FixtureModifyBootImageConfig(name, func(config *bootImageConfig) {
616		config.installDir = installDir
617	})
618}
619