// Copyright 2021 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package rust import ( "fmt" "path/filepath" "reflect" "strings" "testing" "android/soong/android" "android/soong/cc" ) func TestVendorSnapshotCapture(t *testing.T) { bp := ` rust_ffi { name: "libffivendor_available", crate_name: "ffivendor_available", srcs: ["lib.rs"], vendor_available: true, include_dirs: ["rust_headers/"], } rust_ffi { name: "libffivendor", crate_name: "ffivendor", srcs: ["lib.rs"], vendor: true, include_dirs: ["rust_headers/"], } rust_library { name: "librustvendor_available", crate_name: "rustvendor_available", srcs: ["lib.rs"], vendor_available: true, include_dirs: ["rust_headers/"], } rust_library_rlib { name: "librustvendor", crate_name: "rustvendor", srcs: ["lib.rs"], vendor: true, include_dirs: ["rust_headers/"], } rust_binary { name: "vendor_available_bin", vendor_available: true, srcs: ["srcs/lib.rs"], } rust_binary { name: "vendor_bin", vendor: true, srcs: ["srcs/lib.rs"], } ` skipTestIfOsNotSupported(t) result := android.GroupFixturePreparers( prepareForRustTest, rustMockedFiles.AddToFixture(), android.FixtureModifyProductVariables( func(variables android.FixtureProductVariables) { variables.DeviceVndkVersion = StringPtr("current") variables.Platform_vndk_version = StringPtr("29") }, ), ).RunTestWithBp(t, bp) ctx := result.TestContext // Check Vendor snapshot output. snapshotDir := "vendor-snapshot" snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") snapshotSingleton := ctx.SingletonForTests("vendor-snapshot") var jsonFiles []string for _, arch := range [][]string{ []string{"arm64", "armv8-a"}, []string{"arm", "armv7-a-neon"}, } { archType := arch[0] archVariant := arch[1] archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) // For shared libraries, only non-VNDK vendor_available modules are captured sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant) sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") cc.CheckSnapshot(t, ctx, snapshotSingleton, "libffivendor_available", "libffivendor_available.so", sharedDir, sharedVariant) jsonFiles = append(jsonFiles, filepath.Join(sharedDir, "libffivendor_available.so.json")) // For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured. staticVariant := fmt.Sprintf("android_vendor.29_%s_%s_static", archType, archVariant) staticDir := filepath.Join(snapshotVariantPath, archDir, "static") cc.CheckSnapshot(t, ctx, snapshotSingleton, "libffivendor_available", "libffivendor_available.a", staticDir, staticVariant) cc.CheckSnapshot(t, ctx, snapshotSingleton, "libffivendor", "libffivendor.a", staticDir, staticVariant) jsonFiles = append(jsonFiles, filepath.Join(staticDir, "libffivendor_available.a.json")) jsonFiles = append(jsonFiles, filepath.Join(staticDir, "libffivendor.a.json")) // For rlib libraries, all vendor:true and vendor_available modules (including VNDK) are captured. rlibVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_rlib-std", archType, archVariant) rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.rlib", rlibDir, rlibVariant) cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor", "librustvendor.rlib", rlibDir, rlibVariant) jsonFiles = append(jsonFiles, filepath.Join(rlibDir, "librustvendor_available.rlib.json")) jsonFiles = append(jsonFiles, filepath.Join(rlibDir, "librustvendor.rlib.json")) // For binary executables, all vendor:true and vendor_available modules are captured. if archType == "arm64" { binaryVariant := fmt.Sprintf("android_vendor.29_%s_%s", archType, archVariant) binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary") cc.CheckSnapshot(t, ctx, snapshotSingleton, "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant) cc.CheckSnapshot(t, ctx, snapshotSingleton, "vendor_bin", "vendor_bin", binaryDir, binaryVariant) jsonFiles = append(jsonFiles, filepath.Join(binaryDir, "vendor_available_bin.json")) jsonFiles = append(jsonFiles, filepath.Join(binaryDir, "vendor_bin.json")) } } for _, jsonFile := range jsonFiles { // verify all json files exist if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { t.Errorf("%q expected but not found; #%v", jsonFile, jsonFiles) } } // fake snapshot should have all outputs in the normal snapshot. fakeSnapshotSingleton := ctx.SingletonForTests("vendor-fake-snapshot") for _, output := range snapshotSingleton.AllOutputs() { fakeOutput := strings.Replace(output, "/vendor-snapshot/", "/fake/vendor-snapshot/", 1) if fakeSnapshotSingleton.MaybeOutput(fakeOutput).Rule == nil { t.Errorf("%q expected but not found", fakeOutput) } } } func TestVendorSnapshotDirected(t *testing.T) { bp := ` rust_ffi_shared { name: "libffivendor_available", crate_name: "ffivendor_available", srcs: ["lib.rs"], vendor_available: true, } rust_library { name: "librustvendor_available", crate_name: "rustvendor_available", srcs: ["lib.rs"], vendor_available: true, } rust_ffi_shared { name: "libffivendor_exclude", crate_name: "ffivendor_exclude", srcs: ["lib.rs"], vendor_available: true, } rust_library { name: "librustvendor_exclude", crate_name: "rustvendor_exclude", srcs: ["lib.rs"], vendor_available: true, } ` ctx := testRustVndk(t, bp) ctx.Config().TestProductVariables.VendorSnapshotModules = make(map[string]bool) ctx.Config().TestProductVariables.VendorSnapshotModules["librustvendor_available"] = true ctx.Config().TestProductVariables.VendorSnapshotModules["libffivendor_available"] = true ctx.Config().TestProductVariables.DirectedVendorSnapshot = true // Check Vendor snapshot output. snapshotDir := "vendor-snapshot" snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") snapshotSingleton := ctx.SingletonForTests("vendor-snapshot") var includeJsonFiles []string for _, arch := range [][]string{ []string{"arm64", "armv8-a"}, []string{"arm", "armv7-a-neon"}, } { archType := arch[0] archVariant := arch[1] archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant) rlibVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_rlib-std", archType, archVariant) sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") // Included modules cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.rlib", rlibDir, rlibVariant) cc.CheckSnapshot(t, ctx, snapshotSingleton, "libffivendor_available", "libffivendor_available.so", sharedDir, sharedVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librustvendor_available.rlib.json")) includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libffivendor_available.so.json")) // Excluded modules. Modules not included in the directed vendor snapshot // are still include as fake modules. cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librustvendor_exclude", "librustvendor_exclude.rlib", rlibDir, rlibVariant) cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "libffivendor_exclude", "libffivendor_exclude.so", sharedDir, sharedVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librustvendor_exclude.rlib.json")) includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libffivendor_exclude.so.json")) } // Verify that each json file for an included module has a rule. for _, jsonFile := range includeJsonFiles { if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { t.Errorf("include json file %q not found", jsonFile) } } } func TestVendorSnapshotExclude(t *testing.T) { // This test verifies that the exclude_from_vendor_snapshot property // makes its way from the Android.bp source file into the module data // structure. It also verifies that modules are correctly included or // excluded in the vendor snapshot based on their path (framework or // vendor) and the exclude_from_vendor_snapshot property. frameworkBp := ` rust_ffi_shared { name: "libinclude", crate_name: "include", srcs: ["include.rs"], vendor_available: true, } rust_ffi_shared { name: "libexclude", crate_name: "exclude", srcs: ["exclude.rs"], vendor: true, exclude_from_vendor_snapshot: true, } rust_ffi_shared { name: "libavailable_exclude", crate_name: "available_exclude", srcs: ["lib.rs"], vendor_available: true, exclude_from_vendor_snapshot: true, } rust_library { name: "librust_include", crate_name: "rust_include", srcs: ["include.rs"], vendor_available: true, } rust_library_rlib { name: "librust_exclude", crate_name: "rust_exclude", srcs: ["exclude.rs"], vendor: true, exclude_from_vendor_snapshot: true, } rust_library { name: "librust_available_exclude", crate_name: "rust_available_exclude", srcs: ["lib.rs"], vendor_available: true, exclude_from_vendor_snapshot: true, } ` mockFS := map[string][]byte{ "framework/Android.bp": []byte(frameworkBp), "framework/include.rs": nil, "framework/exclude.rs": nil, } ctx := testRustVndkFs(t, "", mockFS) // Test an include and exclude framework module. cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "libinclude", false, sharedVendorVariant) cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "libexclude", true, sharedVendorVariant) cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "libavailable_exclude", true, sharedVendorVariant) cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_include", false, rlibVendorVariant) cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_exclude", true, rlibVendorVariant) cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_available_exclude", true, rlibVendorVariant) // Verify the content of the vendor snapshot. snapshotDir := "vendor-snapshot" snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") snapshotSingleton := ctx.SingletonForTests("vendor-snapshot") var includeJsonFiles []string var excludeJsonFiles []string for _, arch := range [][]string{ []string{"arm64", "armv8-a"}, []string{"arm", "armv7-a-neon"}, } { archType := arch[0] archVariant := arch[1] archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant) sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") rlibVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_rlib-std", archType, archVariant) rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") // Included modules cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json")) cc.CheckSnapshot(t, ctx, snapshotSingleton, "librust_include", "librust_include.rlib", rlibDir, rlibVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librust_include.rlib.json")) // Excluded modules cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant) excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json")) cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant) excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json")) cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librust_exclude", "librust_exclude.rlib", rlibDir, rlibVariant) excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librust_exclude.rlib.json")) cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librust_available_exclude", "librust_available_exclude.rlib", rlibDir, rlibVariant) excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librust_available_exclude.rlib.json")) } // Verify that each json file for an included module has a rule. for _, jsonFile := range includeJsonFiles { if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { t.Errorf("include json file %q not found", jsonFile) } } // Verify that each json file for an excluded module has no rule. for _, jsonFile := range excludeJsonFiles { if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil { t.Errorf("exclude json file %q found", jsonFile) } } } func TestVendorSnapshotUse(t *testing.T) { frameworkBp := ` cc_library { name: "libvndk", vendor_available: true, product_available: true, vndk: { enabled: true, }, nocrt: true, } cc_library { name: "libvendor", vendor: true, nocrt: true, no_libcrt: true, stl: "none", system_shared_libs: [], } cc_library { name: "libvendor_available", vendor_available: true, nocrt: true, no_libcrt: true, stl: "none", system_shared_libs: [], } cc_library { name: "lib32", vendor: true, nocrt: true, no_libcrt: true, stl: "none", system_shared_libs: [], compile_multilib: "32", } cc_library { name: "lib64", vendor: true, nocrt: true, no_libcrt: true, stl: "none", system_shared_libs: [], compile_multilib: "64", } rust_binary { name: "bin", vendor: true, srcs: ["bin.rs"], } rust_binary { name: "bin32", vendor: true, compile_multilib: "32", srcs: ["bin.rs"], } rust_library { name: "librust_vendor_available", crate_name: "rust_vendor", vendor_available: true, srcs: ["client.rs"], } ` vndkBp := ` vndk_prebuilt_shared { name: "libvndk", version: "30", target_arch: "arm64", vendor_available: true, product_available: true, vndk: { enabled: true, }, arch: { arm64: { srcs: ["libvndk.so"], export_include_dirs: ["include/libvndk"], }, arm: { srcs: ["libvndk.so"], export_include_dirs: ["include/libvndk"], }, }, } // old snapshot module which has to be ignored vndk_prebuilt_shared { name: "libvndk", version: "26", target_arch: "arm64", vendor_available: true, product_available: true, vndk: { enabled: true, }, arch: { arm64: { srcs: ["libvndk.so"], export_include_dirs: ["include/libvndk"], }, arm: { srcs: ["libvndk.so"], export_include_dirs: ["include/libvndk"], }, }, } // different arch snapshot which has to be ignored vndk_prebuilt_shared { name: "libvndk", version: "30", target_arch: "arm", vendor_available: true, product_available: true, vndk: { enabled: true, }, arch: { arm: { srcs: ["libvndk.so"], export_include_dirs: ["include/libvndk"], }, }, } ` vendorProprietaryBp := ` cc_library { name: "libvendor_without_snapshot", vendor: true, nocrt: true, no_libcrt: true, stl: "none", system_shared_libs: [], } rust_ffi_shared { name: "libclient", crate_name: "client", vendor: true, shared_libs: ["libvndk", "libvendor_available"], static_libs: ["libvendor", "libvendor_without_snapshot"], rustlibs: ["librust_vendor_available"], arch: { arm64: { shared_libs: ["lib64"], }, arm: { shared_libs: ["lib32"], }, }, srcs: ["client.rs"], } rust_library_rlib { name: "libclient_rust", crate_name: "client_rust", vendor: true, shared_libs: ["libvndk", "libvendor_available"], static_libs: ["libvendor", "libvendor_without_snapshot"], rustlibs: ["librust_vendor_available"], arch: { arm64: { shared_libs: ["lib64"], }, arm: { shared_libs: ["lib32"], }, }, srcs: ["client.rs"], } rust_binary { name: "bin_without_snapshot", vendor: true, static_libs: ["libvndk"], srcs: ["bin.rs"], rustlibs: ["librust_vendor_available"], } vendor_snapshot { name: "vendor_snapshot", version: "30", arch: { arm64: { vndk_libs: [ "libvndk", ], static_libs: [ "libvendor", "libvndk", "libclang_rt.builtins", "note_memtag_heap_sync", ], shared_libs: [ "libvendor_available", "lib64", ], rlibs: [ "libstd", "librust_vendor_available", ], binaries: [ "bin", ], objects: [ "crtend_so", "crtbegin_so", "crtbegin_dynamic", "crtend_android" ], }, arm: { vndk_libs: [ "libvndk", ], static_libs: [ "libvendor", "libvndk", "libclang_rt.builtins", ], shared_libs: [ "libvendor_available", "lib32", ], rlibs: [ "libstd", "librust_vendor_available", ], binaries: [ "bin32", ], objects: [ "crtend_so", "crtbegin_so", "crtbegin_dynamic", "crtend_android" ], }, } } vendor_snapshot_object { name: "crtend_so", version: "30", target_arch: "arm64", vendor: true, stl: "none", crt: true, arch: { arm64: { src: "crtend_so.o", }, arm: { src: "crtend_so.o", }, }, } vendor_snapshot_object { name: "crtbegin_so", version: "30", target_arch: "arm64", vendor: true, stl: "none", crt: true, arch: { arm64: { src: "crtbegin_so.o", }, arm: { src: "crtbegin_so.o", }, }, } vendor_snapshot_rlib { name: "libstd", version: "30", target_arch: "arm64", vendor: true, sysroot: true, arch: { arm64: { src: "libstd.rlib", }, arm: { src: "libstd.rlib", }, }, } vendor_snapshot_rlib { name: "librust_vendor_available", version: "30", target_arch: "arm64", vendor: true, arch: { arm64: { src: "librust_vendor_available.rlib", }, arm: { src: "librust_vendor_available.rlib", }, }, } vendor_snapshot_object { name: "crtend_android", version: "30", target_arch: "arm64", vendor: true, stl: "none", crt: true, arch: { arm64: { src: "crtend_so.o", }, arm: { src: "crtend_so.o", }, }, } vendor_snapshot_object { name: "crtbegin_dynamic", version: "30", target_arch: "arm64", vendor: true, stl: "none", crt: true, arch: { arm64: { src: "crtbegin_so.o", }, arm: { src: "crtbegin_so.o", }, }, } vendor_snapshot_static { name: "libvndk", version: "30", target_arch: "arm64", compile_multilib: "both", vendor: true, arch: { arm64: { src: "libvndk.a", }, arm: { src: "libvndk.a", }, }, shared_libs: ["libvndk"], export_shared_lib_headers: ["libvndk"], } vendor_snapshot_static { name: "libclang_rt.builtins", version: "30", target_arch: "arm64", vendor: true, arch: { arm: { src: "libclang_rt.builtins-arm-android.a", }, arm64: { src: "libclang_rt.builtins-aarch64-android.a", }, }, } vendor_snapshot_shared { name: "lib32", version: "30", target_arch: "arm64", compile_multilib: "32", vendor: true, arch: { arm: { src: "lib32.so", }, }, } vendor_snapshot_shared { name: "lib64", version: "30", target_arch: "arm64", compile_multilib: "64", vendor: true, arch: { arm64: { src: "lib64.so", }, }, } vendor_snapshot_shared { name: "liblog", version: "30", target_arch: "arm64", compile_multilib: "64", vendor: true, arch: { arm64: { src: "liblog.so", }, }, } vendor_snapshot_static { name: "libvendor", version: "30", target_arch: "arm64", compile_multilib: "both", vendor: true, arch: { arm64: { src: "libvendor.a", export_include_dirs: ["include/libvendor"], }, arm: { src: "libvendor.a", export_include_dirs: ["include/libvendor"], }, }, } vendor_snapshot_shared { name: "libvendor_available", version: "30", target_arch: "arm64", compile_multilib: "both", vendor: true, arch: { arm64: { src: "libvendor_available.so", export_include_dirs: ["include/libvendor"], }, arm: { src: "libvendor_available.so", export_include_dirs: ["include/libvendor"], }, }, } vendor_snapshot_binary { name: "bin", version: "30", target_arch: "arm64", compile_multilib: "64", vendor: true, arch: { arm64: { src: "bin", }, }, } vendor_snapshot_binary { name: "bin32", version: "30", target_arch: "arm64", compile_multilib: "32", vendor: true, arch: { arm: { src: "bin32", }, }, } // Test sanitizers use the snapshot libraries rust_binary { name: "memtag_binary", srcs: ["vendor/bin.rs"], vendor: true, compile_multilib: "64", sanitize: { memtag_heap: true, diag: { memtag_heap: true, } }, } // old snapshot module which has to be ignored vendor_snapshot_binary { name: "bin", version: "26", target_arch: "arm64", compile_multilib: "first", vendor: true, arch: { arm64: { src: "bin", }, }, } // different arch snapshot which has to be ignored vendor_snapshot_binary { name: "bin", version: "30", target_arch: "arm", compile_multilib: "first", vendor: true, arch: { arm64: { src: "bin", }, }, } vendor_snapshot_static { name: "note_memtag_heap_sync", vendor: true, target_arch: "arm64", version: "30", arch: { arm64: { src: "note_memtag_heap_sync.a", }, }, } ` mockFS := android.MockFS{ "framework/Android.bp": []byte(frameworkBp), "framework/bin.rs": nil, "note_memtag_heap_sync.a": nil, "vendor/Android.bp": []byte(vendorProprietaryBp), "vendor/bin": nil, "vendor/bin32": nil, "vendor/bin.rs": nil, "vendor/client.rs": nil, "vendor/include/libvndk/a.h": nil, "vendor/include/libvendor/b.h": nil, "vendor/libvndk.a": nil, "vendor/libvendor.a": nil, "vendor/libvendor.so": nil, "vendor/lib32.so": nil, "vendor/lib64.so": nil, "vendor/liblog.so": nil, "vendor/libstd.rlib": nil, "vendor/librust_vendor_available.rlib": nil, "vendor/crtbegin_so.o": nil, "vendor/crtend_so.o": nil, "vendor/libclang_rt.builtins-aarch64-android.a": nil, "vendor/libclang_rt.builtins-arm-android.a": nil, "vndk/Android.bp": []byte(vndkBp), "vndk/include/libvndk/a.h": nil, "vndk/libvndk.so": nil, } sharedVariant := "android_vendor.30_arm64_armv8-a_shared" rlibVariant := "android_vendor.30_arm64_armv8-a_rlib_rlib-std" staticVariant := "android_vendor.30_arm64_armv8-a_static" binaryVariant := "android_vendor.30_arm64_armv8-a" shared32Variant := "android_vendor.30_arm_armv7-a-neon_shared" binary32Variant := "android_vendor.30_arm_armv7-a-neon" ctx := testRustVndkFsVersions(t, "", mockFS, "30", "current", "31") // libclient uses libvndk.vndk.30.arm64, libvendor.vendor_static.30.arm64, libvendor_without_snapshot libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("rustLink").Args["linkFlags"] for _, input := range [][]string{ []string{sharedVariant, "libvndk.vndk.30.arm64"}, []string{staticVariant, "libvendor.vendor_static.30.arm64"}, []string{staticVariant, "libvendor_without_snapshot"}, } { outputPaths := cc.GetOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */) if !strings.Contains(libclientLdFlags, outputPaths[0].String()) { t.Errorf("libflags for libclient must contain %#v, but was %#v", outputPaths[0], libclientLdFlags) } } libclientAndroidMkSharedLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkSharedLibs if g, w := libclientAndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "lib64", "liblog.vendor", "libc.vendor", "libm.vendor", "libdl.vendor"}; !reflect.DeepEqual(g, w) { t.Errorf("wanted libclient AndroidMkSharedLibs %q, got %q", w, g) } libclientAndroidMkStaticLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkStaticLibs if g, w := libclientAndroidMkStaticLibs, []string{"libvendor", "libvendor_without_snapshot", "libclang_rt.builtins.vendor"}; !reflect.DeepEqual(g, w) { t.Errorf("wanted libclient AndroidMkStaticLibs %q, got %q", w, g) } libclientAndroidMkRlibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkRlibs if g, w := libclientAndroidMkRlibs, []string{"librust_vendor_available.vendor.rlib-std", "libstd.vendor"}; !reflect.DeepEqual(g, w) { t.Errorf("wanted libclient libclientAndroidMkRlibs %q, got %q", w, g) } libclientAndroidMkDylibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkDylibs if len(libclientAndroidMkDylibs) > 0 { t.Errorf("wanted libclient libclientAndroidMkDylibs [], got %q", libclientAndroidMkDylibs) } libclient32AndroidMkSharedLibs := ctx.ModuleForTests("libclient", shared32Variant).Module().(*Module).Properties.AndroidMkSharedLibs if g, w := libclient32AndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "lib32", "liblog.vendor", "libc.vendor", "libm.vendor", "libdl.vendor"}; !reflect.DeepEqual(g, w) { t.Errorf("wanted libclient32 AndroidMkSharedLibs %q, got %q", w, g) } libclientRustAndroidMkRlibs := ctx.ModuleForTests("libclient_rust", rlibVariant).Module().(*Module).Properties.AndroidMkRlibs if g, w := libclientRustAndroidMkRlibs, []string{"librust_vendor_available.vendor.rlib-std", "libstd.vendor"}; !reflect.DeepEqual(g, w) { t.Errorf("wanted libclient libclientAndroidMkRlibs %q, got %q", w, g) } // rust vendor snapshot must have ".vendor" suffix in AndroidMk librustVendorAvailableSnapshotModule := ctx.ModuleForTests("librust_vendor_available.vendor_rlib.30.arm64", rlibVariant).Module() librustVendorSnapshotMkName := android.AndroidMkEntriesForTest(t, ctx, librustVendorAvailableSnapshotModule)[0].EntryMap["LOCAL_MODULE"][0] expectedRustVendorSnapshotName := "librust_vendor_available.vendor.rlib-std" if librustVendorSnapshotMkName != expectedRustVendorSnapshotName { t.Errorf("Unexpected rust vendor snapshot name in AndroidMk: %q, expected: %q\n", librustVendorSnapshotMkName, expectedRustVendorSnapshotName) } rustVendorBinModule := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Module() rustVendorBinMkRlibName := android.AndroidMkEntriesForTest(t, ctx, rustVendorBinModule)[0].EntryMap["LOCAL_RLIB_LIBRARIES"][0] if rustVendorBinMkRlibName != expectedRustVendorSnapshotName { t.Errorf("Unexpected rust rlib name in AndroidMk: %q, expected: %q\n", rustVendorBinMkRlibName, expectedRustVendorSnapshotName) } binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustLink").Args["linkFlags"] libVndkStaticOutputPaths := cc.GetOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.30.arm64"}) if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) { t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v", libVndkStaticOutputPaths[0], binWithoutSnapshotLdFlags) } // bin is installed by bin.vendor_binary.30.arm64 ctx.ModuleForTests("bin.vendor_binary.30.arm64", binaryVariant).Output("bin") // bin32 is installed by bin32.vendor_binary.30.arm64 ctx.ModuleForTests("bin32.vendor_binary.30.arm64", binary32Variant).Output("bin32") // bin_without_snapshot is installed by bin_without_snapshot ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Output("bin_without_snapshot") // libvendor, libvendor_available and bin don't have vendor.30 variant libvendorVariants := ctx.ModuleVariantsForTests("libvendor") if android.InList(sharedVariant, libvendorVariants) { t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant) } libvendorAvailableVariants := ctx.ModuleVariantsForTests("libvendor_available") if android.InList(sharedVariant, libvendorAvailableVariants) { t.Errorf("libvendor_available must not have variant %#v, but it does", sharedVariant) } binVariants := ctx.ModuleVariantsForTests("bin") if android.InList(binaryVariant, binVariants) { t.Errorf("bin must not have variant %#v, but it does", sharedVariant) } memtagStaticLibs := ctx.ModuleForTests("memtag_binary", "android_vendor.30_arm64_armv8-a").Module().(*Module).Properties.AndroidMkStaticLibs if g, w := memtagStaticLibs, []string{"libclang_rt.builtins.vendor", "note_memtag_heap_sync.vendor"}; !reflect.DeepEqual(g, w) { t.Errorf("wanted memtag_binary AndroidMkStaticLibs %q, got %q", w, g) } } func TestRecoverySnapshotCapture(t *testing.T) { bp := ` rust_ffi { name: "librecovery", recovery: true, srcs: ["foo.rs"], crate_name: "recovery", } rust_ffi { name: "librecovery_available", recovery_available: true, srcs: ["foo.rs"], crate_name: "recovery_available", } rust_library_rlib { name: "librecovery_rlib", recovery: true, srcs: ["foo.rs"], crate_name: "recovery_rlib", } rust_library_rlib { name: "librecovery_available_rlib", recovery_available: true, srcs: ["foo.rs"], crate_name: "recovery_available_rlib", } rust_binary { name: "recovery_bin", recovery: true, srcs: ["foo.rs"], } rust_binary { name: "recovery_available_bin", recovery_available: true, srcs: ["foo.rs"], } ` // Check Recovery snapshot output. ctx := testRustRecoveryFsVersions(t, bp, rustMockedFiles, "", "29", "current") snapshotDir := "recovery-snapshot" snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") snapshotSingleton := ctx.SingletonForTests("recovery-snapshot") var jsonFiles []string for _, arch := range [][]string{ []string{"arm64", "armv8-a"}, } { archType := arch[0] archVariant := arch[1] archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) // For shared libraries, all recovery:true and recovery_available modules are captured. sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant) sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant) cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant) jsonFiles = append(jsonFiles, filepath.Join(sharedDir, "librecovery.so.json"), filepath.Join(sharedDir, "librecovery_available.so.json")) // For static libraries, all recovery:true and recovery_available modules are captured. staticVariant := fmt.Sprintf("android_recovery_%s_%s_static", archType, archVariant) staticDir := filepath.Join(snapshotVariantPath, archDir, "static") cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.a", staticDir, staticVariant) cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.a", staticDir, staticVariant) jsonFiles = append(jsonFiles, filepath.Join(staticDir, "librecovery.a.json"), filepath.Join(staticDir, "librecovery_available.a.json")) // For rlib libraries, all recovery:true and recovery_available modules are captured. rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant) rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant) cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available_rlib", "librecovery_available_rlib.rlib", rlibDir, rlibVariant) jsonFiles = append(jsonFiles, filepath.Join(rlibDir, "librecovery_rlib.rlib.json"), filepath.Join(rlibDir, "librecovery_available_rlib.rlib.json")) // For binary executables, all recovery:true and recovery_available modules are captured. if archType == "arm64" { binaryVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant) binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary") cc.CheckSnapshot(t, ctx, snapshotSingleton, "recovery_bin", "recovery_bin", binaryDir, binaryVariant) cc.CheckSnapshot(t, ctx, snapshotSingleton, "recovery_available_bin", "recovery_available_bin", binaryDir, binaryVariant) jsonFiles = append(jsonFiles, filepath.Join(binaryDir, "recovery_bin.json"), filepath.Join(binaryDir, "recovery_available_bin.json")) } } for _, jsonFile := range jsonFiles { // verify all json files exist if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { t.Errorf("%q expected but not found", jsonFile) } } } func TestRecoverySnapshotExclude(t *testing.T) { // This test verifies that the exclude_from_recovery_snapshot property // makes its way from the Android.bp source file into the module data // structure. It also verifies that modules are correctly included or // excluded in the recovery snapshot based on their path (framework or // vendor) and the exclude_from_recovery_snapshot property. frameworkBp := ` rust_ffi_shared { name: "libinclude", srcs: ["src/include.rs"], recovery_available: true, crate_name: "include", } rust_ffi_shared { name: "libexclude", srcs: ["src/exclude.rs"], recovery: true, exclude_from_recovery_snapshot: true, crate_name: "exclude", } rust_ffi_shared { name: "libavailable_exclude", srcs: ["src/exclude.rs"], recovery_available: true, exclude_from_recovery_snapshot: true, crate_name: "available_exclude", } rust_library_rlib { name: "libinclude_rlib", srcs: ["src/include.rs"], recovery_available: true, crate_name: "include_rlib", } rust_library_rlib { name: "libexclude_rlib", srcs: ["src/exclude.rs"], recovery: true, exclude_from_recovery_snapshot: true, crate_name: "exclude_rlib", } rust_library_rlib { name: "libavailable_exclude_rlib", srcs: ["src/exclude.rs"], recovery_available: true, exclude_from_recovery_snapshot: true, crate_name: "available_exclude_rlib", } ` vendorProprietaryBp := ` rust_ffi_shared { name: "librecovery", srcs: ["recovery.rs"], recovery: true, crate_name: "recovery", } rust_library_rlib { name: "librecovery_rlib", srcs: ["recovery.rs"], recovery: true, crate_name: "recovery_rlib", } ` mockFS := map[string][]byte{ "framework/Android.bp": []byte(frameworkBp), "framework/include.rs": nil, "framework/exclude.rs": nil, "device/Android.bp": []byte(vendorProprietaryBp), "device/recovery.rs": nil, } ctx := testRustRecoveryFsVersions(t, "", mockFS, "", "29", "current") // Test an include and exclude framework module. cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false, sharedRecoveryVariant) cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true, sharedRecoveryVariant) cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true, sharedRecoveryVariant) cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude_rlib", false, rlibRecoveryVariant) cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude_rlib", true, rlibRecoveryVariant) cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude_rlib", true, rlibRecoveryVariant) // A recovery module is excluded, but by its path not the exclude_from_recovery_snapshot property // ('device/' and 'vendor/' are default excluded). See snapshot/recovery_snapshot.go for more detail. cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false, sharedRecoveryVariant) cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery_rlib", false, rlibRecoveryVariant) // Verify the content of the recovery snapshot. snapshotDir := "recovery-snapshot" snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") snapshotSingleton := ctx.SingletonForTests("recovery-snapshot") var includeJsonFiles []string var excludeJsonFiles []string for _, arch := range [][]string{ []string{"arm64", "armv8-a"}, } { archType := arch[0] archVariant := arch[1] archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant) rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant) sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") // Included modules cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json")) cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude_rlib", "libinclude_rlib.rlib", rlibDir, rlibVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "libinclude_rlib.rlib.json")) // Excluded modules cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant) excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json")) cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant) excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json")) cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant) excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json")) cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude_rlib", "libexclude_rlib.rlib", rlibDir, rlibVariant) excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libexclude_rlib.rlib.json")) cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant) excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librecovery_rlib.rlib.json")) cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude_rlib", "libavailable_exclude_rlib.rlib", rlibDir, rlibVariant) excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libavailable_exclude_rlib.rlib.json")) } // Verify that each json file for an included module has a rule. for _, jsonFile := range includeJsonFiles { if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { t.Errorf("include json file %q not found", jsonFile) } } // Verify that each json file for an excluded module has no rule. for _, jsonFile := range excludeJsonFiles { if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil { t.Errorf("exclude json file %q found", jsonFile) } } } func TestRecoverySnapshotDirected(t *testing.T) { bp := ` rust_ffi_shared { name: "librecovery", recovery: true, crate_name: "recovery", srcs: ["foo.rs"], } rust_ffi_shared { name: "librecovery_available", recovery_available: true, crate_name: "recovery_available", srcs: ["foo.rs"], } rust_library_rlib { name: "librecovery_rlib", recovery: true, crate_name: "recovery", srcs: ["foo.rs"], } rust_library_rlib { name: "librecovery_available_rlib", recovery_available: true, crate_name: "recovery_available", srcs: ["foo.rs"], } /* TODO: Uncomment when Rust supports the "prefer" property for prebuilts rust_library_rlib { name: "libfoo_rlib", recovery: true, crate_name: "foo", } rust_prebuilt_rlib { name: "libfoo_rlib", recovery: true, prefer: true, srcs: ["libfoo.rlib"], crate_name: "foo", } */ ` ctx := testRustRecoveryFsVersions(t, bp, rustMockedFiles, "current", "29", "current") ctx.Config().TestProductVariables.RecoverySnapshotModules = make(map[string]bool) ctx.Config().TestProductVariables.RecoverySnapshotModules["librecovery"] = true ctx.Config().TestProductVariables.RecoverySnapshotModules["librecovery_rlib"] = true ctx.Config().TestProductVariables.DirectedRecoverySnapshot = true // Check recovery snapshot output. snapshotDir := "recovery-snapshot" snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") snapshotSingleton := ctx.SingletonForTests("recovery-snapshot") var includeJsonFiles []string for _, arch := range [][]string{ []string{"arm64", "armv8-a"}, } { archType := arch[0] archVariant := arch[1] archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant) rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant) sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") // Included modules cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json")) cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_rlib.rlib.json")) // TODO: When Rust supports the "prefer" property for prebuilts, perform this check. /* // Check that snapshot captures "prefer: true" prebuilt cc.CheckSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo_rlib", "libfoo_rlib.rlib", rlibDir, rlibVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo_rlib.rlib.json")) */ // Excluded modules. Modules not included in the directed recovery snapshot // are still included as fake modules. cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery_available.so.json")) cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available_rlib", "librecovery_available_rlib.rlib", rlibDir, rlibVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_available_rlib.rlib.json")) } // Verify that each json file for an included module has a rule. for _, jsonFile := range includeJsonFiles { if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { t.Errorf("include json file %q not found, %#v", jsonFile, includeJsonFiles) } } }