| // 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 snapshot |
| |
| import ( |
| "path/filepath" |
| "sort" |
| |
| "android/soong/android" |
| ) |
| |
| // This file contains singletons to capture snapshots. This singleton will generate snapshot of each target |
| // image, and capturing snapshot module will be delegated to each module which implements GenerateSnapshotAction |
| // function and register with RegisterSnapshotAction. |
| |
| var pctx = android.NewPackageContext("android/soong/snapshot") |
| |
| func init() { |
| pctx.Import("android/soong/android") |
| } |
| |
| type SnapshotSingleton struct { |
| // Name, e.g., "vendor", "recovery", "ramdisk". |
| name string |
| |
| // Make variable that points to the snapshot file, e.g., |
| // "SOONG_RECOVERY_SNAPSHOT_ZIP". |
| makeVar string |
| |
| // Path to the snapshot zip file. |
| snapshotZipFile android.OptionalPath |
| |
| // Implementation of the image interface specific to the image |
| // 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 |
| } |
| |
| // The output files to be included in the snapshot. |
| type SnapshotPaths struct { |
| // All files to be included in the snapshot |
| OutputFiles android.Paths |
| |
| // Notice files of the snapshot output files |
| NoticeFiles android.Paths |
| } |
| |
| // Interface of function to capture snapshot from each module |
| // Returns snapshot ouputs and notice files. |
| type GenerateSnapshotAction func(snapshot SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) SnapshotPaths |
| |
| var snapshotActionList []GenerateSnapshotAction |
| |
| // Register GenerateSnapshotAction function so it can be called while generating snapshot |
| func RegisterSnapshotAction(x GenerateSnapshotAction) { |
| snapshotActionList = append(snapshotActionList, x) |
| } |
| |
| func (c *SnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { |
| if !c.Image.shouldGenerateSnapshot(ctx) { |
| return |
| } |
| |
| var snapshotOutputs android.Paths |
| |
| // Snapshot zipped artifacts will be captured under {SNAPSHOT_ARCH} directory |
| |
| 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()) |
| noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES") |
| installedNotices := make(map[string]bool) |
| |
| for _, f := range snapshotActionList { |
| snapshotPaths := f(*c, ctx, snapshotArchDir) |
| snapshotOutputs = append(snapshotOutputs, snapshotPaths.OutputFiles...) |
| for _, notice := range snapshotPaths.NoticeFiles { |
| if _, ok := installedNotices[notice.String()]; !ok { |
| installedNotices[notice.String()] = true |
| snapshotOutputs = append(snapshotOutputs, CopyFileRule( |
| pctx, ctx, notice, filepath.Join(noticeDir, notice.String()))) |
| } |
| } |
| } |
| |
| // All artifacts are ready. Sort them to normalize ninja and then zip. |
| sort.Slice(snapshotOutputs, func(i, j int) bool { |
| return snapshotOutputs[i].String() < snapshotOutputs[j].String() |
| }) |
| |
| zipPath := android.PathForOutput( |
| ctx, |
| snapshotDir, |
| c.name+"-"+ctx.Config().DeviceName()+".zip") |
| zipRule := android.NewRuleBuilder(pctx, ctx) |
| |
| // filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr |
| snapshotOutputList := android.PathForOutput( |
| ctx, |
| snapshotDir, |
| c.name+"-"+ctx.Config().DeviceName()+"_list") |
| rspFile := snapshotOutputList.ReplaceExtension(ctx, "rsp") |
| zipRule.Command(). |
| Text("tr"). |
| FlagWithArg("-d ", "\\'"). |
| FlagWithRspFileInputList("< ", rspFile, snapshotOutputs). |
| FlagWithOutput("> ", snapshotOutputList) |
| |
| zipRule.Temporary(snapshotOutputList) |
| |
| zipRule.Command(). |
| BuiltTool("soong_zip"). |
| FlagWithOutput("-o ", zipPath). |
| FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()). |
| FlagWithInput("-l ", snapshotOutputList) |
| |
| zipRule.Build(zipPath.String(), c.name+" snapshot "+zipPath.String()) |
| zipRule.DeleteTemporaryFiles() |
| c.snapshotZipFile = android.OptionalPathForPath(zipPath) |
| } |
| |
| func (c *SnapshotSingleton) MakeVars(ctx android.MakeVarsContext) { |
| ctx.Strict( |
| c.makeVar, |
| c.snapshotZipFile.String()) |
| } |