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 cc
16
17import (
18	"android/soong/android"
19	"fmt"
20	"path/filepath"
21	"reflect"
22	"strings"
23	"testing"
24)
25
26func TestVendorSnapshotCapture(t *testing.T) {
27	bp := `
28	cc_library {
29		name: "libvndk",
30		vendor_available: true,
31		product_available: true,
32		vndk: {
33			enabled: true,
34		},
35		nocrt: true,
36	}
37
38	cc_library {
39		name: "libvendor",
40		vendor: true,
41		nocrt: true,
42	}
43
44	cc_library {
45		name: "libvendor_available",
46		vendor_available: true,
47		nocrt: true,
48	}
49
50	cc_library_headers {
51		name: "libvendor_headers",
52		vendor_available: true,
53		nocrt: true,
54	}
55
56	cc_binary {
57		name: "vendor_bin",
58		vendor: true,
59		nocrt: true,
60	}
61
62	cc_binary {
63		name: "vendor_available_bin",
64		vendor_available: true,
65		nocrt: true,
66	}
67
68	toolchain_library {
69		name: "libb",
70		vendor_available: true,
71		src: "libb.a",
72	}
73
74	cc_object {
75		name: "obj",
76		vendor_available: true,
77	}
78
79	cc_library {
80		name: "libllndk",
81		llndk: {
82			symbol_file: "libllndk.map.txt",
83		},
84	}
85`
86
87	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
88	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
89	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
90	ctx := testCcWithConfig(t, config)
91
92	// Check Vendor snapshot output.
93
94	snapshotDir := "vendor-snapshot"
95	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
96	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
97
98	var jsonFiles []string
99
100	for _, arch := range [][]string{
101		[]string{"arm64", "armv8-a"},
102		[]string{"arm", "armv7-a-neon"},
103	} {
104		archType := arch[0]
105		archVariant := arch[1]
106		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
107
108		// For shared libraries, only non-VNDK vendor_available modules are captured
109		sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant)
110		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
111		checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
112		checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
113		jsonFiles = append(jsonFiles,
114			filepath.Join(sharedDir, "libvendor.so.json"),
115			filepath.Join(sharedDir, "libvendor_available.so.json"))
116
117		// LLNDK modules are not captured
118		checkSnapshotExclude(t, ctx, snapshotSingleton, "libllndk", "libllndk.so", sharedDir, sharedVariant)
119
120		// For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured.
121		// Also cfi variants are captured, except for prebuilts like toolchain_library
122		staticVariant := fmt.Sprintf("android_vendor.29_%s_%s_static", archType, archVariant)
123		staticCfiVariant := fmt.Sprintf("android_vendor.29_%s_%s_static_cfi", archType, archVariant)
124		staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
125		checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant)
126		checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.a", staticDir, staticVariant)
127		checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.cfi.a", staticDir, staticCfiVariant)
128		checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.a", staticDir, staticVariant)
129		checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.cfi.a", staticDir, staticCfiVariant)
130		checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.a", staticDir, staticVariant)
131		checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.cfi.a", staticDir, staticCfiVariant)
132		jsonFiles = append(jsonFiles,
133			filepath.Join(staticDir, "libb.a.json"),
134			filepath.Join(staticDir, "libvndk.a.json"),
135			filepath.Join(staticDir, "libvndk.cfi.a.json"),
136			filepath.Join(staticDir, "libvendor.a.json"),
137			filepath.Join(staticDir, "libvendor.cfi.a.json"),
138			filepath.Join(staticDir, "libvendor_available.a.json"),
139			filepath.Join(staticDir, "libvendor_available.cfi.a.json"))
140
141		// For binary executables, all vendor:true and vendor_available modules are captured.
142		if archType == "arm64" {
143			binaryVariant := fmt.Sprintf("android_vendor.29_%s_%s", archType, archVariant)
144			binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
145			checkSnapshot(t, ctx, snapshotSingleton, "vendor_bin", "vendor_bin", binaryDir, binaryVariant)
146			checkSnapshot(t, ctx, snapshotSingleton, "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant)
147			jsonFiles = append(jsonFiles,
148				filepath.Join(binaryDir, "vendor_bin.json"),
149				filepath.Join(binaryDir, "vendor_available_bin.json"))
150		}
151
152		// For header libraries, all vendor:true and vendor_available modules are captured.
153		headerDir := filepath.Join(snapshotVariantPath, archDir, "header")
154		jsonFiles = append(jsonFiles, filepath.Join(headerDir, "libvendor_headers.json"))
155
156		// For object modules, all vendor:true and vendor_available modules are captured.
157		objectVariant := fmt.Sprintf("android_vendor.29_%s_%s", archType, archVariant)
158		objectDir := filepath.Join(snapshotVariantPath, archDir, "object")
159		checkSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant)
160		jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.json"))
161	}
162
163	for _, jsonFile := range jsonFiles {
164		// verify all json files exist
165		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
166			t.Errorf("%q expected but not found", jsonFile)
167		}
168	}
169
170	// fake snapshot should have all outputs in the normal snapshot.
171	fakeSnapshotSingleton := ctx.SingletonForTests("vendor-fake-snapshot")
172	for _, output := range snapshotSingleton.AllOutputs() {
173		fakeOutput := strings.Replace(output, "/vendor-snapshot/", "/fake/vendor-snapshot/", 1)
174		if fakeSnapshotSingleton.MaybeOutput(fakeOutput).Rule == nil {
175			t.Errorf("%q expected but not found", fakeOutput)
176		}
177	}
178}
179
180func TestVendorSnapshotDirected(t *testing.T) {
181	bp := `
182	cc_library_shared {
183		name: "libvendor",
184		vendor: true,
185		nocrt: true,
186	}
187
188	cc_library_shared {
189		name: "libvendor_available",
190		vendor_available: true,
191		nocrt: true,
192	}
193
194	genrule {
195		name: "libfoo_gen",
196		cmd: "",
197		out: ["libfoo.so"],
198	}
199
200	cc_prebuilt_library_shared {
201		name: "libfoo",
202		vendor: true,
203		prefer: true,
204		srcs: [":libfoo_gen"],
205	}
206
207	cc_library_shared {
208		name: "libfoo",
209		vendor: true,
210		nocrt: true,
211	}
212`
213	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
214	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
215	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
216	config.TestProductVariables.DirectedVendorSnapshot = true
217	config.TestProductVariables.VendorSnapshotModules = make(map[string]bool)
218	config.TestProductVariables.VendorSnapshotModules["libvendor"] = true
219	config.TestProductVariables.VendorSnapshotModules["libfoo"] = true
220	ctx := testCcWithConfig(t, config)
221
222	// Check Vendor snapshot output.
223
224	snapshotDir := "vendor-snapshot"
225	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
226	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
227
228	var includeJsonFiles []string
229
230	for _, arch := range [][]string{
231		[]string{"arm64", "armv8-a"},
232		[]string{"arm", "armv7-a-neon"},
233	} {
234		archType := arch[0]
235		archVariant := arch[1]
236		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
237
238		sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant)
239		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
240
241		// Included modules
242		checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
243		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json"))
244		// Check that snapshot captures "prefer: true" prebuilt
245		checkSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo", "libfoo.so", sharedDir, sharedVariant)
246		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo.so.json"))
247
248		// Excluded modules. Modules not included in the directed vendor snapshot
249		// are still include as fake modules.
250		checkSnapshotRule(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
251		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libvendor_available.so.json"))
252	}
253
254	// Verify that each json file for an included module has a rule.
255	for _, jsonFile := range includeJsonFiles {
256		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
257			t.Errorf("include json file %q not found", jsonFile)
258		}
259	}
260}
261
262func TestVendorSnapshotUse(t *testing.T) {
263	frameworkBp := `
264	cc_library {
265		name: "libvndk",
266		vendor_available: true,
267		product_available: true,
268		vndk: {
269			enabled: true,
270		},
271		nocrt: true,
272	}
273
274	cc_library {
275		name: "libvendor",
276		vendor: true,
277		nocrt: true,
278		no_libcrt: true,
279		stl: "none",
280		system_shared_libs: [],
281	}
282
283	cc_library {
284		name: "libvendor_available",
285		vendor_available: true,
286		nocrt: true,
287		no_libcrt: true,
288		stl: "none",
289		system_shared_libs: [],
290	}
291
292	cc_library {
293		name: "lib32",
294		vendor: true,
295		nocrt: true,
296		no_libcrt: true,
297		stl: "none",
298		system_shared_libs: [],
299		compile_multilib: "32",
300	}
301
302	cc_library {
303		name: "lib64",
304		vendor: true,
305		nocrt: true,
306		no_libcrt: true,
307		stl: "none",
308		system_shared_libs: [],
309		compile_multilib: "64",
310	}
311
312	cc_library {
313		name: "libllndk",
314		llndk: {
315			symbol_file: "libllndk.map.txt",
316		},
317	}
318
319	cc_binary {
320		name: "bin",
321		vendor: true,
322		nocrt: true,
323		no_libcrt: true,
324		stl: "none",
325		system_shared_libs: [],
326	}
327
328	cc_binary {
329		name: "bin32",
330		vendor: true,
331		nocrt: true,
332		no_libcrt: true,
333		stl: "none",
334		system_shared_libs: [],
335		compile_multilib: "32",
336	}
337`
338
339	vndkBp := `
340	vndk_prebuilt_shared {
341		name: "libvndk",
342		version: "31",
343		target_arch: "arm64",
344		vendor_available: true,
345		product_available: true,
346		vndk: {
347			enabled: true,
348		},
349		arch: {
350			arm64: {
351				srcs: ["libvndk.so"],
352				export_include_dirs: ["include/libvndk"],
353			},
354			arm: {
355				srcs: ["libvndk.so"],
356				export_include_dirs: ["include/libvndk"],
357			},
358		},
359	}
360
361	// old snapshot module which has to be ignored
362	vndk_prebuilt_shared {
363		name: "libvndk",
364		version: "26",
365		target_arch: "arm64",
366		vendor_available: true,
367		product_available: true,
368		vndk: {
369			enabled: true,
370		},
371		arch: {
372			arm64: {
373				srcs: ["libvndk.so"],
374				export_include_dirs: ["include/libvndk"],
375			},
376			arm: {
377				srcs: ["libvndk.so"],
378				export_include_dirs: ["include/libvndk"],
379			},
380		},
381	}
382
383	// different arch snapshot which has to be ignored
384	vndk_prebuilt_shared {
385		name: "libvndk",
386		version: "31",
387		target_arch: "arm",
388		vendor_available: true,
389		product_available: true,
390		vndk: {
391			enabled: true,
392		},
393		arch: {
394			arm: {
395				srcs: ["libvndk.so"],
396				export_include_dirs: ["include/libvndk"],
397			},
398		},
399	}
400
401	vndk_prebuilt_shared {
402		name: "libllndk",
403		version: "31",
404		target_arch: "arm64",
405		vendor_available: true,
406		product_available: true,
407		arch: {
408			arm64: {
409				srcs: ["libllndk.so"],
410			},
411			arm: {
412				srcs: ["libllndk.so"],
413			},
414		},
415	}
416`
417
418	vendorProprietaryBp := `
419	cc_library {
420		name: "libvendor_without_snapshot",
421		vendor: true,
422		nocrt: true,
423		no_libcrt: true,
424		stl: "none",
425		system_shared_libs: [],
426	}
427
428	cc_library_shared {
429		name: "libclient",
430		vendor: true,
431		nocrt: true,
432		no_libcrt: true,
433		stl: "none",
434		system_shared_libs: [],
435		shared_libs: ["libvndk", "libvendor_available", "libllndk"],
436		static_libs: ["libvendor", "libvendor_without_snapshot"],
437		arch: {
438			arm64: {
439				shared_libs: ["lib64"],
440			},
441			arm: {
442				shared_libs: ["lib32"],
443			},
444		},
445		srcs: ["client.cpp"],
446	}
447
448	cc_library_shared {
449		name: "libclient_cfi",
450		vendor: true,
451		nocrt: true,
452		no_libcrt: true,
453		stl: "none",
454		system_shared_libs: [],
455		static_libs: ["libvendor"],
456		sanitize: {
457			cfi: true,
458		},
459		srcs: ["client.cpp"],
460	}
461
462	cc_binary {
463		name: "bin_without_snapshot",
464		vendor: true,
465		nocrt: true,
466		no_libcrt: true,
467		stl: "libc++_static",
468		system_shared_libs: [],
469		static_libs: ["libvndk"],
470		srcs: ["bin.cpp"],
471	}
472
473	vendor_snapshot {
474		name: "vendor_snapshot",
475		version: "31",
476		arch: {
477			arm64: {
478				vndk_libs: [
479					"libvndk",
480					"libllndk",
481				],
482				static_libs: [
483					"libc++_static",
484					"libc++demangle",
485					"libunwind",
486					"libvendor",
487					"libvendor_available",
488					"libvndk",
489					"lib64",
490				],
491				shared_libs: [
492					"libvendor",
493					"libvendor_available",
494					"lib64",
495				],
496				binaries: [
497					"bin",
498				],
499			},
500			arm: {
501				vndk_libs: [
502					"libvndk",
503					"libllndk",
504				],
505				static_libs: [
506					"libvendor",
507					"libvendor_available",
508					"libvndk",
509					"lib32",
510				],
511				shared_libs: [
512					"libvendor",
513					"libvendor_available",
514					"lib32",
515				],
516				binaries: [
517					"bin32",
518				],
519			},
520		}
521	}
522
523	vendor_snapshot_static {
524		name: "libvndk",
525		version: "31",
526		target_arch: "arm64",
527		compile_multilib: "both",
528		vendor: true,
529		arch: {
530			arm64: {
531				src: "libvndk.a",
532			},
533			arm: {
534				src: "libvndk.a",
535			},
536		},
537		shared_libs: ["libvndk"],
538		export_shared_lib_headers: ["libvndk"],
539	}
540
541	vendor_snapshot_shared {
542		name: "libvendor",
543		version: "31",
544		target_arch: "arm64",
545		compile_multilib: "both",
546		vendor: true,
547		shared_libs: [
548			"libvendor_without_snapshot",
549			"libvendor_available",
550			"libvndk",
551		],
552		arch: {
553			arm64: {
554				src: "libvendor.so",
555				export_include_dirs: ["include/libvendor"],
556			},
557			arm: {
558				src: "libvendor.so",
559				export_include_dirs: ["include/libvendor"],
560			},
561		},
562	}
563
564	vendor_snapshot_static {
565		name: "lib32",
566		version: "31",
567		target_arch: "arm64",
568		compile_multilib: "32",
569		vendor: true,
570		arch: {
571			arm: {
572				src: "lib32.a",
573			},
574		},
575	}
576
577	vendor_snapshot_shared {
578		name: "lib32",
579		version: "31",
580		target_arch: "arm64",
581		compile_multilib: "32",
582		vendor: true,
583		arch: {
584			arm: {
585				src: "lib32.so",
586			},
587		},
588	}
589
590	vendor_snapshot_static {
591		name: "lib64",
592		version: "31",
593		target_arch: "arm64",
594		compile_multilib: "64",
595		vendor: true,
596		arch: {
597			arm64: {
598				src: "lib64.a",
599			},
600		},
601	}
602
603	vendor_snapshot_shared {
604		name: "lib64",
605		version: "31",
606		target_arch: "arm64",
607		compile_multilib: "64",
608		vendor: true,
609		arch: {
610			arm64: {
611				src: "lib64.so",
612			},
613		},
614	}
615
616	vendor_snapshot_static {
617		name: "libvendor",
618		version: "31",
619		target_arch: "arm64",
620		compile_multilib: "both",
621		vendor: true,
622		arch: {
623			arm64: {
624				cfi: {
625					src: "libvendor.cfi.a",
626					export_include_dirs: ["include/libvendor_cfi"],
627				},
628				src: "libvendor.a",
629				export_include_dirs: ["include/libvendor"],
630			},
631			arm: {
632				cfi: {
633					src: "libvendor.cfi.a",
634					export_include_dirs: ["include/libvendor_cfi"],
635				},
636				src: "libvendor.a",
637				export_include_dirs: ["include/libvendor"],
638			},
639		},
640	}
641
642	vendor_snapshot_shared {
643		name: "libvendor_available",
644		version: "31",
645		target_arch: "arm64",
646		compile_multilib: "both",
647		vendor: true,
648		arch: {
649			arm64: {
650				src: "libvendor_available.so",
651				export_include_dirs: ["include/libvendor"],
652			},
653			arm: {
654				src: "libvendor_available.so",
655				export_include_dirs: ["include/libvendor"],
656			},
657		},
658	}
659
660	vendor_snapshot_static {
661		name: "libvendor_available",
662		version: "31",
663		target_arch: "arm64",
664		compile_multilib: "both",
665		vendor: true,
666		arch: {
667			arm64: {
668				src: "libvendor_available.a",
669				export_include_dirs: ["include/libvendor"],
670			},
671			arm: {
672				src: "libvendor_available.so",
673				export_include_dirs: ["include/libvendor"],
674			},
675		},
676	}
677
678	vendor_snapshot_static {
679		name: "libc++_static",
680		version: "31",
681		target_arch: "arm64",
682		compile_multilib: "64",
683		vendor: true,
684		arch: {
685			arm64: {
686				src: "libc++_static.a",
687			},
688		},
689	}
690
691	vendor_snapshot_static {
692		name: "libc++demangle",
693		version: "31",
694		target_arch: "arm64",
695		compile_multilib: "64",
696		vendor: true,
697		arch: {
698			arm64: {
699				src: "libc++demangle.a",
700			},
701		},
702	}
703
704	vendor_snapshot_static {
705		name: "libunwind",
706		version: "31",
707		target_arch: "arm64",
708		compile_multilib: "64",
709		vendor: true,
710		arch: {
711			arm64: {
712				src: "libunwind.a",
713			},
714		},
715	}
716
717	vendor_snapshot_binary {
718		name: "bin",
719		version: "31",
720		target_arch: "arm64",
721		compile_multilib: "64",
722		vendor: true,
723		arch: {
724			arm64: {
725				src: "bin",
726			},
727		},
728	}
729
730	vendor_snapshot_binary {
731		name: "bin32",
732		version: "31",
733		target_arch: "arm64",
734		compile_multilib: "32",
735		vendor: true,
736		arch: {
737			arm: {
738				src: "bin32",
739			},
740		},
741	}
742
743	// old snapshot module which has to be ignored
744	vendor_snapshot_binary {
745		name: "bin",
746		version: "26",
747		target_arch: "arm64",
748		compile_multilib: "first",
749		vendor: true,
750		arch: {
751			arm64: {
752				src: "bin",
753			},
754		},
755	}
756
757	// different arch snapshot which has to be ignored
758	vendor_snapshot_binary {
759		name: "bin",
760		version: "31",
761		target_arch: "arm",
762		compile_multilib: "first",
763		vendor: true,
764		arch: {
765			arm64: {
766				src: "bin",
767			},
768		},
769	}
770`
771	depsBp := GatherRequiredDepsForTest(android.Android)
772
773	mockFS := map[string][]byte{
774		"deps/Android.bp":                  []byte(depsBp),
775		"framework/Android.bp":             []byte(frameworkBp),
776		"framework/symbol.txt":             nil,
777		"vendor/Android.bp":                []byte(vendorProprietaryBp),
778		"vendor/bin":                       nil,
779		"vendor/bin32":                     nil,
780		"vendor/bin.cpp":                   nil,
781		"vendor/client.cpp":                nil,
782		"vendor/include/libvndk/a.h":       nil,
783		"vendor/include/libvendor/b.h":     nil,
784		"vendor/include/libvendor_cfi/c.h": nil,
785		"vendor/libc++_static.a":           nil,
786		"vendor/libc++demangle.a":          nil,
787		"vendor/libunwind.a":               nil,
788		"vendor/libvndk.a":                 nil,
789		"vendor/libvendor.a":               nil,
790		"vendor/libvendor.cfi.a":           nil,
791		"vendor/libvendor.so":              nil,
792		"vendor/lib32.a":                   nil,
793		"vendor/lib32.so":                  nil,
794		"vendor/lib64.a":                   nil,
795		"vendor/lib64.so":                  nil,
796		"vndk/Android.bp":                  []byte(vndkBp),
797		"vndk/include/libvndk/a.h":         nil,
798		"vndk/libvndk.so":                  nil,
799		"vndk/libllndk.so":                 nil,
800	}
801
802	config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
803	config.TestProductVariables.DeviceVndkVersion = StringPtr("31")
804	config.TestProductVariables.Platform_vndk_version = StringPtr("32")
805	ctx := CreateTestContext(config)
806	ctx.Register()
807
808	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "vendor/Android.bp", "vndk/Android.bp"})
809	android.FailIfErrored(t, errs)
810	_, errs = ctx.PrepareBuildActions(config)
811	android.FailIfErrored(t, errs)
812
813	sharedVariant := "android_vendor.31_arm64_armv8-a_shared"
814	staticVariant := "android_vendor.31_arm64_armv8-a_static"
815	binaryVariant := "android_vendor.31_arm64_armv8-a"
816
817	sharedCfiVariant := "android_vendor.31_arm64_armv8-a_shared_cfi"
818	staticCfiVariant := "android_vendor.31_arm64_armv8-a_static_cfi"
819
820	shared32Variant := "android_vendor.31_arm_armv7-a-neon_shared"
821	binary32Variant := "android_vendor.31_arm_armv7-a-neon"
822
823	// libclient uses libvndk.vndk.31.arm64, libvendor.vendor_static.31.arm64, libvendor_without_snapshot
824	libclientCcFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("cc").Args["cFlags"]
825	for _, includeFlags := range []string{
826		"-Ivndk/include/libvndk",     // libvndk
827		"-Ivendor/include/libvendor", // libvendor
828	} {
829		if !strings.Contains(libclientCcFlags, includeFlags) {
830			t.Errorf("flags for libclient must contain %#v, but was %#v.",
831				includeFlags, libclientCcFlags)
832		}
833	}
834
835	libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("ld").Args["libFlags"]
836	for _, input := range [][]string{
837		[]string{sharedVariant, "libvndk.vndk.31.arm64"},
838		[]string{sharedVariant, "libllndk.vndk.31.arm64"},
839		[]string{staticVariant, "libvendor.vendor_static.31.arm64"},
840		[]string{staticVariant, "libvendor_without_snapshot"},
841	} {
842		outputPaths := getOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */)
843		if !strings.Contains(libclientLdFlags, outputPaths[0].String()) {
844			t.Errorf("libflags for libclient must contain %#v, but was %#v", outputPaths[0], libclientLdFlags)
845		}
846	}
847
848	libclientAndroidMkSharedLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkSharedLibs
849	if g, w := libclientAndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "libllndk.vendor", "lib64"}; !reflect.DeepEqual(g, w) {
850		t.Errorf("wanted libclient AndroidMkSharedLibs %q, got %q", w, g)
851	}
852
853	libclientAndroidMkStaticLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkStaticLibs
854	if g, w := libclientAndroidMkStaticLibs, []string{"libvendor", "libvendor_without_snapshot"}; !reflect.DeepEqual(g, w) {
855		t.Errorf("wanted libclient AndroidMkStaticLibs %q, got %q", w, g)
856	}
857
858	libclient32AndroidMkSharedLibs := ctx.ModuleForTests("libclient", shared32Variant).Module().(*Module).Properties.AndroidMkSharedLibs
859	if g, w := libclient32AndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "libllndk.vendor", "lib32"}; !reflect.DeepEqual(g, w) {
860		t.Errorf("wanted libclient32 AndroidMkSharedLibs %q, got %q", w, g)
861	}
862
863	// libclient_cfi uses libvendor.vendor_static.31.arm64's cfi variant
864	libclientCfiCcFlags := ctx.ModuleForTests("libclient_cfi", sharedCfiVariant).Rule("cc").Args["cFlags"]
865	if !strings.Contains(libclientCfiCcFlags, "-Ivendor/include/libvendor_cfi") {
866		t.Errorf("flags for libclient_cfi must contain %#v, but was %#v.",
867			"-Ivendor/include/libvendor_cfi", libclientCfiCcFlags)
868	}
869
870	libclientCfiLdFlags := ctx.ModuleForTests("libclient_cfi", sharedCfiVariant).Rule("ld").Args["libFlags"]
871	libvendorCfiOutputPaths := getOutputPaths(ctx, staticCfiVariant, []string{"libvendor.vendor_static.31.arm64"})
872	if !strings.Contains(libclientCfiLdFlags, libvendorCfiOutputPaths[0].String()) {
873		t.Errorf("libflags for libclientCfi must contain %#v, but was %#v", libvendorCfiOutputPaths[0], libclientCfiLdFlags)
874	}
875
876	// bin_without_snapshot uses libvndk.vendor_static.31.arm64 (which reexports vndk's exported headers)
877	binWithoutSnapshotCcFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("cc").Args["cFlags"]
878	if !strings.Contains(binWithoutSnapshotCcFlags, "-Ivndk/include/libvndk") {
879		t.Errorf("flags for bin_without_snapshot must contain %#v, but was %#v.",
880			"-Ivendor/include/libvndk", binWithoutSnapshotCcFlags)
881	}
882
883	binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("ld").Args["libFlags"]
884	libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.31.arm64"})
885	if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) {
886		t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v",
887			libVndkStaticOutputPaths[0], binWithoutSnapshotLdFlags)
888	}
889
890	// libvendor.so is installed by libvendor.vendor_shared.31.arm64
891	ctx.ModuleForTests("libvendor.vendor_shared.31.arm64", sharedVariant).Output("libvendor.so")
892
893	// lib64.so is installed by lib64.vendor_shared.31.arm64
894	ctx.ModuleForTests("lib64.vendor_shared.31.arm64", sharedVariant).Output("lib64.so")
895
896	// lib32.so is installed by lib32.vendor_shared.31.arm64
897	ctx.ModuleForTests("lib32.vendor_shared.31.arm64", shared32Variant).Output("lib32.so")
898
899	// libvendor_available.so is installed by libvendor_available.vendor_shared.31.arm64
900	ctx.ModuleForTests("libvendor_available.vendor_shared.31.arm64", sharedVariant).Output("libvendor_available.so")
901
902	// libvendor_without_snapshot.so is installed by libvendor_without_snapshot
903	ctx.ModuleForTests("libvendor_without_snapshot", sharedVariant).Output("libvendor_without_snapshot.so")
904
905	// bin is installed by bin.vendor_binary.31.arm64
906	ctx.ModuleForTests("bin.vendor_binary.31.arm64", binaryVariant).Output("bin")
907
908	// bin32 is installed by bin32.vendor_binary.31.arm64
909	ctx.ModuleForTests("bin32.vendor_binary.31.arm64", binary32Variant).Output("bin32")
910
911	// bin_without_snapshot is installed by bin_without_snapshot
912	ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Output("bin_without_snapshot")
913
914	// libvendor, libvendor_available and bin don't have vendor.31 variant
915	libvendorVariants := ctx.ModuleVariantsForTests("libvendor")
916	if inList(sharedVariant, libvendorVariants) {
917		t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant)
918	}
919
920	libvendorAvailableVariants := ctx.ModuleVariantsForTests("libvendor_available")
921	if inList(sharedVariant, libvendorAvailableVariants) {
922		t.Errorf("libvendor_available must not have variant %#v, but it does", sharedVariant)
923	}
924
925	binVariants := ctx.ModuleVariantsForTests("bin")
926	if inList(binaryVariant, binVariants) {
927		t.Errorf("bin must not have variant %#v, but it does", sharedVariant)
928	}
929}
930
931func TestVendorSnapshotSanitizer(t *testing.T) {
932	bp := `
933	vendor_snapshot {
934		name: "vendor_snapshot",
935		version: "28",
936		arch: {
937			arm64: {
938				static_libs: [
939					"libsnapshot",
940					"note_memtag_heap_sync",
941				],
942			},
943		},
944	}
945	vendor_snapshot_static {
946		name: "libsnapshot",
947		vendor: true,
948		target_arch: "arm64",
949		version: "28",
950		arch: {
951			arm64: {
952				src: "libsnapshot.a",
953				cfi: {
954					src: "libsnapshot.cfi.a",
955				}
956			},
957		},
958	}
959
960	vendor_snapshot_static {
961		name: "note_memtag_heap_sync",
962		vendor: true,
963		target_arch: "arm64",
964		version: "28",
965		arch: {
966			arm64: {
967				src: "note_memtag_heap_sync.a",
968			},
969		},
970	}
971
972	cc_test {
973		name: "vstest",
974		gtest: false,
975		vendor: true,
976		compile_multilib: "64",
977		nocrt: true,
978		no_libcrt: true,
979		stl: "none",
980		static_libs: ["libsnapshot"],
981		system_shared_libs: [],
982	}
983`
984
985	mockFS := map[string][]byte{
986		"vendor/Android.bp":              []byte(bp),
987		"vendor/libc++demangle.a":        nil,
988		"vendor/libsnapshot.a":           nil,
989		"vendor/libsnapshot.cfi.a":       nil,
990		"vendor/note_memtag_heap_sync.a": nil,
991	}
992
993	config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
994	config.TestProductVariables.DeviceVndkVersion = StringPtr("28")
995	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
996	ctx := testCcWithConfig(t, config)
997
998	// Check non-cfi and cfi variant.
999	staticVariant := "android_vendor.28_arm64_armv8-a_static"
1000	staticCfiVariant := "android_vendor.28_arm64_armv8-a_static_cfi"
1001
1002	staticModule := ctx.ModuleForTests("libsnapshot.vendor_static.28.arm64", staticVariant).Module().(*Module)
1003	assertString(t, staticModule.outputFile.Path().Base(), "libsnapshot.a")
1004
1005	staticCfiModule := ctx.ModuleForTests("libsnapshot.vendor_static.28.arm64", staticCfiVariant).Module().(*Module)
1006	assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a")
1007}
1008
1009func assertExcludeFromVendorSnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool) {
1010	t.Helper()
1011	m := ctx.ModuleForTests(name, vendorVariant).Module().(*Module)
1012	if m.ExcludeFromVendorSnapshot() != expected {
1013		t.Errorf("expected %q ExcludeFromVendorSnapshot to be %t", m.String(), expected)
1014	}
1015}
1016
1017func assertExcludeFromRecoverySnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool) {
1018	t.Helper()
1019	m := ctx.ModuleForTests(name, recoveryVariant).Module().(*Module)
1020	if m.ExcludeFromRecoverySnapshot() != expected {
1021		t.Errorf("expected %q ExcludeFromRecoverySnapshot to be %t", m.String(), expected)
1022	}
1023}
1024
1025func TestVendorSnapshotExclude(t *testing.T) {
1026
1027	// This test verifies that the exclude_from_vendor_snapshot property
1028	// makes its way from the Android.bp source file into the module data
1029	// structure. It also verifies that modules are correctly included or
1030	// excluded in the vendor snapshot based on their path (framework or
1031	// vendor) and the exclude_from_vendor_snapshot property.
1032
1033	frameworkBp := `
1034		cc_library_shared {
1035			name: "libinclude",
1036			srcs: ["src/include.cpp"],
1037			vendor_available: true,
1038		}
1039		cc_library_shared {
1040			name: "libexclude",
1041			srcs: ["src/exclude.cpp"],
1042			vendor: true,
1043			exclude_from_vendor_snapshot: true,
1044		}
1045		cc_library_shared {
1046			name: "libavailable_exclude",
1047			srcs: ["src/exclude.cpp"],
1048			vendor_available: true,
1049			exclude_from_vendor_snapshot: true,
1050		}
1051	`
1052
1053	vendorProprietaryBp := `
1054		cc_library_shared {
1055			name: "libvendor",
1056			srcs: ["vendor.cpp"],
1057			vendor: true,
1058		}
1059	`
1060
1061	depsBp := GatherRequiredDepsForTest(android.Android)
1062
1063	mockFS := map[string][]byte{
1064		"deps/Android.bp":       []byte(depsBp),
1065		"framework/Android.bp":  []byte(frameworkBp),
1066		"framework/include.cpp": nil,
1067		"framework/exclude.cpp": nil,
1068		"device/Android.bp":     []byte(vendorProprietaryBp),
1069		"device/vendor.cpp":     nil,
1070	}
1071
1072	config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
1073	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
1074	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
1075	ctx := CreateTestContext(config)
1076	ctx.Register()
1077
1078	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"})
1079	android.FailIfErrored(t, errs)
1080	_, errs = ctx.PrepareBuildActions(config)
1081	android.FailIfErrored(t, errs)
1082
1083	// Test an include and exclude framework module.
1084	assertExcludeFromVendorSnapshotIs(t, ctx, "libinclude", false)
1085	assertExcludeFromVendorSnapshotIs(t, ctx, "libexclude", true)
1086	assertExcludeFromVendorSnapshotIs(t, ctx, "libavailable_exclude", true)
1087
1088	// A vendor module is excluded, but by its path, not the
1089	// exclude_from_vendor_snapshot property.
1090	assertExcludeFromVendorSnapshotIs(t, ctx, "libvendor", false)
1091
1092	// Verify the content of the vendor snapshot.
1093
1094	snapshotDir := "vendor-snapshot"
1095	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
1096	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
1097
1098	var includeJsonFiles []string
1099	var excludeJsonFiles []string
1100
1101	for _, arch := range [][]string{
1102		[]string{"arm64", "armv8-a"},
1103		[]string{"arm", "armv7-a-neon"},
1104	} {
1105		archType := arch[0]
1106		archVariant := arch[1]
1107		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
1108
1109		sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant)
1110		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
1111
1112		// Included modules
1113		checkSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant)
1114		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json"))
1115
1116		// Excluded modules
1117		checkSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant)
1118		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json"))
1119		checkSnapshotExclude(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
1120		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json"))
1121		checkSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant)
1122		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json"))
1123	}
1124
1125	// Verify that each json file for an included module has a rule.
1126	for _, jsonFile := range includeJsonFiles {
1127		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
1128			t.Errorf("include json file %q not found", jsonFile)
1129		}
1130	}
1131
1132	// Verify that each json file for an excluded module has no rule.
1133	for _, jsonFile := range excludeJsonFiles {
1134		if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
1135			t.Errorf("exclude json file %q found", jsonFile)
1136		}
1137	}
1138}
1139
1140func TestVendorSnapshotExcludeInVendorProprietaryPathErrors(t *testing.T) {
1141
1142	// This test verifies that using the exclude_from_vendor_snapshot
1143	// property on a module in a vendor proprietary path generates an
1144	// error. These modules are already excluded, so we prohibit using the
1145	// property in this way, which could add to confusion.
1146
1147	vendorProprietaryBp := `
1148		cc_library_shared {
1149			name: "libvendor",
1150			srcs: ["vendor.cpp"],
1151			vendor: true,
1152			exclude_from_vendor_snapshot: true,
1153		}
1154	`
1155
1156	depsBp := GatherRequiredDepsForTest(android.Android)
1157
1158	mockFS := map[string][]byte{
1159		"deps/Android.bp":   []byte(depsBp),
1160		"device/Android.bp": []byte(vendorProprietaryBp),
1161		"device/vendor.cpp": nil,
1162	}
1163
1164	config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
1165	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
1166	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
1167	ctx := CreateTestContext(config)
1168	ctx.Register()
1169
1170	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "device/Android.bp"})
1171	android.FailIfErrored(t, errs)
1172
1173	_, errs = ctx.PrepareBuildActions(config)
1174	android.CheckErrorsAgainstExpectations(t, errs, []string{
1175		`module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
1176		`module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
1177		`module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
1178		`module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
1179		`module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
1180		`module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
1181	})
1182}
1183
1184func TestRecoverySnapshotCapture(t *testing.T) {
1185	bp := `
1186	cc_library {
1187		name: "libvndk",
1188		vendor_available: true,
1189		recovery_available: true,
1190		product_available: true,
1191		vndk: {
1192			enabled: true,
1193		},
1194		nocrt: true,
1195	}
1196
1197	cc_library {
1198		name: "librecovery",
1199		recovery: true,
1200		nocrt: true,
1201	}
1202
1203	cc_library {
1204		name: "librecovery_available",
1205		recovery_available: true,
1206		nocrt: true,
1207	}
1208
1209	cc_library_headers {
1210		name: "librecovery_headers",
1211		recovery_available: true,
1212		nocrt: true,
1213	}
1214
1215	cc_binary {
1216		name: "recovery_bin",
1217		recovery: true,
1218		nocrt: true,
1219	}
1220
1221	cc_binary {
1222		name: "recovery_available_bin",
1223		recovery_available: true,
1224		nocrt: true,
1225	}
1226
1227	toolchain_library {
1228		name: "libb",
1229		recovery_available: true,
1230		src: "libb.a",
1231	}
1232
1233	cc_object {
1234		name: "obj",
1235		recovery_available: true,
1236	}
1237`
1238	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
1239	config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
1240	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
1241	ctx := testCcWithConfig(t, config)
1242
1243	// Check Recovery snapshot output.
1244
1245	snapshotDir := "recovery-snapshot"
1246	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
1247	snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
1248
1249	var jsonFiles []string
1250
1251	for _, arch := range [][]string{
1252		[]string{"arm64", "armv8-a"},
1253	} {
1254		archType := arch[0]
1255		archVariant := arch[1]
1256		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
1257
1258		// For shared libraries, only recovery_available modules are captured.
1259		sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
1260		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
1261		checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", sharedDir, sharedVariant)
1262		checkSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
1263		checkSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant)
1264		jsonFiles = append(jsonFiles,
1265			filepath.Join(sharedDir, "libvndk.so.json"),
1266			filepath.Join(sharedDir, "librecovery.so.json"),
1267			filepath.Join(sharedDir, "librecovery_available.so.json"))
1268
1269		// For static libraries, all recovery:true and recovery_available modules are captured.
1270		staticVariant := fmt.Sprintf("android_recovery_%s_%s_static", archType, archVariant)
1271		staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
1272		checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant)
1273		checkSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.a", staticDir, staticVariant)
1274		checkSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.a", staticDir, staticVariant)
1275		jsonFiles = append(jsonFiles,
1276			filepath.Join(staticDir, "libb.a.json"),
1277			filepath.Join(staticDir, "librecovery.a.json"),
1278			filepath.Join(staticDir, "librecovery_available.a.json"))
1279
1280		// For binary executables, all recovery:true and recovery_available modules are captured.
1281		if archType == "arm64" {
1282			binaryVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant)
1283			binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
1284			checkSnapshot(t, ctx, snapshotSingleton, "recovery_bin", "recovery_bin", binaryDir, binaryVariant)
1285			checkSnapshot(t, ctx, snapshotSingleton, "recovery_available_bin", "recovery_available_bin", binaryDir, binaryVariant)
1286			jsonFiles = append(jsonFiles,
1287				filepath.Join(binaryDir, "recovery_bin.json"),
1288				filepath.Join(binaryDir, "recovery_available_bin.json"))
1289		}
1290
1291		// For header libraries, all vendor:true and vendor_available modules are captured.
1292		headerDir := filepath.Join(snapshotVariantPath, archDir, "header")
1293		jsonFiles = append(jsonFiles, filepath.Join(headerDir, "librecovery_headers.json"))
1294
1295		// For object modules, all vendor:true and vendor_available modules are captured.
1296		objectVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant)
1297		objectDir := filepath.Join(snapshotVariantPath, archDir, "object")
1298		checkSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant)
1299		jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.json"))
1300	}
1301
1302	for _, jsonFile := range jsonFiles {
1303		// verify all json files exist
1304		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
1305			t.Errorf("%q expected but not found", jsonFile)
1306		}
1307	}
1308}
1309
1310func TestRecoverySnapshotExclude(t *testing.T) {
1311	// This test verifies that the exclude_from_recovery_snapshot property
1312	// makes its way from the Android.bp source file into the module data
1313	// structure. It also verifies that modules are correctly included or
1314	// excluded in the recovery snapshot based on their path (framework or
1315	// vendor) and the exclude_from_recovery_snapshot property.
1316
1317	frameworkBp := `
1318		cc_library_shared {
1319			name: "libinclude",
1320			srcs: ["src/include.cpp"],
1321			recovery_available: true,
1322		}
1323		cc_library_shared {
1324			name: "libexclude",
1325			srcs: ["src/exclude.cpp"],
1326			recovery: true,
1327			exclude_from_recovery_snapshot: true,
1328		}
1329		cc_library_shared {
1330			name: "libavailable_exclude",
1331			srcs: ["src/exclude.cpp"],
1332			recovery_available: true,
1333			exclude_from_recovery_snapshot: true,
1334		}
1335	`
1336
1337	vendorProprietaryBp := `
1338		cc_library_shared {
1339			name: "librecovery",
1340			srcs: ["recovery.cpp"],
1341			recovery: true,
1342		}
1343	`
1344
1345	depsBp := GatherRequiredDepsForTest(android.Android)
1346
1347	mockFS := map[string][]byte{
1348		"deps/Android.bp":       []byte(depsBp),
1349		"framework/Android.bp":  []byte(frameworkBp),
1350		"framework/include.cpp": nil,
1351		"framework/exclude.cpp": nil,
1352		"device/Android.bp":     []byte(vendorProprietaryBp),
1353		"device/recovery.cpp":   nil,
1354	}
1355
1356	config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
1357	config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
1358	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
1359	ctx := CreateTestContext(config)
1360	ctx.Register()
1361
1362	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"})
1363	android.FailIfErrored(t, errs)
1364	_, errs = ctx.PrepareBuildActions(config)
1365	android.FailIfErrored(t, errs)
1366
1367	// Test an include and exclude framework module.
1368	assertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false)
1369	assertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true)
1370	assertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true)
1371
1372	// A recovery module is excluded, but by its path, not the
1373	// exclude_from_recovery_snapshot property.
1374	assertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false)
1375
1376	// Verify the content of the recovery snapshot.
1377
1378	snapshotDir := "recovery-snapshot"
1379	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
1380	snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
1381
1382	var includeJsonFiles []string
1383	var excludeJsonFiles []string
1384
1385	for _, arch := range [][]string{
1386		[]string{"arm64", "armv8-a"},
1387	} {
1388		archType := arch[0]
1389		archVariant := arch[1]
1390		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
1391
1392		sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
1393		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
1394
1395		// Included modules
1396		checkSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant)
1397		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json"))
1398
1399		// Excluded modules
1400		checkSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant)
1401		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json"))
1402		checkSnapshotExclude(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
1403		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json"))
1404		checkSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant)
1405		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json"))
1406	}
1407
1408	// Verify that each json file for an included module has a rule.
1409	for _, jsonFile := range includeJsonFiles {
1410		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
1411			t.Errorf("include json file %q not found", jsonFile)
1412		}
1413	}
1414
1415	// Verify that each json file for an excluded module has no rule.
1416	for _, jsonFile := range excludeJsonFiles {
1417		if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
1418			t.Errorf("exclude json file %q found", jsonFile)
1419		}
1420	}
1421}
1422
1423func TestRecoverySnapshotDirected(t *testing.T) {
1424	bp := `
1425	cc_library_shared {
1426		name: "librecovery",
1427		recovery: true,
1428		nocrt: true,
1429	}
1430
1431	cc_library_shared {
1432		name: "librecovery_available",
1433		recovery_available: true,
1434		nocrt: true,
1435	}
1436
1437	genrule {
1438		name: "libfoo_gen",
1439		cmd: "",
1440		out: ["libfoo.so"],
1441	}
1442
1443	cc_prebuilt_library_shared {
1444		name: "libfoo",
1445		recovery: true,
1446		prefer: true,
1447		srcs: [":libfoo_gen"],
1448	}
1449
1450	cc_library_shared {
1451		name: "libfoo",
1452		recovery: true,
1453		nocrt: true,
1454	}
1455`
1456	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
1457	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
1458	config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
1459	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
1460	config.TestProductVariables.DirectedRecoverySnapshot = true
1461	config.TestProductVariables.RecoverySnapshotModules = make(map[string]bool)
1462	config.TestProductVariables.RecoverySnapshotModules["librecovery"] = true
1463	config.TestProductVariables.RecoverySnapshotModules["libfoo"] = true
1464	ctx := testCcWithConfig(t, config)
1465
1466	// Check recovery snapshot output.
1467
1468	snapshotDir := "recovery-snapshot"
1469	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
1470	snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
1471
1472	var includeJsonFiles []string
1473
1474	for _, arch := range [][]string{
1475		[]string{"arm64", "armv8-a"},
1476	} {
1477		archType := arch[0]
1478		archVariant := arch[1]
1479		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
1480
1481		sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
1482		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
1483
1484		// Included modules
1485		checkSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
1486		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json"))
1487		// Check that snapshot captures "prefer: true" prebuilt
1488		checkSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo", "libfoo.so", sharedDir, sharedVariant)
1489		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo.so.json"))
1490
1491		// Excluded modules. Modules not included in the directed recovery snapshot
1492		// are still include as fake modules.
1493		checkSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant)
1494		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery_available.so.json"))
1495	}
1496
1497	// Verify that each json file for an included module has a rule.
1498	for _, jsonFile := range includeJsonFiles {
1499		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
1500			t.Errorf("include json file %q not found", jsonFile)
1501		}
1502	}
1503}
1504