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