From e9aec6aacadc783473412e6d906f4309bc4bd3f8 Mon Sep 17 00:00:00 2001 From: Inseob Kim Date: Tue, 5 Jan 2021 20:03:22 +0900 Subject: [PATCH] Implement fake vendor snapshot A fake vendor snapshot is a vendor snapshot whose prebuilt binaries and captured headers are all empty. It's much faster to be built than the real vendor snapshot, so users can exploit the fake vendor snapshot to reduce the size of vendor snapshot they need, by installing the fake snapshot and then inspecting the ninja dependencies. Bug: 157967325 Test: m dist vendor-fake-snapshot Change-Id: I5e16e8dbbf9dd5e753cdd471ca73d06984a6cb2c --- cc/cc_test.go | 15 +++++++++++++ cc/snapshot_prebuilt.go | 2 ++ cc/testing.go | 1 + cc/vendor_snapshot.go | 48 ++++++++++++++++++++++++++++++++++------- 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/cc/cc_test.go b/cc/cc_test.go index 2d02a6a6d..2190b89ae 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -1245,6 +1245,15 @@ func TestVendorSnapshotCapture(t *testing.T) { t.Errorf("%q expected but not found", jsonFile) } } + + // 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 TestVendorSnapshotUse(t *testing.T) { @@ -1676,6 +1685,8 @@ func TestVendorSnapshotExcludeInVendorProprietaryPathErrors(t *testing.T) { `module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`, `module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`, `module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`, + `module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`, + `module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`, }) } @@ -1719,6 +1730,10 @@ func TestVendorSnapshotExcludeWithVendorAvailable(t *testing.T) { `module "libinclude\{.+,image:,arch:arm_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`, `module "libinclude\{.+,image:vendor.+,arch:arm64_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`, `module "libinclude\{.+,image:vendor.+,arch:arm_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`, + `module "libinclude\{.+,image:,arch:arm64_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`, + `module "libinclude\{.+,image:,arch:arm_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`, + `module "libinclude\{.+,image:vendor.+,arch:arm64_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`, + `module "libinclude\{.+,image:vendor.+,arch:arm_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`, }) } diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go index 8c5d1a405..e3f3a4d67 100644 --- a/cc/snapshot_prebuilt.go +++ b/cc/snapshot_prebuilt.go @@ -94,6 +94,8 @@ func (vendorSnapshotImage) init() { android.RegisterModuleType("vendor_snapshot_header", VendorSnapshotHeaderFactory) android.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory) android.RegisterModuleType("vendor_snapshot_object", VendorSnapshotObjectFactory) + + android.RegisterSingletonType("vendor-fake-snapshot", VendorFakeSnapshotSingleton) } func (vendorSnapshotImage) shouldGenerateSnapshot(ctx android.SingletonContext) bool { diff --git a/cc/testing.go b/cc/testing.go index fc5b030c7..ac990bdd3 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -577,6 +577,7 @@ func CreateTestContext(config android.Config) *android.TestContext { RegisterRequiredBuildComponentsForTest(ctx) ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton) ctx.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton) + ctx.RegisterSingletonType("vendor-fake-snapshot", VendorFakeSnapshotSingleton) ctx.RegisterSingletonType("recovery-snapshot", RecoverySnapshotSingleton) return ctx diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go index 417516bf9..0e1dd6b4c 100644 --- a/cc/vendor_snapshot.go +++ b/cc/vendor_snapshot.go @@ -34,6 +34,16 @@ var vendorSnapshotSingleton = snapshotSingleton{ android.OptionalPath{}, true, vendorSnapshotImageSingleton, + false, /* fake */ +} + +var vendorFakeSnapshotSingleton = snapshotSingleton{ + "vendor", + "SOONG_VENDOR_FAKE_SNAPSHOT_ZIP", + android.OptionalPath{}, + true, + vendorSnapshotImageSingleton, + true, /* fake */ } var recoverySnapshotSingleton = snapshotSingleton{ @@ -42,12 +52,17 @@ var recoverySnapshotSingleton = snapshotSingleton{ android.OptionalPath{}, false, recoverySnapshotImageSingleton, + false, /* fake */ } func VendorSnapshotSingleton() android.Singleton { return &vendorSnapshotSingleton } +func VendorFakeSnapshotSingleton() android.Singleton { + return &vendorFakeSnapshotSingleton +} + func RecoverySnapshotSingleton() android.Singleton { return &recoverySnapshotSingleton } @@ -70,6 +85,11 @@ type snapshotSingleton struct { // associated with this snapshot (e.g., specific to the vendor image, // recovery image, etc.). image snapshotImage + + // Whether this singleton is for fake snapshot or not. + // Fake snapshot is a snapshot whose prebuilt binaries and headers are empty. + // It is much faster to generate, and can be used to inspect dependencies. + fake bool } var ( @@ -351,6 +371,11 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { */ snapshotDir := c.name + "-snapshot" + if c.fake { + // If this is a fake snapshot singleton, place all files under fake/ subdirectory to avoid + // collision with real snapshot files + snapshotDir = filepath.Join("fake", snapshotDir) + } snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch()) includeDir := filepath.Join(snapshotArchDir, "include") @@ -362,6 +387,15 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { var headers android.Paths + copyFile := copyFileRule + if c.fake { + // All prebuilt binaries and headers are installed by copyFile function. This makes a fake + // snapshot just touch prebuilts and headers, rather than installing real files. + copyFile = func(ctx android.SingletonContext, path android.Path, out string) android.OutputPath { + return writeStringToFileRule(ctx, "", out) + } + } + // installSnapshot function copies prebuilt file (.so, .a, or executable) and json flag file. // For executables, init_rc and vintf_fragments files are also copied. installSnapshot := func(m *Module) android.Paths { @@ -400,7 +434,7 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { out := filepath.Join(configsDir, path.Base()) if !installedConfigs[out] { installedConfigs[out] = true - ret = append(ret, copyFileRule(ctx, path, out)) + ret = append(ret, copyFile(ctx, path, out)) } } @@ -451,7 +485,7 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { prop.ModuleName += ".cfi" } snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, stem) - ret = append(ret, copyFileRule(ctx, libPath, snapshotLibOut)) + ret = append(ret, copyFile(ctx, libPath, snapshotLibOut)) } else { stem = ctx.ModuleName(m) } @@ -465,7 +499,7 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { // install bin binPath := m.outputFile.Path() snapshotBinOut := filepath.Join(snapshotArchDir, targetArch, "binary", binPath.Base()) - ret = append(ret, copyFileRule(ctx, binPath, snapshotBinOut)) + ret = append(ret, copyFile(ctx, binPath, snapshotBinOut)) propOut = snapshotBinOut + ".json" } else if m.object() { // object files aren't installed to the device, so their names can conflict. @@ -473,7 +507,7 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { objPath := m.outputFile.Path() snapshotObjOut := filepath.Join(snapshotArchDir, targetArch, "object", ctx.ModuleName(m)+filepath.Ext(objPath.Base())) - ret = append(ret, copyFileRule(ctx, objPath, snapshotObjOut)) + ret = append(ret, copyFile(ctx, objPath, snapshotObjOut)) propOut = snapshotObjOut + ".json" } else { ctx.Errorf("unknown module %q in vendor snapshot", m.String()) @@ -538,16 +572,14 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { // skip already copied notice file if !installedNotices[noticeOut] { installedNotices[noticeOut] = true - snapshotOutputs = append(snapshotOutputs, combineNoticesRule( - ctx, m.NoticeFiles(), noticeOut)) + snapshotOutputs = append(snapshotOutputs, combineNoticesRule(ctx, m.NoticeFiles(), noticeOut)) } } }) // install all headers after removing duplicates for _, header := range android.FirstUniquePaths(headers) { - snapshotOutputs = append(snapshotOutputs, copyFileRule( - ctx, header, filepath.Join(includeDir, header.String()))) + snapshotOutputs = append(snapshotOutputs, copyFile(ctx, header, filepath.Join(includeDir, header.String()))) } // All artifacts are ready. Sort them to normalize ninja and then zip.