• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2021 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 filesystem
16
17import (
18	"os"
19	"path/filepath"
20	"testing"
21
22	"android/soong/android"
23	"android/soong/bpf"
24	"android/soong/cc"
25	"android/soong/etc"
26	"android/soong/java"
27	"android/soong/phony"
28
29	"github.com/google/blueprint/proptools"
30)
31
32func TestMain(m *testing.M) {
33	os.Exit(m.Run())
34}
35
36var fixture = android.GroupFixturePreparers(
37	android.PrepareForIntegrationTestWithAndroid,
38	android.PrepareForTestWithAndroidBuildComponents,
39	bpf.PrepareForTestWithBpf,
40	cc.PrepareForIntegrationTestWithCc,
41	etc.PrepareForTestWithPrebuiltEtc,
42	java.PrepareForTestWithJavaBuildComponents,
43	java.PrepareForTestWithJavaDefaultModules,
44	phony.PrepareForTestWithPhony,
45	PrepareForTestWithFilesystemBuildComponents,
46)
47
48func TestFileSystemDeps(t *testing.T) {
49	result := fixture.RunTestWithBp(t, `
50		android_filesystem {
51			name: "myfilesystem",
52			multilib: {
53				common: {
54					deps: [
55						"bpf.o",
56						"phony",
57					],
58				},
59				lib32: {
60					deps: [
61						"foo",
62						"libbar",
63					],
64				},
65				lib64: {
66					deps: [
67						"libbar",
68					],
69				},
70			},
71			compile_multilib: "both",
72		}
73
74		bpf {
75			name: "bpf.o",
76			srcs: ["bpf.c"],
77		}
78
79		cc_binary {
80			name: "foo",
81			compile_multilib: "prefer32",
82		}
83
84		cc_library {
85			name: "libbar",
86			required: ["libbaz"],
87			target: {
88				platform: {
89					required: ["lib_platform_only"],
90				},
91			},
92		}
93
94		cc_library {
95			name: "libbaz",
96		}
97
98		cc_library {
99			name: "lib_platform_only",
100		}
101
102		phony {
103			name: "phony",
104			required: [
105				"libquz",
106				"myapp",
107			],
108		}
109
110		cc_library {
111			name: "libquz",
112		}
113
114		android_app {
115			name: "myapp",
116			platform_apis: true,
117			installable: true,
118		}
119	`)
120
121	// produces "myfilesystem.img"
122	result.ModuleForTests("myfilesystem", "android_common").Output("myfilesystem.img")
123
124	fs := result.ModuleForTests("myfilesystem", "android_common").Module().(*filesystem)
125	expected := []string{
126		"app/myapp/myapp.apk",
127		"bin/foo",
128		"lib/libbar.so",
129		"lib64/libbar.so",
130		"lib64/libbaz.so",
131		"lib64/libquz.so",
132		"lib64/lib_platform_only.so",
133		"etc/bpf/bpf.o",
134	}
135	for _, e := range expected {
136		android.AssertStringListContains(t, "missing entry", fs.entries, e)
137	}
138}
139
140func TestIncludeMakeBuiltFiles(t *testing.T) {
141	result := fixture.RunTestWithBp(t, `
142		android_filesystem {
143			name: "myfilesystem",
144			include_make_built_files: "system",
145		}
146	`)
147
148	output := result.ModuleForTests("myfilesystem", "android_common").Output("myfilesystem.img")
149
150	stampFile := filepath.Join(result.Config.OutDir(), "target/product/test_device/obj/PACKAGING/system_intermediates/staging_dir.stamp")
151	fileListFile := filepath.Join(result.Config.OutDir(), "target/product/test_device/obj/PACKAGING/system_intermediates/file_list.txt")
152	android.AssertStringListContains(t, "deps of filesystem must include the staging dir stamp file", output.Implicits.Strings(), stampFile)
153	android.AssertStringListContains(t, "deps of filesystem must include the staging dir file list", output.Implicits.Strings(), fileListFile)
154}
155
156func TestFileSystemFillsLinkerConfigWithStubLibs(t *testing.T) {
157	result := fixture.RunTestWithBp(t, `
158		android_system_image {
159			name: "myfilesystem",
160			deps: [
161				"libfoo",
162				"libbar",
163			],
164			linker_config_src: "linker.config.json",
165		}
166
167		cc_library {
168			name: "libfoo",
169			stubs: {
170				symbol_file: "libfoo.map.txt",
171			},
172		}
173
174		cc_library {
175			name: "libbar",
176		}
177	`)
178
179	module := result.ModuleForTests("myfilesystem", "android_common")
180	output := module.Output("system/etc/linker.config.pb")
181
182	android.AssertStringDoesContain(t, "linker.config.pb should have libfoo",
183		output.RuleParams.Command, "libfoo.so")
184	android.AssertStringDoesNotContain(t, "linker.config.pb should not have libbar",
185		output.RuleParams.Command, "libbar.so")
186}
187
188func registerComponent(ctx android.RegistrationContext) {
189	ctx.RegisterModuleType("component", componentFactory)
190}
191
192func componentFactory() android.Module {
193	m := &component{}
194	m.AddProperties(&m.properties)
195	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
196	return m
197}
198
199type component struct {
200	android.ModuleBase
201	properties struct {
202		Install_copy_in_data []string
203	}
204}
205
206func (c *component) GenerateAndroidBuildActions(ctx android.ModuleContext) {
207	output := android.PathForModuleOut(ctx, c.Name())
208	dir := android.PathForModuleInstall(ctx, "components")
209	ctx.InstallFile(dir, c.Name(), output)
210
211	dataDir := android.PathForModuleInPartitionInstall(ctx, "data", "components")
212	for _, d := range c.properties.Install_copy_in_data {
213		ctx.InstallFile(dataDir, d, output)
214	}
215}
216
217func TestFileSystemGathersItemsOnlyInSystemPartition(t *testing.T) {
218	f := android.GroupFixturePreparers(fixture, android.FixtureRegisterWithContext(registerComponent))
219	result := f.RunTestWithBp(t, `
220		android_system_image {
221			name: "myfilesystem",
222			multilib: {
223				common: {
224					deps: ["foo"],
225				},
226			},
227			linker_config_src: "linker.config.json",
228		}
229		component {
230			name: "foo",
231			install_copy_in_data: ["bar"],
232		}
233	`)
234
235	module := result.ModuleForTests("myfilesystem", "android_common").Module().(*systemImage)
236	android.AssertDeepEquals(t, "entries should have foo only", []string{"components/foo"}, module.entries)
237}
238
239func TestAvbGenVbmetaImage(t *testing.T) {
240	result := fixture.RunTestWithBp(t, `
241		avb_gen_vbmeta_image {
242			name: "input_hashdesc",
243			src: "input.img",
244			partition_name: "input_partition_name",
245			salt: "2222",
246		}`)
247	cmd := result.ModuleForTests("input_hashdesc", "android_arm64_armv8-a").Rule("avbGenVbmetaImage").RuleParams.Command
248	android.AssertStringDoesContain(t, "Can't find correct --partition_name argument",
249		cmd, "--partition_name input_partition_name")
250	android.AssertStringDoesContain(t, "Can't find --do_not_append_vbmeta_image",
251		cmd, "--do_not_append_vbmeta_image")
252	android.AssertStringDoesContain(t, "Can't find --output_vbmeta_image",
253		cmd, "--output_vbmeta_image ")
254	android.AssertStringDoesContain(t, "Can't find --salt argument",
255		cmd, "--salt 2222")
256}
257
258func TestAvbAddHashFooter(t *testing.T) {
259	result := fixture.RunTestWithBp(t, `
260		avb_gen_vbmeta_image {
261			name: "input_hashdesc",
262			src: "input.img",
263			partition_name: "input",
264			salt: "2222",
265		}
266
267		avb_add_hash_footer {
268			name: "myfooter",
269			src: "input.img",
270			filename: "output.img",
271			partition_name: "mypartition",
272			private_key: "mykey",
273			salt: "1111",
274			props: [
275				{
276					name: "prop1",
277					value: "value1",
278				},
279				{
280					name: "prop2",
281					file: "value_file",
282				},
283			],
284			include_descriptors_from_images: ["input_hashdesc"],
285		}
286	`)
287	cmd := result.ModuleForTests("myfooter", "android_arm64_armv8-a").Rule("avbAddHashFooter").RuleParams.Command
288	android.AssertStringDoesContain(t, "Can't find correct --partition_name argument",
289		cmd, "--partition_name mypartition")
290	android.AssertStringDoesContain(t, "Can't find correct --key argument",
291		cmd, "--key mykey")
292	android.AssertStringDoesContain(t, "Can't find --salt argument",
293		cmd, "--salt 1111")
294	android.AssertStringDoesContain(t, "Can't find --prop argument",
295		cmd, "--prop 'prop1:value1'")
296	android.AssertStringDoesContain(t, "Can't find --prop_from_file argument",
297		cmd, "--prop_from_file 'prop2:value_file'")
298	android.AssertStringDoesContain(t, "Can't find --include_descriptors_from_image",
299		cmd, "--include_descriptors_from_image ")
300}
301
302func TestFileSystemWithCoverageVariants(t *testing.T) {
303	context := android.GroupFixturePreparers(
304		fixture,
305		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
306			variables.GcovCoverage = proptools.BoolPtr(true)
307			variables.Native_coverage = proptools.BoolPtr(true)
308		}),
309	)
310
311	result := context.RunTestWithBp(t, `
312		prebuilt_etc {
313			name: "prebuilt",
314			src: ":myfilesystem",
315		}
316
317		android_system_image {
318			name: "myfilesystem",
319			deps: [
320				"libfoo",
321			],
322			linker_config_src: "linker.config.json",
323		}
324
325		cc_library {
326			name: "libfoo",
327			shared_libs: [
328				"libbar",
329			],
330			stl: "none",
331		}
332
333		cc_library {
334			name: "libbar",
335			stl: "none",
336		}
337	`)
338
339	filesystem := result.ModuleForTests("myfilesystem", "android_common_cov")
340	inputs := filesystem.Output("myfilesystem.img").Implicits
341	android.AssertStringListContains(t, "filesystem should have libfoo(cov)",
342		inputs.Strings(),
343		"out/soong/.intermediates/libfoo/android_arm64_armv8-a_shared_cov/libfoo.so")
344	android.AssertStringListContains(t, "filesystem should have libbar(cov)",
345		inputs.Strings(),
346		"out/soong/.intermediates/libbar/android_arm64_armv8-a_shared_cov/libbar.so")
347
348	filesystemOutput := filesystem.Output("myfilesystem.img").Output
349	prebuiltInput := result.ModuleForTests("prebuilt", "android_arm64_armv8-a").Rule("Cp").Input
350	if filesystemOutput != prebuiltInput {
351		t.Error("prebuilt should use cov variant of filesystem")
352	}
353}
354
355func TestSystemImageDefaults(t *testing.T) {
356	result := fixture.RunTestWithBp(t, `
357		android_filesystem_defaults {
358			name: "defaults",
359			multilib: {
360				common: {
361					deps: [
362						"phony",
363					],
364				},
365				lib64: {
366					deps: [
367						"libbar",
368					],
369				},
370			},
371			compile_multilib: "both",
372		}
373
374		android_system_image {
375			name: "system",
376			defaults: ["defaults"],
377			multilib: {
378				lib32: {
379					deps: [
380						"foo",
381						"libbar",
382					],
383				},
384			},
385		}
386
387		cc_binary {
388			name: "foo",
389			compile_multilib: "prefer32",
390		}
391
392		cc_library {
393			name: "libbar",
394			required: ["libbaz"],
395		}
396
397		cc_library {
398			name: "libbaz",
399		}
400
401		phony {
402			name: "phony",
403			required: ["libquz"],
404		}
405
406		cc_library {
407			name: "libquz",
408		}
409	`)
410
411	fs := result.ModuleForTests("system", "android_common").Module().(*systemImage)
412	expected := []string{
413		"bin/foo",
414		"lib/libbar.so",
415		"lib64/libbar.so",
416		"lib64/libbaz.so",
417		"lib64/libquz.so",
418	}
419	for _, e := range expected {
420		android.AssertStringListContains(t, "missing entry", fs.entries, e)
421	}
422}
423
424func TestInconsistentPartitionTypesInDefaults(t *testing.T) {
425	fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(
426		"doesn't match with the partition type")).
427		RunTestWithBp(t, `
428		android_filesystem_defaults {
429			name: "system_ext_def",
430			partition_type: "system_ext",
431		}
432
433		android_filesystem_defaults {
434			name: "system_def",
435			partition_type: "system",
436			defaults: ["system_ext_def"],
437		}
438
439		android_system_image {
440			name: "system",
441			defaults: ["system_def"],
442		}
443	`)
444}
445
446func TestPreventDuplicatedEntries(t *testing.T) {
447	fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(
448		"packaging conflict at")).
449		RunTestWithBp(t, `
450		android_filesystem {
451			name: "fs",
452			deps: [
453				"foo",
454				"foo_dup",
455			],
456		}
457
458		cc_binary {
459			name: "foo",
460		}
461
462		cc_binary {
463			name: "foo_dup",
464			stem: "foo",
465		}
466	`)
467}
468
469func TestTrackPhonyAsRequiredDep(t *testing.T) {
470	result := fixture.RunTestWithBp(t, `
471		android_filesystem {
472			name: "fs",
473			deps: ["foo"],
474		}
475
476		cc_binary {
477			name: "foo",
478			required: ["phony"],
479		}
480
481		phony {
482			name: "phony",
483			required: ["libbar"],
484		}
485
486		cc_library {
487			name: "libbar",
488		}
489	`)
490
491	fs := result.ModuleForTests("fs", "android_common").Module().(*filesystem)
492	expected := []string{
493		"bin/foo",
494		"lib64/libbar.so",
495	}
496	for _, e := range expected {
497		android.AssertStringListContains(t, "missing entry", fs.entries, e)
498	}
499}
500
501func TestFilterOutUnsupportedArches(t *testing.T) {
502	result := fixture.RunTestWithBp(t, `
503		android_filesystem {
504			name: "fs_64_only",
505			deps: ["foo"],
506		}
507
508		android_filesystem {
509			name: "fs_64_32",
510			compile_multilib: "both",
511			deps: ["foo"],
512		}
513
514		cc_binary {
515			name: "foo",
516			required: ["phony"],
517		}
518
519		phony {
520			name: "phony",
521			required: [
522				"libbar",
523				"app",
524			],
525		}
526
527		cc_library {
528			name: "libbar",
529		}
530
531		android_app {
532			name: "app",
533			srcs: ["a.java"],
534			platform_apis: true,
535		}
536	`)
537	testcases := []struct {
538		fsName     string
539		expected   []string
540		unexpected []string
541	}{
542		{
543			fsName:     "fs_64_only",
544			expected:   []string{"app/app/app.apk", "bin/foo", "lib64/libbar.so"},
545			unexpected: []string{"lib/libbar.so"},
546		},
547		{
548			fsName:     "fs_64_32",
549			expected:   []string{"app/app/app.apk", "bin/foo", "lib64/libbar.so", "lib/libbar.so"},
550			unexpected: []string{},
551		},
552	}
553	for _, c := range testcases {
554		fs := result.ModuleForTests(c.fsName, "android_common").Module().(*filesystem)
555		for _, e := range c.expected {
556			android.AssertStringListContains(t, "missing entry", fs.entries, e)
557		}
558		for _, e := range c.unexpected {
559			android.AssertStringListDoesNotContain(t, "unexpected entry", fs.entries, e)
560		}
561	}
562}
563