diff options
48 files changed, 5266 insertions, 1448 deletions
diff --git a/android/arch.go b/android/arch.go index 18ff13e9c..ad91c7e36 100644 --- a/android/arch.go +++ b/android/arch.go @@ -127,6 +127,7 @@ var archVariants = map[ArchType][]string{ "cortex-a76", "krait", "kryo", + "kryo300", "kryo385", "exynos-m1", "exynos-m2", @@ -141,6 +142,7 @@ var archVariants = map[ArchType][]string{ "cortex-a75", "cortex-a76", "kryo", + "kryo300", "kryo385", "exynos-m1", "exynos-m2", @@ -1625,6 +1627,7 @@ func getMegaDeviceConfig() []archConfig { {"arm", "armv7-a-neon", "cortex-a76", []string{"armeabi-v7a"}}, {"arm", "armv7-a-neon", "krait", []string{"armeabi-v7a"}}, {"arm", "armv7-a-neon", "kryo", []string{"armeabi-v7a"}}, + {"arm", "armv7-a-neon", "kryo300", []string{"armeabi-v7a"}}, {"arm", "armv7-a-neon", "kryo385", []string{"armeabi-v7a"}}, {"arm", "armv7-a-neon", "exynos-m1", []string{"armeabi-v7a"}}, {"arm", "armv7-a-neon", "exynos-m2", []string{"armeabi-v7a"}}, @@ -1636,6 +1639,7 @@ func getMegaDeviceConfig() []archConfig { {"arm64", "armv8-a", "exynos-m2", []string{"arm64-v8a"}}, {"arm64", "armv8-2a", "cortex-a75", []string{"arm64-v8a"}}, {"arm64", "armv8-2a", "cortex-a76", []string{"arm64-v8a"}}, + {"arm64", "armv8-2a", "kryo300", []string{"arm64-v8a"}}, {"arm64", "armv8-2a", "kryo385", []string{"arm64-v8a"}}, {"mips", "mips32-fp", "", []string{"mips"}}, {"mips", "mips32r2-fp", "", []string{"mips"}}, diff --git a/android/config.go b/android/config.go index 34177291f..28d9de9cd 100644 --- a/android/config.go +++ b/android/config.go @@ -36,6 +36,9 @@ import ( var Bool = proptools.Bool var String = proptools.String +// StringDefault re-exports proptools.StringDefault for the android package. +var StringDefault = proptools.StringDefault + const FutureApiLevel = 10000 // The configuration file name @@ -964,6 +967,10 @@ func (c *config) HasMultilibConflict(arch ArchType) bool { return c.multilibConflicts[arch] } +func (c *config) PrebuiltHiddenApiDir(ctx PathContext) string { + return String(c.productVariables.PrebuiltHiddenApiDir) +} + func (c *deviceConfig) Arches() []Arch { var arches []Arch for _, target := range c.config.Targets[Android] { @@ -991,6 +998,14 @@ func (c *deviceConfig) VndkVersion() string { return String(c.config.productVariables.DeviceVndkVersion) } +func (c *deviceConfig) RecoverySnapshotVersion() string { + return String(c.config.productVariables.RecoverySnapshotVersion) +} + +func (c *deviceConfig) RamdiskSnapshotVersion() string { + return String(c.config.productVariables.RamdiskSnapshotVersion) +} + func (c *deviceConfig) PlatformVndkVersion() string { return String(c.config.productVariables.Platform_vndk_version) } @@ -1172,6 +1187,27 @@ func (c *config) IntegerOverflowDisabledForPath(path string) bool { return HasAnyPrefix(path, c.productVariables.IntegerOverflowExcludePaths) } +func (c *config) IntegerOverflowEnabledForPath(path string) bool { + if c.productVariables.IntegerOverflowIncludePaths == nil { + return false + } + return HasAnyPrefix(path, c.productVariables.IntegerOverflowIncludePaths) +} + +func (c *config) BoundSanitizerEnabledForPath(path string) bool { + if c.productVariables.BoundSanitizerIncludePaths == nil { + return false + } + return HasAnyPrefix(path, c.productVariables.BoundSanitizerIncludePaths) +} + +func (c *config) BoundSanitizerDisabledForPath(path string) bool { + if c.productVariables.BoundSanitizerExcludePaths == nil { + return false + } + return HasAnyPrefix(path, c.productVariables.BoundSanitizerExcludePaths) +} + func (c *config) CFIDisabledForPath(path string) bool { if c.productVariables.CFIExcludePaths == nil { return false @@ -1277,3 +1313,83 @@ func (c *deviceConfig) DeviceSecondaryArchVariant() string { func (c *deviceConfig) BoardUsesRecoveryAsBoot() bool { return Bool(c.config.productVariables.BoardUsesRecoveryAsBoot) } + +func (c *deviceConfig) DirectedVendorSnapshot() bool { + return c.config.productVariables.DirectedVendorSnapshot +} + +func (c *deviceConfig) VendorSnapshotModules() map[string]bool { + return c.config.productVariables.VendorSnapshotModules +} + +func (c *deviceConfig) DirectedRecoverySnapshot() bool { + return c.config.productVariables.DirectedRecoverySnapshot +} + +func (c *deviceConfig) RecoverySnapshotModules() map[string]bool { + return c.config.productVariables.RecoverySnapshotModules +} + +func (c *deviceConfig) DirectedRamdiskSnapshot() bool { + return c.config.productVariables.DirectedRamdiskSnapshot +} + +func (c *deviceConfig) RamdiskSnapshotModules() map[string]bool { + return c.config.productVariables.RamdiskSnapshotModules +} + +func createDirsMap(previous map[string]bool, dirs []string) (map[string]bool, error) { + var ret = make(map[string]bool) + for _, dir := range dirs { + clean := filepath.Clean(dir) + if previous[clean] || ret[clean] { + return nil, fmt.Errorf("Duplicate entry %s", dir) + } + ret[clean] = true + } + return ret, nil +} + +func (c *deviceConfig) createDirsMapOnce(onceKey OnceKey, previous map[string]bool, dirs []string) map[string]bool { + dirMap := c.Once(onceKey, func() interface{} { + ret, err := createDirsMap(previous, dirs) + if err != nil { + panic(fmt.Errorf("%s: %w", *onceKey.key.(*string), err)) + } + return ret + }) + if dirMap == nil { + return nil + } + return dirMap.(map[string]bool) +} + +var vendorSnapshotDirsExcludedKey = NewOnceKey("VendorSnapshotDirsExcludedMap") + +func (c *deviceConfig) VendorSnapshotDirsExcludedMap() map[string]bool { + return c.createDirsMapOnce(vendorSnapshotDirsExcludedKey, nil, + c.config.productVariables.VendorSnapshotDirsExcluded) +} + +var vendorSnapshotDirsIncludedKey = NewOnceKey("VendorSnapshotDirsIncludedMap") + +func (c *deviceConfig) VendorSnapshotDirsIncludedMap() map[string]bool { + excludedMap := c.VendorSnapshotDirsExcludedMap() + return c.createDirsMapOnce(vendorSnapshotDirsIncludedKey, excludedMap, + c.config.productVariables.VendorSnapshotDirsIncluded) +} + +var recoverySnapshotDirsExcludedKey = NewOnceKey("RecoverySnapshotDirsExcludedMap") + +func (c *deviceConfig) RecoverySnapshotDirsExcludedMap() map[string]bool { + return c.createDirsMapOnce(recoverySnapshotDirsExcludedKey, nil, + c.config.productVariables.RecoverySnapshotDirsExcluded) +} + +var recoverySnapshotDirsIncludedKey = NewOnceKey("RecoverySnapshotDirsIncludedMap") + +func (c *deviceConfig) RecoverySnapshotDirsIncludedMap() map[string]bool { + excludedMap := c.RecoverySnapshotDirsExcludedMap() + return c.createDirsMapOnce(recoverySnapshotDirsIncludedKey, excludedMap, + c.config.productVariables.RecoverySnapshotDirsIncluded) +} diff --git a/android/env.go b/android/env.go index 46bd3d6c5..59e088713 100644 --- a/android/env.go +++ b/android/env.go @@ -32,6 +32,7 @@ import ( var originalEnv map[string]string var SoongDelveListen string var SoongDelvePath string +var SdclangEnv map[string]string func init() { // Delve support needs to read this environment variable very early, before NewConfig has created a way to @@ -41,10 +42,12 @@ func init() { SoongDelvePath, _ = exec.LookPath("dlv") originalEnv = make(map[string]string) + SdclangEnv = make(map[string]string) for _, env := range os.Environ() { idx := strings.IndexRune(env, '=') if idx != -1 { originalEnv[env[:idx]] = env[idx+1:] + SdclangEnv[env[:idx]] = env[idx+1:] } } // Clear the environment to prevent use of os.Getenv(), which would not provide dependencies on environment diff --git a/android/module.go b/android/module.go index a498839ce..880915377 100644 --- a/android/module.go +++ b/android/module.go @@ -231,6 +231,8 @@ type Module interface { InstallBypassMake() bool SkipInstall() IsSkipInstall() bool + ReplacedByPrebuilt() + IsReplacedByPrebuilt() bool ExportedToMake() bool InitRc() Paths VintfFragments() Paths @@ -512,6 +514,12 @@ type commonProperties struct { SkipInstall bool `blueprint:"mutated"` + // Whether the module has been replaced by a prebuilt + ReplacedByPrebuilt bool `blueprint:"mutated"` + + // Disabled by mutators. If set to true, it overrides Enabled property. + ForcedDisabled bool `blueprint:"mutated"` + NamespaceExportedToMake bool `blueprint:"mutated"` MissingDeps []string `blueprint:"mutated"` @@ -941,6 +949,9 @@ func (m *ModuleBase) PartitionTag(config DeviceConfig) string { } func (m *ModuleBase) Enabled() bool { + if m.commonProperties.ForcedDisabled { + return false + } if m.commonProperties.Enabled == nil { return !m.Os().DefaultDisabled } @@ -948,7 +959,7 @@ func (m *ModuleBase) Enabled() bool { } func (m *ModuleBase) Disable() { - m.commonProperties.Enabled = proptools.BoolPtr(false) + m.commonProperties.ForcedDisabled = true } func (m *ModuleBase) SkipInstall() { @@ -959,6 +970,15 @@ func (m *ModuleBase) IsSkipInstall() bool { return m.commonProperties.SkipInstall == true } +func (m *ModuleBase) ReplacedByPrebuilt() { + m.commonProperties.ReplacedByPrebuilt = true + m.SkipInstall() +} + +func (m *ModuleBase) IsReplacedByPrebuilt() bool { + return m.commonProperties.ReplacedByPrebuilt +} + func (m *ModuleBase) ExportedToMake() bool { return m.commonProperties.NamespaceExportedToMake } diff --git a/android/prebuilt.go b/android/prebuilt.go index ee4a13af2..8ad81e6cd 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -227,7 +227,7 @@ func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) { p := m.(PrebuiltInterface).Prebuilt() if p.usePrebuilt(ctx, s) { p.properties.UsePrebuilt = true - s.SkipInstall() + s.ReplacedByPrebuilt() } }) } diff --git a/android/variable.go b/android/variable.go index 983c23567..34d145e8a 100644 --- a/android/variable.go +++ b/android/variable.go @@ -131,6 +131,34 @@ type variableProperties struct { Srcs []string `android:"arch_variant"` Exclude_srcs []string `android:"arch_variant"` } `android:"arch_variant"` + + Real_hal struct { + Cflags []string + Exclude_srcs []string + Include_dirs []string + Shared_libs []string + Static_libs []string + Srcs []string + } + + Qmaa_hal struct { + Cflags []string + Exclude_srcs []string + Include_dirs []string + Shared_libs []string + Static_libs []string + Srcs []string + } + + Device_support_hwfde struct { + Cflags []string + Header_libs []string + Shared_libs []string + } + + Device_support_hwfde_perf struct { + Cflags []string + } } `android:"arch_variant"` } @@ -163,6 +191,9 @@ type productVariables struct { DeviceVndkVersion *string `json:",omitempty"` DeviceSystemSdkVersions []string `json:",omitempty"` + RecoverySnapshotVersion *string `json:",omitempty"` + RamdiskSnapshotVersion *string `json:",omitempty"` + DeviceSecondaryArch *string `json:",omitempty"` DeviceSecondaryArchVariant *string `json:",omitempty"` DeviceSecondaryCpuVariant *string `json:",omitempty"` @@ -203,6 +234,10 @@ type productVariables struct { AppsDefaultVersionName *string `json:",omitempty"` + Real_hal *bool `json:",omitempty"` + Qmaa_hal *bool `json:",omitempty"` + Device_support_hwfde *bool `json:",omitempty"` + Device_support_hwfde_perf *bool `json:",omitempty"` Allow_missing_dependencies *bool `json:",omitempty"` Unbundled_build *bool `json:",omitempty"` Unbundled_build_sdks_from_source *bool `json:",omitempty"` @@ -234,6 +269,10 @@ type productVariables struct { UpdatableBootJars []string `json:",omitempty"` IntegerOverflowExcludePaths []string `json:",omitempty"` + IntegerOverflowIncludePaths []string `json:",omitempty"` + + BoundSanitizerExcludePaths []string `json:",omitempty"` + BoundSanitizerIncludePaths []string `json:",omitempty"` EnableCFI *bool `json:",omitempty"` CFIExcludePaths []string `json:",omitempty"` @@ -292,6 +331,20 @@ type productVariables struct { VndkUseCoreVariant *bool `json:",omitempty"` VndkSnapshotBuildArtifacts *bool `json:",omitempty"` + DirectedVendorSnapshot bool `json:",omitempty"` + VendorSnapshotModules map[string]bool `json:",omitempty"` + + DirectedRecoverySnapshot bool `json:",omitempty"` + RecoverySnapshotModules map[string]bool `json:",omitempty"` + + DirectedRamdiskSnapshot bool `json:",omitempty"` + RamdiskSnapshotModules map[string]bool `json:",omitempty"` + + VendorSnapshotDirsIncluded []string `json:",omitempty"` + VendorSnapshotDirsExcluded []string `json:",omitempty"` + RecoverySnapshotDirsExcluded []string `json:",omitempty"` + RecoverySnapshotDirsIncluded []string `json:",omitempty"` + BoardVendorSepolicyDirs []string `json:",omitempty"` BoardOdmSepolicyDirs []string `json:",omitempty"` BoardPlatPublicSepolicyDirs []string `json:",omitempty"` @@ -336,6 +389,8 @@ type productVariables struct { InstallExtraFlattenedApexes *bool `json:",omitempty"` BoardUsesRecoveryAsBoot *bool `json:",omitempty"` + + PrebuiltHiddenApiDir *string `json:",omitempty"` } func boolPtr(v bool) *bool { diff --git a/apex/apex.go b/apex/apex.go index 7da8e1cf2..3c07903ed 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -627,6 +627,13 @@ func makeApexAvailableBaseline() map[string][]string { "android.hidl.manager-V1.0-java", "android.hidl.manager-V1.1-java", "android.hidl.manager-V1.2-java", + "vendor.qti.hardware.wifi.hostapd-V1.0-java", + "vendor.qti.hardware.wifi.hostapd-V1.1-java", + "vendor.qti.hardware.wifi.hostapd-V1.2-java", + "vendor.qti.hardware.wifi.supplicant-V2.0-java", + "vendor.qti.hardware.wifi.supplicant-V2.1-java", + "vendor.qti.hardware.wifi.supplicant-V2.2-java", + "vendor.qti.hardware.fstman-V1.0-java", "bouncycastle-unbundled", "dnsresolver_aidl_interface-V2-java", "error_prone_annotations", @@ -1759,6 +1766,7 @@ type javaDependency interface { } var _ javaDependency = (*java.Library)(nil) +var _ javaDependency = (*java.Import)(nil) var _ javaDependency = (*java.SdkLibrary)(nil) var _ javaDependency = (*java.DexImport)(nil) var _ javaDependency = (*java.SdkLibraryImport)(nil) @@ -2048,7 +2056,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { } case javaLibTag: switch child.(type) { - case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport: + case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport, *java.Import: af := apexFileForJavaLibrary(ctx, child.(javaDependency), child.(android.Module)) if !af.Ok() { ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName) diff --git a/apex/apex_test.go b/apex/apex_test.go index 8803a5f97..9f930d1e7 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -3484,6 +3484,34 @@ func TestErrorsIfDepsAreNotEnabled(t *testing.T) { `) } +func TestApexWithJavaImport(t *testing.T) { + ctx, _ := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + java_libs: ["myjavaimport"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + java_import { + name: "myjavaimport", + apex_available: ["myapex"], + jars: ["my.jar"], + compile_dex: true, + } + `) + + module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + apexRule := module.Rule("apexRule") + copyCmds := apexRule.Args["copy_commands"] + ensureContains(t, copyCmds, "image.apex/javalib/myjavaimport.jar") +} + func TestApexWithApps(t *testing.T) { ctx, _ := testApex(t, ` apex { diff --git a/cc/Android.bp b/cc/Android.bp index 9ece05f6c..c2c08d1c3 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -19,6 +19,7 @@ bootstrap_go_package { "check.go", "coverage.go", "gen.go", + "image.go", "linkable.go", "lto.go", "makevars.go", @@ -29,6 +30,7 @@ bootstrap_go_package { "sanitize.go", "sabi.go", "sdk.go", + "snapshot_prebuilt.go", "snapshot_utils.go", "stl.go", "strip.go", diff --git a/cc/androidmk.go b/cc/androidmk.go index fede601b4..0ad2fcfe3 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -92,6 +92,12 @@ func (c *Module) AndroidMkEntries() []android.AndroidMkEntries { if len(c.Properties.AndroidMkWholeStaticLibs) > 0 { entries.AddStrings("LOCAL_WHOLE_STATIC_LIBRARIES", c.Properties.AndroidMkWholeStaticLibs...) } + if len(c.Properties.AndroidMkHeaderLibs) > 0 { + entries.AddStrings("LOCAL_HEADER_LIBRARIES", c.Properties.AndroidMkHeaderLibs...) + } + if lib, ok := c.compiler.(*libraryDecorator); ok { + entries.AddStrings("LOCAL_SRC_FILES", lib.baseCompiler.srcsBeforeGen.Strings()...) + } entries.SetString("LOCAL_SOONG_LINK_TYPE", c.makeLinkType) if c.UseVndk() { entries.SetBool("LOCAL_USE_VNDK", true) @@ -486,7 +492,7 @@ func (c *vndkPrebuiltLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, en }) } -func (c *vendorSnapshotLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { +func (c *snapshotLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { // Each vendor snapshot is exported to androidMk only when BOARD_VNDK_VERSION != current // and the version of the prebuilt is same as BOARD_VNDK_VERSION. if c.shared() { @@ -497,12 +503,14 @@ func (c *vendorSnapshotLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries.Class = "HEADER_LIBRARIES" } - if c.androidMkVendorSuffix { - entries.SubName = vendorSuffix - } else { - entries.SubName = "" + entries.SubName = "" + + if c.sanitizerProperties.CfiEnabled { + entries.SubName += ".cfi" } + entries.SubName += c.androidMkSuffix + entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { c.libraryDecorator.androidMkWriteExportedFlags(entries) @@ -512,7 +520,10 @@ func (c *vendorSnapshotLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext) entries.SetString("LOCAL_MODULE_SUFFIX", suffix) entries.SetString("LOCAL_MODULE_STEM", stem) - if c.shared() { + // TODO(b/181815415) remove isLlndk() when possible + if c.isLlndk() { + entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) + } else if c.shared() { entries.SetString("LOCAL_MODULE_PATH", path) } if c.tocFile.Valid() { @@ -526,28 +537,18 @@ func (c *vendorSnapshotLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, }) } -func (c *vendorSnapshotBinaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { +func (c *snapshotBinaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { entries.Class = "EXECUTABLES" - - if c.androidMkVendorSuffix { - entries.SubName = vendorSuffix - } else { - entries.SubName = "" - } + entries.SubName = c.androidMkSuffix entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { entries.AddStrings("LOCAL_MODULE_SYMLINKS", c.Properties.Symlinks...) }) } -func (c *vendorSnapshotObjectLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { +func (c *snapshotObjectLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { entries.Class = "STATIC_LIBRARIES" - - if c.androidMkVendorSuffix { - entries.SubName = vendorSuffix - } else { - entries.SubName = "" - } + entries.SubName = c.androidMkSuffix entries.ExtraFooters = append(entries.ExtraFooters, func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) { diff --git a/cc/builder.go b/cc/builder.go index 5deb1299e..6423339b6 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -322,6 +322,7 @@ type builderFlags struct { aidlFlags string rsFlags string toolchain config.Toolchain + sdclang bool tidy bool gcovCoverage bool sAbiDump bool @@ -519,7 +520,13 @@ func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and ccDesc := ccCmd - ccCmd = "${config.ClangBin}/" + ccCmd + var extraFlags string + if flags.sdclang { + ccCmd = "${config.SDClangBin}/" + ccCmd + extraFlags = " ${config.SDClangFlags}" + } else { + ccCmd = "${config.ClangBin}/" + ccCmd + } var implicitOutputs android.WritablePaths if coverage { @@ -537,7 +544,7 @@ func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and Implicits: cFlagsDeps, OrderOnly: pathDeps, Args: map[string]string{ - "cFlags": moduleFlags, + "cFlags": moduleFlags + extraFlags, "ccCmd": ccCmd, }, }) @@ -618,6 +625,9 @@ func TransformObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths, flags builderFlags, outputFile android.ModuleOutPath, deps android.Paths) { arCmd := "${config.ClangBin}/llvm-ar" + if flags.sdclang { + arCmd = "${config.ClangBin}/llvm-ar" + } arFlags := "crsPD" if !ctx.Darwin() { arFlags += " -format=gnu" @@ -642,7 +652,14 @@ func TransformObjToDynamicBinary(ctx android.ModuleContext, objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps android.Paths, crtBegin, crtEnd android.OptionalPath, groupLate bool, flags builderFlags, outputFile android.WritablePath, implicitOutputs android.WritablePaths) { - ldCmd := "${config.ClangBin}/clang++" + var ldCmd string + var extraFlags string + if flags.sdclang { + ldCmd = "${config.SDClangBin}/clang++" + extraFlags = " ${config.SDClangFlags}" + } else { + ldCmd = "${config.ClangBin}/clang++" + } var libFlagsList []string @@ -697,7 +714,7 @@ func TransformObjToDynamicBinary(ctx android.ModuleContext, "crtBegin": crtBegin.String(), "libFlags": strings.Join(libFlagsList, " "), "extraLibFlags": flags.extraLibFlags, - "ldFlags": flags.globalLdFlags + " " + flags.localLdFlags, + "ldFlags": flags.globalLdFlags + " " + flags.localLdFlags + " " + extraFlags, "crtEnd": crtEnd.String(), } if ctx.Config().IsEnvTrue("RBE_CXX_LINKS") { @@ -800,6 +817,19 @@ func SourceAbiDiff(ctx android.ModuleContext, inputDump android.Path, referenceD if isVndkExt { localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-allow-extensions") } + var sdclangAbiCheckIgnoreList = []string{ + "libbinder", + "libhwbinder", + "libprotobuf-cpp-lite", + "libprotobuf-cpp-full", + "libunwindstack", + "libvixl-arm64", + "libvixl-arm", + } + if config.SDClang && !inList("-advice-only", localAbiCheckAllowFlags) && + inList(ctx.ModuleName(), sdclangAbiCheckIgnoreList) { + localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-advice-only") + } ctx.Build(pctx, android.BuildParams{ Rule: sAbiDiff, @@ -851,12 +881,19 @@ func TransformSharedObjectToToc(ctx android.ModuleContext, inputFile android.Pat func TransformObjsToObj(ctx android.ModuleContext, objFiles android.Paths, flags builderFlags, outputFile android.WritablePath, deps android.Paths) { - ldCmd := "${config.ClangBin}/clang++" + var ldCmd string + var extraFlags string + if flags.sdclang { + ldCmd = "${config.SDClangBin}/clang++" + extraFlags = " ${config.SDClangFlags}" + } else { + ldCmd = "${config.ClangBin}/clang++" + } rule := partialLd args := map[string]string{ "ldCmd": ldCmd, - "ldFlags": flags.globalLdFlags + " " + flags.localLdFlags, + "ldFlags": flags.globalLdFlags + " " + flags.localLdFlags + " " + extraFlags, } if ctx.Config().IsEnvTrue("RBE_CXX_LINKS") { rule = partialLdRE @@ -52,6 +52,10 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) { ctx.BottomUp("sysprop_cc", SyspropMutator).Parallel() ctx.BottomUp("vendor_snapshot", VendorSnapshotMutator).Parallel() ctx.BottomUp("vendor_snapshot_source", VendorSnapshotSourceMutator).Parallel() + ctx.BottomUp("recovery_snapshot", RecoverySnapshotMutator).Parallel() + ctx.BottomUp("recovery_snapshot_source", RecoverySnapshotSourceMutator).Parallel() + ctx.BottomUp("ramdisk_snapshot", RamdiskSnapshotMutator).Parallel() + ctx.BottomUp("ramdisk_snapshot_source", RamdiskSnapshotSourceMutator).Parallel() }) ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { @@ -183,6 +187,7 @@ type Flags struct { SystemIncludeFlags []string Toolchain config.Toolchain + Sdclang bool Tidy bool GcovCoverage bool SAbiDump bool @@ -209,6 +214,9 @@ type BaseProperties struct { // Deprecated. true is the default, false is invalid. Clang *bool `android:"arch_variant"` + // compile module with SDLLVM instead of AOSP LLVM + Sdclang *bool `android:"arch_variant"` + // Minimum sdk version supported when compiling against the ndk. Setting this property causes // two variants to be built, one for the platform and one for apps. Sdk_version *string @@ -223,6 +231,7 @@ type BaseProperties struct { AndroidMkStaticLibs []string `blueprint:"mutated"` AndroidMkRuntimeLibs []string `blueprint:"mutated"` AndroidMkWholeStaticLibs []string `blueprint:"mutated"` + AndroidMkHeaderLibs []string `blueprint:"mutated"` HideFromMake bool `blueprint:"mutated"` PreventInstall bool `blueprint:"mutated"` ApexesProvidingSharedLibs []string `blueprint:"mutated"` @@ -270,6 +279,27 @@ type BaseProperties struct { // Set when both SDK and platform variants are exported to Make to trigger renaming the SDK // variant to have a ".sdk" suffix. SdkAndPlatformVariantVisibleToMake bool `blueprint:"mutated"` + + // Normally Soong uses the directory structure to decide which modules + // should be included (framework) or excluded (non-framework) from the + // different snapshots (vendor, recovery, etc.), but this property + // allows a partner to exclude a module normally thought of as a + // framework module from the vendor snapshot. + Exclude_from_vendor_snapshot *bool + + // Normally Soong uses the directory structure to decide which modules + // should be included (framework) or excluded (non-framework) from the + // different snapshots (vendor, recovery, etc.), but this property + // allows a partner to exclude a module normally thought of as a + // framework module from the recovery snapshot. + Exclude_from_recovery_snapshot *bool + + // Normally Soong uses the directory structure to decide which modules + // should be included (framework) or excluded (non-framework) from the + // different snapshots (vendor, recovery, etc.), but this property + // allows a partner to exclude a module normally thought of as a + // framework module from the ramdisk snapshot. + Exclude_from_ramdisk_snapshot *bool } type VendorProperties struct { @@ -930,48 +960,6 @@ func (c *Module) getVndkExtendsModuleName() string { return "" } -// Returns true only when this module is configured to have core, product and vendor -// variants. -func (c *Module) HasVendorVariant() bool { - return c.IsVndk() || Bool(c.VendorProperties.Vendor_available) -} - -const ( - // VendorVariationPrefix is the variant prefix used for /vendor code that compiles - // against the VNDK. - VendorVariationPrefix = "vendor." - - // ProductVariationPrefix is the variant prefix used for /product code that compiles - // against the VNDK. - ProductVariationPrefix = "product." -) - -// Returns true if the module is "product" variant. Usually these modules are installed in /product -func (c *Module) inProduct() bool { - return c.Properties.ImageVariationPrefix == ProductVariationPrefix -} - -// Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor -func (c *Module) inVendor() bool { - return c.Properties.ImageVariationPrefix == VendorVariationPrefix -} - -func (c *Module) InRamdisk() bool { - return c.ModuleBase.InRamdisk() || c.ModuleBase.InstallInRamdisk() -} - -func (c *Module) InRecovery() bool { - return c.ModuleBase.InRecovery() || c.ModuleBase.InstallInRecovery() -} - -func (c *Module) OnlyInRamdisk() bool { - return c.ModuleBase.InstallInRamdisk() -} - -func (c *Module) OnlyInRecovery() bool { - return c.ModuleBase.InstallInRecovery() -} - func (c *Module) IsStubs() bool { if library, ok := c.linker.(*libraryDecorator); ok { return library.buildStubs() @@ -1045,6 +1033,19 @@ func (c *Module) ExportedGeneratedHeaders() android.Paths { return nil } +func (c *Module) ExcludeFromVendorSnapshot() bool { + return Bool(c.Properties.Exclude_from_vendor_snapshot) +} + +func (c *Module) ExcludeFromRecoverySnapshot() bool { + return Bool(c.Properties.Exclude_from_recovery_snapshot) +} + +func (c *Module) ExcludeFromRamdiskSnapshot() bool { + return Bool(c.Properties.Exclude_from_ramdisk_snapshot) +} + + func isBionic(name string) bool { switch name { case "libc", "libm", "libdl", "libdl_android", "linker": @@ -1079,16 +1080,6 @@ type moduleContext struct { moduleContextImpl } -func (ctx *moduleContext) ProductSpecific() bool { - return ctx.ModuleContext.ProductSpecific() || - (ctx.mod.HasVendorVariant() && ctx.mod.inProduct() && !ctx.mod.IsVndk()) -} - -func (ctx *moduleContext) SocSpecific() bool { - return ctx.ModuleContext.SocSpecific() || - (ctx.mod.HasVendorVariant() && ctx.mod.inVendor() && !ctx.mod.IsVndk()) -} - type moduleContextImpl struct { mod *Module ctx BaseModuleContext @@ -1184,22 +1175,6 @@ func (ctx *moduleContextImpl) mustUseVendorVariant() bool { return ctx.mod.MustUseVendorVariant() } -func (ctx *moduleContextImpl) inProduct() bool { - return ctx.mod.inProduct() -} - -func (ctx *moduleContextImpl) inVendor() bool { - return ctx.mod.inVendor() -} - -func (ctx *moduleContextImpl) inRamdisk() bool { - return ctx.mod.InRamdisk() -} - -func (ctx *moduleContextImpl) inRecovery() bool { - return ctx.mod.InRecovery() -} - // Check whether ABI dumps should be created for this module. func (ctx *moduleContextImpl) shouldCreateSourceAbiDump() bool { if ctx.ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") { @@ -1466,6 +1441,7 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { flags := Flags{ Toolchain: c.toolchain(ctx), EmitXrefs: ctx.Config().EmitXrefRules(), + Sdclang: c.sdclang(ctx), } if c.compiler != nil { flags = c.compiler.compilerFlags(ctx, flags, deps) @@ -1555,9 +1531,10 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { // Note: this is still non-installable } - // glob exported headers for snapshot, if BOARD_VNDK_VERSION is current. - if i, ok := c.linker.(snapshotLibraryInterface); ok && ctx.DeviceConfig().VndkVersion() == "current" { - if isSnapshotAware(ctx, c) { + // glob exported headers for snapshot, if BOARD_VNDK_VERSION is current or + // RECOVERY_SNAPSHOT_VERSION is current or RAMDISK_SNAPSHOT_VERSION is current. + if i, ok := c.linker.(snapshotLibraryInterface); ok { + if shouldCollectHeadersForSnapshot(ctx, c) { i.collectHeadersForSnapshot(ctx) } } @@ -1756,19 +1733,22 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { vendorPublicLibraries := vendorPublicLibraries(actx.Config()) vendorSnapshotSharedLibs := vendorSnapshotSharedLibs(actx.Config()) + recoverySnapshotSharedLibs := recoverySnapshotSharedLibs(actx.Config()) + ramdiskSnapshotSharedLibs := ramdiskSnapshotSharedLibs(actx.Config()) rewriteVendorLibs := func(lib string) string { - if isLlndkLibrary(lib, ctx.Config()) { - return lib + llndkLibrarySuffix - } - - // only modules with BOARD_VNDK_VERSION uses snapshot. - if c.VndkVersion() != actx.DeviceConfig().VndkVersion() { - return lib + // Only a module with BOARD_VNDK_VERSION uses snapshot. + // We check this before checking if the library is an + // llndk so that the snapshot can contain llndk + // libraries. + if c.VndkVersion() == actx.DeviceConfig().VndkVersion() { + if snapshot, ok := vendorSnapshotSharedLibs.get(lib, actx.Arch().ArchType); ok { + return snapshot + } } - if snapshot, ok := vendorSnapshotSharedLibs.get(lib, actx.Arch().ArchType); ok { - return snapshot + if isLlndkLibrary(lib, ctx.Config()) { + return lib + llndkLibrarySuffix } return lib @@ -1780,7 +1760,31 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { for _, entry := range list { // strip #version suffix out name, _ := StubsLibNameAndVersion(entry) - if ctx.useSdk() && inList(name, ndkPrebuiltSharedLibraries) { + if c.InRecovery() { + recoverySnapshotVersion := + actx.DeviceConfig().RecoverySnapshotVersion() + if recoverySnapshotVersion == "current" || + recoverySnapshotVersion == "" { + nonvariantLibs = append(nonvariantLibs, name) + } else if snapshot, ok := recoverySnapshotSharedLibs.get( + name, actx.Arch().ArchType); ok { + nonvariantLibs = append(nonvariantLibs, snapshot) + } else { + nonvariantLibs = append(nonvariantLibs, name) + } + } else if c.InRamdisk() { + ramdiskSnapshotVersion := + actx.DeviceConfig().RamdiskSnapshotVersion() + if ramdiskSnapshotVersion == "current" || + ramdiskSnapshotVersion == "" { + nonvariantLibs = append(nonvariantLibs, name) + } else if snapshot, ok := ramdiskSnapshotSharedLibs.get( + name, actx.Arch().ArchType); ok { + nonvariantLibs = append(nonvariantLibs, snapshot) + } else { + nonvariantLibs = append(nonvariantLibs, name) + } + } else if ctx.useSdk() && inList(name, ndkPrebuiltSharedLibraries) { if !inList(name, ndkMigratedLibs) { nonvariantLibs = append(nonvariantLibs, name+".ndk."+version) } else { @@ -1838,14 +1842,55 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { return lib } - vendorSnapshotHeaderLibs := vendorSnapshotHeaderLibs(actx.Config()) + snapshotHeaderLibs := vendorSnapshotHeaderLibs(actx.Config()) + snapshotStaticLibs := vendorSnapshotStaticLibs(actx.Config()) + snapshotObjects := vendorSnapshotObjects(actx.Config()) + + if c.InRecovery() { + rewriteSnapshotLibs = func(lib string, snapshotMap *snapshotMap) string { + recoverySnapshotVersion := + actx.DeviceConfig().RecoverySnapshotVersion() + if recoverySnapshotVersion == "current" || + recoverySnapshotVersion == "" { + return lib + } else if snapshot, ok := snapshotMap.get(lib, actx.Arch().ArchType); ok { + return snapshot + } + + return lib + } + + snapshotHeaderLibs = recoverySnapshotHeaderLibs(actx.Config()) + snapshotStaticLibs = recoverySnapshotStaticLibs(actx.Config()) + snapshotObjects = recoverySnapshotObjects(actx.Config()) + } + + if c.InRamdisk() { + rewriteSnapshotLibs = func(lib string, snapshotMap *snapshotMap) string { + ramdiskSnapshotVersion := + actx.DeviceConfig().RamdiskSnapshotVersion() + if ramdiskSnapshotVersion == "current" || + ramdiskSnapshotVersion == "" { + return lib + } else if snapshot, ok := snapshotMap.get(lib, actx.Arch().ArchType); ok { + return snapshot + } + + return lib + } + + snapshotHeaderLibs = ramdiskSnapshotHeaderLibs(actx.Config()) + snapshotStaticLibs = ramdiskSnapshotStaticLibs(actx.Config()) + snapshotObjects = ramdiskSnapshotObjects(actx.Config()) + } + for _, lib := range deps.HeaderLibs { depTag := headerDepTag if inList(lib, deps.ReexportHeaderLibHeaders) { depTag = headerExportDepTag } - lib = rewriteSnapshotLibs(lib, vendorSnapshotHeaderLibs) + lib = rewriteSnapshotLibs(lib, snapshotHeaderLibs) if buildStubs { actx.AddFarVariationDependencies(append(ctx.Target().Variations(), c.ImageVariation()), @@ -1862,7 +1907,6 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { } syspropImplLibraries := syspropImplLibraries(actx.Config()) - vendorSnapshotStaticLibs := vendorSnapshotStaticLibs(actx.Config()) for _, lib := range deps.WholeStaticLibs { depTag := wholeStaticDepTag @@ -1870,7 +1914,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { lib = impl } - lib = rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs) + lib = rewriteSnapshotLibs(lib, snapshotStaticLibs) actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, @@ -1887,7 +1931,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { lib = impl } - lib = rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs) + lib = rewriteSnapshotLibs(lib, snapshotStaticLibs) actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, @@ -1900,13 +1944,13 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { if deps.StaticUnwinderIfLegacy { actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, - }, staticUnwinderDepTag, rewriteSnapshotLibs(staticUnwinder(actx), vendorSnapshotStaticLibs)) + }, staticUnwinderDepTag, rewriteSnapshotLibs(staticUnwinder(actx), snapshotStaticLibs)) } for _, lib := range deps.LateStaticLibs { actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, - }, lateStaticDepTag, rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs)) + }, lateStaticDepTag, rewriteSnapshotLibs(lib, snapshotStaticLibs)) } addSharedLibDependencies := func(depTag DependencyTag, name string, version string) { @@ -1980,14 +2024,13 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { } actx.AddVariationDependencies(nil, objDepTag, deps.ObjFiles...) - - vendorSnapshotObjects := vendorSnapshotObjects(actx.Config()) - if deps.CrtBegin != "" { - actx.AddVariationDependencies(nil, CrtBeginDepTag, rewriteSnapshotLibs(deps.CrtBegin, vendorSnapshotObjects)) + actx.AddVariationDependencies(nil, CrtBeginDepTag, + rewriteSnapshotLibs(deps.CrtBegin, snapshotObjects)) } if deps.CrtEnd != "" { - actx.AddVariationDependencies(nil, CrtEndDepTag, rewriteSnapshotLibs(deps.CrtEnd, vendorSnapshotObjects)) + actx.AddVariationDependencies(nil, CrtEndDepTag, + rewriteSnapshotLibs(deps.CrtEnd, snapshotObjects)) } if deps.LinkerFlagsFile != "" { actx.AddDependency(c, linkerFlagsDepTag, deps.LinkerFlagsFile) @@ -2175,6 +2218,21 @@ func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) { } } +func (c *Module) sdclang(ctx BaseModuleContext) bool { + sdclang := Bool(c.Properties.Sdclang) + + // SDLLVM is not for host build + if ctx.Host() || config.ForceSDClangOff { + return false + } + + if c.Properties.Sdclang == nil && config.SDClang { + return true + } + + return sdclang +} + // Convert dependencies to paths. Returns a PathDeps containing paths func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { var depPaths PathDeps @@ -2182,8 +2240,6 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { directStaticDeps := []LinkableInterface{} directSharedDeps := []LinkableInterface{} - vendorPublicLibraries := vendorPublicLibraries(ctx.Config()) - reexportExporter := func(exporter exportedFlagsProducer) { depPaths.ReexportedDirs = append(depPaths.ReexportedDirs, exporter.exportedDirs()...) depPaths.ReexportedSystemDirs = append(depPaths.ReexportedSystemDirs, exporter.exportedSystemDirs()...) @@ -2523,59 +2579,6 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { *depPtr = append(*depPtr, dep.Path()) } - vendorSuffixModules := vendorSuffixModules(ctx.Config()) - - baseLibName := func(depName string) string { - libName := strings.TrimSuffix(depName, llndkLibrarySuffix) - libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix) - libName = strings.TrimPrefix(libName, "prebuilt_") - return libName - } - - makeLibName := func(depName string) string { - libName := baseLibName(depName) - isLLndk := isLlndkLibrary(libName, ctx.Config()) - isVendorPublicLib := inList(libName, *vendorPublicLibraries) - bothVendorAndCoreVariantsExist := ccDep.HasVendorVariant() || isLLndk - - if c, ok := ccDep.(*Module); ok { - // Use base module name for snapshots when exporting to Makefile. - if c.isSnapshotPrebuilt() { - baseName := c.BaseModuleName() - - if c.IsVndk() { - return baseName + ".vendor" - } - - if vendorSuffixModules[baseName] { - return baseName + ".vendor" - } else { - return baseName - } - } - } - - if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() && !c.InRamdisk() && !c.InRecovery() { - // The vendor module is a no-vendor-variant VNDK library. Depend on the - // core module instead. - return libName - } else if c.UseVndk() && bothVendorAndCoreVariantsExist { - // The vendor module in Make will have been renamed to not conflict with the core - // module, so update the dependency name here accordingly. - return libName + c.getNameSuffixWithVndkVersion(ctx) - } else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib { - return libName + vendorPublicLibrarySuffix - } else if ccDep.InRamdisk() && !ccDep.OnlyInRamdisk() { - return libName + ramdiskSuffix - } else if ccDep.InRecovery() && !ccDep.OnlyInRecovery() { - return libName + recoverySuffix - } else if ccDep.Module().Target().NativeBridge == android.NativeBridgeEnabled { - return libName + nativeBridgeSuffix - } else { - return libName - } - } - // Export the shared libs to Make. switch depTag { case SharedDepTag, sharedExportDepTag, lateSharedDepTag, earlySharedDepTag: @@ -2593,7 +2596,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // Note: the order of libs in this list is not important because // they merely serve as Make dependencies and do not affect this lib itself. c.Properties.AndroidMkSharedLibs = append( - c.Properties.AndroidMkSharedLibs, makeLibName(depName)) + c.Properties.AndroidMkSharedLibs, c.makeLibName(ctx, ccDep, depName)) // Record baseLibName for snapshots. c.Properties.SnapshotSharedLibs = append(c.Properties.SnapshotSharedLibs, baseLibName(depName)) case ndkStubDepTag, ndkLateStubDepTag: @@ -2602,15 +2605,18 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depName+"."+ccDep.ApiLevel()) case StaticDepTag, staticExportDepTag, lateStaticDepTag: c.Properties.AndroidMkStaticLibs = append( - c.Properties.AndroidMkStaticLibs, makeLibName(depName)) + c.Properties.AndroidMkStaticLibs, c.makeLibName(ctx, ccDep, depName)) case runtimeDepTag: c.Properties.AndroidMkRuntimeLibs = append( - c.Properties.AndroidMkRuntimeLibs, makeLibName(depName)) + c.Properties.AndroidMkRuntimeLibs, c.makeLibName(ctx, ccDep, depName)) // Record baseLibName for snapshots. c.Properties.SnapshotRuntimeLibs = append(c.Properties.SnapshotRuntimeLibs, baseLibName(depName)) case wholeStaticDepTag: c.Properties.AndroidMkWholeStaticLibs = append( - c.Properties.AndroidMkWholeStaticLibs, makeLibName(depName)) + c.Properties.AndroidMkWholeStaticLibs, c.makeLibName(ctx, ccDep, depName)) + case headerDepTag: + c.Properties.AndroidMkHeaderLibs = append( + c.Properties.AndroidMkHeaderLibs, c.makeLibName(ctx, ccDep, depName)) } }) @@ -2636,6 +2642,68 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return depPaths } +// baseLibName trims known prefixes and suffixes +func baseLibName(depName string) string { + libName := strings.TrimSuffix(depName, llndkLibrarySuffix) + libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix) + libName = strings.TrimPrefix(libName, "prebuilt_") + return libName +} + +func (c *Module) makeLibName(ctx android.ModuleContext, ccDep LinkableInterface, depName string) string { + vendorSuffixModules := vendorSuffixModules(ctx.Config()) + recoverySuffixModules := recoverySuffixModules(ctx.Config()) + ramdiskSuffixModules := ramdiskSuffixModules(ctx.Config()) + vendorPublicLibraries := vendorPublicLibraries(ctx.Config()) + + libName := baseLibName(depName) + isLLndk := isLlndkLibrary(libName, ctx.Config()) + isVendorPublicLib := inList(libName, *vendorPublicLibraries) + bothVendorAndCoreVariantsExist := ccDep.HasVendorVariant() || isLLndk + + if c, ok := ccDep.(*Module); ok { + // Use base module name for snapshots when exporting to Makefile. + if c.isSnapshotPrebuilt() { + baseName := c.BaseModuleName() + + if c.IsVndk() { + return baseName + ".vendor" + } + + if c.inVendor() && vendorSuffixModules[baseName] { + return baseName + ".vendor" + } else if c.InRecovery() && recoverySuffixModules[baseName] { + return baseName + ".recovery" + } else if c.InRamdisk() && ramdiskSuffixModules[baseName] { + return baseName + ".ramdisk" + } else { + return baseName + } + } + } + + if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() && + !c.InRamdisk() && !c.InRecovery() { + // The vendor module is a no-vendor-variant VNDK library. Depend on the + // core module instead. + return libName + } else if c.UseVndk() && bothVendorAndCoreVariantsExist { + // The vendor module in Make will have been renamed to not conflict with the core + // module, so update the dependency name here accordingly. + return libName + c.getNameSuffixWithVndkVersion(ctx) + } else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib { + return libName + vendorPublicLibrarySuffix + } else if ccDep.InRamdisk() && !ccDep.OnlyInRamdisk() { + return libName + ramdiskSuffix + } else if ccDep.InRecovery() && !ccDep.OnlyInRecovery() { + return libName + recoverySuffix + } else if ccDep.Module().Target().NativeBridge == android.NativeBridgeEnabled { + return libName + nativeBridgeSuffix + } else { + return libName + } +} + func (c *Module) InstallInData() bool { if c.installer == nil { return false @@ -2944,227 +3012,6 @@ func squashRecoverySrcs(m *Module) { } } -var _ android.ImageInterface = (*Module)(nil) - -func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { - // Sanity check - vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific() - productSpecific := mctx.ProductSpecific() - - if m.VendorProperties.Vendor_available != nil && vendorSpecific { - mctx.PropertyErrorf("vendor_available", - "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`") - } - - if vndkdep := m.vndkdep; vndkdep != nil { - if vndkdep.isVndk() { - if vendorSpecific || productSpecific { - if !vndkdep.isVndkExt() { - mctx.PropertyErrorf("vndk", - "must set `extends: \"...\"` to vndk extension") - } else if m.VendorProperties.Vendor_available != nil { - mctx.PropertyErrorf("vendor_available", - "must not set at the same time as `vndk: {extends: \"...\"}`") - } - } else { - if vndkdep.isVndkExt() { - mctx.PropertyErrorf("vndk", - "must set `vendor: true` or `product_specific: true` to set `extends: %q`", - m.getVndkExtendsModuleName()) - } - if m.VendorProperties.Vendor_available == nil { - mctx.PropertyErrorf("vndk", - "vendor_available must be set to either true or false when `vndk: {enabled: true}`") - } - } - } else { - if vndkdep.isVndkSp() { - mctx.PropertyErrorf("vndk", - "must set `enabled: true` to set `support_system_process: true`") - } - if vndkdep.isVndkExt() { - mctx.PropertyErrorf("vndk", - "must set `enabled: true` to set `extends: %q`", - m.getVndkExtendsModuleName()) - } - } - } - - var coreVariantNeeded bool = false - var ramdiskVariantNeeded bool = false - var recoveryVariantNeeded bool = false - - var vendorVariants []string - var productVariants []string - - platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion() - boardVndkVersion := mctx.DeviceConfig().VndkVersion() - productVndkVersion := mctx.DeviceConfig().ProductVndkVersion() - if boardVndkVersion == "current" { - boardVndkVersion = platformVndkVersion - } - if productVndkVersion == "current" { - productVndkVersion = platformVndkVersion - } - - if boardVndkVersion == "" { - // If the device isn't compiling against the VNDK, we always - // use the core mode. - coreVariantNeeded = true - } else if _, ok := m.linker.(*llndkStubDecorator); ok { - // LL-NDK stubs only exist in the vendor and product variants, - // since the real libraries will be used in the core variant. - vendorVariants = append(vendorVariants, - platformVndkVersion, - boardVndkVersion, - ) - productVariants = append(productVariants, - platformVndkVersion, - productVndkVersion, - ) - } else if _, ok := m.linker.(*llndkHeadersDecorator); ok { - // ... and LL-NDK headers as well - vendorVariants = append(vendorVariants, - platformVndkVersion, - boardVndkVersion, - ) - productVariants = append(productVariants, - platformVndkVersion, - productVndkVersion, - ) - } else if m.isSnapshotPrebuilt() { - // Make vendor variants only for the versions in BOARD_VNDK_VERSION and - // PRODUCT_EXTRA_VNDK_VERSIONS. - if snapshot, ok := m.linker.(interface { - version() string - }); ok { - vendorVariants = append(vendorVariants, snapshot.version()) - } else { - mctx.ModuleErrorf("version is unknown for snapshot prebuilt") - } - } else if m.HasVendorVariant() && !m.isVndkExt() { - // This will be available in /system, /vendor and /product - // or a /system directory that is available to vendor and product. - coreVariantNeeded = true - - // We assume that modules under proprietary paths are compatible for - // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or - // PLATFORM_VNDK_VERSION. - if isVendorProprietaryPath(mctx.ModuleDir()) { - vendorVariants = append(vendorVariants, boardVndkVersion) - } else { - vendorVariants = append(vendorVariants, platformVndkVersion) - } - - // vendor_available modules are also available to /product. - productVariants = append(productVariants, platformVndkVersion) - // VNDK is always PLATFORM_VNDK_VERSION - if !m.IsVndk() { - productVariants = append(productVariants, productVndkVersion) - } - } else if vendorSpecific && String(m.Properties.Sdk_version) == "" { - // This will be available in /vendor (or /odm) only - // We assume that modules under proprietary paths are compatible for - // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or - // PLATFORM_VNDK_VERSION. - if isVendorProprietaryPath(mctx.ModuleDir()) { - vendorVariants = append(vendorVariants, boardVndkVersion) - } else { - vendorVariants = append(vendorVariants, platformVndkVersion) - } - } else { - // This is either in /system (or similar: /data), or is a - // modules built with the NDK. Modules built with the NDK - // will be restricted using the existing link type checks. - coreVariantNeeded = true - } - - if boardVndkVersion != "" && productVndkVersion != "" { - if coreVariantNeeded && productSpecific && String(m.Properties.Sdk_version) == "" { - // The module has "product_specific: true" that does not create core variant. - coreVariantNeeded = false - productVariants = append(productVariants, productVndkVersion) - } - } else { - // Unless PRODUCT_PRODUCT_VNDK_VERSION is set, product partition has no - // restriction to use system libs. - // No product variants defined in this case. - productVariants = []string{} - } - - if Bool(m.Properties.Ramdisk_available) { - ramdiskVariantNeeded = true - } - - if m.ModuleBase.InstallInRamdisk() { - ramdiskVariantNeeded = true - coreVariantNeeded = false - } - - if Bool(m.Properties.Recovery_available) { - recoveryVariantNeeded = true - } - - if m.ModuleBase.InstallInRecovery() { - recoveryVariantNeeded = true - coreVariantNeeded = false - } - - for _, variant := range android.FirstUniqueStrings(vendorVariants) { - m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, VendorVariationPrefix+variant) - } - - for _, variant := range android.FirstUniqueStrings(productVariants) { - m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, ProductVariationPrefix+variant) - } - - m.Properties.RamdiskVariantNeeded = ramdiskVariantNeeded - m.Properties.RecoveryVariantNeeded = recoveryVariantNeeded - m.Properties.CoreVariantNeeded = coreVariantNeeded -} - -func (c *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool { - return c.Properties.CoreVariantNeeded -} - -func (c *Module) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { - return c.Properties.RamdiskVariantNeeded -} - -func (c *Module) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { - return c.Properties.RecoveryVariantNeeded -} - -func (c *Module) ExtraImageVariations(ctx android.BaseModuleContext) []string { - return c.Properties.ExtraVariants -} - -func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) { - m := module.(*Module) - if variant == android.RamdiskVariation { - m.MakeAsPlatform() - } else if variant == android.RecoveryVariation { - m.MakeAsPlatform() - squashRecoverySrcs(m) - } else if strings.HasPrefix(variant, VendorVariationPrefix) { - m.Properties.ImageVariationPrefix = VendorVariationPrefix - m.Properties.VndkVersion = strings.TrimPrefix(variant, VendorVariationPrefix) - squashVendorSrcs(m) - - // Makefile shouldn't know vendor modules other than BOARD_VNDK_VERSION. - // Hide other vendor variants to avoid collision. - vndkVersion := ctx.DeviceConfig().VndkVersion() - if vndkVersion != "current" && vndkVersion != "" && vndkVersion != m.Properties.VndkVersion { - m.Properties.HideFromMake = true - m.SkipInstall() - } - } else if strings.HasPrefix(variant, ProductVariationPrefix) { - m.Properties.ImageVariationPrefix = ProductVariationPrefix - m.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix) - squashVendorSrcs(m) - } -} - func getCurrentNdkPrebuiltVersion(ctx DepsContext) string { if ctx.Config().PlatformSdkVersionInt() > config.NdkMaxPrebuiltVersionInt { return strconv.Itoa(config.NdkMaxPrebuiltVersionInt) diff --git a/cc/cc_test.go b/cc/cc_test.go index f73e02172..2d2a99af6 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -258,7 +258,8 @@ func checkVndkModule(t *testing.T, ctx *android.TestContext, name, subDir string } } -func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) { +func checkSnapshotIncludeExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string, include bool, fake bool) { + t.Helper() mod, ok := ctx.ModuleForTests(moduleName, variant).Module().(android.OutputFileProducer) if !ok { t.Errorf("%q must have output\n", moduleName) @@ -271,12 +272,37 @@ func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.Tes } snapshotPath := filepath.Join(subDir, snapshotFilename) - out := singleton.Output(snapshotPath) - if out.Input.String() != outputFiles[0].String() { - t.Errorf("The input of snapshot %q must be %q, but %q", moduleName, out.Input.String(), outputFiles[0]) + if include { + out := singleton.Output(snapshotPath) + if fake { + if out.Rule == nil { + t.Errorf("Missing rule for module %q output file %q", moduleName, outputFiles[0]) + } + } else { + if out.Input.String() != outputFiles[0].String() { + t.Errorf("The input of snapshot %q must be %q, but %q", moduleName, out.Input.String(), outputFiles[0]) + } + } + } else { + out := singleton.MaybeOutput(snapshotPath) + if out.Rule != nil { + t.Errorf("There must be no rule for module %q output file %q", moduleName, outputFiles[0]) + } } } +func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) { + checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true, false) +} + +func checkSnapshotExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) { + checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, false, false) +} + +func checkSnapshotRule(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) { + checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true, true) +} + func checkWriteFileOutput(t *testing.T, params android.TestingBuildParams, expected []string) { t.Helper() assertString(t, params.Rule.String(), android.WriteFile.String()) @@ -833,131 +859,6 @@ func TestDoubleLoadbleDep(t *testing.T) { `) } -func TestVendorSnapshot(t *testing.T) { - bp := ` - cc_library { - name: "libvndk", - vendor_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvendor", - vendor: true, - nocrt: true, - } - - cc_library { - name: "libvendor_available", - vendor_available: true, - nocrt: true, - } - - cc_library_headers { - name: "libvendor_headers", - vendor_available: true, - nocrt: true, - } - - cc_binary { - name: "vendor_bin", - vendor: true, - nocrt: true, - } - - cc_binary { - name: "vendor_available_bin", - vendor_available: true, - nocrt: true, - } - - toolchain_library { - name: "libb", - vendor_available: true, - src: "libb.a", - } - - cc_object { - name: "obj", - vendor_available: true, - } -` - config := TestConfig(buildDir, android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("VER") - ctx := testCcWithConfig(t, config) - - // Check Vendor snapshot output. - - snapshotDir := "vendor-snapshot" - snapshotVariantPath := filepath.Join(buildDir, 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.VER_%s_%s_shared", archType, archVariant) - sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") - checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant) - checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant) - jsonFiles = append(jsonFiles, - filepath.Join(sharedDir, "libvendor.so.json"), - filepath.Join(sharedDir, "libvendor_available.so.json")) - - // For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured. - staticVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static", archType, archVariant) - staticDir := filepath.Join(snapshotVariantPath, archDir, "static") - checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant) - checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.a", staticDir, staticVariant) - checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.a", staticDir, staticVariant) - checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.a", staticDir, staticVariant) - jsonFiles = append(jsonFiles, - filepath.Join(staticDir, "libb.a.json"), - filepath.Join(staticDir, "libvndk.a.json"), - filepath.Join(staticDir, "libvendor.a.json"), - filepath.Join(staticDir, "libvendor_available.a.json")) - - // For binary executables, all vendor:true and vendor_available modules are captured. - if archType == "arm64" { - binaryVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant) - binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary") - checkSnapshot(t, ctx, snapshotSingleton, "vendor_bin", "vendor_bin", binaryDir, binaryVariant) - checkSnapshot(t, ctx, snapshotSingleton, "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant) - jsonFiles = append(jsonFiles, - filepath.Join(binaryDir, "vendor_bin.json"), - filepath.Join(binaryDir, "vendor_available_bin.json")) - } - - // For header libraries, all vendor:true and vendor_available modules are captured. - headerDir := filepath.Join(snapshotVariantPath, archDir, "header") - jsonFiles = append(jsonFiles, filepath.Join(headerDir, "libvendor_headers.json")) - - // For object modules, all vendor:true and vendor_available modules are captured. - objectVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant) - objectDir := filepath.Join(snapshotVariantPath, archDir, "object") - checkSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant) - jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.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 TestDoubleLoadableDepError(t *testing.T) { // Check whether an error is emitted when a LLNDK depends on a non-double_loadable VNDK lib. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` diff --git a/cc/config/global.go b/cc/config/global.go index 473c8067d..b633a7224 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -15,6 +15,13 @@ package config import ( + "encoding/json" + "fmt" + //"io/ioutil" + "os" + //"path" + //"path/filepath" + "strconv" "strings" "android/soong/android" @@ -112,7 +119,9 @@ var ( noOverrideGlobalCflags = []string{ "-Werror=int-to-pointer-cast", "-Werror=pointer-to-int-cast", - "-Werror=fortify-source", + // SDClang does not support -Werror=fortify-source. + // TODO: b/142476859 + // "-Werror=fortify-source", } IllegalFlags = []string{ @@ -126,6 +135,10 @@ var ( NdkMaxPrebuiltVersionInt = 27 + SDClang = false + SDClangPath = "" + ForceSDClangOff = false + // prebuilts/clang default settings. ClangDefaultBase = "prebuilts/clang/host" ClangDefaultVersion = "clang-r383902b1" @@ -212,6 +225,8 @@ func init() { pctx.PrefixedExistentPathsForSourcesVariable("CommonNativehelperInclude", "-I", []string{"libnativehelper/include_jni"}) + setSdclangVars() + pctx.SourcePathVariable("ClangDefaultBase", ClangDefaultBase) pctx.VariableFunc("ClangBase", func(ctx android.PackageVarContext) string { if override := ctx.Config().Getenv("LLVM_PREBUILTS_BASE"); override != "" { @@ -264,6 +279,149 @@ func init() { pctx.VariableFunc("REAbiLinkerExecStrategy", remoteexec.EnvOverrideFunc("RBE_ABI_LINKER_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) } +func setSdclangVars() { + sdclangPath := "" + sdclangAEFlag := "" + sdclangFlags := "" + + product := android.SdclangEnv["TARGET_PRODUCT"] + aeConfigPath := android.SdclangEnv["SDCLANG_AE_CONFIG"] + sdclangConfigPath := android.SdclangEnv["SDCLANG_CONFIG"] + sdclangSA := android.SdclangEnv["SDCLANG_SA_ENABLED"] + + type sdclangAEConfig struct { + SDCLANG_AE_FLAG string + } + + // Load AE config file and set AE flag + if file, err := os.Open(aeConfigPath); err == nil { + decoder := json.NewDecoder(file) + aeConfig := sdclangAEConfig{} + if err := decoder.Decode(&aeConfig); err == nil { + sdclangAEFlag = aeConfig.SDCLANG_AE_FLAG + } else { + panic(err) + } + } + + // Load SD Clang config file and set SD Clang variables + var sdclangConfig interface{} + if file, err := os.Open(sdclangConfigPath); err == nil { + decoder := json.NewDecoder(file) + // Parse the config file + if err := decoder.Decode(&sdclangConfig); err == nil { + config := sdclangConfig.(map[string]interface{}) + // Retrieve the default block + if dev, ok := config["default"]; ok { + devConfig := dev.(map[string]interface{}) + // FORCE_SDCLANG_OFF is required in the default block + if _, ok := devConfig["FORCE_SDCLANG_OFF"]; ok { + ForceSDClangOff = devConfig["FORCE_SDCLANG_OFF"].(bool) + } + // SDCLANG is optional in the default block + if _, ok := devConfig["SDCLANG"]; ok { + SDClang = devConfig["SDCLANG"].(bool) + } + // SDCLANG_PATH is required in the default block + if _, ok := devConfig["SDCLANG_PATH"]; ok { + sdclangPath = devConfig["SDCLANG_PATH"].(string) + } else { + panic("SDCLANG_PATH is required in the default block") + } + // SDCLANG_FLAGS is optional in the default block + if _, ok := devConfig["SDCLANG_FLAGS"]; ok { + sdclangFlags = devConfig["SDCLANG_FLAGS"].(string) + } + } else { + panic("Default block is required in the SD Clang config file") + } + // Retrieve the device specific block if it exists in the config file + if dev, ok := config[product]; ok { + devConfig := dev.(map[string]interface{}) + // SDCLANG is optional in the device specific block + if _, ok := devConfig["SDCLANG"]; ok { + SDClang = devConfig["SDCLANG"].(bool) + } + // SDCLANG_PATH is optional in the device specific block + if _, ok := devConfig["SDCLANG_PATH"]; ok { + sdclangPath = devConfig["SDCLANG_PATH"].(string) + } + // SDCLANG_FLAGS is optional in the device specific block + if _, ok := devConfig["SDCLANG_FLAGS"]; ok { + sdclangFlags = devConfig["SDCLANG_FLAGS"].(string) + } + } + b, _ := strconv.ParseBool(sdclangSA) + if(b) { + llvmsa_loc := "llvmsa" + s := []string{sdclangFlags, "--compile-and-analyze", llvmsa_loc} + sdclangFlags = strings.Join(s, " ") + fmt.Println("Clang SA is enabled: ", sdclangFlags) + } else { + fmt.Println("Clang SA is not enabled") + } + } else { + panic(err) + } + } else { + fmt.Println(err) + } + + // Override SDCLANG if the varialbe is set in the environment + if sdclang := android.SdclangEnv["SDCLANG"]; sdclang != "" { + if override, err := strconv.ParseBool(sdclang); err == nil { + SDClang = override + } + } + + // Sanity check SDCLANG_PATH + if envPath := android.SdclangEnv["SDCLANG_PATH"]; sdclangPath == "" && envPath == "" { + panic("SDCLANG_PATH can not be empty") + } + + // Override SDCLANG_PATH if the variable is set in the environment + pctx.VariableFunc("SDClangBin", func(ctx android.PackageVarContext) string { + if override := ctx.Config().Getenv("SDCLANG_PATH"); override != "" { + return override + } + return sdclangPath + }) + + // Override SDCLANG_COMMON_FLAGS if the variable is set in the environment + pctx.VariableFunc("SDClangFlags", func(ctx android.PackageVarContext) string { + if override := ctx.Config().Getenv("SDCLANG_COMMON_FLAGS"); override != "" { + return override + } + return sdclangAEFlag + " " + sdclangFlags + }) + + SDClangPath = sdclangPath + // Find the path to SDLLVM's ASan libraries + // TODO (b/117846004): Disable setting SDClangAsanLibDir due to unit test path issues + //absPath := sdclangPath + //if envPath := android.SdclangEnv["SDCLANG_PATH"]; envPath != "" { + // absPath = envPath + //} + //if !filepath.IsAbs(absPath) { + // absPath = path.Join(androidRoot, absPath) + //} + // + //libDirPrefix := "../lib/clang" + //libDir, err := ioutil.ReadDir(path.Join(absPath, libDirPrefix)) + //if err != nil { + // libDirPrefix = "../lib64/clang" + // libDir, err = ioutil.ReadDir(path.Join(absPath, libDirPrefix)) + //} + //if err != nil { + // panic(err) + //} + //if len(libDir) != 1 || !libDir[0].IsDir() { + // panic("Failed to find sanitizer libraries") + //} + // + //pctx.StaticVariable("SDClangAsanLibDir", path.Join(absPath, libDirPrefix, libDir[0].Name(), "lib/linux")) +} + var HostPrebuiltTag = pctx.VariableConfigMethod("HostPrebuiltTag", android.Config.PrebuiltOS) func bionicHeaders(kernelArch string) string { diff --git a/cc/config/vndk.go b/cc/config/vndk.go index 6f2e80741..ccf6eed12 100644 --- a/cc/config/vndk.go +++ b/cc/config/vndk.go @@ -47,4 +47,5 @@ var VndkMustUseVendorVariantList = []string{ "libstagefright_xmlparser", "libui", "libxml2", + "libmedia_helper",//Remove it from the list once the workaround patch is cleared in S } diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go index 13b55112a..7e306c5cb 100644 --- a/cc/config/x86_linux_host.go +++ b/cc/config/x86_linux_host.go @@ -107,6 +107,7 @@ var ( "resolv", "rt", "util", + "supc++", }, "-l") ) diff --git a/cc/genrule.go b/cc/genrule.go index 66d178456..e6ef62ad8 100644 --- a/cc/genrule.go +++ b/cc/genrule.go @@ -64,12 +64,29 @@ func (g *GenruleExtraProperties) CoreVariantNeeded(ctx android.BaseModuleContext return Bool(g.Vendor_available) || !(ctx.SocSpecific() || ctx.DeviceSpecific()) } -func (g *GenruleExtraProperties) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { - return Bool(g.Ramdisk_available) -} + func (g *GenruleExtraProperties) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { - return Bool(g.Recovery_available) + // If the build is using a snapshot, the recovery variant under AOSP directories + // is not needed. + recoverySnapshotVersion := ctx.DeviceConfig().RecoverySnapshotVersion() + if recoverySnapshotVersion != "current" && recoverySnapshotVersion != "" && + !isRecoveryProprietaryModule(ctx) { + return false + } else { + return Bool(g.Recovery_available) + } +} +func (g *GenruleExtraProperties) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { + // If the build is using a snapshot, the ramdisk variant under AOSP directories + // is not needed. + ramdiskSnapshotVersion := ctx.DeviceConfig().RamdiskSnapshotVersion() + if ramdiskSnapshotVersion != "current" && ramdiskSnapshotVersion != "" && + !isRamdiskProprietaryModule(ctx) { + return false + } else { + return Bool(g.Ramdisk_available) + } } func (g *GenruleExtraProperties) ExtraImageVariations(ctx android.BaseModuleContext) []string { @@ -84,7 +101,7 @@ func (g *GenruleExtraProperties) ExtraImageVariations(ctx android.BaseModuleCont // If not, we assume modules under proprietary paths are compatible for // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, that is // PLATFORM_VNDK_VERSION. - if vndkVersion == "current" || !isVendorProprietaryPath(ctx.ModuleDir()) { + if vndkVersion == "current" || !isVendorProprietaryModule(ctx) { variants = append(variants, VendorVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion()) } else { variants = append(variants, VendorVariationPrefix+vndkVersion) diff --git a/cc/image.go b/cc/image.go new file mode 100644 index 000000000..6b3b08315 --- /dev/null +++ b/cc/image.go @@ -0,0 +1,408 @@ +// Copyright 2020 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 cc + +// This file contains image variant related things, including image mutator functions, utility +// functions to determine where a module is installed, etc. + +import ( + "strings" + + "android/soong/android" +) + +var _ android.ImageInterface = (*Module)(nil) + +type imageVariantType string + +const ( + coreImageVariant imageVariantType = "core" + vendorImageVariant imageVariantType = "vendor" + productImageVariant imageVariantType = "product" + ramdiskImageVariant imageVariantType = "ramdisk" + recoveryImageVariant imageVariantType = "recovery" + hostImageVariant imageVariantType = "host" +) + +func (c *Module) getImageVariantType() imageVariantType { + if c.Host() { + return hostImageVariant + } else if c.inVendor() { + return vendorImageVariant + } else if c.inProduct() { + return productImageVariant + } else if c.InRamdisk() { + return ramdiskImageVariant + } else if c.InRecovery() { + return recoveryImageVariant + } else { + return coreImageVariant + } +} + +const ( + // VendorVariationPrefix is the variant prefix used for /vendor code that compiles + // against the VNDK. + VendorVariationPrefix = "vendor." + + // ProductVariationPrefix is the variant prefix used for /product code that compiles + // against the VNDK. + ProductVariationPrefix = "product." +) + +func (ctx *moduleContext) ProductSpecific() bool { + return ctx.ModuleContext.ProductSpecific() || + (ctx.mod.HasVendorVariant() && ctx.mod.inProduct() && !ctx.mod.IsVndk()) +} + +func (ctx *moduleContext) SocSpecific() bool { + return ctx.ModuleContext.SocSpecific() || + (ctx.mod.HasVendorVariant() && ctx.mod.inVendor() && !ctx.mod.IsVndk()) +} + +func (ctx *moduleContextImpl) inProduct() bool { + return ctx.mod.inProduct() +} + +func (ctx *moduleContextImpl) inVendor() bool { + return ctx.mod.inVendor() +} + +func (ctx *moduleContextImpl) inRamdisk() bool { + return ctx.mod.InRamdisk() +} + +func (ctx *moduleContextImpl) inRecovery() bool { + return ctx.mod.InRecovery() +} + +// Returns true only when this module is configured to have core, product and vendor +// variants. +func (c *Module) HasVendorVariant() bool { + return c.IsVndk() || Bool(c.VendorProperties.Vendor_available) +} + +// Returns true if the module is "product" variant. Usually these modules are installed in /product +func (c *Module) inProduct() bool { + return c.Properties.ImageVariationPrefix == ProductVariationPrefix +} + +// Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor +func (c *Module) inVendor() bool { + return c.Properties.ImageVariationPrefix == VendorVariationPrefix +} + +func (c *Module) InRamdisk() bool { + return c.ModuleBase.InRamdisk() || c.ModuleBase.InstallInRamdisk() +} + +func (c *Module) InRecovery() bool { + return c.ModuleBase.InRecovery() || c.ModuleBase.InstallInRecovery() +} + +func (c *Module) OnlyInRamdisk() bool { + return c.ModuleBase.InstallInRamdisk() +} + +func (c *Module) OnlyInRecovery() bool { + return c.ModuleBase.InstallInRecovery() +} + +func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { + // Validation check + vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific() + productSpecific := mctx.ProductSpecific() + + if m.VendorProperties.Vendor_available != nil && vendorSpecific { + mctx.PropertyErrorf("vendor_available", + "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`") + } + + if vndkdep := m.vndkdep; vndkdep != nil { + if vndkdep.isVndk() { + if vendorSpecific || productSpecific { + if !vndkdep.isVndkExt() { + mctx.PropertyErrorf("vndk", + "must set `extends: \"...\"` to vndk extension") + } else if m.VendorProperties.Vendor_available != nil { + mctx.PropertyErrorf("vendor_available", + "must not set at the same time as `vndk: {extends: \"...\"}`") + } + } else { + if vndkdep.isVndkExt() { + mctx.PropertyErrorf("vndk", + "must set `vendor: true` or `product_specific: true` to set `extends: %q`", + m.getVndkExtendsModuleName()) + } + if m.VendorProperties.Vendor_available == nil { + mctx.PropertyErrorf("vndk", + "vendor_available must be set to either true or false when `vndk: {enabled: true}`") + } + } + } else { + if vndkdep.isVndkSp() { + mctx.PropertyErrorf("vndk", + "must set `enabled: true` to set `support_system_process: true`") + } + if vndkdep.isVndkExt() { + mctx.PropertyErrorf("vndk", + "must set `enabled: true` to set `extends: %q`", + m.getVndkExtendsModuleName()) + } + } + } + + var coreVariantNeeded bool = false + var ramdiskVariantNeeded bool = false + var recoveryVariantNeeded bool = false + + var vendorVariants []string + var productVariants []string + + platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion() + boardVndkVersion := mctx.DeviceConfig().VndkVersion() + productVndkVersion := mctx.DeviceConfig().ProductVndkVersion() + recoverySnapshotVersion := mctx.DeviceConfig().RecoverySnapshotVersion() + usingRecoverySnapshot := recoverySnapshotVersion != "current" && + recoverySnapshotVersion != "" + ramdiskSnapshotVersion := mctx.DeviceConfig().RamdiskSnapshotVersion() + usingRamdiskSnapshot := ramdiskSnapshotVersion != "current" && + ramdiskSnapshotVersion != "" + if boardVndkVersion == "current" { + boardVndkVersion = platformVndkVersion + } + if productVndkVersion == "current" { + productVndkVersion = platformVndkVersion + } + usingVendorSnapshot := boardVndkVersion != platformVndkVersion + + if boardVndkVersion == "" { + // If the device isn't compiling against the VNDK, we always + // use the core mode. + coreVariantNeeded = true + } else if _, ok := m.linker.(*llndkStubDecorator); ok { + // LL-NDK stubs only exist in the vendor and product variants, + // since the real libraries will be used in the core variant. + + if usingVendorSnapshot { + // If we're using the vendor snapshot, avoid providing + // the boardVndkVersion. This requires that the vendor + // snapshot provide the library instead, which happens + // below as a snapshot prebuilt. + vendorVariants = append(vendorVariants, + platformVndkVersion, + ) + } else { + vendorVariants = append(vendorVariants, + platformVndkVersion, + boardVndkVersion, + ) + } + + productVariants = append(productVariants, + platformVndkVersion, + productVndkVersion, + ) + } else if _, ok := m.linker.(*llndkHeadersDecorator); ok { + // ... and LL-NDK headers as well + + if usingVendorSnapshot { + // If we're using the vendor snapshot, avoid providing + // the boardVndkVersion. This requires that the vendor + // snapshot provide the headers instead, which happens + // below as a snapshot prebuilt. + vendorVariants = append(vendorVariants, + platformVndkVersion, + ) + } else { + vendorVariants = append(vendorVariants, + platformVndkVersion, + boardVndkVersion, + ) + } + + productVariants = append(productVariants, + platformVndkVersion, + productVndkVersion, + ) + } else if m.isSnapshotPrebuilt() { + // Make vendor variants only for the versions in BOARD_VNDK_VERSION and + // PRODUCT_EXTRA_VNDK_VERSIONS. + if snapshot, ok := m.linker.(interface { + version() string + }); ok { + if m.InstallInRecovery() { + recoveryVariantNeeded = true + } else if m.InstallInRamdisk() { + ramdiskVariantNeeded = true + } else { + vendorVariants = append(vendorVariants, snapshot.version()) + } + } else { + mctx.ModuleErrorf("version is unknown for snapshot prebuilt") + } + } else if m.HasVendorVariant() && !m.isVndkExt() { + // This will be available in /system, /vendor and /product + // or a /system directory that is available to vendor and product. + coreVariantNeeded = true + + // We assume that modules under proprietary paths are compatible for + // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or + // PLATFORM_VNDK_VERSION. + if isVendorProprietaryModule(mctx) { + vendorVariants = append(vendorVariants, boardVndkVersion) + } else { + vendorVariants = append(vendorVariants, platformVndkVersion) + } + + // vendor_available modules are also available to /product. + productVariants = append(productVariants, platformVndkVersion) + // VNDK is always PLATFORM_VNDK_VERSION + if !m.IsVndk() { + productVariants = append(productVariants, productVndkVersion) + } + } else if vendorSpecific && String(m.Properties.Sdk_version) == "" { + // This will be available in /vendor (or /odm) only + + // kernel_headers is a special module type whose exported headers + // are coming from DeviceKernelHeaders() which is always vendor + // dependent. They'll always have both vendor variants. + // For other modules, we assume that modules under proprietary + // paths are compatible for BOARD_VNDK_VERSION. The other modules + // are regarded as AOSP, which is PLATFORM_VNDK_VERSION. + if _, ok := m.linker.(*kernelHeadersDecorator); ok { + vendorVariants = append(vendorVariants, + platformVndkVersion, + boardVndkVersion, + ) + } else if isVendorProprietaryModule(mctx) { + vendorVariants = append(vendorVariants, boardVndkVersion) + } else { + vendorVariants = append(vendorVariants, platformVndkVersion) + } + } else { + // This is either in /system (or similar: /data), or is a + // modules built with the NDK. Modules built with the NDK + // will be restricted using the existing link type checks. + coreVariantNeeded = true + } + + if boardVndkVersion != "" && productVndkVersion != "" { + if coreVariantNeeded && productSpecific && String(m.Properties.Sdk_version) == "" { + // The module has "product_specific: true" that does not create core variant. + coreVariantNeeded = false + productVariants = append(productVariants, productVndkVersion) + } + } else { + // Unless PRODUCT_PRODUCT_VNDK_VERSION is set, product partition has no + // restriction to use system libs. + // No product variants defined in this case. + productVariants = []string{} + } + + if Bool(m.Properties.Ramdisk_available) { + ramdiskVariantNeeded = true + } + + if m.ModuleBase.InstallInRamdisk() { + ramdiskVariantNeeded = true + coreVariantNeeded = false + } + + if Bool(m.Properties.Recovery_available) { + recoveryVariantNeeded = true + } + + if m.ModuleBase.InstallInRecovery() { + recoveryVariantNeeded = true + coreVariantNeeded = false + } + + // If using a snapshot, the recovery variant under AOSP directories is not needed, + // except for kernel headers, which needs all variants. + if _, ok := m.linker.(*kernelHeadersDecorator); !ok && + !m.isSnapshotPrebuilt() && + usingRecoverySnapshot && + !isRecoveryProprietaryModule(mctx) { + recoveryVariantNeeded = false + } + if _, ok := m.linker.(*kernelHeadersDecorator); !ok && + !m.isSnapshotPrebuilt() && + usingRamdiskSnapshot && + !isRamdiskProprietaryModule(mctx) { + ramdiskVariantNeeded = false + } + + for _, variant := range android.FirstUniqueStrings(vendorVariants) { + m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, VendorVariationPrefix+variant) + } + + for _, variant := range android.FirstUniqueStrings(productVariants) { + m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, ProductVariationPrefix+variant) + } + + m.Properties.RamdiskVariantNeeded = ramdiskVariantNeeded + m.Properties.RecoveryVariantNeeded = recoveryVariantNeeded + m.Properties.CoreVariantNeeded = coreVariantNeeded + + // Disable the module if no variants are needed. + if !ramdiskVariantNeeded && + !recoveryVariantNeeded && + !coreVariantNeeded && + len(m.Properties.ExtraVariants) == 0 { + m.Disable() + } +} + +func (c *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool { + return c.Properties.CoreVariantNeeded +} + +func (c *Module) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { + return c.Properties.RamdiskVariantNeeded +} + +func (c *Module) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { + return c.Properties.RecoveryVariantNeeded +} + +func (c *Module) ExtraImageVariations(ctx android.BaseModuleContext) []string { + return c.Properties.ExtraVariants +} + +func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) { + m := module.(*Module) + if variant == android.RamdiskVariation { + m.MakeAsPlatform() + } else if variant == android.RecoveryVariation { + m.MakeAsPlatform() + squashRecoverySrcs(m) + } else if strings.HasPrefix(variant, VendorVariationPrefix) { + m.Properties.ImageVariationPrefix = VendorVariationPrefix + m.Properties.VndkVersion = strings.TrimPrefix(variant, VendorVariationPrefix) + squashVendorSrcs(m) + + // Makefile shouldn't know vendor modules other than BOARD_VNDK_VERSION. + // Hide other vendor variants to avoid collision. + vndkVersion := ctx.DeviceConfig().VndkVersion() + if vndkVersion != "current" && vndkVersion != "" && vndkVersion != m.Properties.VndkVersion { + m.Properties.HideFromMake = true + m.SkipInstall() + } + } else if strings.HasPrefix(variant, ProductVariationPrefix) { + m.Properties.ImageVariationPrefix = ProductVariationPrefix + m.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix) + squashVendorSrcs(m) + } +} diff --git a/cc/library.go b/cc/library.go index 3deb17300..147865bd0 100644 --- a/cc/library.go +++ b/cc/library.go @@ -1073,9 +1073,14 @@ func getRefAbiDumpFile(ctx ModuleContext, vndkVersion, fileName string) android. func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) { if library.shouldCreateSourceAbiDump(ctx) { - vndkVersion := ctx.DeviceConfig().PlatformVndkVersion() - if ver := ctx.DeviceConfig().VndkVersion(); ver != "" && ver != "current" { - vndkVersion = ver + var vndkVersion string + + if ctx.useVndk() { + // For modules linking against vndk, follow its vndk version + vndkVersion = ctx.Module().(*Module).VndkVersion() + } else { + // Regard the other modules as PLATFORM_VNDK_VERSION + vndkVersion = ctx.DeviceConfig().PlatformVndkVersion() } exportIncludeDirs := library.flagExporter.exportedIncludes(ctx) @@ -1560,9 +1565,8 @@ func createVersionVariations(mctx android.BottomUpMutatorContext, versions []str func VersionVariantAvailable(module interface { Host() bool InRamdisk() bool - InRecovery() bool }) bool { - return !module.Host() && !module.InRamdisk() && !module.InRecovery() + return !module.Host() && !module.InRamdisk() } // VersionMutator splits a module into the mandatory non-stubs variant diff --git a/cc/llndk_library.go b/cc/llndk_library.go index 7ff20f472..19f5641ae 100644 --- a/cc/llndk_library.go +++ b/cc/llndk_library.go @@ -116,6 +116,7 @@ func (stub *llndkStubDecorator) processHeaders(ctx ModuleContext, srcHeaderDir s srcDir := android.PathForModuleSrc(ctx, srcHeaderDir) srcFiles := ctx.GlobFiles(filepath.Join(srcDir.String(), "**/*.h"), nil) + var depPaths []android.Path var installPaths []android.WritablePath for _, header := range srcFiles { headerDir := filepath.Dir(header.String()) @@ -126,9 +127,14 @@ func (stub *llndkStubDecorator) processHeaders(ctx ModuleContext, srcHeaderDir s continue } - installPaths = append(installPaths, outDir.Join(ctx, relHeaderDir, header.Base())) + outputPath := outDir.Join(ctx, relHeaderDir, header.Base()) + depPaths = append(depPaths, outputPath) + installPaths = append(installPaths, outputPath) } + // Add the processed, exported headers so that they can be collected in + // a snapshot later, if necessary. + stub.addExportedGeneratedHeaders(depPaths...) return processHeadersWithVersioner(ctx, srcDir, outDir, srcFiles, installPaths) } @@ -225,6 +231,8 @@ func (headers *llndkHeadersDecorator) Name(name string) string { func llndkHeadersFactory() android.Module { module, library := NewLibrary(android.DeviceSupported) library.HeaderOnly() + module.stl = nil + module.sanitize = nil decorator := &llndkHeadersDecorator{ libraryDecorator: library, @@ -16,6 +16,8 @@ package cc import ( "android/soong/android" + "android/soong/cc/config" + "strings" ) // LTO (link-time optimization) allows the compiler to optimize and generate @@ -89,7 +91,13 @@ func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags { if lto.LTO() { var ltoFlag string if Bool(lto.Properties.Lto.Thin) { - ltoFlag = "-flto=thin -fsplit-lto-unit" + // TODO(b/129607781) sdclang does not currently support + // the "-fsplit-lto-unit" option + if flags.Sdclang && !strings.Contains(config.SDClangPath, "9.0") { + ltoFlag = "-flto=thin" + } else { + ltoFlag = "-flto=thin -fsplit-lto-unit" + } } else { ltoFlag = "-flto" } diff --git a/cc/makevars.go b/cc/makevars.go index 0f9f4c1e1..3c8c3558d 100644 --- a/cc/makevars.go +++ b/cc/makevars.go @@ -17,6 +17,7 @@ package cc import ( "fmt" "sort" + "strconv" "strings" "sync" @@ -71,6 +72,7 @@ func (c *notOnHostContext) Host() bool { } func makeVarsProvider(ctx android.MakeVarsContext) { + sdclangMakeVars(ctx) vendorPublicLibraries := vendorPublicLibraries(ctx.Config()) ctx.Strict("LLVM_RELEASE_VERSION", "${config.ClangShortVersion}") @@ -100,6 +102,8 @@ func makeVarsProvider(ctx android.MakeVarsContext) { ctx.Strict("NDK_PREBUILT_SHARED_LIBRARIES", strings.Join(ndkPrebuiltSharedLibs, " ")) ctx.Strict("BOARD_VNDK_VERSION", ctx.DeviceConfig().VndkVersion()) + ctx.Strict("RECOVERY_SNAPSHOT_VERSION", ctx.DeviceConfig().RecoverySnapshotVersion()) + ctx.Strict("RAMDISK_SNAPSHOT_VERSION", ctx.DeviceConfig().RamdiskSnapshotVersion()) // Filter vendor_public_library that are exported to make exportedVendorPublicLibraries := []string{} @@ -190,6 +194,17 @@ func makeVarsProvider(ctx android.MakeVarsContext) { } } +func sdclangMakeVars(ctx android.MakeVarsContext) { + if config.ForceSDClangOff { + ctx.Strict("FORCE_SDCLANG_OFF", strconv.FormatBool(config.ForceSDClangOff)) + } + if config.SDClang { + ctx.Strict("SDCLANG", strconv.FormatBool(config.SDClang)) + } + ctx.Strict("SDCLANG_PATH", "${config.SDClangBin}") + ctx.Strict("SDCLANG_COMMON_FLAGS", "${config.SDClangFlags}") +} + func makeVarsToolchain(ctx android.MakeVarsContext, secondPrefix string, target android.Target) { var typePrefix string diff --git a/cc/sanitize.go b/cc/sanitize.go index 463a02ac2..54020e8a5 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -61,9 +61,7 @@ var ( cfiAsflags = []string{"-flto", "-fvisibility=default"} cfiLdflags = []string{"-flto", "-fsanitize-cfi-cross-dso", "-fsanitize=cfi", "-Wl,-plugin-opt,O1"} - cfiExportsMapPath = "build/soong/cc/config/cfi_exports.map" - cfiStaticLibsMutex sync.Mutex - hwasanStaticLibsMutex sync.Mutex + cfiExportsMapPath = "build/soong/cc/config/cfi_exports.map" intOverflowCflags = []string{"-fsanitize-blacklist=build/soong/cc/config/integer_overflow_blacklist.txt"} @@ -303,6 +301,35 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { } } + if s.Integer_overflow == nil && ctx.Config().IntegerOverflowEnabledForPath(ctx.ModuleDir()) && ctx.Arch().ArchType == android.Arm64 { + s.Integer_overflow = boolPtr(true) + } + + if ctx.Config().BoundSanitizerEnabledForPath(ctx.ModuleDir()) && ctx.Arch().ArchType == android.Arm64 { + s.Misc_undefined = append(s.Misc_undefined, "bounds") + } + + if ctx.Config().BoundSanitizerDisabledForPath(ctx.ModuleDir()) && ctx.Arch().ArchType == android.Arm64 { + indx := indexList("bounds", s.Misc_undefined) + if (indexList("bounds", s.Misc_undefined) != -1) { + s.Misc_undefined = append(s.Misc_undefined[0:indx], s.Misc_undefined[indx+1:]...) + } + } + + // Disable integer-overflow in exclude path + if ctx.Config().IntegerOverflowDisabledForPath(ctx.ModuleDir()) && ctx.Arch().ArchType == android.Arm64 { + indx := indexList("signed-integer-overflow", s.Misc_undefined) + if (indexList("signed-integer-overflow", s.Misc_undefined) != -1) { + s.Misc_undefined = append(s.Misc_undefined[0:indx], s.Misc_undefined[indx+1:]...) + } + + indx = indexList("unsigned-integer-overflow", s.Misc_undefined) + if (indexList("unsigned-integer-overflow", s.Misc_undefined) != -1) { + s.Misc_undefined = append(s.Misc_undefined[0:indx], s.Misc_undefined[indx+1:]...) + } + s.Integer_overflow = nil + } + // Enable CFI for all components in the include paths (for Aarch64 only) if s.Cfi == nil && ctx.Config().CFIEnabledForPath(ctx.ModuleDir()) && ctx.Arch().ArchType == android.Arm64 { s.Cfi = boolPtr(true) @@ -310,17 +337,24 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { s.Diag.Cfi = boolPtr(true) } } + // Disable CFI for all component in the exclude path (for Aarch64 only) + if ctx.Config().CFIDisabledForPath(ctx.ModuleDir()) && ctx.Arch().ArchType == android.Arm64 { + s.Cfi = nil + if inList("cfi", ctx.Config().SanitizeDeviceDiag()) { + s.Diag.Cfi = nil + } + } // CFI needs gold linker, and mips toolchain does not have one. if !ctx.Config().EnableCFI() || ctx.Arch().ArchType == android.Mips || ctx.Arch().ArchType == android.Mips64 { - s.Cfi = nil - s.Diag.Cfi = nil + s.Cfi = boolPtr(false) + s.Diag.Cfi = boolPtr(false) } // Also disable CFI for arm32 until b/35157333 is fixed. if ctx.Arch().ArchType == android.Arm { - s.Cfi = nil - s.Diag.Cfi = nil + s.Cfi = boolPtr(false) + s.Diag.Cfi = boolPtr(false) } // HWASan requires AArch64 hardware feature (top-byte-ignore). @@ -335,14 +369,14 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { // Also disable CFI if ASAN is enabled. if Bool(s.Address) || Bool(s.Hwaddress) { - s.Cfi = nil - s.Diag.Cfi = nil + s.Cfi = boolPtr(false) + s.Diag.Cfi = boolPtr(false) } // Disable sanitizers that depend on the UBSan runtime for windows/darwin builds. if !ctx.Os().Linux() { - s.Cfi = nil - s.Diag.Cfi = nil + s.Cfi = boolPtr(false) + s.Diag.Cfi = boolPtr(false) s.Misc_undefined = nil s.Undefined = nil s.All_undefined = nil @@ -351,14 +385,15 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { // Also disable CFI for VNDK variants of components if ctx.isVndk() && ctx.useVndk() { - s.Cfi = nil - s.Diag.Cfi = nil - } - - // Also disable CFI if building against snapshot. - vndkVersion := ctx.DeviceConfig().VndkVersion() - if ctx.useVndk() && vndkVersion != "current" && vndkVersion != "" { - s.Cfi = nil + if ctx.static() { + // Cfi variant for static vndk should be captured as vendor snapshot, + // so don't strictly disable Cfi. + s.Cfi = nil + s.Diag.Cfi = nil + } else { + s.Cfi = boolPtr(false) + s.Diag.Cfi = boolPtr(false) + } } // HWASan ramdisk (which is built from recovery) goes over some bootloader limit. @@ -403,7 +438,7 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { // TODO(b/131771163): CFI transiently depends on LTO, and thus Fuzzer is // mutually incompatible. if Bool(s.Fuzzer) { - s.Cfi = nil + s.Cfi = boolPtr(false) } } @@ -724,27 +759,64 @@ func isSanitizableDependencyTag(tag blueprint.DependencyTag) bool { return ok && t.Library || t == reuseObjTag || t == objDepTag } +// Determines if the current module is a static library going to be captured +// as vendor snapshot. Such modules must create both cfi and non-cfi variants, +// except for ones which explicitly disable cfi. +func needsCfiForVendorSnapshot(mctx android.TopDownMutatorContext) bool { + if isVendorProprietaryModule(mctx) { + return false + } + + c := mctx.Module().(*Module) + + if !c.inVendor() { + return false + } + + if !c.static() { + return false + } + + if c.Prebuilt() != nil { + return false + } + + return c.sanitize != nil && + !Bool(c.sanitize.Properties.Sanitize.Never) && + !c.sanitize.isSanitizerExplicitlyDisabled(cfi) +} + // Propagate sanitizer requirements down from binaries func sanitizerDepsMutator(t sanitizerType) func(android.TopDownMutatorContext) { return func(mctx android.TopDownMutatorContext) { - if c, ok := mctx.Module().(*Module); ok && c.sanitize.isSanitizerEnabled(t) { - mctx.WalkDeps(func(child, parent android.Module) bool { - if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) { - return false - } - if d, ok := child.(*Module); ok && d.sanitize != nil && - !Bool(d.sanitize.Properties.Sanitize.Never) && - !d.sanitize.isSanitizerExplicitlyDisabled(t) { - if t == cfi || t == hwasan || t == scs { - if d.static() { + if c, ok := mctx.Module().(*Module); ok { + enabled := c.sanitize.isSanitizerEnabled(t) + if t == cfi && needsCfiForVendorSnapshot(mctx) { + // We shouldn't change the result of isSanitizerEnabled(cfi) to correctly + // determine defaultVariation in sanitizerMutator below. + // Instead, just mark SanitizeDep to forcefully create cfi variant. + enabled = true + c.sanitize.Properties.SanitizeDep = true + } + if enabled { + mctx.WalkDeps(func(child, parent android.Module) bool { + if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) { + return false + } + if d, ok := child.(*Module); ok && d.sanitize != nil && + !Bool(d.sanitize.Properties.Sanitize.Never) && + !d.sanitize.isSanitizerExplicitlyDisabled(t) { + if t == cfi || t == hwasan || t == scs { + if d.static() { + d.sanitize.Properties.SanitizeDep = true + } + } else { d.sanitize.Properties.SanitizeDep = true } - } else { - d.sanitize.Properties.SanitizeDep = true } - } - return true - }) + return true + }) + } } else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok { // If an APEX module includes a lib which is enabled for a sanitizer T, then // the APEX module is also enabled for the same sanitizer type. @@ -793,7 +865,7 @@ func sanitizerRuntimeDepsMutator(mctx android.TopDownMutatorContext) { return true } - if p, ok := d.linker.(*vendorSnapshotLibraryDecorator); ok { + if p, ok := d.linker.(*snapshotLibraryDecorator); ok { if Bool(p.properties.Sanitize_minimal_dep) { c.sanitize.Properties.MinimalRuntimeDep = true } @@ -1047,15 +1119,9 @@ func sanitizerMutator(t sanitizerType) func(android.BottomUpMutatorContext) { // Export the static lib name to make if c.static() && c.ExportedToMake() { if t == cfi { - appendStringSync(c.Name(), cfiStaticLibs(mctx.Config()), &cfiStaticLibsMutex) + cfiStaticLibs(mctx.Config()).add(c, c.Name()) } else if t == hwasan { - if c.UseVndk() { - appendStringSync(c.Name(), hwasanVendorStaticLibs(mctx.Config()), - &hwasanStaticLibsMutex) - } else { - appendStringSync(c.Name(), hwasanStaticLibs(mctx.Config()), - &hwasanStaticLibsMutex) - } + hwasanStaticLibs(mctx.Config()).add(c, c.Name()) } } } else { @@ -1080,38 +1146,96 @@ func sanitizerMutator(t sanitizerType) func(android.BottomUpMutatorContext) { } else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok && sanitizeable.IsSanitizerEnabled(mctx, t.name()) { // APEX modules fall here mctx.CreateVariations(t.variationName()) + } else if c, ok := mctx.Module().(*Module); ok { + // Check if it's a snapshot module supporting sanitizer + if s, ok := c.linker.(snapshotSanitizer); ok && s.isSanitizerEnabled(t) { + // Set default variation as above. + defaultVariation := t.variationName() + mctx.SetDefaultDependencyVariation(&defaultVariation) + modules := mctx.CreateVariations("", t.variationName()) + modules[0].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, false) + modules[1].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, true) + + // Export the static lib name to make + if c.static() && c.ExportedToMake() { + if t == cfi { + // use BaseModuleName which is the name for Make. + cfiStaticLibs(mctx.Config()).add(c, c.BaseModuleName()) + } + } + } } } } -var cfiStaticLibsKey = android.NewOnceKey("cfiStaticLibs") +type sanitizerStaticLibsMap struct { + // libsMap contains one list of modules per each image and each arch. + // e.g. libs[vendor]["arm"] contains arm modules installed to vendor + libsMap map[imageVariantType]map[string][]string + libsMapLock sync.Mutex + sanitizerType sanitizerType +} -func cfiStaticLibs(config android.Config) *[]string { - return config.Once(cfiStaticLibsKey, func() interface{} { - return &[]string{} - }).(*[]string) +func newSanitizerStaticLibsMap(t sanitizerType) *sanitizerStaticLibsMap { + return &sanitizerStaticLibsMap{ + sanitizerType: t, + libsMap: make(map[imageVariantType]map[string][]string), + } } -var hwasanStaticLibsKey = android.NewOnceKey("hwasanStaticLibs") +// Add the current module to sanitizer static libs maps +// Each module should pass its exported name as names of Make and Soong can differ. +func (s *sanitizerStaticLibsMap) add(c *Module, name string) { + image := c.getImageVariantType() + arch := c.Arch().ArchType.String() -func hwasanStaticLibs(config android.Config) *[]string { - return config.Once(hwasanStaticLibsKey, func() interface{} { - return &[]string{} - }).(*[]string) + s.libsMapLock.Lock() + defer s.libsMapLock.Unlock() + + if _, ok := s.libsMap[image]; !ok { + s.libsMap[image] = make(map[string][]string) + } + + s.libsMap[image][arch] = append(s.libsMap[image][arch], name) +} + +// Exports makefile variables in the following format: +// SOONG_{sanitizer}_{image}_{arch}_STATIC_LIBRARIES +// e.g. SOONG_cfi_core_x86_STATIC_LIBRARIES +// These are to be used by use_soong_sanitized_static_libraries. +// See build/make/core/binary.mk for more details. +func (s *sanitizerStaticLibsMap) exportToMake(ctx android.MakeVarsContext) { + for _, image := range android.SortedStringKeys(s.libsMap) { + archMap := s.libsMap[imageVariantType(image)] + for _, arch := range android.SortedStringKeys(archMap) { + libs := archMap[arch] + sort.Strings(libs) + + key := fmt.Sprintf( + "SOONG_%s_%s_%s_STATIC_LIBRARIES", + s.sanitizerType.variationName(), + image, // already upper + arch) + + ctx.Strict(key, strings.Join(libs, " ")) + } + } } -var hwasanVendorStaticLibsKey = android.NewOnceKey("hwasanVendorStaticLibs") +var cfiStaticLibsKey = android.NewOnceKey("cfiStaticLibs") -func hwasanVendorStaticLibs(config android.Config) *[]string { - return config.Once(hwasanVendorStaticLibsKey, func() interface{} { - return &[]string{} - }).(*[]string) +func cfiStaticLibs(config android.Config) *sanitizerStaticLibsMap { + return config.Once(cfiStaticLibsKey, func() interface{} { + return newSanitizerStaticLibsMap(cfi) + }).(*sanitizerStaticLibsMap) } -func appendStringSync(item string, list *[]string, mutex *sync.Mutex) { - mutex.Lock() - *list = append(*list, item) - mutex.Unlock() +var hwasanStaticLibsKey = android.NewOnceKey("hwasanStaticLibs") + +func hwasanStaticLibs(config android.Config) *sanitizerStaticLibsMap { + return config.Once(hwasanStaticLibsKey, func() interface{} { + return newSanitizerStaticLibsMap(hwasan) + }).(*sanitizerStaticLibsMap) } func enableMinimalRuntime(sanitize *sanitize) bool { @@ -1141,17 +1265,9 @@ func enableUbsanRuntime(sanitize *sanitize) bool { } func cfiMakeVarsProvider(ctx android.MakeVarsContext) { - cfiStaticLibs := cfiStaticLibs(ctx.Config()) - sort.Strings(*cfiStaticLibs) - ctx.Strict("SOONG_CFI_STATIC_LIBRARIES", strings.Join(*cfiStaticLibs, " ")) + cfiStaticLibs(ctx.Config()).exportToMake(ctx) } func hwasanMakeVarsProvider(ctx android.MakeVarsContext) { - hwasanStaticLibs := hwasanStaticLibs(ctx.Config()) - sort.Strings(*hwasanStaticLibs) - ctx.Strict("SOONG_HWASAN_STATIC_LIBRARIES", strings.Join(*hwasanStaticLibs, " ")) - - hwasanVendorStaticLibs := hwasanVendorStaticLibs(ctx.Config()) - sort.Strings(*hwasanVendorStaticLibs) - ctx.Strict("SOONG_HWASAN_VENDOR_STATIC_LIBRARIES", strings.Join(*hwasanVendorStaticLibs, " ")) + hwasanStaticLibs(ctx.Config()).exportToMake(ctx) } diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go new file mode 100644 index 000000000..5989dd8d5 --- /dev/null +++ b/cc/snapshot_prebuilt.go @@ -0,0 +1,1310 @@ +// Copyright 2020 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 cc + +// This file defines snapshot prebuilt modules, e.g. vendor snapshot and recovery snapshot. Such +// snapshot modules will override original source modules with setting BOARD_VNDK_VERSION, with +// snapshot mutators and snapshot information maps which are also defined in this file. + +import ( + "path/filepath" + "strings" + "sync" + + "android/soong/android" + + "github.com/google/blueprint/proptools" +) + +// Defines the specifics of different images to which the snapshot process is applicable, e.g., +// vendor, recovery, ramdisk. +type snapshotImage interface { + // Used to register callbacks with the build system. + init() + + // Returns true if a snapshot should be generated for this image. + shouldGenerateSnapshot(ctx android.SingletonContext) bool + + // Function that returns true if the module is included in this image. + // Using a function return instead of a value to prevent early + // evalution of a function that may be not be defined. + inImage(m *Module) func() bool + + // Returns the value of the "available" property for a given module for + // and snapshot, e.g., "vendor_available", "recovery_available", etc. + // or nil if the property is not defined. + available(m *Module) *bool + + // Returns true if a dir under source tree is an SoC-owned proprietary + // directory, such as device/, vendor/, etc. + // + // For a given snapshot (e.g., vendor, recovery, etc.) if + // isProprietaryPath(dir, deviceConfig) returns true, then the module in dir + // will be built from sources. + isProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool + + // Whether to include VNDK in the snapshot for this image. + includeVndk() bool + + // Whether a given module has been explicitly excluded from the + // snapshot, e.g., using the exclude_from_vendor_snapshot or + // exclude_from_recovery_snapshot properties. + excludeFromSnapshot(m *Module) bool + + // Returns the snapshotMap to be used for a given module and config, or nil if the + // module is not included in this image. + getSnapshotMap(m *Module, cfg android.Config) *snapshotMap + + // Returns mutex used for mutual exclusion when updating the snapshot maps. + getMutex() *sync.Mutex + + // For a given arch, a maps of which modules are included in this image. + suffixModules(config android.Config) map[string]bool + + // Whether to add a given module to the suffix map. + shouldBeAddedToSuffixModules(m *Module) bool + + // Returns true if the build is using a snapshot for this image. + isUsingSnapshot(cfg android.DeviceConfig) bool + + // Whether to skip the module mutator for a module in a given context. + skipModuleMutator(ctx android.BottomUpMutatorContext) bool + + // Whether to skip the source mutator for a given module. + skipSourceMutator(ctx android.BottomUpMutatorContext) bool + + // Whether to exclude a given module from the directed snapshot or not. + // If the makefile variable DIRECTED_{IMAGE}_SNAPSHOT is true, directed snapshot is turned on, + // and only modules listed in {IMAGE}_SNAPSHOT_MODULES will be captured. + excludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool +} + +type vendorSnapshotImage struct{} +type recoverySnapshotImage struct{} +type ramdiskSnapshotImage struct{} + +type directoryMap map[string]bool + +var ( + // Modules under following directories are ignored. They are OEM's and vendor's + // proprietary modules(device/, kernel/, vendor/, and hardware/). + defaultDirectoryExcludedMap = directoryMap{ + "device": true, + "hardware": true, + "kernel": true, + "vendor": true, + // QC specific directories to be ignored + "disregard": true, + } + + // Modules under following directories are included as they are in AOSP, + // although hardware/ and kernel/ are normally for vendor's own. + defaultDirectoryIncludedMap = directoryMap{ + "kernel/configs": true, + "kernel/prebuilts": true, + "kernel/tests": true, + "hardware/interfaces": true, + "hardware/libhardware": true, + "hardware/libhardware_legacy": true, + "hardware/ril": true, + } +) + +func (vendorSnapshotImage) init() { + android.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton) + android.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory) + android.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory) + 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 { + // BOARD_VNDK_VERSION must be set to 'current' in order to generate a snapshot. + return ctx.DeviceConfig().VndkVersion() == "current" +} + +func (vendorSnapshotImage) inImage(m *Module) func() bool { + return m.inVendor +} + +func (vendorSnapshotImage) available(m *Module) *bool { + return m.VendorProperties.Vendor_available +} + +func isDirectoryExcluded(dir string, excludedMap directoryMap, includedMap directoryMap) bool { + if dir == "." || dir == "/" { + return false + } + if includedMap[dir] { + return false + } else if excludedMap[dir] { + return true + } else if defaultDirectoryIncludedMap[dir] { + return false + } else if defaultDirectoryExcludedMap[dir] { + return true + } else { + return isDirectoryExcluded(filepath.Dir(dir), excludedMap, includedMap) + } +} + +func (vendorSnapshotImage) isProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool { + return isDirectoryExcluded(dir, deviceConfig.VendorSnapshotDirsExcludedMap(), deviceConfig.VendorSnapshotDirsIncludedMap()) +} + +// vendor snapshot includes static/header libraries with vndk: {enabled: true}. +func (vendorSnapshotImage) includeVndk() bool { + return true +} + +func (vendorSnapshotImage) excludeFromSnapshot(m *Module) bool { + return m.ExcludeFromVendorSnapshot() +} + +func (vendorSnapshotImage) getSnapshotMap(m *Module, cfg android.Config) *snapshotMap { + if lib, ok := m.linker.(libraryInterface); ok { + if lib.static() { + return vendorSnapshotStaticLibs(cfg) + } else if lib.shared() { + return vendorSnapshotSharedLibs(cfg) + } else { + // header + return vendorSnapshotHeaderLibs(cfg) + } + } else if m.binary() { + return vendorSnapshotBinaries(cfg) + } else if m.object() { + return vendorSnapshotObjects(cfg) + } else { + return nil + } +} + +func (vendorSnapshotImage) getMutex() *sync.Mutex { + return &vendorSnapshotsLock +} + +func (vendorSnapshotImage) suffixModules(config android.Config) map[string]bool { + return vendorSuffixModules(config) +} + +func (vendorSnapshotImage) shouldBeAddedToSuffixModules(module *Module) bool { + // vendor suffix should be added to snapshots if the source module isn't vendor: true. + if module.SocSpecific() { + return false + } + + // But we can't just check SocSpecific() since we already passed the image mutator. + // Check ramdisk and recovery to see if we are real "vendor: true" module. + ramdiskAvailable := module.InRamdisk() && !module.OnlyInRamdisk() + recoveryAvailable := module.InRecovery() && !module.OnlyInRecovery() + + return !ramdiskAvailable && !recoveryAvailable +} + +func (vendorSnapshotImage) isUsingSnapshot(cfg android.DeviceConfig) bool { + vndkVersion := cfg.VndkVersion() + return vndkVersion != "current" && vndkVersion != "" +} + +func (vendorSnapshotImage) skipModuleMutator(ctx android.BottomUpMutatorContext) bool { + vndkVersion := ctx.DeviceConfig().VndkVersion() + module, ok := ctx.Module().(*Module) + return !ok || module.VndkVersion() != vndkVersion +} + +func (vendorSnapshotImage) skipSourceMutator(ctx android.BottomUpMutatorContext) bool { + vndkVersion := ctx.DeviceConfig().VndkVersion() + module, ok := ctx.Module().(*Module) + if !ok { + return true + } + if module.VndkVersion() != vndkVersion { + return true + } + return false +} + +// returns true iff a given module SHOULD BE EXCLUDED, false if included +func (vendorSnapshotImage) excludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool { + // If we're using full snapshot, not directed snapshot, capture every module + if !cfg.DirectedVendorSnapshot() { + return false + } + // Else, checks if name is in VENDOR_SNAPSHOT_MODULES. + return !cfg.VendorSnapshotModules()[name] +} + +func (recoverySnapshotImage) init() { + android.RegisterSingletonType("recovery-snapshot", RecoverySnapshotSingleton) + android.RegisterModuleType("recovery_snapshot_shared", RecoverySnapshotSharedFactory) + android.RegisterModuleType("recovery_snapshot_static", RecoverySnapshotStaticFactory) + android.RegisterModuleType("recovery_snapshot_header", RecoverySnapshotHeaderFactory) + android.RegisterModuleType("recovery_snapshot_binary", RecoverySnapshotBinaryFactory) + android.RegisterModuleType("recovery_snapshot_object", RecoverySnapshotObjectFactory) +} + +func (recoverySnapshotImage) shouldGenerateSnapshot(ctx android.SingletonContext) bool { + // RECOVERY_SNAPSHOT_VERSION must be set to 'current' in order to generate a + // snapshot. + return ctx.DeviceConfig().RecoverySnapshotVersion() == "current" +} + +func (recoverySnapshotImage) inImage(m *Module) func() bool { + return m.InRecovery +} + +func (recoverySnapshotImage) available(m *Module) *bool { + return m.Properties.Recovery_available +} + +func (recoverySnapshotImage) isProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool { + return isDirectoryExcluded(dir, deviceConfig.RecoverySnapshotDirsExcludedMap(), deviceConfig.RecoverySnapshotDirsIncludedMap()) +} + +// recovery snapshot does NOT treat vndk specially. +func (recoverySnapshotImage) includeVndk() bool { + return false +} + +func (recoverySnapshotImage) excludeFromSnapshot(m *Module) bool { + return m.ExcludeFromRecoverySnapshot() +} + +func (recoverySnapshotImage) getSnapshotMap(m *Module, cfg android.Config) *snapshotMap { + if lib, ok := m.linker.(libraryInterface); ok { + if lib.static() { + return recoverySnapshotStaticLibs(cfg) + } else if lib.shared() { + return recoverySnapshotSharedLibs(cfg) + } else { + // header + return recoverySnapshotHeaderLibs(cfg) + } + } else if m.binary() { + return recoverySnapshotBinaries(cfg) + } else if m.object() { + return recoverySnapshotObjects(cfg) + } else { + return nil + } +} + +func (recoverySnapshotImage) getMutex() *sync.Mutex { + return &recoverySnapshotsLock +} + +func (recoverySnapshotImage) suffixModules(config android.Config) map[string]bool { + return recoverySuffixModules(config) +} + +func (recoverySnapshotImage) shouldBeAddedToSuffixModules(module *Module) bool { + return proptools.BoolDefault(module.Properties.Recovery_available, false) +} + +func (recoverySnapshotImage) isUsingSnapshot(cfg android.DeviceConfig) bool { + recoverySnapshotVersion := cfg.RecoverySnapshotVersion() + return recoverySnapshotVersion != "current" && recoverySnapshotVersion != "" +} + +func (recoverySnapshotImage) skipModuleMutator(ctx android.BottomUpMutatorContext) bool { + module, ok := ctx.Module().(*Module) + return !ok || !module.InRecovery() +} + +func (recoverySnapshotImage) skipSourceMutator(ctx android.BottomUpMutatorContext) bool { + module, ok := ctx.Module().(*Module) + return !ok || !module.InRecovery() +} + +func (recoverySnapshotImage) excludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool { + // If we're using full snapshot, not directed snapshot, capture every module + if !cfg.DirectedRecoverySnapshot() { + return false + } + // Else, checks if name is in RECOVERY_SNAPSHOT_MODULES. + return !cfg.RecoverySnapshotModules()[name] +} + +func (ramdiskSnapshotImage) init() { + android.RegisterSingletonType("ramdisk-snapshot", RamdiskSnapshotSingleton) + android.RegisterModuleType("ramdisk_snapshot_shared", RamdiskSnapshotSharedFactory) + android.RegisterModuleType("ramdisk_snapshot_static", RamdiskSnapshotStaticFactory) + android.RegisterModuleType("ramdisk_snapshot_header", RamdiskSnapshotHeaderFactory) + android.RegisterModuleType("ramdisk_snapshot_binary", RamdiskSnapshotBinaryFactory) + android.RegisterModuleType("ramdisk_snapshot_object", RamdiskSnapshotObjectFactory) +} + +func (ramdiskSnapshotImage) shouldGenerateSnapshot(ctx android.SingletonContext) bool { + // RAMDISK_SNAPSHOT_VERSION must be set to 'current' in order to generate a + // snapshot. + return ctx.DeviceConfig().RamdiskSnapshotVersion() == "current" +} + +func (ramdiskSnapshotImage) inImage(m *Module) func() bool { + return m.InRamdisk +} + +func (ramdiskSnapshotImage) available(m *Module) *bool { + return m.Properties.Ramdisk_available +} + +func (ramdiskSnapshotImage) isProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool { + return isDirectoryExcluded(dir, nil, nil) +} + +// ramdisk snapshot does NOT treat vndk specially. +func (ramdiskSnapshotImage) includeVndk() bool { + return false +} + +func (ramdiskSnapshotImage) excludeFromSnapshot(m *Module) bool { + return m.ExcludeFromRamdiskSnapshot() +} + +func (ramdiskSnapshotImage) getSnapshotMap(m *Module, cfg android.Config) *snapshotMap { + if lib, ok := m.linker.(libraryInterface); ok { + if lib.static() { + return ramdiskSnapshotStaticLibs(cfg) + } else if lib.shared() { + return ramdiskSnapshotSharedLibs(cfg) + } else { + // header + return ramdiskSnapshotHeaderLibs(cfg) + } + } else if m.binary() { + return ramdiskSnapshotBinaries(cfg) + } else if m.object() { + return ramdiskSnapshotObjects(cfg) + } else { + return nil + } +} + +func (ramdiskSnapshotImage) getMutex() *sync.Mutex { + return &ramdiskSnapshotsLock +} + +func (ramdiskSnapshotImage) suffixModules(config android.Config) map[string]bool { + return ramdiskSuffixModules(config) +} + +func (ramdiskSnapshotImage) shouldBeAddedToSuffixModules(module *Module) bool { + return proptools.BoolDefault(module.Properties.Ramdisk_available, false) +} + +func (ramdiskSnapshotImage) isUsingSnapshot(cfg android.DeviceConfig) bool { + ramdiskSnapshotVersion := cfg.RamdiskSnapshotVersion() + return ramdiskSnapshotVersion != "current" && ramdiskSnapshotVersion != "" +} + +func (ramdiskSnapshotImage) skipModuleMutator(ctx android.BottomUpMutatorContext) bool { + module, ok := ctx.Module().(*Module) + return !ok || !module.InRamdisk() +} + +func (ramdiskSnapshotImage) skipSourceMutator(ctx android.BottomUpMutatorContext) bool { + module, ok := ctx.Module().(*Module) + return !ok || !module.InRamdisk() +} + +func (ramdiskSnapshotImage) excludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool { + // If we're using full snapshot, not directed snapshot, capture every module + if !cfg.DirectedRamdiskSnapshot() { + return false + } + // Else, checks if name is in RAMDSIK_SNAPSHOT_MODULES. + return !cfg.RamdiskSnapshotModules()[name] +} + +var vendorSnapshotImageSingleton vendorSnapshotImage +var recoverySnapshotImageSingleton recoverySnapshotImage +var ramdiskSnapshotImageSingleton ramdiskSnapshotImage + +func init() { + vendorSnapshotImageSingleton.init() + recoverySnapshotImageSingleton.init() + ramdiskSnapshotImageSingleton.init() +} + +const ( + vendorSnapshotHeaderSuffix = ".vendor_header." + vendorSnapshotSharedSuffix = ".vendor_shared." + vendorSnapshotStaticSuffix = ".vendor_static." + vendorSnapshotBinarySuffix = ".vendor_binary." + vendorSnapshotObjectSuffix = ".vendor_object." +) + +const ( + recoverySnapshotHeaderSuffix = ".recovery_header." + recoverySnapshotSharedSuffix = ".recovery_shared." + recoverySnapshotStaticSuffix = ".recovery_static." + recoverySnapshotBinarySuffix = ".recovery_binary." + recoverySnapshotObjectSuffix = ".recovery_object." +) + +const ( + ramdiskSnapshotHeaderSuffix = ".ramdisk_header." + ramdiskSnapshotSharedSuffix = ".ramdisk_shared." + ramdiskSnapshotStaticSuffix = ".ramdisk_static." + ramdiskSnapshotBinarySuffix = ".ramdisk_binary." + ramdiskSnapshotObjectSuffix = ".ramdisk_object." +) + +var ( + vendorSnapshotsLock sync.Mutex + vendorSuffixModulesKey = android.NewOnceKey("vendorSuffixModules") + vendorSnapshotHeaderLibsKey = android.NewOnceKey("vendorSnapshotHeaderLibs") + vendorSnapshotStaticLibsKey = android.NewOnceKey("vendorSnapshotStaticLibs") + vendorSnapshotSharedLibsKey = android.NewOnceKey("vendorSnapshotSharedLibs") + vendorSnapshotBinariesKey = android.NewOnceKey("vendorSnapshotBinaries") + vendorSnapshotObjectsKey = android.NewOnceKey("vendorSnapshotObjects") +) + +var ( + recoverySnapshotsLock sync.Mutex + recoverySuffixModulesKey = android.NewOnceKey("recoverySuffixModules") + recoverySnapshotHeaderLibsKey = android.NewOnceKey("recoverySnapshotHeaderLibs") + recoverySnapshotStaticLibsKey = android.NewOnceKey("recoverySnapshotStaticLibs") + recoverySnapshotSharedLibsKey = android.NewOnceKey("recoverySnapshotSharedLibs") + recoverySnapshotBinariesKey = android.NewOnceKey("recoverySnapshotBinaries") + recoverySnapshotObjectsKey = android.NewOnceKey("recoverySnapshotObjects") +) +var ( + ramdiskSnapshotsLock sync.Mutex + ramdiskSuffixModulesKey = android.NewOnceKey("ramdiskSuffixModules") + ramdiskSnapshotHeaderLibsKey = android.NewOnceKey("ramdiskSnapshotHeaderLibs") + ramdiskSnapshotStaticLibsKey = android.NewOnceKey("ramdiskSnapshotStaticLibs") + ramdiskSnapshotSharedLibsKey = android.NewOnceKey("ramdiskSnapshotSharedLibs") + ramdiskSnapshotBinariesKey = android.NewOnceKey("ramdiskSnapshotBinaries") + ramdiskSnapshotObjectsKey = android.NewOnceKey("ramdiskSnapshotObjects") +) + +// vendorSuffixModules holds names of modules whose vendor variants should have the vendor suffix. +// This is determined by source modules, and then this will be used when exporting snapshot modules +// to Makefile. +// +// For example, if libbase has "vendor_available: true", the name of core variant will be "libbase" +// while the name of vendor variant will be "libbase.vendor". In such cases, the vendor snapshot of +// "libbase" should be exported with the name "libbase.vendor". +// +// Refer to VendorSnapshotSourceMutator and makeLibName which use this. +func vendorSuffixModules(config android.Config) map[string]bool { + return config.Once(vendorSuffixModulesKey, func() interface{} { + return make(map[string]bool) + }).(map[string]bool) +} + +// these are vendor snapshot maps holding names of vendor snapshot modules +func vendorSnapshotHeaderLibs(config android.Config) *snapshotMap { + return config.Once(vendorSnapshotHeaderLibsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func vendorSnapshotSharedLibs(config android.Config) *snapshotMap { + return config.Once(vendorSnapshotSharedLibsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func vendorSnapshotStaticLibs(config android.Config) *snapshotMap { + return config.Once(vendorSnapshotStaticLibsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func vendorSnapshotBinaries(config android.Config) *snapshotMap { + return config.Once(vendorSnapshotBinariesKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func vendorSnapshotObjects(config android.Config) *snapshotMap { + return config.Once(vendorSnapshotObjectsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func recoverySuffixModules(config android.Config) map[string]bool { + return config.Once(recoverySuffixModulesKey, func() interface{} { + return make(map[string]bool) + }).(map[string]bool) +} + +func recoverySnapshotHeaderLibs(config android.Config) *snapshotMap { + return config.Once(recoverySnapshotHeaderLibsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func recoverySnapshotSharedLibs(config android.Config) *snapshotMap { + return config.Once(recoverySnapshotSharedLibsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func recoverySnapshotStaticLibs(config android.Config) *snapshotMap { + return config.Once(recoverySnapshotStaticLibsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func recoverySnapshotBinaries(config android.Config) *snapshotMap { + return config.Once(recoverySnapshotBinariesKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func recoverySnapshotObjects(config android.Config) *snapshotMap { + return config.Once(recoverySnapshotObjectsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func ramdiskSuffixModules(config android.Config) map[string]bool { + return config.Once(ramdiskSuffixModulesKey, func() interface{} { + return make(map[string]bool) + }).(map[string]bool) +} + +func ramdiskSnapshotHeaderLibs(config android.Config) *snapshotMap { + return config.Once(ramdiskSnapshotHeaderLibsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func ramdiskSnapshotSharedLibs(config android.Config) *snapshotMap { + return config.Once(ramdiskSnapshotSharedLibsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func ramdiskSnapshotStaticLibs(config android.Config) *snapshotMap { + return config.Once(ramdiskSnapshotStaticLibsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func ramdiskSnapshotBinaries(config android.Config) *snapshotMap { + return config.Once(ramdiskSnapshotBinariesKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func ramdiskSnapshotObjects(config android.Config) *snapshotMap { + return config.Once(ramdiskSnapshotObjectsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +type baseSnapshotDecoratorProperties struct { + // snapshot version. + Version string + + // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64') + Target_arch string + + // Suffix to be added to the module name, e.g., vendor_shared, + // recovery_shared, etc. + Module_suffix string +} + +// baseSnapshotDecorator provides common basic functions for all snapshot modules, such as snapshot +// version, snapshot arch, etc. It also adds a special suffix to Soong module name, so it doesn't +// collide with source modules. e.g. the following example module, +// +// vendor_snapshot_static { +// name: "libbase", +// arch: "arm64", +// version: 30, +// ... +// } +// +// will be seen as "libbase.vendor_static.30.arm64" by Soong. +type baseSnapshotDecorator struct { + baseProperties baseSnapshotDecoratorProperties +} + +func (p *baseSnapshotDecorator) Name(name string) string { + return name + p.NameSuffix() +} + +func (p *baseSnapshotDecorator) NameSuffix() string { + versionSuffix := p.version() + if p.arch() != "" { + versionSuffix += "." + p.arch() + } + + return p.baseProperties.Module_suffix + versionSuffix +} + +func (p *baseSnapshotDecorator) version() string { + return p.baseProperties.Version +} + +func (p *baseSnapshotDecorator) arch() string { + return p.baseProperties.Target_arch +} + +func (p *baseSnapshotDecorator) module_suffix() string { + return p.baseProperties.Module_suffix +} + +func (p *baseSnapshotDecorator) isSnapshotPrebuilt() bool { + return true +} + +// Call this with a module suffix after creating a snapshot module, such as +// vendorSnapshotSharedSuffix, recoverySnapshotBinarySuffix, etc. +func (p *baseSnapshotDecorator) init(m *Module, suffix string) { + p.baseProperties.Module_suffix = suffix + m.AddProperties(&p.baseProperties) + android.AddLoadHook(m, func(ctx android.LoadHookContext) { + vendorSnapshotLoadHook(ctx, p) + }) +} + +// vendorSnapshotLoadHook disables snapshots if it's not BOARD_VNDK_VERSION. +// As vendor snapshot is only for vendor, such modules won't be used at all. +func vendorSnapshotLoadHook(ctx android.LoadHookContext, p *baseSnapshotDecorator) { + if p.version() != ctx.DeviceConfig().VndkVersion() { + ctx.Module().Disable() + return + } +} + +// +// Module definitions for snapshots of libraries (shared, static, header). +// +// Modules (vendor|recovery)_snapshot_(shared|static|header) are defined here. Shared libraries and +// static libraries have their prebuilt library files (.so for shared, .a for static) as their src, +// which can be installed or linked against. Also they export flags needed when linked, such as +// include directories, c flags, sanitize dependency information, etc. +// +// These modules are auto-generated by development/vendor_snapshot/update.py. +type snapshotLibraryProperties struct { + // Prebuilt file for each arch. + Src *string `android:"arch_variant"` + + // list of directories that will be added to the include path (using -I). + Export_include_dirs []string `android:"arch_variant"` + + // list of directories that will be added to the system path (using -isystem). + Export_system_include_dirs []string `android:"arch_variant"` + + // list of flags that will be used for any module that links against this module. + Export_flags []string `android:"arch_variant"` + + // Whether this prebuilt needs to depend on sanitize ubsan runtime or not. + Sanitize_ubsan_dep *bool `android:"arch_variant"` + + // Whether this prebuilt needs to depend on sanitize minimal runtime or not. + Sanitize_minimal_dep *bool `android:"arch_variant"` + + // TODO(b/181815415) remove Is_llndk when possible + // Whether this prebuilt is a snapshot of an llndk library. + Is_llndk *bool +} + +type snapshotSanitizer interface { + isSanitizerEnabled(t sanitizerType) bool + setSanitizerVariation(t sanitizerType, enabled bool) +} + +type snapshotLibraryDecorator struct { + baseSnapshotDecorator + *libraryDecorator + properties snapshotLibraryProperties + sanitizerProperties struct { + CfiEnabled bool `blueprint:"mutated"` + + // Library flags for cfi variant. + Cfi snapshotLibraryProperties `android:"arch_variant"` + } + androidMkSuffix string +} + +func (p *snapshotLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { + p.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), p.NameSuffix()) + return p.libraryDecorator.linkerFlags(ctx, flags) +} + +func (p *snapshotLibraryDecorator) matchesWithDevice(config android.DeviceConfig) bool { + arches := config.Arches() + if len(arches) == 0 || arches[0].ArchType.String() != p.arch() { + return false + } + if !p.header() && p.properties.Src == nil { + return false + } + return true +} + +// cc modules' link functions are to link compiled objects into final binaries. +// As snapshots are prebuilts, this just returns the prebuilt binary after doing things which are +// done by normal library decorator, e.g. exporting flags. +func (p *snapshotLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { + m := ctx.Module().(*Module) + + if m.inVendor() && vendorSuffixModules(ctx.Config())[m.BaseModuleName()] { + p.androidMkSuffix = vendorSuffix + } else if m.InRecovery() && recoverySuffixModules(ctx.Config())[m.BaseModuleName()] { + p.androidMkSuffix = recoverySuffix + } else if m.InRamdisk() && ramdiskSuffixModules(ctx.Config())[m.BaseModuleName()] { + p.androidMkSuffix = ramdiskSuffix + } + if p.header() { + return p.libraryDecorator.link(ctx, flags, deps, objs) + } + + if p.sanitizerProperties.CfiEnabled { + p.properties = p.sanitizerProperties.Cfi + } + + if !p.matchesWithDevice(ctx.DeviceConfig()) { + return nil + } + + p.libraryDecorator.reexportDirs(android.PathsForModuleSrc(ctx, p.properties.Export_include_dirs)...) + p.libraryDecorator.reexportSystemDirs(android.PathsForModuleSrc(ctx, p.properties.Export_system_include_dirs)...) + p.libraryDecorator.reexportFlags(p.properties.Export_flags...) + + in := android.PathForModuleSrc(ctx, *p.properties.Src) + p.unstrippedOutputFile = in + + if p.shared() { + libName := in.Base() + builderFlags := flagsToBuilderFlags(flags) + + // Optimize out relinking against shared libraries whose interface hasn't changed by + // depending on a table of contents file instead of the library itself. + tocFile := android.PathForModuleOut(ctx, libName+".toc") + p.tocFile = android.OptionalPathForPath(tocFile) + TransformSharedObjectToToc(ctx, in, tocFile, builderFlags) + } + + return in +} + +func (p *snapshotLibraryDecorator) install(ctx ModuleContext, file android.Path) { + if p.matchesWithDevice(ctx.DeviceConfig()) && (p.shared() || p.static()) { + p.baseInstaller.install(ctx, file) + } +} + +func (p *snapshotLibraryDecorator) nativeCoverage() bool { + return false +} + +func (p *snapshotLibraryDecorator) isSanitizerEnabled(t sanitizerType) bool { + switch t { + case cfi: + return p.sanitizerProperties.Cfi.Src != nil + default: + return false + } +} + +func (p *snapshotLibraryDecorator) setSanitizerVariation(t sanitizerType, enabled bool) { + if !enabled { + return + } + switch t { + case cfi: + p.sanitizerProperties.CfiEnabled = true + default: + return + } +} + +// TODO(b/181815415) remove isLlndk() when possible +func (p *snapshotLibraryDecorator) isLlndk() bool { + return Bool(p.properties.Is_llndk) +} + +func snapshotLibraryFactory(suffix string) (*Module, *snapshotLibraryDecorator) { + module, library := NewLibrary(android.DeviceSupported) + + module.stl = nil + module.sanitize = nil + library.StripProperties.Strip.None = BoolPtr(true) + + prebuilt := &snapshotLibraryDecorator{ + libraryDecorator: library, + } + + prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true) + prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true) + + // Prevent default system libs (libc, libm, and libdl) from being linked + if prebuilt.baseLinker.Properties.System_shared_libs == nil { + prebuilt.baseLinker.Properties.System_shared_libs = []string{} + } + + module.compiler = nil + module.linker = prebuilt + module.installer = prebuilt + + prebuilt.init(module, suffix) + module.AddProperties( + &prebuilt.properties, + &prebuilt.sanitizerProperties, + ) + + return module, prebuilt +} + +// vendor_snapshot_shared is a special prebuilt shared library which is auto-generated by +// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_shared +// overrides the vendor variant of the cc shared library with the same name, if BOARD_VNDK_VERSION +// is set. +func VendorSnapshotSharedFactory() android.Module { + module, prebuilt := snapshotLibraryFactory(vendorSnapshotSharedSuffix) + prebuilt.libraryDecorator.BuildOnlyShared() + return module.Init() +} + +// recovery_snapshot_shared is a special prebuilt shared library which is auto-generated by +// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_shared +// overrides the recovery variant of the cc shared library with the same name, if BOARD_VNDK_VERSION +// is set. +func RecoverySnapshotSharedFactory() android.Module { + module, prebuilt := snapshotLibraryFactory(recoverySnapshotSharedSuffix) + prebuilt.libraryDecorator.BuildOnlyShared() + return module.Init() +} + +// ramdisk_snapshot_shared is a special prebuilt shared library which is auto-generated by +// development/vendor_snapshot/update.py. As a part of ramdisk snapshot, ramdisk_snapshot_shared +// overrides the ramdisk variant of the cc shared library with the same name, if BOARD_VNDK_VERSION +// is set. +func RamdiskSnapshotSharedFactory() android.Module { + module, prebuilt := snapshotLibraryFactory(ramdiskSnapshotSharedSuffix) + prebuilt.libraryDecorator.BuildOnlyShared() + return module.Init() +} + +// vendor_snapshot_static is a special prebuilt static library which is auto-generated by +// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_static +// overrides the vendor variant of the cc static library with the same name, if BOARD_VNDK_VERSION +// is set. +func VendorSnapshotStaticFactory() android.Module { + module, prebuilt := snapshotLibraryFactory(vendorSnapshotStaticSuffix) + prebuilt.libraryDecorator.BuildOnlyStatic() + return module.Init() +} + +// recovery_snapshot_static is a special prebuilt static library which is auto-generated by +// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_static +// overrides the recovery variant of the cc static library with the same name, if BOARD_VNDK_VERSION +// is set. +func RecoverySnapshotStaticFactory() android.Module { + module, prebuilt := snapshotLibraryFactory(recoverySnapshotStaticSuffix) + prebuilt.libraryDecorator.BuildOnlyStatic() + return module.Init() +} + +// ramdisk_snapshot_static is a special prebuilt static library which is auto-generated by +// development/vendor_snapshot/update.py. As a part of ramdisk snapshot, ramdisk_snapshot_static +// overrides the ramdisk variant of the cc static library with the same name, if BOARD_VNDK_VERSION +// is set. +func RamdiskSnapshotStaticFactory() android.Module { + module, prebuilt := snapshotLibraryFactory(ramdiskSnapshotStaticSuffix) + prebuilt.libraryDecorator.BuildOnlyStatic() + return module.Init() +} + +// vendor_snapshot_header is a special header library which is auto-generated by +// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_header +// overrides the vendor variant of the cc header library with the same name, if BOARD_VNDK_VERSION +// is set. +func VendorSnapshotHeaderFactory() android.Module { + module, prebuilt := snapshotLibraryFactory(vendorSnapshotHeaderSuffix) + prebuilt.libraryDecorator.HeaderOnly() + return module.Init() +} + +// recovery_snapshot_header is a special header library which is auto-generated by +// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_header +// overrides the recovery variant of the cc header library with the same name, if BOARD_VNDK_VERSION +// is set. +func RecoverySnapshotHeaderFactory() android.Module { + module, prebuilt := snapshotLibraryFactory(recoverySnapshotHeaderSuffix) + prebuilt.libraryDecorator.HeaderOnly() + return module.Init() +} + +// ramdisk_snapshot_header is a special header library which is auto-generated by +// development/vendor_snapshot/update.py. As a part of ramdisk snapshot, ramdisk_snapshot_header +// overrides the ramdisk variant of the cc header library with the same name, if BOARD_VNDK_VERSION +// is set. +func RamdiskSnapshotHeaderFactory() android.Module { + module, prebuilt := snapshotLibraryFactory(ramdiskSnapshotHeaderSuffix) + prebuilt.libraryDecorator.HeaderOnly() + return module.Init() +} + +var _ snapshotSanitizer = (*snapshotLibraryDecorator)(nil) + +// +// Module definitions for snapshots of executable binaries. +// +// Modules (vendor|recovery)_snapshot_binary are defined here. They have their prebuilt executable +// binaries (e.g. toybox, sh) as their src, which can be installed. +// +// These modules are auto-generated by development/vendor_snapshot/update.py. +type snapshotBinaryProperties struct { + // Prebuilt file for each arch. + Src *string `android:"arch_variant"` +} + +type snapshotBinaryDecorator struct { + baseSnapshotDecorator + *binaryDecorator + properties snapshotBinaryProperties + androidMkSuffix string +} + +func (p *snapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) bool { + if config.DeviceArch() != p.arch() { + return false + } + if p.properties.Src == nil { + return false + } + return true +} + +// cc modules' link functions are to link compiled objects into final binaries. +// As snapshots are prebuilts, this just returns the prebuilt binary +func (p *snapshotBinaryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { + if !p.matchesWithDevice(ctx.DeviceConfig()) { + return nil + } + + in := android.PathForModuleSrc(ctx, *p.properties.Src) + p.unstrippedOutputFile = in + binName := in.Base() + + m := ctx.Module().(*Module) + if m.inVendor() && vendorSuffixModules(ctx.Config())[m.BaseModuleName()] { + p.androidMkSuffix = vendorSuffix + } else if m.InRecovery() && recoverySuffixModules(ctx.Config())[m.BaseModuleName()] { + p.androidMkSuffix = recoverySuffix + } else if m.InRamdisk() && ramdiskSuffixModules(ctx.Config())[m.BaseModuleName()] { + p.androidMkSuffix = ramdiskSuffix + + } + + // use cpExecutable to make it executable + outputFile := android.PathForModuleOut(ctx, binName) + ctx.Build(pctx, android.BuildParams{ + Rule: android.CpExecutable, + Description: "prebuilt", + Output: outputFile, + Input: in, + }) + + return outputFile +} + +func (p *snapshotBinaryDecorator) nativeCoverage() bool { + return false +} + +// vendor_snapshot_binary is a special prebuilt executable binary which is auto-generated by +// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_binary +// overrides the vendor variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set. +func VendorSnapshotBinaryFactory() android.Module { + return snapshotBinaryFactory(vendorSnapshotBinarySuffix) +} + +// recovery_snapshot_binary is a special prebuilt executable binary which is auto-generated by +// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_binary +// overrides the recovery variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set. +func RecoverySnapshotBinaryFactory() android.Module { + return snapshotBinaryFactory(recoverySnapshotBinarySuffix) +} + +// ramdisk_snapshot_binary is a special prebuilt executable binary which is auto-generated by +// development/vendor_snapshot/update.py. As a part of ramdisk snapshot, ramdisk_snapshot_binary +// overrides the ramdisk variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set. +func RamdiskSnapshotBinaryFactory() android.Module { + return snapshotBinaryFactory(ramdiskSnapshotBinarySuffix) +} + +func snapshotBinaryFactory(suffix string) android.Module { + module, binary := NewBinary(android.DeviceSupported) + binary.baseLinker.Properties.No_libcrt = BoolPtr(true) + binary.baseLinker.Properties.Nocrt = BoolPtr(true) + + // Prevent default system libs (libc, libm, and libdl) from being linked + if binary.baseLinker.Properties.System_shared_libs == nil { + binary.baseLinker.Properties.System_shared_libs = []string{} + } + + prebuilt := &snapshotBinaryDecorator{ + binaryDecorator: binary, + } + + module.compiler = nil + module.sanitize = nil + module.stl = nil + module.linker = prebuilt + + prebuilt.init(module, suffix) + module.AddProperties(&prebuilt.properties) + return module.Init() +} + +// +// Module definitions for snapshots of object files (*.o). +// +// Modules (vendor|recovery)_snapshot_object are defined here. They have their prebuilt object +// files (*.o) as their src. +// +// These modules are auto-generated by development/vendor_snapshot/update.py. +type vendorSnapshotObjectProperties struct { + // Prebuilt file for each arch. + Src *string `android:"arch_variant"` +} + +type snapshotObjectLinker struct { + baseSnapshotDecorator + objectLinker + properties vendorSnapshotObjectProperties + androidMkSuffix string +} + +func (p *snapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bool { + if config.DeviceArch() != p.arch() { + return false + } + if p.properties.Src == nil { + return false + } + return true +} + +// cc modules' link functions are to link compiled objects into final binaries. +// As snapshots are prebuilts, this just returns the prebuilt binary +func (p *snapshotObjectLinker) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { + if !p.matchesWithDevice(ctx.DeviceConfig()) { + return nil + } + + m := ctx.Module().(*Module) + + if m.inVendor() && vendorSuffixModules(ctx.Config())[m.BaseModuleName()] { + p.androidMkSuffix = vendorSuffix + } else if m.InRecovery() && recoverySuffixModules(ctx.Config())[m.BaseModuleName()] { + p.androidMkSuffix = recoverySuffix + } else if m.InRamdisk() && ramdiskSuffixModules(ctx.Config())[m.BaseModuleName()] { + p.androidMkSuffix = ramdiskSuffix + } + + return android.PathForModuleSrc(ctx, *p.properties.Src) +} + +func (p *snapshotObjectLinker) nativeCoverage() bool { + return false +} + +// vendor_snapshot_object is a special prebuilt compiled object file which is auto-generated by +// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_object +// overrides the vendor variant of the cc object with the same name, if BOARD_VNDK_VERSION is set. +func VendorSnapshotObjectFactory() android.Module { + module := newObject() + + prebuilt := &snapshotObjectLinker{ + objectLinker: objectLinker{ + baseLinker: NewBaseLinker(nil), + }, + } + module.linker = prebuilt + + prebuilt.init(module, vendorSnapshotObjectSuffix) + module.AddProperties(&prebuilt.properties) + return module.Init() +} + +// recovery_snapshot_object is a special prebuilt compiled object file which is auto-generated by +// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_object +// overrides the recovery variant of the cc object with the same name, if BOARD_VNDK_VERSION is set. +func RecoverySnapshotObjectFactory() android.Module { + module := newObject() + + prebuilt := &snapshotObjectLinker{ + objectLinker: objectLinker{ + baseLinker: NewBaseLinker(nil), + }, + } + module.linker = prebuilt + + prebuilt.init(module, recoverySnapshotObjectSuffix) + module.AddProperties(&prebuilt.properties) + return module.Init() +} + +// ramdisk_snapshot_object is a special prebuilt compiled object file which is auto-generated by +// development/vendor_snapshot/update.py. As a part of ramdisk snapshot, ramdisk_snapshot_object +// overrides the recovery variant of the cc object with the same name, if BOARD_VNDK_VERSION is set. +func RamdiskSnapshotObjectFactory() android.Module { + module := newObject() + + prebuilt := &snapshotObjectLinker{ + objectLinker: objectLinker{ + baseLinker: NewBaseLinker(nil), + }, + } + module.linker = prebuilt + + prebuilt.init(module, ramdiskSnapshotObjectSuffix) + module.AddProperties(&prebuilt.properties) + return module.Init() +} + +type snapshotInterface interface { + matchesWithDevice(config android.DeviceConfig) bool +} + +var _ snapshotInterface = (*vndkPrebuiltLibraryDecorator)(nil) +var _ snapshotInterface = (*snapshotLibraryDecorator)(nil) +var _ snapshotInterface = (*snapshotBinaryDecorator)(nil) +var _ snapshotInterface = (*snapshotObjectLinker)(nil) + +// +// Mutators that helps vendor snapshot modules override source modules. +// + +// VendorSnapshotMutator gathers all snapshots for vendor, and disable all snapshots which don't +// match with device, e.g. +// - snapshot version is different with BOARD_VNDK_VERSION +// - snapshot arch is different with device's arch (e.g. arm vs x86) +// +// This also handles vndk_prebuilt_shared, except for they won't be disabled in any cases, given +// that any versions of VNDK might be packed into vndk APEX. +// +// TODO(b/145966707): remove mutator and utilize android.Prebuilt to override source modules +func VendorSnapshotMutator(ctx android.BottomUpMutatorContext) { + snapshotMutator(ctx, vendorSnapshotImageSingleton) +} + +func RecoverySnapshotMutator(ctx android.BottomUpMutatorContext) { + snapshotMutator(ctx, recoverySnapshotImageSingleton) +} + +func RamdiskSnapshotMutator(ctx android.BottomUpMutatorContext) { + snapshotMutator(ctx, ramdiskSnapshotImageSingleton) +} + +func snapshotMutator(ctx android.BottomUpMutatorContext, image snapshotImage) { + if !image.isUsingSnapshot(ctx.DeviceConfig()) { + return + } + module, ok := ctx.Module().(*Module) + if !ok || !module.Enabled() { + return + } + if image.skipModuleMutator(ctx) { + return + } + if !module.isSnapshotPrebuilt() { + return + } + + // isSnapshotPrebuilt ensures snapshotInterface + if !module.linker.(snapshotInterface).matchesWithDevice(ctx.DeviceConfig()) { + // Disable unnecessary snapshot module, but do not disable + // vndk_prebuilt_shared because they might be packed into vndk APEX + if !module.IsVndk() { + module.Disable() + } + return + } + + var snapshotMap *snapshotMap = image.getSnapshotMap(module, ctx.Config()) + if snapshotMap == nil { + return + } + + mutex := image.getMutex() + mutex.Lock() + defer mutex.Unlock() + snapshotMap.add(module.BaseModuleName(), ctx.Arch().ArchType, ctx.ModuleName()) +} + +// VendorSnapshotSourceMutator disables source modules which have corresponding snapshots. +func VendorSnapshotSourceMutator(ctx android.BottomUpMutatorContext) { + snapshotSourceMutator(ctx, vendorSnapshotImageSingleton) +} + +func RecoverySnapshotSourceMutator(ctx android.BottomUpMutatorContext) { + snapshotSourceMutator(ctx, recoverySnapshotImageSingleton) +} +func RamdiskSnapshotSourceMutator(ctx android.BottomUpMutatorContext) { + snapshotSourceMutator(ctx, ramdiskSnapshotImageSingleton) +} + +func snapshotSourceMutator(ctx android.BottomUpMutatorContext, image snapshotImage) { + if !ctx.Device() { + return + } + if !image.isUsingSnapshot(ctx.DeviceConfig()) { + return + } + + module, ok := ctx.Module().(*Module) + if !ok { + return + } + + if image.shouldBeAddedToSuffixModules(module) { + mutex := image.getMutex() + mutex.Lock() + defer mutex.Unlock() + + image.suffixModules(ctx.Config())[ctx.ModuleName()] = true + } + + if module.isSnapshotPrebuilt() { + return + } + if image.skipSourceMutator(ctx) { + return + } + + var snapshotMap *snapshotMap = image.getSnapshotMap(module, ctx.Config()) + if snapshotMap == nil { + return + } + + if _, ok := snapshotMap.get(ctx.ModuleName(), ctx.Arch().ArchType); !ok { + // Corresponding snapshot doesn't exist + return + } + + // Disables source modules if corresponding snapshot exists. + if lib, ok := module.linker.(libraryInterface); ok && lib.buildStatic() && lib.buildShared() { + // But do not disable because the shared variant depends on the static variant. + module.SkipInstall() + module.Properties.HideFromMake = true + } else { + module.Disable() + } +} diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go index 26e7c8d13..2739a7828 100644 --- a/cc/snapshot_utils.go +++ b/cc/snapshot_utils.go @@ -58,38 +58,22 @@ func (s *snapshotMap) get(name string, arch android.ArchType) (snapshot string, return snapshot, found } -func isSnapshotAware(ctx android.ModuleContext, m *Module) bool { +// shouldCollectHeadersForSnapshot determines if the module is a possible candidate for snapshot. +// If it's true, collectHeadersForSnapshot will be called in GenerateAndroidBuildActions. +func shouldCollectHeadersForSnapshot(ctx android.ModuleContext, m *Module) bool { + if ctx.DeviceConfig().VndkVersion() != "current" && + ctx.DeviceConfig().RecoverySnapshotVersion() != "current" && + ctx.DeviceConfig().RamdiskSnapshotVersion() != "current" { + return false + } if _, _, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m); ok { return ctx.Config().VndkSnapshotBuildArtifacts() - } else if isVendorSnapshotModule(m, ctx.ModuleDir()) { - return true + } + for _, image := range []snapshotImage{vendorSnapshotImageSingleton, recoverySnapshotImageSingleton, + ramdiskSnapshotImageSingleton } { + if isSnapshotAware(ctx.DeviceConfig(), m, image.isProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()), image) { + return true + } } return false } - -func copyFile(ctx android.SingletonContext, path android.Path, out string) android.OutputPath { - outPath := android.PathForOutput(ctx, out) - ctx.Build(pctx, android.BuildParams{ - Rule: android.Cp, - Input: path, - Output: outPath, - Description: "Cp " + out, - Args: map[string]string{ - "cpFlags": "-f -L", - }, - }) - return outPath -} - -func writeStringToFile(ctx android.SingletonContext, content, out string) android.OutputPath { - outPath := android.PathForOutput(ctx, out) - ctx.Build(pctx, android.BuildParams{ - Rule: android.WriteFile, - Output: outPath, - Description: "WriteFile " + out, - Args: map[string]string{ - "content": content, - }, - }) - return outPath -} diff --git a/cc/testing.go b/cc/testing.go index 7a86a8d28..a8c494b49 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -16,6 +16,7 @@ package cc import ( "android/soong/android" + "android/soong/genrule" ) func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) { @@ -32,6 +33,7 @@ func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) { ctx.RegisterModuleType("cc_object", ObjectFactory) ctx.RegisterModuleType("ndk_prebuilt_shared_stl", NdkPrebuiltSharedStlFactory) ctx.RegisterModuleType("ndk_prebuilt_object", NdkPrebuiltObjectFactory) + ctx.RegisterModuleType("genrule", genrule.GenRuleFactory) } func GatherRequiredDepsForTest(oses ...android.OsType) string { @@ -464,10 +466,14 @@ func CreateTestContext() *android.TestContext { ctx.RegisterModuleType("filegroup", android.FileGroupFactory) ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory) ctx.RegisterModuleType("vndk_libraries_txt", VndkLibrariesTxtFactory) + ctx.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory) ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) RegisterRequiredBuildComponentsForTest(ctx) ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton) ctx.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton) + ctx.RegisterSingletonType("vendor-fake-snapshot", VendorFakeSnapshotSingleton) + ctx.RegisterSingletonType("recovery-snapshot", RecoverySnapshotSingleton) + ctx.RegisterSingletonType("ramdisk-snapshot", RamdiskSnapshotSingleton) return ctx } diff --git a/cc/util.go b/cc/util.go index af26268e2..ce29a08af 100644 --- a/cc/util.go +++ b/cc/util.go @@ -82,6 +82,7 @@ func flagsToBuilderFlags(in Flags) builderFlags { tidyFlags: strings.Join(in.TidyFlags, " "), sAbiFlags: strings.Join(in.SAbiFlags, " "), toolchain: in.Toolchain, + sdclang: in.Sdclang, gcovCoverage: in.GcovCoverage, tidy: in.Tidy, sAbiDump: in.SAbiDump, @@ -120,3 +121,41 @@ func makeSymlinkCmd(linkDirOnDevice string, linkName string, target string) stri return "mkdir -p " + dir + " && " + "ln -sf " + target + " " + filepath.Join(dir, linkName) } + +func copyFileRule(ctx android.SingletonContext, path android.Path, out string) android.OutputPath { + outPath := android.PathForOutput(ctx, out) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: path, + Output: outPath, + Description: "Cp " + out, + Args: map[string]string{ + "cpFlags": "-f -L", + }, + }) + return outPath +} + +func combineNoticesRule(ctx android.SingletonContext, paths android.Paths, out string) android.OutputPath { + outPath := android.PathForOutput(ctx, out) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cat, + Inputs: paths, + Output: outPath, + Description: "combine notices for " + out, + }) + return outPath +} + +func writeStringToFileRule(ctx android.SingletonContext, content, out string) android.OutputPath { + outPath := android.PathForOutput(ctx, out) + ctx.Build(pctx, android.BuildParams{ + Rule: android.WriteFile, + Output: outPath, + Description: "WriteFile " + out, + Args: map[string]string{ + "content": content, + }, + }) + return outPath +} diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go index b11b1a82e..ed2c370d8 100644 --- a/cc/vendor_snapshot.go +++ b/cc/vendor_snapshot.go @@ -18,524 +18,198 @@ import ( "path/filepath" "sort" "strings" - "sync" "github.com/google/blueprint/proptools" "android/soong/android" ) -const ( - vendorSnapshotHeaderSuffix = ".vendor_header." - vendorSnapshotSharedSuffix = ".vendor_shared." - vendorSnapshotStaticSuffix = ".vendor_static." - vendorSnapshotBinarySuffix = ".vendor_binary." - vendorSnapshotObjectSuffix = ".vendor_object." -) - -var ( - vendorSnapshotsLock sync.Mutex - vendorSuffixModulesKey = android.NewOnceKey("vendorSuffixModules") - vendorSnapshotHeaderLibsKey = android.NewOnceKey("vendorSnapshotHeaderLibs") - vendorSnapshotStaticLibsKey = android.NewOnceKey("vendorSnapshotStaticLibs") - vendorSnapshotSharedLibsKey = android.NewOnceKey("vendorSnapshotSharedLibs") - vendorSnapshotBinariesKey = android.NewOnceKey("vendorSnapshotBinaries") - vendorSnapshotObjectsKey = android.NewOnceKey("vendorSnapshotObjects") -) - -// vendor snapshot maps hold names of vendor snapshot modules per arch -func vendorSuffixModules(config android.Config) map[string]bool { - return config.Once(vendorSuffixModulesKey, func() interface{} { - return make(map[string]bool) - }).(map[string]bool) +var vendorSnapshotSingleton = snapshotSingleton{ + "vendor", + "SOONG_VENDOR_SNAPSHOT_ZIP", + android.OptionalPath{}, + true, + vendorSnapshotImageSingleton, + false, /* fake */ + true, /* usesLlndkLibraries */ +} + +var vendorFakeSnapshotSingleton = snapshotSingleton{ + "vendor", + "SOONG_VENDOR_FAKE_SNAPSHOT_ZIP", + android.OptionalPath{}, + true, + vendorSnapshotImageSingleton, + true, /* fake */ + true, /* usesLlndkLibraries */ +} + +var recoverySnapshotSingleton = snapshotSingleton{ + "recovery", + "SOONG_RECOVERY_SNAPSHOT_ZIP", + android.OptionalPath{}, + false, + recoverySnapshotImageSingleton, + false, /* fake */ + false, /* usesLlndkLibraries */ +} + +var ramdiskSnapshotSingleton = snapshotSingleton{ + "ramdisk", + "SOONG_RAMDISK_SNAPSHOT_ZIP", + android.OptionalPath{}, + false, + ramdiskSnapshotImageSingleton, + false, /* fake */ + false, /* usesLlndkLibraries */ } -func vendorSnapshotHeaderLibs(config android.Config) *snapshotMap { - return config.Once(vendorSnapshotHeaderLibsKey, func() interface{} { - return newSnapshotMap() - }).(*snapshotMap) -} - -func vendorSnapshotSharedLibs(config android.Config) *snapshotMap { - return config.Once(vendorSnapshotSharedLibsKey, func() interface{} { - return newSnapshotMap() - }).(*snapshotMap) +func VendorSnapshotSingleton() android.Singleton { + return &vendorSnapshotSingleton } -func vendorSnapshotStaticLibs(config android.Config) *snapshotMap { - return config.Once(vendorSnapshotStaticLibsKey, func() interface{} { - return newSnapshotMap() - }).(*snapshotMap) +func VendorFakeSnapshotSingleton() android.Singleton { + return &vendorFakeSnapshotSingleton } -func vendorSnapshotBinaries(config android.Config) *snapshotMap { - return config.Once(vendorSnapshotBinariesKey, func() interface{} { - return newSnapshotMap() - }).(*snapshotMap) +func RecoverySnapshotSingleton() android.Singleton { + return &recoverySnapshotSingleton } -func vendorSnapshotObjects(config android.Config) *snapshotMap { - return config.Once(vendorSnapshotObjectsKey, func() interface{} { - return newSnapshotMap() - }).(*snapshotMap) +func RamdiskSnapshotSingleton() android.Singleton { + return &ramdiskSnapshotSingleton } -type vendorSnapshotLibraryProperties struct { - // snapshot version. - Version string +type snapshotSingleton struct { + // Name, e.g., "vendor", "recovery", "ramdisk". + name string - // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64') - Target_arch string + // Make variable that points to the snapshot file, e.g., + // "SOONG_RECOVERY_SNAPSHOT_ZIP". + makeVar string - // Prebuilt file for each arch. - Src *string `android:"arch_variant"` + // Path to the snapshot zip file. + snapshotZipFile android.OptionalPath - // list of flags that will be used for any module that links against this module. - Export_flags []string `android:"arch_variant"` + // Whether the image supports VNDK extension modules. + supportsVndkExt bool - // Check the prebuilt ELF files (e.g. DT_SONAME, DT_NEEDED, resolution of undefined symbols, - // etc). - Check_elf_files *bool + // 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 prebuilt needs to depend on sanitize ubsan runtime or not. - Sanitize_ubsan_dep *bool `android:"arch_variant"` + // 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 - // Whether this prebuilt needs to depend on sanitize minimal runtime or not. - Sanitize_minimal_dep *bool `android:"arch_variant"` + // Whether the image uses llndk libraries. + usesLlndkLibraries bool } -type vendorSnapshotLibraryDecorator struct { - *libraryDecorator - properties vendorSnapshotLibraryProperties - androidMkVendorSuffix bool -} - -func (p *vendorSnapshotLibraryDecorator) Name(name string) string { - return name + p.NameSuffix() -} - -func (p *vendorSnapshotLibraryDecorator) NameSuffix() string { - versionSuffix := p.version() - if p.arch() != "" { - versionSuffix += "." + p.arch() - } - - var linkageSuffix string - if p.buildShared() { - linkageSuffix = vendorSnapshotSharedSuffix - } else if p.buildStatic() { - linkageSuffix = vendorSnapshotStaticSuffix - } else { - linkageSuffix = vendorSnapshotHeaderSuffix - } - - return linkageSuffix + versionSuffix +// Determine if a dir under source tree is an SoC-owned proprietary directory based +// on vendor snapshot configuration +// Examples: device/, vendor/ +func isVendorProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool { + return VendorSnapshotSingleton().(*snapshotSingleton).image.isProprietaryPath(dir, deviceConfig) } -func (p *vendorSnapshotLibraryDecorator) version() string { - return p.properties.Version +// Determine if a dir under source tree is an SoC-owned proprietary directory based +// on recovery snapshot configuration +// Examples: device/, vendor/ +func isRecoveryProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool { + return RecoverySnapshotSingleton().(*snapshotSingleton).image.isProprietaryPath(dir, deviceConfig) } -func (p *vendorSnapshotLibraryDecorator) arch() string { - return p.properties.Target_arch +// Determine if a dir under source tree is an SoC-owned proprietary directory based +// on ramdisk snapshot configuration +// Examples: device/, vendor/ +func isRamdiskProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool { + return RamdiskSnapshotSingleton().(*snapshotSingleton).image.isProprietaryPath(dir, deviceConfig) } -func (p *vendorSnapshotLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { - p.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), p.NameSuffix()) - return p.libraryDecorator.linkerFlags(ctx, flags) -} - -func (p *vendorSnapshotLibraryDecorator) matchesWithDevice(config android.DeviceConfig) bool { - arches := config.Arches() - if len(arches) == 0 || arches[0].ArchType.String() != p.arch() { - return false - } - if !p.header() && p.properties.Src == nil { - return false - } - return true -} - -func (p *vendorSnapshotLibraryDecorator) link(ctx ModuleContext, - flags Flags, deps PathDeps, objs Objects) android.Path { - m := ctx.Module().(*Module) - p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()] - - if p.header() { - return p.libraryDecorator.link(ctx, flags, deps, objs) - } - - if !p.matchesWithDevice(ctx.DeviceConfig()) { - return nil +func isVendorProprietaryModule(ctx android.BaseModuleContext) bool { + // Any module in a vendor proprietary path is a vendor proprietary + // module. + if isVendorProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) { + return true } - p.libraryDecorator.exportIncludes(ctx) - p.libraryDecorator.reexportFlags(p.properties.Export_flags...) - - in := android.PathForModuleSrc(ctx, *p.properties.Src) - p.unstrippedOutputFile = in - - if p.shared() { - libName := in.Base() - builderFlags := flagsToBuilderFlags(flags) - - // Optimize out relinking against shared libraries whose interface hasn't changed by - // depending on a table of contents file instead of the library itself. - tocFile := android.PathForModuleOut(ctx, libName+".toc") - p.tocFile = android.OptionalPathForPath(tocFile) - TransformSharedObjectToToc(ctx, in, tocFile, builderFlags) + // However if the module is not in a vendor proprietary path, it may + // still be a vendor proprietary module. This happens for cc modules + // that are excluded from the vendor snapshot, and it means that the + // vendor has assumed control of the framework-provided module. + if c, ok := ctx.Module().(*Module); ok { + if c.ExcludeFromVendorSnapshot() { + return true + } } - return in -} - -func (p *vendorSnapshotLibraryDecorator) nativeCoverage() bool { return false } -func (p *vendorSnapshotLibraryDecorator) isSnapshotPrebuilt() bool { - return true -} - -func (p *vendorSnapshotLibraryDecorator) install(ctx ModuleContext, file android.Path) { - if p.matchesWithDevice(ctx.DeviceConfig()) && (p.shared() || p.static()) { - p.baseInstaller.install(ctx, file) - } -} - -type vendorSnapshotInterface interface { - version() string -} - -func vendorSnapshotLoadHook(ctx android.LoadHookContext, p vendorSnapshotInterface) { - if p.version() != ctx.DeviceConfig().VndkVersion() { - ctx.Module().Disable() - return - } -} - -func vendorSnapshotLibrary() (*Module, *vendorSnapshotLibraryDecorator) { - module, library := NewLibrary(android.DeviceSupported) - - module.stl = nil - module.sanitize = nil - library.StripProperties.Strip.None = BoolPtr(true) - - prebuilt := &vendorSnapshotLibraryDecorator{ - libraryDecorator: library, - } - - prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true) - prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true) - - // Prevent default system libs (libc, libm, and libdl) from being linked - if prebuilt.baseLinker.Properties.System_shared_libs == nil { - prebuilt.baseLinker.Properties.System_shared_libs = []string{} - } - - module.compiler = nil - module.linker = prebuilt - module.installer = prebuilt - - module.AddProperties( - &prebuilt.properties, - ) - - return module, prebuilt -} - -func VendorSnapshotSharedFactory() android.Module { - module, prebuilt := vendorSnapshotLibrary() - prebuilt.libraryDecorator.BuildOnlyShared() - android.AddLoadHook(module, func(ctx android.LoadHookContext) { - vendorSnapshotLoadHook(ctx, prebuilt) - }) - return module.Init() -} - -func VendorSnapshotStaticFactory() android.Module { - module, prebuilt := vendorSnapshotLibrary() - prebuilt.libraryDecorator.BuildOnlyStatic() - android.AddLoadHook(module, func(ctx android.LoadHookContext) { - vendorSnapshotLoadHook(ctx, prebuilt) - }) - return module.Init() -} - -func VendorSnapshotHeaderFactory() android.Module { - module, prebuilt := vendorSnapshotLibrary() - prebuilt.libraryDecorator.HeaderOnly() - android.AddLoadHook(module, func(ctx android.LoadHookContext) { - vendorSnapshotLoadHook(ctx, prebuilt) - }) - return module.Init() -} - -type vendorSnapshotBinaryProperties struct { - // snapshot version. - Version string - - // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64_ab') - Target_arch string +func isRecoveryProprietaryModule(ctx android.BaseModuleContext) bool { - // Prebuilt file for each arch. - Src *string `android:"arch_variant"` -} - -type vendorSnapshotBinaryDecorator struct { - *binaryDecorator - properties vendorSnapshotBinaryProperties - androidMkVendorSuffix bool -} - -func (p *vendorSnapshotBinaryDecorator) Name(name string) string { - return name + p.NameSuffix() -} - -func (p *vendorSnapshotBinaryDecorator) NameSuffix() string { - versionSuffix := p.version() - if p.arch() != "" { - versionSuffix += "." + p.arch() - } - return vendorSnapshotBinarySuffix + versionSuffix -} - -func (p *vendorSnapshotBinaryDecorator) version() string { - return p.properties.Version -} - -func (p *vendorSnapshotBinaryDecorator) arch() string { - return p.properties.Target_arch -} - -func (p *vendorSnapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) bool { - if config.DeviceArch() != p.arch() { - return false - } - if p.properties.Src == nil { - return false + // Any module in a vendor proprietary path is a vendor proprietary + // module. + if isRecoveryProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) { + return true } - return true -} -func (p *vendorSnapshotBinaryDecorator) link(ctx ModuleContext, - flags Flags, deps PathDeps, objs Objects) android.Path { - if !p.matchesWithDevice(ctx.DeviceConfig()) { - return nil - } + // However if the module is not in a vendor proprietary path, it may + // still be a vendor proprietary module. This happens for cc modules + // that are excluded from the vendor snapshot, and it means that the + // vendor has assumed control of the framework-provided module. - in := android.PathForModuleSrc(ctx, *p.properties.Src) - builderFlags := flagsToBuilderFlags(flags) - p.unstrippedOutputFile = in - binName := in.Base() - if p.needsStrip(ctx) { - stripped := android.PathForModuleOut(ctx, "stripped", binName) - p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags) - in = stripped + if c, ok := ctx.Module().(*Module); ok { + if c.ExcludeFromRecoverySnapshot() { + return true + } } - m := ctx.Module().(*Module) - p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()] - - // use cpExecutable to make it executable - outputFile := android.PathForModuleOut(ctx, binName) - ctx.Build(pctx, android.BuildParams{ - Rule: android.CpExecutable, - Description: "prebuilt", - Output: outputFile, - Input: in, - }) - - return outputFile -} - -func (p *vendorSnapshotBinaryDecorator) isSnapshotPrebuilt() bool { - return true + return false } +func isRamdiskProprietaryModule(ctx android.BaseModuleContext) bool { -func VendorSnapshotBinaryFactory() android.Module { - module, binary := NewBinary(android.DeviceSupported) - binary.baseLinker.Properties.No_libcrt = BoolPtr(true) - binary.baseLinker.Properties.Nocrt = BoolPtr(true) - - // Prevent default system libs (libc, libm, and libdl) from being linked - if binary.baseLinker.Properties.System_shared_libs == nil { - binary.baseLinker.Properties.System_shared_libs = []string{} - } - - prebuilt := &vendorSnapshotBinaryDecorator{ - binaryDecorator: binary, + // Any module in a vendor proprietary path is a vendor proprietary + // module. + if isRamdiskProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) { + return true } - module.compiler = nil - module.sanitize = nil - module.stl = nil - module.linker = prebuilt - - android.AddLoadHook(module, func(ctx android.LoadHookContext) { - vendorSnapshotLoadHook(ctx, prebuilt) - }) - - module.AddProperties(&prebuilt.properties) - return module.Init() -} - -type vendorSnapshotObjectProperties struct { - // snapshot version. - Version string + // However if the module is not in a vendor proprietary path, it may + // still be a vendor proprietary module. This happens for cc modules + // that are excluded from the vendor snapshot, and it means that the + // vendor has assumed control of the framework-provided module. - // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64_ab') - Target_arch string - - // Prebuilt file for each arch. - Src *string `android:"arch_variant"` -} - -type vendorSnapshotObjectLinker struct { - objectLinker - properties vendorSnapshotObjectProperties - androidMkVendorSuffix bool -} - -func (p *vendorSnapshotObjectLinker) Name(name string) string { - return name + p.NameSuffix() -} - -func (p *vendorSnapshotObjectLinker) NameSuffix() string { - versionSuffix := p.version() - if p.arch() != "" { - versionSuffix += "." + p.arch() + if c, ok := ctx.Module().(*Module); ok { + if c.ExcludeFromRamdiskSnapshot() { + return true + } } - return vendorSnapshotObjectSuffix + versionSuffix -} - -func (p *vendorSnapshotObjectLinker) version() string { - return p.properties.Version -} -func (p *vendorSnapshotObjectLinker) arch() string { - return p.properties.Target_arch + return false } -func (p *vendorSnapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bool { - if config.DeviceArch() != p.arch() { +// Determines if the module is a candidate for snapshot. +func isSnapshotAware(cfg android.DeviceConfig, m *Module, inProprietaryPath bool, image snapshotImage) bool { + if !m.Enabled() || m.Properties.HideFromMake { return false } - if p.properties.Src == nil { + // When android/prebuilt.go selects between source and prebuilt, it sets + // SkipInstall on the other one to avoid duplicate install rules in make. + if m.IsSkipInstall() { return false } - return true -} - -func (p *vendorSnapshotObjectLinker) link(ctx ModuleContext, - flags Flags, deps PathDeps, objs Objects) android.Path { - if !p.matchesWithDevice(ctx.DeviceConfig()) { - return nil - } - - m := ctx.Module().(*Module) - p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()] - - return android.PathForModuleSrc(ctx, *p.properties.Src) -} - -func (p *vendorSnapshotObjectLinker) nativeCoverage() bool { - return false -} - -func (p *vendorSnapshotObjectLinker) isSnapshotPrebuilt() bool { - return true -} - -func VendorSnapshotObjectFactory() android.Module { - module := newObject() - - prebuilt := &vendorSnapshotObjectLinker{ - objectLinker: objectLinker{ - baseLinker: NewBaseLinker(nil), - }, - } - module.linker = prebuilt - - android.AddLoadHook(module, func(ctx android.LoadHookContext) { - vendorSnapshotLoadHook(ctx, prebuilt) - }) - - module.AddProperties(&prebuilt.properties) - return module.Init() -} - -func init() { - android.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton) - android.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory) - android.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory) - android.RegisterModuleType("vendor_snapshot_header", VendorSnapshotHeaderFactory) - android.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory) - android.RegisterModuleType("vendor_snapshot_object", VendorSnapshotObjectFactory) -} - -func VendorSnapshotSingleton() android.Singleton { - return &vendorSnapshotSingleton{} -} - -type vendorSnapshotSingleton struct { - vendorSnapshotZipFile android.OptionalPath -} - -var ( - // Modules under following directories are ignored. They are OEM's and vendor's - // proprietary modules(device/, vendor/, and hardware/). - // TODO(b/65377115): Clean up these with more maintainable way - vendorProprietaryDirs = []string{ - "device", - "vendor", - "hardware", - } - - // Modules under following directories are included as they are in AOSP, - // although hardware/ is normally for vendor's own. - // TODO(b/65377115): Clean up these with more maintainable way - aospDirsUnderProprietary = []string{ - "hardware/interfaces", - "hardware/libhardware", - "hardware/libhardware_legacy", - "hardware/ril", - } -) - -// Determine if a dir under source tree is an SoC-owned proprietary directory, such as -// device/, vendor/, etc. -func isVendorProprietaryPath(dir string) bool { - for _, p := range vendorProprietaryDirs { - if strings.HasPrefix(dir, p) { - // filter out AOSP defined directories, e.g. hardware/interfaces/ - aosp := false - for _, p := range aospDirsUnderProprietary { - if strings.HasPrefix(dir, p) { - aosp = true - break - } - } - if !aosp { - return true - } - } - } - return false -} - -// Determine if a module is going to be included in vendor snapshot or not. -// -// Targets of vendor snapshot are "vendor: true" or "vendor_available: true" modules in -// AOSP. They are not guaranteed to be compatible with older vendor images. (e.g. might -// depend on newer VNDK) So they are captured as vendor snapshot To build older vendor -// image and newer system image altogether. -func isVendorSnapshotModule(m *Module, moduleDir string) bool { - if !m.Enabled() || m.Properties.HideFromMake { + // skip proprietary modules, but (for the vendor snapshot only) + // include all VNDK (static) + if inProprietaryPath && (!image.includeVndk() || !m.IsVndk()) { return false } - // skip proprietary modules, but include all VNDK (static) - if isVendorProprietaryPath(moduleDir) && !m.IsVndk() { + // If the module would be included based on its path, check to see if + // the module is marked to be excluded. If so, skip it. + if image.excludeFromSnapshot(m) { return false } if m.Target().Os.Class != android.Device { @@ -545,7 +219,7 @@ func isVendorSnapshotModule(m *Module, moduleDir string) bool { return false } // the module must be installed in /vendor - if !m.IsForPlatform() || m.isSnapshotPrebuilt() || !m.inVendor() { + if !m.IsForPlatform() || m.isSnapshotPrebuilt() || !image.inImage(m)() { return false } // skip kernel_headers which always depend on vendor @@ -557,40 +231,45 @@ func isVendorSnapshotModule(m *Module, moduleDir string) bool { if l, ok := m.linker.(snapshotLibraryInterface); ok { // TODO(b/65377115): add full support for sanitizer if m.sanitize != nil { - // cfi, scs and hwasan export both sanitized and unsanitized variants for static and header + // scs and hwasan export both sanitized and unsanitized variants for static and header // Always use unsanitized variants of them. - for _, t := range []sanitizerType{cfi, scs, hwasan} { + for _, t := range []sanitizerType{scs, hwasan} { if !l.shared() && m.sanitize.isSanitizerEnabled(t) { return false } } + // cfi also exports both variants. But for static, we capture both. + if !l.static() && !l.shared() && m.sanitize.isSanitizerEnabled(cfi) { + return false + } } if l.static() { - return m.outputFile.Valid() && proptools.BoolDefault(m.VendorProperties.Vendor_available, true) + return m.outputFile.Valid() && proptools.BoolDefault(image.available(m), true) } if l.shared() { if !m.outputFile.Valid() { return false } - if !m.IsVndk() { - return true + if image.includeVndk() { + if !m.IsVndk() { + return true + } + return m.isVndkExt() } - return m.isVndkExt() } return true } // Binaries and Objects if m.binary() || m.object() { - return m.outputFile.Valid() && proptools.BoolDefault(m.VendorProperties.Vendor_available, true) + return m.outputFile.Valid() && proptools.BoolDefault(image.available(m), true) } return false } -func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { - // BOARD_VNDK_VERSION must be set to 'current' in order to generate a vendor snapshot. - if ctx.DeviceConfig().VndkVersion() != "current" { +func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { + if !c.image.shouldGenerateSnapshot(ctx) { return } @@ -629,7 +308,12 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont (header files of same directory structure with source tree) */ - snapshotDir := "vendor-snapshot" + 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") @@ -641,7 +325,19 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont var headers android.Paths - installSnapshot := func(m *Module) android.Paths { + copyFile := func(ctx android.SingletonContext, path android.Path, out string, fake bool) android.OutputPath { + if 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. + return writeStringToFileRule(ctx, "", out) + } else { + return copyFileRule(ctx, path, 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, fake bool) android.Paths { targetArch := "arch-" + m.Target().Arch.ArchType.String() if m.Target().Arch.ArchVariant != "" { targetArch += "-" + m.Target().Arch.ArchVariant @@ -657,8 +353,10 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont ExportedDirs []string `json:",omitempty"` ExportedSystemDirs []string `json:",omitempty"` ExportedFlags []string `json:",omitempty"` + Sanitize string `json:",omitempty"` SanitizeMinimalDep bool `json:",omitempty"` SanitizeUbsanDep bool `json:",omitempty"` + IsLlndk bool `json:",omitempty"` // binary flags Symlinks []string `json:",omitempty"` @@ -674,8 +372,13 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont }{} // Common properties among snapshots. - prop.ModuleName = ctx.ModuleName(m) - if m.isVndkExt() { + if m.isLlndk(ctx.Config()) && c.usesLlndkLibraries { + prop.ModuleName = m.BaseModuleName() + prop.IsLlndk = true + } else { + prop.ModuleName = ctx.ModuleName(m) + } + if c.supportsVndkExt && m.isVndkExt() { // vndk exts are installed to /vendor/lib(64)?/vndk(-sp)? if m.isVndkSp() { prop.RelativeInstallPath = "vndk-sp" @@ -699,13 +402,14 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont out := filepath.Join(configsDir, path.Base()) if !installedConfigs[out] { installedConfigs[out] = true - ret = append(ret, copyFile(ctx, path, out)) + ret = append(ret, copyFile(ctx, path, out, fake)) } } var propOut string if l, ok := m.linker.(snapshotLibraryInterface); ok { + // library flags prop.ExportedFlags = l.exportedFlags() for _, dir := range l.exportedDirs() { @@ -738,8 +442,17 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont if libType != "header" { libPath := m.outputFile.Path() stem = libPath.Base() + if l.static() && m.sanitize != nil && m.sanitize.isSanitizerEnabled(cfi) { + // both cfi and non-cfi variant for static libraries can exist. + // attach .cfi to distinguish between cfi and non-cfi. + // e.g. libbase.a -> libbase.cfi.a + ext := filepath.Ext(stem) + stem = strings.TrimSuffix(stem, ext) + ".cfi" + ext + prop.Sanitize = "cfi" + prop.ModuleName += ".cfi" + } snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, stem) - ret = append(ret, copyFile(ctx, libPath, snapshotLibOut)) + ret = append(ret, copyFile(ctx, libPath, snapshotLibOut, fake)) } else { stem = ctx.ModuleName(m) } @@ -753,7 +466,7 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont // install bin binPath := m.outputFile.Path() snapshotBinOut := filepath.Join(snapshotArchDir, targetArch, "binary", binPath.Base()) - ret = append(ret, copyFile(ctx, binPath, snapshotBinOut)) + ret = append(ret, copyFile(ctx, binPath, snapshotBinOut, fake)) propOut = snapshotBinOut + ".json" } else if m.object() { // object files aren't installed to the device, so their names can conflict. @@ -761,7 +474,7 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont objPath := m.outputFile.Path() snapshotObjOut := filepath.Join(snapshotArchDir, targetArch, "object", ctx.ModuleName(m)+filepath.Ext(objPath.Base())) - ret = append(ret, copyFile(ctx, objPath, snapshotObjOut)) + ret = append(ret, copyFile(ctx, objPath, snapshotObjOut, fake)) propOut = snapshotObjOut + ".json" } else { ctx.Errorf("unknown module %q in vendor snapshot", m.String()) @@ -773,7 +486,7 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont ctx.Errorf("json marshal to %q failed: %#v", propOut, err) return nil } - ret = append(ret, writeStringToFile(ctx, string(j), propOut)) + ret = append(ret, writeStringToFileRule(ctx, string(j), propOut)) return ret } @@ -785,11 +498,44 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont } moduleDir := ctx.ModuleDir(module) - if !isVendorSnapshotModule(m, moduleDir) { + inProprietaryPath := c.image.isProprietaryPath(moduleDir, ctx.DeviceConfig()) + + if c.image.excludeFromSnapshot(m) { + if inProprietaryPath { + // Error: exclude_from_vendor_snapshot applies + // to framework-path modules only. + ctx.Errorf("module %q in vendor proprietary path %q may not use \"exclude_from_vendor_snapshot: true\"", m.String(), moduleDir) + return + } + if Bool(c.image.available(m)) { + // Error: may not combine "vendor_available: + // true" with "exclude_from_vendor_snapshot: + // true". + ctx.Errorf( + "module %q may not use both \""+ + c.name+ + "_available: true\" and \"exclude_from_vendor_snapshot: true\"", + m.String()) + return + } + } + + if !isSnapshotAware(ctx.DeviceConfig(), m, inProprietaryPath, c.image) { return } - snapshotOutputs = append(snapshotOutputs, installSnapshot(m)...) + // If we are using directed snapshot and a module is not included in the + // list, we will still include the module as if it was a fake module. + // The reason is that soong needs all the dependencies to be present, even + // if they are not using during the build. + installAsFake := c.fake + if c.image.excludeFromDirectedSnapshot(ctx.DeviceConfig(), m.BaseModuleName()) { + installAsFake = true + } + + // installSnapshot installs prebuilts and json flag files + snapshotOutputs = append(snapshotOutputs, installSnapshot(m, installAsFake)...) + // just gather headers and notice files here, because they are to be deduplicated if l, ok := m.linker.(snapshotLibraryInterface); ok { headers = append(headers, l.snapshotHeaders()...) } @@ -800,16 +546,14 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont // skip already copied notice file if !installedNotices[noticeOut] { installedNotices[noticeOut] = true - snapshotOutputs = append(snapshotOutputs, copyFile( - ctx, m.NoticeFile().Path(), noticeOut)) + snapshotOutputs = append(snapshotOutputs, copyFile(ctx, m.NoticeFile().Path(), noticeOut, installAsFake)) } } }) // install all headers after removing duplicates for _, header := range android.FirstUniquePaths(headers) { - snapshotOutputs = append(snapshotOutputs, copyFile( - ctx, header, filepath.Join(includeDir, header.String()))) + snapshotOutputs = append(snapshotOutputs, copyFile(ctx, header, filepath.Join(includeDir, header.String()), c.fake)) } // All artifacts are ready. Sort them to normalize ninja and then zip. @@ -817,11 +561,17 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont return snapshotOutputs[i].String() < snapshotOutputs[j].String() }) - zipPath := android.PathForOutput(ctx, snapshotDir, "vendor-"+ctx.Config().DeviceName()+".zip") + zipPath := android.PathForOutput( + ctx, + snapshotDir, + c.name+"-"+ctx.Config().DeviceName()+".zip") zipRule := android.NewRuleBuilder() // filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr - snapshotOutputList := android.PathForOutput(ctx, snapshotDir, "vendor-"+ctx.Config().DeviceName()+"_list") + snapshotOutputList := android.PathForOutput( + ctx, + snapshotDir, + c.name+"-"+ctx.Config().DeviceName()+"_list") zipRule.Command(). Text("tr"). FlagWithArg("-d ", "\\'"). @@ -836,148 +586,13 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()). FlagWithInput("-l ", snapshotOutputList) - zipRule.Build(pctx, ctx, zipPath.String(), "vendor snapshot "+zipPath.String()) + zipRule.Build(pctx, ctx, zipPath.String(), c.name+" snapshot "+zipPath.String()) zipRule.DeleteTemporaryFiles() - c.vendorSnapshotZipFile = android.OptionalPathForPath(zipPath) -} - -func (c *vendorSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) { - ctx.Strict("SOONG_VENDOR_SNAPSHOT_ZIP", c.vendorSnapshotZipFile.String()) -} - -type snapshotInterface interface { - matchesWithDevice(config android.DeviceConfig) bool -} - -var _ snapshotInterface = (*vndkPrebuiltLibraryDecorator)(nil) -var _ snapshotInterface = (*vendorSnapshotLibraryDecorator)(nil) -var _ snapshotInterface = (*vendorSnapshotBinaryDecorator)(nil) -var _ snapshotInterface = (*vendorSnapshotObjectLinker)(nil) - -// gathers all snapshot modules for vendor, and disable unnecessary snapshots -// TODO(b/145966707): remove mutator and utilize android.Prebuilt to override source modules -func VendorSnapshotMutator(ctx android.BottomUpMutatorContext) { - vndkVersion := ctx.DeviceConfig().VndkVersion() - // don't need snapshot if current - if vndkVersion == "current" || vndkVersion == "" { - return - } - - module, ok := ctx.Module().(*Module) - if !ok || !module.Enabled() || module.VndkVersion() != vndkVersion { - return - } - - if !module.isSnapshotPrebuilt() { - return - } - - // isSnapshotPrebuilt ensures snapshotInterface - if !module.linker.(snapshotInterface).matchesWithDevice(ctx.DeviceConfig()) { - // Disable unnecessary snapshot module, but do not disable - // vndk_prebuilt_shared because they might be packed into vndk APEX - if !module.IsVndk() { - module.Disable() - } - return - } - - var snapshotMap *snapshotMap - - if lib, ok := module.linker.(libraryInterface); ok { - if lib.static() { - snapshotMap = vendorSnapshotStaticLibs(ctx.Config()) - } else if lib.shared() { - snapshotMap = vendorSnapshotSharedLibs(ctx.Config()) - } else { - // header - snapshotMap = vendorSnapshotHeaderLibs(ctx.Config()) - } - } else if _, ok := module.linker.(*vendorSnapshotBinaryDecorator); ok { - snapshotMap = vendorSnapshotBinaries(ctx.Config()) - } else if _, ok := module.linker.(*vendorSnapshotObjectLinker); ok { - snapshotMap = vendorSnapshotObjects(ctx.Config()) - } else { - return - } - - vendorSnapshotsLock.Lock() - defer vendorSnapshotsLock.Unlock() - snapshotMap.add(module.BaseModuleName(), ctx.Arch().ArchType, ctx.ModuleName()) + c.snapshotZipFile = android.OptionalPathForPath(zipPath) } -// Disables source modules which have snapshots -func VendorSnapshotSourceMutator(ctx android.BottomUpMutatorContext) { - if !ctx.Device() { - return - } - - vndkVersion := ctx.DeviceConfig().VndkVersion() - // don't need snapshot if current - if vndkVersion == "current" || vndkVersion == "" { - return - } - - module, ok := ctx.Module().(*Module) - if !ok { - return - } - - // vendor suffix should be added to snapshots if the source module isn't vendor: true. - if !module.SocSpecific() { - // But we can't just check SocSpecific() since we already passed the image mutator. - // Check ramdisk and recovery to see if we are real "vendor: true" module. - ramdisk_available := module.InRamdisk() && !module.OnlyInRamdisk() - recovery_available := module.InRecovery() && !module.OnlyInRecovery() - - if !ramdisk_available && !recovery_available { - vendorSnapshotsLock.Lock() - defer vendorSnapshotsLock.Unlock() - - vendorSuffixModules(ctx.Config())[ctx.ModuleName()] = true - } - } - - if module.isSnapshotPrebuilt() || module.VndkVersion() != ctx.DeviceConfig().VndkVersion() { - // only non-snapshot modules with BOARD_VNDK_VERSION - return - } - - // .. and also filter out llndk library - if module.isLlndk(ctx.Config()) { - return - } - - var snapshotMap *snapshotMap - - if lib, ok := module.linker.(libraryInterface); ok { - if lib.static() { - snapshotMap = vendorSnapshotStaticLibs(ctx.Config()) - } else if lib.shared() { - snapshotMap = vendorSnapshotSharedLibs(ctx.Config()) - } else { - // header - snapshotMap = vendorSnapshotHeaderLibs(ctx.Config()) - } - } else if module.binary() { - snapshotMap = vendorSnapshotBinaries(ctx.Config()) - } else if module.object() { - snapshotMap = vendorSnapshotObjects(ctx.Config()) - } else { - return - } - - if _, ok := snapshotMap.get(ctx.ModuleName(), ctx.Arch().ArchType); !ok { - // Corresponding snapshot doesn't exist - return - } - - // Disables source modules if corresponding snapshot exists. - if lib, ok := module.linker.(libraryInterface); ok && lib.buildStatic() && lib.buildShared() { - // But do not disable because the shared variant depends on the static variant. - module.SkipInstall() - module.Properties.HideFromMake = true - } else { - module.Disable() - } +func (c *snapshotSingleton) MakeVars(ctx android.MakeVarsContext) { + ctx.Strict( + c.makeVar, + c.snapshotZipFile.String()) } diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go new file mode 100644 index 000000000..67f2b3ddf --- /dev/null +++ b/cc/vendor_snapshot_test.go @@ -0,0 +1,1456 @@ +// Copyright 2021 Google Inc. All rights reserved. +// +// 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 cc + +import ( + "android/soong/android" + "fmt" + "path/filepath" + "reflect" + "strings" + "testing" +) + +func TestVendorSnapshotCapture(t *testing.T) { + bp := ` + cc_library { + name: "libvndk", + vendor_available: true, + product_available: true, + vndk: { + enabled: true, + }, + nocrt: true, + } + + cc_library { + name: "libvendor", + vendor: true, + nocrt: true, + } + + cc_library { + name: "libvendor_available", + vendor_available: true, + nocrt: true, + } + + cc_library_headers { + name: "libvendor_headers", + vendor_available: true, + nocrt: true, + } + + cc_binary { + name: "vendor_bin", + vendor: true, + nocrt: true, + } + + cc_binary { + name: "vendor_available_bin", + vendor_available: true, + nocrt: true, + } + + toolchain_library { + name: "libb", + vendor_available: true, + src: "libb.a", + } + + cc_object { + name: "obj", + vendor_available: true, + } + + cc_library { + name: "libllndk", + llndk_stubs: "libllndk.llndk", + } + + llndk_library { + name: "libllndk.llndk", + symbol_file: "", + } +` + config := TestConfig(buildDir, android.Android, nil, bp, nil) + config.TestProductVariables.DeviceVndkVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := testCcWithConfig(t, config) + + // Check Vendor snapshot output. + + snapshotDir := "vendor-snapshot" + snapshotVariantPath := filepath.Join(buildDir, 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.VER_%s_%s_shared", archType, archVariant) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant) + checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant) + jsonFiles = append(jsonFiles, + filepath.Join(sharedDir, "libvendor.so.json"), + filepath.Join(sharedDir, "libvendor_available.so.json")) + + // LLNDK modules are not captured + checkSnapshotExclude(t, ctx, snapshotSingleton, "libllndk", "libllndk.so", sharedDir, sharedVariant) + + // For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured. + // Also cfi variants are captured, except for prebuilts like toolchain_library + staticVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static", archType, archVariant) + staticCfiVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static_cfi", archType, archVariant) + staticDir := filepath.Join(snapshotVariantPath, archDir, "static") + checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant) + checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.a", staticDir, staticVariant) + checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.cfi.a", staticDir, staticCfiVariant) + checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.a", staticDir, staticVariant) + checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.cfi.a", staticDir, staticCfiVariant) + checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.a", staticDir, staticVariant) + checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.cfi.a", staticDir, staticCfiVariant) + jsonFiles = append(jsonFiles, + filepath.Join(staticDir, "libb.a.json"), + filepath.Join(staticDir, "libvndk.a.json"), + filepath.Join(staticDir, "libvndk.cfi.a.json"), + filepath.Join(staticDir, "libvendor.a.json"), + filepath.Join(staticDir, "libvendor.cfi.a.json"), + filepath.Join(staticDir, "libvendor_available.a.json"), + filepath.Join(staticDir, "libvendor_available.cfi.a.json")) + + // For binary executables, all vendor:true and vendor_available modules are captured. + if archType == "arm64" { + binaryVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant) + binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary") + checkSnapshot(t, ctx, snapshotSingleton, "vendor_bin", "vendor_bin", binaryDir, binaryVariant) + checkSnapshot(t, ctx, snapshotSingleton, "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant) + jsonFiles = append(jsonFiles, + filepath.Join(binaryDir, "vendor_bin.json"), + filepath.Join(binaryDir, "vendor_available_bin.json")) + } + + // For header libraries, all vendor:true and vendor_available modules are captured. + headerDir := filepath.Join(snapshotVariantPath, archDir, "header") + jsonFiles = append(jsonFiles, filepath.Join(headerDir, "libvendor_headers.json")) + + // For object modules, all vendor:true and vendor_available modules are captured. + objectVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant) + objectDir := filepath.Join(snapshotVariantPath, archDir, "object") + checkSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant) + jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.json")) + } + + for _, jsonFile := range jsonFiles { + // verify all json files exist + if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { + 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 TestVendorSnapshotDirected(t *testing.T) { + bp := ` + cc_library_shared { + name: "libvendor", + vendor: true, + nocrt: true, + } + + cc_library_shared { + name: "libvendor_available", + vendor_available: true, + nocrt: true, + } + + genrule { + name: "libfoo_gen", + cmd: "", + out: ["libfoo.so"], + } + + cc_prebuilt_library_shared { + name: "libfoo", + vendor: true, + prefer: true, + srcs: [":libfoo_gen"], + } + + cc_library_shared { + name: "libfoo", + vendor: true, + nocrt: true, + } +` + config := TestConfig(buildDir, android.Android, nil, bp, nil) + config.TestProductVariables.DeviceVndkVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + config.TestProductVariables.DirectedVendorSnapshot = true + config.TestProductVariables.VendorSnapshotModules = make(map[string]bool) + config.TestProductVariables.VendorSnapshotModules["libvendor"] = true + config.TestProductVariables.VendorSnapshotModules["libfoo"] = true + ctx := testCcWithConfig(t, config) + + // Check Vendor snapshot output. + + snapshotDir := "vendor-snapshot" + snapshotVariantPath := filepath.Join(buildDir, 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.VER_%s_%s_shared", archType, archVariant) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + + // Included modules + checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json")) + // Check that snapshot captures "prefer: true" prebuilt + checkSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo", "libfoo.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo.so.json")) + + // Excluded modules. Modules not included in the directed vendor snapshot + // are still include as fake modules. + checkSnapshotRule(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libvendor_available.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 TestVendorSnapshotUse(t *testing.T) { + frameworkBp := ` + cc_library { + name: "libvndk", + vendor_available: true, + product_available: true, + vndk: { + enabled: true, + }, + nocrt: true, + compile_multilib: "64", + } + + cc_library { + name: "libvendor", + vendor: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + compile_multilib: "64", + } + + cc_library { + name: "libvendor_available", + vendor_available: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + compile_multilib: "64", + } + + cc_binary { + name: "bin", + vendor: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + compile_multilib: "64", + } +` + + vndkBp := ` + vndk_prebuilt_shared { + name: "libvndk", + version: "BOARD", + target_arch: "arm64", + vendor_available: true, + product_available: true, + vndk: { + enabled: true, + }, + arch: { + arm64: { + srcs: ["libvndk.so"], + export_include_dirs: ["include/libvndk"], + }, + }, + } + + // old snapshot module which has to be ignored + vndk_prebuilt_shared { + name: "libvndk", + version: "OLD", + target_arch: "arm64", + vendor_available: true, + product_available: true, + vndk: { + enabled: true, + }, + arch: { + arm64: { + 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: [], + compile_multilib: "64", + } + + cc_library_shared { + name: "libclient", + vendor: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + shared_libs: ["libvndk", "libvendor_available"], + static_libs: ["libvendor", "libvendor_without_snapshot"], + compile_multilib: "64", + srcs: ["client.cpp"], + } + + cc_binary { + name: "bin_without_snapshot", + vendor: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + static_libs: ["libvndk"], + compile_multilib: "64", + srcs: ["bin.cpp"], + } + + vendor_snapshot { + name: "vendor_snapshot", + compile_multilib: "first", + version: "BOARD", + vndk_libs: [ + "libvndk", + ], + static_libs: [ + "libvendor", + "libvendor_available", + "libvndk", + ], + shared_libs: [ + "libvendor", + "libvendor_available", + ], + binaries: [ + "bin", + ], + } + + vendor_snapshot_static { + name: "libvndk", + version: "BOARD", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "libvndk.a", + export_include_dirs: ["include/libvndk"], + }, + }, + } + + vendor_snapshot_shared { + name: "libvendor", + version: "BOARD", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "libvendor.so", + export_include_dirs: ["include/libvendor"], + }, + }, + } + + vendor_snapshot_static { + name: "libvendor", + version: "BOARD", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "libvendor.a", + export_include_dirs: ["include/libvendor"], + }, + }, + } + + vendor_snapshot_shared { + name: "libvendor_available", + androidmk_suffix: ".vendor", + version: "BOARD", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "libvendor_available.so", + export_include_dirs: ["include/libvendor"], + }, + }, + } + + vendor_snapshot_static { + name: "libvendor_available", + androidmk_suffix: ".vendor", + version: "BOARD", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "libvendor_available.a", + export_include_dirs: ["include/libvendor"], + }, + }, + } + + vendor_snapshot_binary { + name: "bin", + version: "BOARD", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "bin", + }, + }, + } + + // old snapshot module which has to be ignored + vendor_snapshot_binary { + name: "bin", + version: "OLD", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "bin", + }, + }, + } +` + depsBp := GatherRequiredDepsForTest(android.Android) + + mockFS := map[string][]byte{ + "deps/Android.bp": []byte(depsBp), + "framework/Android.bp": []byte(frameworkBp), + "vendor/Android.bp": []byte(vendorProprietaryBp), + "vendor/bin": nil, + "vendor/bin.cpp": nil, + "vendor/client.cpp": 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, + "vndk/Android.bp": []byte(vndkBp), + "vndk/include/libvndk/a.h": nil, + "vndk/libvndk.so": nil, + } + + config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := CreateTestContext(config) + ctx.Register() + + _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "vendor/Android.bp", "vndk/Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + + sharedVariant := "android_vendor.BOARD_arm64_armv8-a_shared" + staticVariant := "android_vendor.BOARD_arm64_armv8-a_static" + binaryVariant := "android_vendor.BOARD_arm64_armv8-a" + + // libclient uses libvndk.vndk.BOARD.arm64, libvendor.vendor_static.BOARD.arm64, libvendor_without_snapshot + libclientCcFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("cc").Args["cFlags"] + for _, includeFlags := range []string{ + "-Ivndk/include/libvndk", // libvndk + "-Ivendor/include/libvendor", // libvendor + } { + if !strings.Contains(libclientCcFlags, includeFlags) { + t.Errorf("flags for libclient must contain %#v, but was %#v.", + includeFlags, libclientCcFlags) + } + } + + libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("ld").Args["libFlags"] + for _, input := range [][]string{ + []string{sharedVariant, "libvndk.vndk.BOARD.arm64"}, + []string{staticVariant, "libvendor.vendor_static.BOARD.arm64"}, + []string{staticVariant, "libvendor_without_snapshot"}, + } { + outputPaths := 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"}; !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"}; !reflect.DeepEqual(g, w) { + t.Errorf("wanted libclient AndroidMkStaticLibs %q, got %q", w, g) + } + + // bin_without_snapshot uses libvndk.vendor_static.BOARD.arm64 + binWithoutSnapshotCcFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("cc").Args["cFlags"] + if !strings.Contains(binWithoutSnapshotCcFlags, "-Ivendor/include/libvndk") { + t.Errorf("flags for bin_without_snapshot must contain %#v, but was %#v.", + "-Ivendor/include/libvndk", binWithoutSnapshotCcFlags) + } + + binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("ld").Args["libFlags"] + libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.BOARD.arm64"}) + if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) { + t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v", + libVndkStaticOutputPaths[0], binWithoutSnapshotLdFlags) + } + + // libvendor.so is installed by libvendor.vendor_shared.BOARD.arm64 + ctx.ModuleForTests("libvendor.vendor_shared.BOARD.arm64", sharedVariant).Output("libvendor.so") + + // libvendor_available.so is installed by libvendor_available.vendor_shared.BOARD.arm64 + ctx.ModuleForTests("libvendor_available.vendor_shared.BOARD.arm64", sharedVariant).Output("libvendor_available.so") + + // libvendor_without_snapshot.so is installed by libvendor_without_snapshot + ctx.ModuleForTests("libvendor_without_snapshot", sharedVariant).Output("libvendor_without_snapshot.so") + + // bin is installed by bin.vendor_binary.BOARD.arm64 + ctx.ModuleForTests("bin.vendor_binary.BOARD.arm64", binaryVariant).Output("bin") + + // 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.BOARD variant + libvendorVariants := ctx.ModuleVariantsForTests("libvendor") + if inList(sharedVariant, libvendorVariants) { + t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant) + } + + libvendorAvailableVariants := ctx.ModuleVariantsForTests("libvendor_available") + if inList(sharedVariant, libvendorAvailableVariants) { + t.Errorf("libvendor_available must not have variant %#v, but it does", sharedVariant) + } + + binVariants := ctx.ModuleVariantsForTests("bin") + if inList(binaryVariant, binVariants) { + t.Errorf("bin must not have variant %#v, but it does", sharedVariant) + } +} + +func TestVendorSnapshotSanitizer(t *testing.T) { + bp := ` + vendor_snapshot_static { + name: "libsnapshot", + vendor: true, + target_arch: "arm64", + version: "BOARD", + arch: { + arm64: { + src: "libsnapshot.a", + cfi: { + src: "libsnapshot.cfi.a", + } + }, + }, + } +` + config := TestConfig(buildDir, android.Android, nil, bp, nil) + config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := testCcWithConfig(t, config) + + // Check non-cfi and cfi variant. + staticVariant := "android_vendor.BOARD_arm64_armv8-a_static" + staticCfiVariant := "android_vendor.BOARD_arm64_armv8-a_static_cfi" + + staticModule := ctx.ModuleForTests("libsnapshot.vendor_static.BOARD.arm64", staticVariant).Module().(*Module) + assertString(t, staticModule.outputFile.Path().Base(), "libsnapshot.a") + + staticCfiModule := ctx.ModuleForTests("libsnapshot.vendor_static.BOARD.arm64", staticCfiVariant).Module().(*Module) + assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a") +} + +func assertExcludeFromVendorSnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool) { + t.Helper() + m := ctx.ModuleForTests(name, vendorVariant).Module().(*Module) + if m.ExcludeFromVendorSnapshot() != expected { + t.Errorf("expected %q ExcludeFromVendorSnapshot to be %t", m.String(), expected) + } +} + +func assertExcludeFromRecoverySnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool) { + t.Helper() + m := ctx.ModuleForTests(name, recoveryVariant).Module().(*Module) + if m.ExcludeFromRecoverySnapshot() != expected { + t.Errorf("expected %q ExcludeFromRecoverySnapshot to be %t", m.String(), expected) + } +} + +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 := ` + cc_library_shared { + name: "libinclude", + srcs: ["src/include.cpp"], + vendor_available: true, + } + cc_library_shared { + name: "libexclude", + srcs: ["src/exclude.cpp"], + vendor: true, + exclude_from_vendor_snapshot: true, + } + cc_library_shared { + name: "libavailable_exclude", + srcs: ["src/exclude.cpp"], + vendor_available: true, + exclude_from_vendor_snapshot: true, + } + ` + + vendorProprietaryBp := ` + cc_library_shared { + name: "libvendor", + srcs: ["vendor.cpp"], + vendor: true, + } + ` + + depsBp := GatherRequiredDepsForTest(android.Android) + + mockFS := map[string][]byte{ + "deps/Android.bp": []byte(depsBp), + "framework/Android.bp": []byte(frameworkBp), + "framework/include.cpp": nil, + "framework/exclude.cpp": nil, + "device/Android.bp": []byte(vendorProprietaryBp), + "device/vendor.cpp": nil, + } + + config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config.TestProductVariables.DeviceVndkVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := CreateTestContext(config) + ctx.Register() + + _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + + // Test an include and exclude framework module. + assertExcludeFromVendorSnapshotIs(t, ctx, "libinclude", false) + assertExcludeFromVendorSnapshotIs(t, ctx, "libexclude", true) + assertExcludeFromVendorSnapshotIs(t, ctx, "libavailable_exclude", true) + + // A vendor module is excluded, but by its path, not the + // exclude_from_vendor_snapshot property. + assertExcludeFromVendorSnapshotIs(t, ctx, "libvendor", false) + + // Verify the content of the vendor snapshot. + + snapshotDir := "vendor-snapshot" + snapshotVariantPath := filepath.Join(buildDir, 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.VER_%s_%s_shared", archType, archVariant) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + + // Included modules + checkSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json")) + + // Excluded modules + checkSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json")) + checkSnapshotExclude(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json")) + checkSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_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) + } + } + + // 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 TestVendorSnapshotExcludeInVendorProprietaryPathErrors(t *testing.T) { + + // This test verifies that using the exclude_from_vendor_snapshot + // property on a module in a vendor proprietary path generates an + // error. These modules are already excluded, so we prohibit using the + // property in this way, which could add to confusion. + + vendorProprietaryBp := ` + cc_library_shared { + name: "libvendor", + srcs: ["vendor.cpp"], + vendor: true, + exclude_from_vendor_snapshot: true, + } + ` + + depsBp := GatherRequiredDepsForTest(android.Android) + + mockFS := map[string][]byte{ + "deps/Android.bp": []byte(depsBp), + "device/Android.bp": []byte(vendorProprietaryBp), + "device/vendor.cpp": nil, + } + + config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config.TestProductVariables.DeviceVndkVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := CreateTestContext(config) + ctx.Register() + + _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "device/Android.bp"}) + android.FailIfErrored(t, errs) + + _, errs = ctx.PrepareBuildActions(config) + android.CheckErrorsAgainstExpectations(t, errs, []string{ + `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"`, + `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"`, + }) +} + +func TestRecoverySnapshotCapture(t *testing.T) { + bp := ` + cc_library { + name: "libvndk", + vendor_available: true, + recovery_available: true, + product_available: true, + vndk: { + enabled: true, + }, + nocrt: true, + } + + cc_library { + name: "librecovery", + recovery: true, + nocrt: true, + } + + cc_library { + name: "librecovery_available", + recovery_available: true, + nocrt: true, + } + + cc_library_headers { + name: "librecovery_headers", + recovery_available: true, + nocrt: true, + } + + cc_binary { + name: "recovery_bin", + recovery: true, + nocrt: true, + } + + cc_binary { + name: "recovery_available_bin", + recovery_available: true, + nocrt: true, + } + + toolchain_library { + name: "libb", + recovery_available: true, + src: "libb.a", + } + + cc_object { + name: "obj", + recovery_available: true, + } +` + config := TestConfig(buildDir, android.Android, nil, bp, nil) + config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := testCcWithConfig(t, config) + + // Check Recovery snapshot output. + + snapshotDir := "recovery-snapshot" + snapshotVariantPath := filepath.Join(buildDir, 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, only recovery_available modules are captured. + sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", sharedDir, sharedVariant) + checkSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant) + checkSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant) + jsonFiles = append(jsonFiles, + filepath.Join(sharedDir, "libvndk.so.json"), + 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") + checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant) + checkSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.a", staticDir, staticVariant) + checkSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.a", staticDir, staticVariant) + jsonFiles = append(jsonFiles, + filepath.Join(staticDir, "libb.a.json"), + filepath.Join(staticDir, "librecovery.a.json"), + filepath.Join(staticDir, "librecovery_available.a.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") + checkSnapshot(t, ctx, snapshotSingleton, "recovery_bin", "recovery_bin", binaryDir, binaryVariant) + 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 header libraries, all vendor:true and vendor_available modules are captured. + headerDir := filepath.Join(snapshotVariantPath, archDir, "header") + jsonFiles = append(jsonFiles, filepath.Join(headerDir, "librecovery_headers.json")) + + // For object modules, all vendor:true and vendor_available modules are captured. + objectVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant) + objectDir := filepath.Join(snapshotVariantPath, archDir, "object") + checkSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant) + jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.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 := ` + cc_library_shared { + name: "libinclude", + srcs: ["src/include.cpp"], + recovery_available: true, + } + cc_library_shared { + name: "libexclude", + srcs: ["src/exclude.cpp"], + recovery: true, + exclude_from_recovery_snapshot: true, + } + cc_library_shared { + name: "libavailable_exclude", + srcs: ["src/exclude.cpp"], + recovery_available: true, + exclude_from_recovery_snapshot: true, + } + ` + + vendorProprietaryBp := ` + cc_library_shared { + name: "librecovery", + srcs: ["recovery.cpp"], + recovery: true, + } + ` + + depsBp := GatherRequiredDepsForTest(android.Android) + + mockFS := map[string][]byte{ + "deps/Android.bp": []byte(depsBp), + "framework/Android.bp": []byte(frameworkBp), + "framework/include.cpp": nil, + "framework/exclude.cpp": nil, + "device/Android.bp": []byte(vendorProprietaryBp), + "device/recovery.cpp": nil, + } + + config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := CreateTestContext(config) + ctx.Register() + + _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + + // Test an include and exclude framework module. + assertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false) + assertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true) + assertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true) + + // A recovery module is excluded, but by its path, not the + // exclude_from_recovery_snapshot property. + assertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false) + + // Verify the content of the recovery snapshot. + + snapshotDir := "recovery-snapshot" + snapshotVariantPath := filepath.Join(buildDir, 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) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + + // Included modules + checkSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json")) + + // Excluded modules + checkSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json")) + checkSnapshotExclude(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json")) + checkSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_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) + } + } + + // 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 := ` + cc_library_shared { + name: "librecovery", + recovery: true, + nocrt: true, + } + + cc_library_shared { + name: "librecovery_available", + recovery_available: true, + nocrt: true, + } + + genrule { + name: "libfoo_gen", + cmd: "", + out: ["libfoo.so"], + } + + cc_prebuilt_library_shared { + name: "libfoo", + recovery: true, + prefer: true, + srcs: [":libfoo_gen"], + } + + cc_library_shared { + name: "libfoo", + recovery: true, + nocrt: true, + } +` + config := TestConfig(buildDir, android.Android, nil, bp, nil) + config.TestProductVariables.DeviceVndkVersion = StringPtr("current") + config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + config.TestProductVariables.DirectedRecoverySnapshot = true + config.TestProductVariables.RecoverySnapshotModules = make(map[string]bool) + config.TestProductVariables.RecoverySnapshotModules["librecovery"] = true + config.TestProductVariables.RecoverySnapshotModules["libfoo"] = true + ctx := testCcWithConfig(t, config) + + // Check recovery snapshot output. + + snapshotDir := "recovery-snapshot" + snapshotVariantPath := filepath.Join(buildDir, 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) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + + // Included modules + checkSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json")) + // Check that snapshot captures "prefer: true" prebuilt + checkSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo", "libfoo.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo.so.json")) + + // Excluded modules. Modules not included in the directed recovery snapshot + // are still include as fake modules. + checkSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery_available.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 TestRamdiskSnapshotCapture(t *testing.T) { + bp := ` + cc_library { + name: "libvndk", + vendor_available: true, + ramdisk_available: true, + product_available: true, + vndk: { + enabled: true, + }, + nocrt: true, + } + + cc_library { + name: "libramdisk", + ramdisk: true, + nocrt: true, + } + + cc_library { + name: "libramdisk_available", + ramdisk_available: true, + nocrt: true, + } + + cc_library_headers { + name: "libramdisk_headers", + ramdisk_available: true, + nocrt: true, + } + + cc_binary { + name: "ramdisk_bin", + ramdisk: true, + nocrt: true, + } + + cc_binary { + name: "ramdisk_available_bin", + ramdisk_available: true, + nocrt: true, + } + + toolchain_library { + name: "libb", + ramdisk_available: true, + src: "libb.a", + } + + cc_object { + name: "obj", + ramdisk_available: true, + } +` + config := TestConfig(buildDir, android.Android, nil, bp, nil) + config.TestProductVariables.RamdiskSnapshotVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := testCcWithConfig(t, config) + + // Check Ramdisk snapshot output. + + snapshotDir := "ramdisk-snapshot" + snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64") + snapshotSingleton := ctx.SingletonForTests("ramdisk-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, only ramdisk_available modules are captured. + sharedVariant := fmt.Sprintf("android_ramdisk_%s_%s_shared", archType, archVariant) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", sharedDir, sharedVariant) + checkSnapshot(t, ctx, snapshotSingleton, "libramdisk", "libramdisk.so", sharedDir, sharedVariant) + checkSnapshot(t, ctx, snapshotSingleton, "libramdisk_available", "libramdisk_available.so", sharedDir, sharedVariant) + jsonFiles = append(jsonFiles, + filepath.Join(sharedDir, "libvndk.so.json"), + filepath.Join(sharedDir, "libramdisk.so.json"), + filepath.Join(sharedDir, "libramdisk_available.so.json")) + + // For static libraries, all ramdisk:true and ramdisk_available modules are captured. + staticVariant := fmt.Sprintf("android_ramdisk_%s_%s_static", archType, archVariant) + staticDir := filepath.Join(snapshotVariantPath, archDir, "static") + checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant) + checkSnapshot(t, ctx, snapshotSingleton, "libramdisk", "libramdisk.a", staticDir, staticVariant) + checkSnapshot(t, ctx, snapshotSingleton, "libramdisk_available", "libramdisk_available.a", staticDir, staticVariant) + jsonFiles = append(jsonFiles, + filepath.Join(staticDir, "libb.a.json"), + filepath.Join(staticDir, "libramdisk.a.json"), + filepath.Join(staticDir, "libramdisk_available.a.json")) + + // For binary executables, all ramdisk:true and ramdisk_available modules are captured. + if archType == "arm64" { + binaryVariant := fmt.Sprintf("android_ramdisk_%s_%s", archType, archVariant) + binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary") + checkSnapshot(t, ctx, snapshotSingleton, "ramdisk_bin", "ramdisk_bin", binaryDir, binaryVariant) + checkSnapshot(t, ctx, snapshotSingleton, "ramdisk_available_bin", "ramdisk_available_bin", binaryDir, binaryVariant) + jsonFiles = append(jsonFiles, + filepath.Join(binaryDir, "ramdisk_bin.json"), + filepath.Join(binaryDir, "ramdisk_available_bin.json")) + } + + // For header libraries, all vendor:true and vendor_available modules are captured. + headerDir := filepath.Join(snapshotVariantPath, archDir, "header") + jsonFiles = append(jsonFiles, filepath.Join(headerDir, "libramdisk_headers.json")) + + // For object modules, all vendor:true and vendor_available modules are captured. + objectVariant := fmt.Sprintf("android_ramdisk_%s_%s", archType, archVariant) + objectDir := filepath.Join(snapshotVariantPath, archDir, "object") + checkSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant) + jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.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 TestRamdiskSnapshotExclude(t *testing.T) { + // This test verifies that the exclude_from_ramdisk_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 ramdisk snapshot based on their path (framework or + // vendor) and the exclude_from_ramdisk_snapshot property. + + frameworkBp := ` + cc_library_shared { + name: "libinclude", + srcs: ["src/include.cpp"], + ramdisk_available: true, + } + cc_library_shared { + name: "libexclude", + srcs: ["src/exclude.cpp"], + ramdisk: true, + exclude_from_ramdisk_snapshot: true, + } + cc_library_shared { + name: "libavailable_exclude", + srcs: ["src/exclude.cpp"], + ramdisk_available: true, + exclude_from_ramdisk_snapshot: true, + } + ` + + vendorProprietaryBp := ` + cc_library_shared { + name: "libramdisk", + srcs: ["ramdisk.cpp"], + ramdisk: true, + } + ` + + depsBp := GatherRequiredDepsForTest(android.Android) + + mockFS := map[string][]byte{ + "deps/Android.bp": []byte(depsBp), + "framework/Android.bp": []byte(frameworkBp), + "framework/include.cpp": nil, + "framework/exclude.cpp": nil, + "device/Android.bp": []byte(vendorProprietaryBp), + "device/ramdisk.cpp": nil, + } + + config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config.TestProductVariables.RamdiskSnapshotVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := CreateTestContext(config) + ctx.Register() + + _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + + // Test an include and exclude framework module. + assertExcludeFromRamdiskSnapshotIs(t, ctx, "libinclude", false) + assertExcludeFromRamdiskSnapshotIs(t, ctx, "libexclude", true) + assertExcludeFromRamdiskSnapshotIs(t, ctx, "libavailable_exclude", true) + + // A ramdisk module is excluded, but by its path, not the + // exclude_from_ramdisk_snapshot property. + assertExcludeFromRamdiskSnapshotIs(t, ctx, "libramdisk", false) + + // Verify the content of the ramdisk snapshot. + + snapshotDir := "ramdisk-snapshot" + snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64") + snapshotSingleton := ctx.SingletonForTests("ramdisk-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_ramdisk_%s_%s_shared", archType, archVariant) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + + // Included modules + checkSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json")) + + // Excluded modules + checkSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json")) + checkSnapshotExclude(t, ctx, snapshotSingleton, "libramdisk", "libramdisk.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libramdisk.so.json")) + checkSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_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) + } + } + + // 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 TestRamdiskSnapshotDirected(t *testing.T) { + bp := ` + cc_library_shared { + name: "libramdisk", + ramdisk: true, + nocrt: true, + } + + cc_library_shared { + name: "libramdisk_available", + ramdisk_available: true, + nocrt: true, + } + + genrule { + name: "libfoo_gen", + cmd: "", + out: ["libfoo.so"], + } + + cc_prebuilt_library_shared { + name: "libfoo", + ramdisk: true, + prefer: true, + srcs: [":libfoo_gen"], + } + + cc_library_shared { + name: "libfoo", + ramdisk: true, + nocrt: true, + } +` + config := TestConfig(buildDir, android.Android, nil, bp, nil) + config.TestProductVariables.DeviceVndkVersion = StringPtr("current") + config.TestProductVariables.RamdiskSnapshotVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + config.TestProductVariables.DirectedRamdiskSnapshot = true + config.TestProductVariables.RamdiskSnapshotModules = make(map[string]bool) + config.TestProductVariables.RamdiskSnapshotModules["libramdisk"] = true + config.TestProductVariables.RamdiskSnapshotModules["libfoo"] = true + ctx := testCcWithConfig(t, config) + + // Check ramdisk snapshot output. + + snapshotDir := "ramdisk-snapshot" + snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64") + snapshotSingleton := ctx.SingletonForTests("ramdisk-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_ramdisk_%s_%s_shared", archType, archVariant) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + + // Included modules + checkSnapshot(t, ctx, snapshotSingleton, "libramdisk", "libramdisk.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libramdisk.so.json")) + // Check that snapshot captures "prefer: true" prebuilt + checkSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo", "libfoo.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo.so.json")) + + // Excluded modules. Modules not included in the directed ramdisk snapshot + // are still include as fake modules. + checkSnapshotRule(t, ctx, snapshotSingleton, "libramdisk_available", "libramdisk_available.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libramdisk_available.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) + } + } +} diff --git a/cc/vndk.go b/cc/vndk.go index a0608696e..339102e28 100644 --- a/cc/vndk.go +++ b/cc/vndk.go @@ -616,7 +616,7 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex libPath := m.outputFile.Path() snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "shared", vndkType, libPath.Base()) - ret = append(ret, copyFile(ctx, libPath, snapshotLibOut)) + ret = append(ret, copyFileRule(ctx, libPath, snapshotLibOut)) if ctx.Config().VndkSnapshotBuildArtifacts() { prop := struct { @@ -637,7 +637,7 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex ctx.Errorf("json marshal to %q failed: %#v", propOut, err) return nil, false } - ret = append(ret, writeStringToFile(ctx, string(j), propOut)) + ret = append(ret, writeStringToFileRule(ctx, string(j), propOut)) } return ret, true } @@ -671,7 +671,7 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex // skip already copied notice file if _, ok := noticeBuilt[noticeName]; !ok { noticeBuilt[noticeName] = true - snapshotOutputs = append(snapshotOutputs, copyFile( + snapshotOutputs = append(snapshotOutputs, copyFileRule( ctx, m.NoticeFile().Path(), filepath.Join(noticeDir, noticeName))) } } @@ -683,7 +683,7 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex // install all headers after removing duplicates for _, header := range android.FirstUniquePaths(headers) { - snapshotOutputs = append(snapshotOutputs, copyFile( + snapshotOutputs = append(snapshotOutputs, copyFileRule( ctx, header, filepath.Join(includeDir, header.String()))) } @@ -693,7 +693,7 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex if !ok || !m.Enabled() || m.Name() == vndkUsingCoreVariantLibrariesTxt { return } - snapshotOutputs = append(snapshotOutputs, copyFile( + snapshotOutputs = append(snapshotOutputs, copyFileRule( ctx, m.OutputFile(), filepath.Join(configsDir, m.Name()))) }) @@ -714,7 +714,7 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex txtBuilder.WriteString(" ") txtBuilder.WriteString(m[k]) } - return writeStringToFile(ctx, txtBuilder.String(), path) + return writeStringToFileRule(ctx, txtBuilder.String(), path) } /* diff --git a/genrule/genrule.go b/genrule/genrule.go index fe877fe8d..9f21a3511 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -31,10 +31,10 @@ import ( ) func init() { - registerGenruleBuildComponents(android.InitRegistrationContext) + RegisterGenruleBuildComponents(android.InitRegistrationContext) } -func registerGenruleBuildComponents(ctx android.RegistrationContext) { +func RegisterGenruleBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("genrule_defaults", defaultsFactory) ctx.RegisterModuleType("gensrcs", GenSrcsFactory) diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go index 4b36600a6..ff5c8e936 100644 --- a/genrule/genrule_test.go +++ b/genrule/genrule_test.go @@ -57,7 +57,7 @@ func testContext(config android.Config) *android.TestContext { ctx.RegisterModuleType("filegroup", android.FileGroupFactory) ctx.RegisterModuleType("tool", toolFactory) - registerGenruleBuildComponents(ctx) + RegisterGenruleBuildComponents(ctx) ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) ctx.Register(config) diff --git a/java/Android.bp b/java/Android.bp index 1fda7f71d..f9ef5511d 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -57,6 +57,7 @@ bootstrap_go_package { "device_host_converter_test.go", "dexpreopt_test.go", "dexpreopt_bootjars_test.go", + "hiddenapi_singleton_test.go", "java_test.go", "jdeps_test.go", "kotlin_test.go", diff --git a/java/androidmk.go b/java/androidmk.go index ae257d7ad..8b7df6f37 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -127,8 +127,8 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...) } - if library.proguardDictionary != nil { - entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.proguardDictionary) + if library.dexer.proguardDictionary.Valid() { + entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.dexer.proguardDictionary.Path()) } entries.SetString("LOCAL_MODULE_STEM", library.Stem()) @@ -194,9 +194,12 @@ func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries { ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(entries *android.AndroidMkEntries) { entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !Bool(prebuilt.properties.Installable)) + if prebuilt.dexJarFile != nil { + entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile) + } entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile) - entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion().raw) + entries.SetString("LOCAL_SDK_VERSION", prebuilt.makeSdkVersion()) entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem()) }, }, @@ -332,8 +335,8 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { if app.jacocoReportClassesFile != nil { entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", app.jacocoReportClassesFile) } - if app.proguardDictionary != nil { - entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", app.proguardDictionary) + if app.dexer.proguardDictionary.Valid() { + entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", app.dexer.proguardDictionary.Path()) } if app.Name() == "framework-res" { @@ -678,6 +681,9 @@ func (a *AndroidAppImport) AndroidMkEntries() []android.AndroidMkEntries { entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", a.dexpreopter.builtInstalled) } entries.AddStrings("LOCAL_INSTALLED_MODULE_STEM", a.installPath.Rel()) + if Bool(a.properties.Export_package_resources) { + entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", a.outputFile) + } }, }, }} diff --git a/java/androidmk_test.go b/java/androidmk_test.go index 7daa6244f..32e6f0e33 100644 --- a/java/androidmk_test.go +++ b/java/androidmk_test.go @@ -169,3 +169,25 @@ func TestDistWithTag(t *testing.T) { t.Errorf("did not expect explicit DistFile, got %v", without_tag_entries[0].DistFile) } } + +func TestImportSoongDexJar(t *testing.T) { + ctx, config := testJava(t, ` + java_import { + name: "my-java-import", + jars: ["a.jar"], + prefer: true, + compile_dex: true, + } + `) + + mod := ctx.ModuleForTests("my-java-import", "android_common").Module() + entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0] + expectedSoongDexJar := buildDir + "/.intermediates/my-java-import/android_common/dex/my-java-import.jar" + actualSoongDexJar := entries.EntryMap["LOCAL_SOONG_DEX_JAR"] + + if len(actualSoongDexJar) != 1 { + t.Errorf("LOCAL_SOONG_DEX_JAR incorrect len %d", len(actualSoongDexJar)) + } else if actualSoongDexJar[0] != expectedSoongDexJar { + t.Errorf("LOCAL_SOONG_DEX_JAR mismatch, actual: %s, expected: %s", actualSoongDexJar[0], expectedSoongDexJar) + } +} diff --git a/java/app.go b/java/app.go index 2ec27f3df..0c9fb9aa3 100755 --- a/java/app.go +++ b/java/app.go @@ -585,11 +585,11 @@ func (a *AndroidApp) installPath(ctx android.ModuleContext) android.InstallPath func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { a.dexpreopter.installPath = a.installPath(ctx) - if a.deviceProperties.Uncompress_dex == nil { + if a.dexProperties.Uncompress_dex == nil { // If the value was not force-set by the user, use reasonable default based on the module. - a.deviceProperties.Uncompress_dex = proptools.BoolPtr(a.shouldUncompressDex(ctx)) + a.dexProperties.Uncompress_dex = proptools.BoolPtr(a.shouldUncompressDex(ctx)) } - a.dexpreopter.uncompressedDex = *a.deviceProperties.Uncompress_dex + a.dexpreopter.uncompressedDex = *a.dexProperties.Uncompress_dex a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries() a.dexpreopter.usesLibs = a.usesLibrary.usesLibraryProperties.Uses_libs a.dexpreopter.optionalUsesLibs = a.usesLibrary.presentOptionalUsesLibs(ctx) @@ -1001,8 +1001,8 @@ var _ cc.Coverage = (*AndroidApp)(nil) func AndroidAppFactory() android.Module { module := &AndroidApp{} - module.Module.deviceProperties.Optimize.EnabledByDefault = true - module.Module.deviceProperties.Optimize.Shrink = proptools.BoolPtr(true) + module.Module.dexProperties.Optimize.EnabledByDefault = true + module.Module.dexProperties.Optimize.Shrink = proptools.BoolPtr(true) module.Module.properties.Instrument = true module.Module.properties.Installable = proptools.BoolPtr(true) @@ -1119,7 +1119,7 @@ func (a *AndroidTest) OverridablePropertiesDepsMutator(ctx android.BottomUpMutat func AndroidTestFactory() android.Module { module := &AndroidTest{} - module.Module.deviceProperties.Optimize.EnabledByDefault = true + module.Module.dexProperties.Optimize.EnabledByDefault = true module.Module.properties.Instrument = true module.Module.properties.Installable = proptools.BoolPtr(true) @@ -1170,7 +1170,7 @@ func (a *AndroidTestHelperApp) InstallInTestcases() bool { func AndroidTestHelperAppFactory() android.Module { module := &AndroidTestHelperApp{} - module.Module.deviceProperties.Optimize.EnabledByDefault = true + module.Module.dexProperties.Optimize.EnabledByDefault = true module.Module.properties.Installable = proptools.BoolPtr(true) module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true) @@ -1338,6 +1338,10 @@ type AndroidAppImportProperties struct { // Optional name for the installed app. If unspecified, it is derived from the module name. Filename *string + + // If set, create package-export.apk, which other packages can + // use to get PRODUCT-agnostic resource data like IDs and type definitions. + Export_package_resources *bool } func (a *AndroidAppImport) IsInstallable() bool { @@ -1381,13 +1385,17 @@ func MergePropertiesFromVariant(ctx android.EarlyModuleContext, } } +func (a *AndroidAppImport) isPrebuiltFrameworkRes() bool { + return a.Name() == "prebuilt_framework-res" +} + func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) { cert := android.SrcIsModule(String(a.properties.Certificate)) if cert != "" { ctx.AddDependency(ctx.Module(), certificateTag, cert) } - a.usesLibrary.deps(ctx, true) + a.usesLibrary.deps(ctx, !a.isPrebuiltFrameworkRes()) } func (a *AndroidAppImport) uncompressEmbeddedJniLibs( @@ -1481,7 +1489,12 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed.OutputPath) var installDir android.InstallPath - if Bool(a.properties.Privileged) { + + if a.isPrebuiltFrameworkRes() { + // framework-res.apk is installed as system/framework/framework-res.apk + installDir = android.PathForModuleInstall(ctx, "framework") + a.preprocessed = true + } else if Bool(a.properties.Privileged) { installDir = android.PathForModuleInstall(ctx, "priv-app", a.BaseModuleName()) } else if ctx.InstallInTestcases() { installDir = android.PathForModuleInstall(ctx, a.BaseModuleName(), ctx.DeviceConfig().DeviceArch()) @@ -1510,7 +1523,15 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext // TODO: Handle EXTERNAL // Sign or align the package if package has not been preprocessed - if a.preprocessed { + + if a.isPrebuiltFrameworkRes() { + a.outputFile = srcApk + certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx) + if len(certificates) != 1 { + ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates) + } + a.certificate = certificates[0] + } else if a.preprocessed { a.outputFile = srcApk a.certificate = PresignedCertificate } else if !Bool(a.properties.Presigned) { @@ -1596,6 +1617,71 @@ func (a *AndroidAppImport) minSdkVersion() sdkSpec { return sdkSpecFrom("") } +func (a *AndroidAppImport) HeaderJars() android.Paths { + return nil +} + +func (a *AndroidAppImport) ImplementationAndResourcesJars() android.Paths { + return nil +} + +func (a *AndroidAppImport) ImplementationJars() android.Paths { + return nil +} + +func (a *AndroidAppImport) ResourceJars() android.Paths { + return nil +} + +func (a *AndroidAppImport) DexJar() android.Path { + return nil +} + +func (a *AndroidAppImport) AidlIncludeDirs() android.Paths { + return nil +} + +func (a *AndroidAppImport) ExportedSdkLibs() []string { + return nil +} + +func (a *AndroidAppImport) ExportedPlugins() (android.Paths, []string) { + return nil, nil +} + +func (a *AndroidAppImport) SrcJarArgs() ([]string, android.Paths) { + return nil, nil +} + +func (a *AndroidAppImport) ExportPackage() android.Path { + if Bool(a.properties.Export_package_resources) { + return a.outputFile + } + return nil +} + +func (a *AndroidAppImport) ExportedProguardFlagFiles() android.Paths { + return nil +} + +func (a *AndroidAppImport) ExportedRRODirs() []rroDir { + return nil +} + +func (a *AndroidAppImport) ExportedStaticPackages() android.Paths { + return nil +} + +func (a *AndroidAppImport) ExportedManifests() android.Paths { + return nil +} + +func (a *AndroidAppImport) ExportedAssets() android.OptionalPath { + return android.OptionalPath{} +} + +var _ AndroidLibraryDependency = (*AndroidAppImport)(nil) + func createVariantGroupType(variants []string, variantGroupName string) reflect.Type { props := reflect.TypeOf((*AndroidAppImportProperties)(nil)) diff --git a/java/app_test.go b/java/app_test.go index 8ef315206..513767d34 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -2374,6 +2374,69 @@ func TestAndroidAppImport_ArchVariants(t *testing.T) { } } +func TestAndroidAppImport_frameworkRes(t *testing.T) { + ctx, config := testJava(t, ` + android_app_import { + name: "framework-res", + certificate: "platform", + apk: "package-res.apk", + prefer: true, + export_package_resources: true, + // Disable dexpreopt and verify_uses_libraries check as the app + // contains no Java code to be dexpreopted. + enforce_uses_libs: false, + dex_preopt: { + enabled: false, + }, + } + `) + + mod := ctx.ModuleForTests("prebuilt_framework-res", "android_common").Module() + a := mod.(*AndroidAppImport) + + if !a.preprocessed { + t.Errorf("prebuilt framework-res is not preprocessed") + } + + expectedInstallPath := buildDir + "/target/product/test_device/system/framework/framework-res.apk" + + if a.dexpreopter.installPath.String() != expectedInstallPath { + t.Errorf("prebuilt framework-res installed to incorrect location, actual: %s, expected: %s", a.dexpreopter.installPath, expectedInstallPath) + + } + + entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0] + + expectedPath := "." + // From apk property above, in the root of the source tree. + expectedPrebuiltModuleFile := "package-res.apk" + // Verify that the apk is preprocessed: The export package is the same + // as the prebuilt. + expectedSoongResourceExportPackage := expectedPrebuiltModuleFile + + actualPath := entries.EntryMap["LOCAL_PATH"] + actualPrebuiltModuleFile := entries.EntryMap["LOCAL_PREBUILT_MODULE_FILE"] + actualSoongResourceExportPackage := entries.EntryMap["LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE"] + + if len(actualPath) != 1 { + t.Errorf("LOCAL_PATH incorrect len %d", len(actualPath)) + } else if actualPath[0] != expectedPath { + t.Errorf("LOCAL_PATH mismatch, actual: %s, expected: %s", actualPath[0], expectedPath) + } + + if len(actualPrebuiltModuleFile) != 1 { + t.Errorf("LOCAL_PREBUILT_MODULE_FILE incorrect len %d", len(actualPrebuiltModuleFile)) + } else if actualPrebuiltModuleFile[0] != expectedPrebuiltModuleFile { + t.Errorf("LOCAL_PREBUILT_MODULE_FILE mismatch, actual: %s, expected: %s", actualPrebuiltModuleFile[0], expectedPrebuiltModuleFile) + } + + if len(actualSoongResourceExportPackage) != 1 { + t.Errorf("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE incorrect len %d", len(actualSoongResourceExportPackage)) + } else if actualSoongResourceExportPackage[0] != expectedSoongResourceExportPackage { + t.Errorf("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE mismatch, actual: %s, expected: %s", actualSoongResourceExportPackage[0], expectedSoongResourceExportPackage) + } +} + func TestAndroidTestImport(t *testing.T) { ctx, config := testJava(t, ` android_test_import { diff --git a/java/dex.go b/java/dex.go index 9e61e95ad..cd45a9319 100644 --- a/java/dex.go +++ b/java/dex.go @@ -24,6 +24,60 @@ import ( "android/soong/remoteexec" ) +type DexProperties struct { + // If set to true, compile dex regardless of installable. Defaults to false. + Compile_dex *bool + + // list of module-specific flags that will be used for dex compiles + Dxflags []string `android:"arch_variant"` + + Optimize struct { + // If false, disable all optimization. Defaults to true for android_app and android_test + // modules, false for java_library and java_test modules. + Enabled *bool + // True if the module containing this has it set by default. + EnabledByDefault bool `blueprint:"mutated"` + + // If true, optimize for size by removing unused code. Defaults to true for apps, + // false for libraries and tests. + Shrink *bool + + // If true, optimize bytecode. Defaults to false. + Optimize *bool + + // If true, obfuscate bytecode. Defaults to false. + Obfuscate *bool + + // If true, do not use the flag files generated by aapt that automatically keep + // classes referenced by the app manifest. Defaults to false. + No_aapt_flags *bool + + // Flags to pass to proguard. + Proguard_flags []string + + // Specifies the locations of files containing proguard flags. + Proguard_flags_files []string `android:"path"` + } + + // Keep the data uncompressed. We always need uncompressed dex for execution, + // so this might actually save space by avoiding storing the same data twice. + // This defaults to reasonable value based on module and should not be set. + // It exists only to support ART tests. + Uncompress_dex *bool +} + +type dexer struct { + dexProperties DexProperties + + // list of extra proguard flag files + extraProguardFlagFiles android.Paths + proguardDictionary android.OptionalPath +} + +func (d *dexer) effectiveOptimizeEnabled() bool { + return BoolDefault(d.dexProperties.Optimize.Enabled, d.dexProperties.Optimize.EnabledByDefault) +} + var d8, d8RE = remoteexec.MultiCommandStaticRules(pctx, "d8", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + @@ -86,8 +140,8 @@ var r8, r8RE = remoteexec.MultiCommandStaticRules(pctx, "r8", }, }, []string{"outDir", "outDict", "r8Flags", "zipFlags"}, []string{"implicits"}) -func (j *Module) dexCommonFlags(ctx android.ModuleContext) []string { - flags := j.deviceProperties.Dxflags +func (d *dexer) dexCommonFlags(ctx android.ModuleContext, minSdkVersion sdkSpec) []string { + flags := d.dexProperties.Dxflags // Translate all the DX flags to D8 ones until all the build files have been migrated // to D8 flags. See: b/69377755 flags = android.RemoveListFromList(flags, @@ -103,30 +157,27 @@ func (j *Module) dexCommonFlags(ctx android.ModuleContext) []string { "--verbose") } - minSdkVersion, err := j.minSdkVersion().effectiveVersion(ctx) + effectiveVersion, err := minSdkVersion.effectiveVersion(ctx) if err != nil { ctx.PropertyErrorf("min_sdk_version", "%s", err) } - flags = append(flags, "--min-api "+minSdkVersion.asNumberString()) + flags = append(flags, "--min-api "+effectiveVersion.asNumberString()) return flags } -func (j *Module) d8Flags(ctx android.ModuleContext, flags javaBuilderFlags) ([]string, android.Paths) { - d8Flags := j.dexCommonFlags(ctx) - +func d8Flags(flags javaBuilderFlags) (d8Flags []string, d8Deps android.Paths) { d8Flags = append(d8Flags, flags.bootClasspath.FormRepeatedClassPath("--lib ")...) d8Flags = append(d8Flags, flags.classpath.FormRepeatedClassPath("--lib ")...) - var d8Deps android.Paths d8Deps = append(d8Deps, flags.bootClasspath...) d8Deps = append(d8Deps, flags.classpath...) return d8Flags, d8Deps } -func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Flags []string, r8Deps android.Paths) { - opt := j.deviceProperties.Optimize +func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Flags []string, r8Deps android.Paths) { + opt := d.dexProperties.Optimize // When an app contains references to APIs that are not in the SDK specified by // its LOCAL_SDK_VERSION for example added by support library or by runtime @@ -140,8 +191,6 @@ func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8F proguardRaiseDeps = append(proguardRaiseDeps, dep.(Dependency).HeaderJars()...) }) - r8Flags = append(r8Flags, j.dexCommonFlags(ctx)...) - r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars")) r8Flags = append(r8Flags, flags.bootClasspath.FormJavaClassPath("-libraryjars")) r8Flags = append(r8Flags, flags.classpath.FormJavaClassPath("-libraryjars")) @@ -154,15 +203,10 @@ func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8F android.PathForSource(ctx, "build/make/core/proguard.flags"), } - if j.shouldInstrumentStatic(ctx) { - flagFiles = append(flagFiles, - android.PathForSource(ctx, "build/make/core/proguard.jacoco.flags")) - } - - flagFiles = append(flagFiles, j.extraProguardFlagFiles...) + flagFiles = append(flagFiles, d.extraProguardFlagFiles...) // TODO(ccross): static android library proguard files - flagFiles = append(flagFiles, android.PathsForModuleSrc(ctx, j.deviceProperties.Optimize.Proguard_flags_files)...) + flagFiles = append(flagFiles, android.PathsForModuleSrc(ctx, opt.Proguard_flags_files)...) r8Flags = append(r8Flags, android.JoinWithPrefix(flagFiles.Strings(), "-include ")) r8Deps = append(r8Deps, flagFiles...) @@ -171,7 +215,7 @@ func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8F r8Deps = append(r8Deps, android.PathForSource(ctx, "build/make/core/proguard_basic_keeps.flags")) - r8Flags = append(r8Flags, j.deviceProperties.Optimize.Proguard_flags...) + r8Flags = append(r8Flags, opt.Proguard_flags...) // TODO(ccross): Don't shrink app instrumentation tests by default. if !Bool(opt.Shrink) { @@ -197,29 +241,30 @@ func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8F return r8Flags, r8Deps } -func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, +func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, minSdkVersion sdkSpec, classesJar android.Path, jarName string) android.ModuleOutPath { - useR8 := j.deviceProperties.EffectiveOptimizeEnabled() - // Compile classes.jar into classes.dex and then javalib.jar javalibJar := android.PathForModuleOut(ctx, "dex", jarName) outDir := android.PathForModuleOut(ctx, "dex") zipFlags := "--ignore_missing_files" - if proptools.Bool(j.deviceProperties.Uncompress_dex) { + if proptools.Bool(d.dexProperties.Uncompress_dex) { zipFlags += " -L 0" } + commonFlags := d.dexCommonFlags(ctx, minSdkVersion) + + useR8 := d.effectiveOptimizeEnabled() if useR8 { proguardDictionary := android.PathForModuleOut(ctx, "proguard_dictionary") - j.proguardDictionary = proguardDictionary - r8Flags, r8Deps := j.r8Flags(ctx, flags) + d.proguardDictionary = android.OptionalPathForPath(proguardDictionary) + r8Flags, r8Deps := d.r8Flags(ctx, flags) rule := r8 args := map[string]string{ - "r8Flags": strings.Join(r8Flags, " "), + "r8Flags": strings.Join(append(commonFlags, r8Flags...), " "), "zipFlags": zipFlags, - "outDict": j.proguardDictionary.String(), + "outDict": proguardDictionary.String(), "outDir": outDir.String(), } if ctx.Config().IsEnvTrue("RBE_R8") { @@ -236,7 +281,7 @@ func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, Args: args, }) } else { - d8Flags, d8Deps := j.d8Flags(ctx, flags) + d8Flags, d8Deps := d8Flags(flags) rule := d8 if ctx.Config().IsEnvTrue("RBE_D8") { rule = d8RE @@ -248,13 +293,13 @@ func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, Input: classesJar, Implicits: d8Deps, Args: map[string]string{ - "d8Flags": strings.Join(d8Flags, " "), + "d8Flags": strings.Join(append(commonFlags, d8Flags...), " "), "zipFlags": zipFlags, "outDir": outDir.String(), }, }) } - if proptools.Bool(j.deviceProperties.Uncompress_dex) { + if proptools.Bool(d.dexProperties.Uncompress_dex) { alignedJavalibJar := android.PathForModuleOut(ctx, "aligned", jarName) TransformZipAlign(ctx, alignedJavalibJar, javalibJar) javalibJar = alignedJavalibJar diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index 95dd0bb09..9a0729d20 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -66,6 +66,19 @@ func (h *hiddenAPISingleton) GenerateBuildActions(ctx android.SingletonContext) stubFlagsRule(ctx) + // If there is a prebuilt hiddenapi dir, generate rules to use the + // files within. Generally, we build the hiddenapi files from source + // during the build, ensuring consistency. It's possible, in a split + // build (framework and vendor) scenario, for the vendor build to use + // prebuilt hiddenapi files from the framework build. In this scenario, + // the framework and vendor builds must use the same source to ensure + // consistency. + + if ctx.Config().PrebuiltHiddenApiDir(ctx) != "" { + h.flags = prebuiltFlagsRule(ctx) + return + } + // These rules depend on files located in frameworks/base, skip them if running in a tree that doesn't have them. if ctx.Config().FrameworksBaseDirExists(ctx) { h.flags = flagsRule(ctx) @@ -163,6 +176,7 @@ func stubFlagsRule(ctx android.SingletonContext) { return } } + bootDexJars = append(bootDexJars, jar) } } @@ -216,6 +230,19 @@ func moduleForGreyListRemovedApis(ctx android.SingletonContext, module android.M } } +func prebuiltFlagsRule(ctx android.SingletonContext) android.Path { + outputPath := hiddenAPISingletonPaths(ctx).flags + inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-flags.csv") + + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Output: outputPath, + Input: inputPath, + }) + + return outputPath +} + // flagsRule creates a rule to build hiddenapi-flags.csv out of flags.csv files generated for boot image modules and // the greylists. func flagsRule(ctx android.SingletonContext) android.Path { @@ -397,6 +424,20 @@ func (h *hiddenAPIIndexSingleton) GenerateBuildActions(ctx android.SingletonCont return } + if ctx.Config().PrebuiltHiddenApiDir(ctx) != "" { + outputPath := hiddenAPISingletonPaths(ctx).index + inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-index.csv") + + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Output: outputPath, + Input: inputPath, + }) + + h.index = outputPath + return + } + indexes := android.Paths{} ctx.VisitAllModules(func(module android.Module) { if h, ok := module.(hiddenAPIIntf); ok { diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go new file mode 100644 index 000000000..e4dc03794 --- /dev/null +++ b/java/hiddenapi_singleton_test.go @@ -0,0 +1,182 @@ +// Copyright 2020 Google Inc. All rights reserved. +// +// 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 java + +import ( + "android/soong/android" + "strings" + "testing" +) + +func testConfigWithBootJars(bp string, bootJars []string, prebuiltHiddenApiDir *string) android.Config { + config := testConfig(nil, bp, nil) + config.TestProductVariables.BootJars = bootJars + config.TestProductVariables.PrebuiltHiddenApiDir = prebuiltHiddenApiDir + return config +} + +func testContextWithHiddenAPI() *android.TestContext { + ctx := testContext() + ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory) + return ctx +} + +func testHiddenAPI(t *testing.T, bp string, bootJars []string, prebuiltHiddenApiDir *string) (*android.TestContext, android.Config) { + t.Helper() + + config := testConfigWithBootJars(bp, bootJars, prebuiltHiddenApiDir) + ctx := testContextWithHiddenAPI() + + run(t, ctx, config) + + return ctx, config +} + +func TestHiddenAPISingleton(t *testing.T) { + ctx, _ := testHiddenAPI(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + } + `, []string{"foo"}, nil) + + hiddenAPI := ctx.SingletonForTests("hiddenapi") + hiddenapiRule := hiddenAPI.Rule("hiddenapi") + want := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar" + if !strings.Contains(hiddenapiRule.RuleParams.Command, want) { + t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", want, hiddenapiRule.RuleParams.Command) + } +} + +func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { + ctx, _ := testHiddenAPI(t, ` + java_import { + name: "foo", + jars: ["a.jar"], + compile_dex: true, + } + `, []string{"foo"}, nil) + + hiddenAPI := ctx.SingletonForTests("hiddenapi") + hiddenapiRule := hiddenAPI.Rule("hiddenapi") + want := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar" + if !strings.Contains(hiddenapiRule.RuleParams.Command, want) { + t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", want, hiddenapiRule.RuleParams.Command) + } +} + +func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { + ctx, _ := testHiddenAPI(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + } + + java_import { + name: "foo", + jars: ["a.jar"], + compile_dex: true, + prefer: false, + } + `, []string{"foo"}, nil) + + hiddenAPI := ctx.SingletonForTests("hiddenapi") + hiddenapiRule := hiddenAPI.Rule("hiddenapi") + fromSourceJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar" + if !strings.Contains(hiddenapiRule.RuleParams.Command, fromSourceJarArg) { + t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", fromSourceJarArg, hiddenapiRule.RuleParams.Command) + } + + prebuiltJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/dex/foo.jar" + if strings.Contains(hiddenapiRule.RuleParams.Command, prebuiltJarArg) { + t.Errorf("Did not expect %s in hiddenapi command, but it was present: %s", prebuiltJarArg, hiddenapiRule.RuleParams.Command) + } +} + +func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) { + ctx, _ := testHiddenAPI(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + } + + java_import { + name: "foo", + jars: ["a.jar"], + compile_dex: true, + prefer: true, + } + `, []string{"foo"}, nil) + + hiddenAPI := ctx.SingletonForTests("hiddenapi") + hiddenapiRule := hiddenAPI.Rule("hiddenapi") + prebuiltJarArg := "--boot-dex=" + buildDir + "/.intermediates/prebuilt_foo/android_common/dex/foo.jar" + if !strings.Contains(hiddenapiRule.RuleParams.Command, prebuiltJarArg) { + t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", prebuiltJarArg, hiddenapiRule.RuleParams.Command) + } + + fromSourceJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar" + if strings.Contains(hiddenapiRule.RuleParams.Command, fromSourceJarArg) { + t.Errorf("Did not expect %s in hiddenapi command, but it was present: %s", fromSourceJarArg, hiddenapiRule.RuleParams.Command) + } +} + +func TestHiddenAPISingletonWithPrebuiltCsvFile(t *testing.T) { + + // The idea behind this test is to ensure that when the build is + // confugured with a PrebuiltHiddenApiDir that the rules for the + // hiddenapi singleton copy the prebuilts to the typical output + // location, and then use that output location for the hiddenapi encode + // dex step. + + // Where to find the prebuilt hiddenapi files: + prebuiltHiddenApiDir := "path/to/prebuilt/hiddenapi" + + ctx, _ := testHiddenAPI(t, ` + java_import { + name: "foo", + jars: ["a.jar"], + compile_dex: true, + } + `, []string{"foo"}, &prebuiltHiddenApiDir) + + expectedCpInput := prebuiltHiddenApiDir + "/hiddenapi-flags.csv" + expectedCpOutput := buildDir + "/hiddenapi/hiddenapi-flags.csv" + expectedFlagsCsv := buildDir + "/hiddenapi/hiddenapi-flags.csv" + + foo := ctx.ModuleForTests("foo", "android_common") + + hiddenAPI := ctx.SingletonForTests("hiddenapi") + cpRule := hiddenAPI.Rule("Cp") + actualCpInput := cpRule.BuildParams.Input + actualCpOutput := cpRule.BuildParams.Output + encodeDexRule := foo.Rule("hiddenAPIEncodeDex") + actualFlagsCsv := encodeDexRule.BuildParams.Args["flagsCsv"] + + if actualCpInput.String() != expectedCpInput { + t.Errorf("Prebuilt hiddenapi cp rule input mismatch, actual: %s, expected: %s", actualCpInput, expectedCpInput) + } + + if actualCpOutput.String() != expectedCpOutput { + t.Errorf("Prebuilt hiddenapi cp rule output mismatch, actual: %s, expected: %s", actualCpOutput, expectedCpOutput) + } + + if actualFlagsCsv != expectedFlagsCsv { + t.Errorf("Prebuilt hiddenapi encode dex rule flags csv mismatch, actual: %s, expected: %s", actualFlagsCsv, expectedFlagsCsv) + } +} diff --git a/java/java.go b/java/java.go index 69826eec3..adeb0f7cc 100644 --- a/java/java.go +++ b/java/java.go @@ -259,9 +259,6 @@ type CompilerProperties struct { } type CompilerDeviceProperties struct { - // list of module-specific flags that will be used for dex compiles - Dxflags []string `android:"arch_variant"` - // if not blank, set to the version of the sdk to compile against. // Defaults to compiling against the current platform. Sdk_version *string @@ -307,37 +304,6 @@ type CompilerDeviceProperties struct { } } - // If set to true, compile dex regardless of installable. Defaults to false. - Compile_dex *bool - - Optimize struct { - // If false, disable all optimization. Defaults to true for android_app and android_test - // modules, false for java_library and java_test modules. - Enabled *bool - // True if the module containing this has it set by default. - EnabledByDefault bool `blueprint:"mutated"` - - // If true, optimize for size by removing unused code. Defaults to true for apps, - // false for libraries and tests. - Shrink *bool - - // If true, optimize bytecode. Defaults to false. - Optimize *bool - - // If true, obfuscate bytecode. Defaults to false. - Obfuscate *bool - - // If true, do not use the flag files generated by aapt that automatically keep - // classes referenced by the app manifest. Defaults to false. - No_aapt_flags *bool - - // Flags to pass to proguard. - Proguard_flags []string - - // Specifies the locations of files containing proguard flags. - Proguard_flags_files []string `android:"path"` - } - // When targeting 1.9 and above, override the modules to use with --system, // otherwise provides defaults libraries to add to the bootclasspath. System_modules *string @@ -351,12 +317,6 @@ type CompilerDeviceProperties struct { // set the name of the output Stem *string - // Keep the data uncompressed. We always need uncompressed dex for execution, - // so this might actually save space by avoiding storing the same data twice. - // This defaults to reasonable value based on module and should not be set. - // It exists only to support ART tests. - Uncompress_dex *bool - IsSDKLibrary bool `blueprint:"mutated"` // If true, generate the signature file of APK Signing Scheme V4, along side the signed APK file. @@ -364,10 +324,6 @@ type CompilerDeviceProperties struct { V4_signature *bool } -func (me *CompilerDeviceProperties) EffectiveOptimizeEnabled() bool { - return BoolDefault(me.Optimize.Enabled, me.Optimize.EnabledByDefault) -} - // Functionality common to Module and Import // // It is embedded in Module so its functionality can be used by methods in Module @@ -436,9 +392,6 @@ type Module struct { // output file containing uninstrumented classes that will be instrumented by jacoco jacocoReportClassesFile android.Path - // output file containing mapping of obfuscated names - proguardDictionary android.Path - // output file of the module, which may be a classes jar or a dex jar outputFile android.Path extraOutputFiles android.Paths @@ -454,9 +407,6 @@ type Module struct { compiledJavaSrcs android.Paths compiledSrcJars android.Paths - // list of extra progurad flag files - extraProguardFlagFiles android.Paths - // manifest file to use instead of properties.Manifest overrideManifest android.OptionalPath @@ -483,6 +433,7 @@ type Module struct { extraResources android.Paths hiddenAPI + dexer dexpreopter linter @@ -503,6 +454,7 @@ func (j *Module) addHostAndDeviceProperties() { j.addHostProperties() j.AddProperties( &j.deviceProperties, + &j.dexer.dexProperties, &j.dexpreoptProperties, &j.linter.properties, ) @@ -515,7 +467,10 @@ func (j *Module) OutputFiles(tag string) (android.Paths, error) { case ".jar": return android.Paths{j.implementationAndResourcesJar}, nil case ".proguard_map": - return android.Paths{j.proguardDictionary}, nil + if j.dexer.proguardDictionary.Valid() { + return android.Paths{j.dexer.proguardDictionary.Path()}, nil + } + return nil, fmt.Errorf("%q was requested, but no output file was found.", tag) default: return nil, fmt.Errorf("unsupported module reference tag %q", tag) } @@ -644,6 +599,21 @@ func (j *Module) shouldInstrumentStatic(ctx android.BaseModuleContext) bool { ctx.Config().UnbundledBuild()) } +func (j *Module) shouldInstrumentInApex(ctx android.BaseModuleContext) bool { + // Force enable the instrumentation for java code that is built for APEXes ... + // except for the jacocoagent itself (because instrumenting jacocoagent using jacocoagent + // doesn't make sense) or framework libraries (e.g. libraries found in the InstrumentFrameworkModules list) unless EMMA_INSTRUMENT_FRAMEWORK is true. + isJacocoAgent := ctx.ModuleName() == "jacocoagent" + if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !isJacocoAgent && !j.IsForPlatform() { + if !inList(ctx.ModuleName(), config.InstrumentFrameworkModules) { + return true + } else if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") { + return true + } + } + return false +} + func (j *Module) sdkVersion() sdkSpec { return sdkSpecFrom(String(j.deviceProperties.Sdk_version)) } @@ -680,28 +650,32 @@ func (j *Module) AvailableFor(what string) bool { return j.ApexModuleBase.AvailableFor(what) } +func sdkDeps(ctx android.BottomUpMutatorContext, sdkContext sdkContext, d dexer) { + sdkDep := decodeSdkDep(ctx, sdkContext) + if sdkDep.useDefaultLibs { + ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...) + ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules) + if sdkDep.hasFrameworkLibs() { + ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...) + } + } else if sdkDep.useModule { + ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...) + ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...) + if d.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() { + ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultBootclasspathLibraries...) + ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultLibraries...) + } + } + if sdkDep.systemModules != "" { + ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules) + } +} + func (j *Module) deps(ctx android.BottomUpMutatorContext) { if ctx.Device() { j.linter.deps(ctx) - sdkDep := decodeSdkDep(ctx, sdkContext(j)) - if sdkDep.useDefaultLibs { - ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...) - ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules) - if sdkDep.hasFrameworkLibs() { - ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...) - } - } else if sdkDep.useModule { - ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...) - ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...) - if j.deviceProperties.EffectiveOptimizeEnabled() && sdkDep.hasStandardLibs() { - ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultBootclasspathLibraries...) - ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultLibraries...) - } - } - if sdkDep.systemModules != "" { - ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules) - } + sdkDeps(ctx, sdkContext(j), j.dexer) } syspropPublicStubs := syspropPublicStubs(ctx.Config()) @@ -1564,11 +1538,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { j.headerJarFile = j.implementationJarFile } - // Force enable the instrumentation for java code that is built for APEXes ... - // except for the jacocoagent itself (because instrumenting jacocoagent using jacocoagent - // doesn't make sense) - isJacocoAgent := ctx.ModuleName() == "jacocoagent" - if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !isJacocoAgent && !j.IsForPlatform() { + if j.shouldInstrumentInApex(ctx) { j.properties.Instrument = true } @@ -1590,8 +1560,8 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // Enable dex compilation for the APEX variants, unless it is disabled explicitly if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !j.IsForPlatform() { - if j.deviceProperties.Compile_dex == nil { - j.deviceProperties.Compile_dex = proptools.BoolPtr(true) + if j.dexProperties.Compile_dex == nil { + j.dexProperties.Compile_dex = proptools.BoolPtr(true) } if j.deviceProperties.Hostdex == nil { j.deviceProperties.Hostdex = proptools.BoolPtr(true) @@ -1599,10 +1569,14 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } if ctx.Device() && j.hasCode(ctx) && - (Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) { + (Bool(j.properties.Installable) || Bool(j.dexProperties.Compile_dex)) { + if j.shouldInstrumentStatic(ctx) { + j.dexer.extraProguardFlagFiles = append(j.dexer.extraProguardFlagFiles, + android.PathForSource(ctx, "build/make/core/proguard.jacoco.flags")) + } // Dex compilation var dexOutputFile android.ModuleOutPath - dexOutputFile = j.compileDex(ctx, flags, outputFile, jarName) + dexOutputFile = j.dexer.compileDex(ctx, flags, j.minSdkVersion(), outputFile, jarName) if ctx.Failed() { return } @@ -1610,9 +1584,25 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { configurationName := j.ConfigurationName() primary := configurationName == ctx.ModuleName() + // A source module that has been replaced by a prebuilt can never be the primary module + // as long as the prebuilt actually provides a build dex jar. If it doesn't then use + // the source module for now. + if j.IsReplacedByPrebuilt() { + ctx.VisitDirectDepsWithTag(android.PrebuiltDepTag, func(prebuilt android.Module) { + if h, ok := prebuilt.(hiddenAPIIntf); ok && h.bootDexJar() != nil { + // It is safe to ignore the source module as the prebuilt module provides an + // appropriate boot dex jar. + primary = false + } else { + // The prebuilt doesn't provide a suitable boot dex jar so keep using the + // source module instead. + } + }) + } + // Hidden API CSV generation and dex encoding dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, j.implementationJarFile, - proptools.Bool(j.deviceProperties.Uncompress_dex)) + proptools.Bool(j.dexProperties.Uncompress_dex)) // merge dex jar with resources if necessary if j.resourceJar != nil { @@ -1620,7 +1610,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { combinedJar := android.PathForModuleOut(ctx, "dex-withres", jarName) TransformJarsToJar(ctx, combinedJar, "for dex resources", jars, android.OptionalPath{}, false, nil, nil) - if *j.deviceProperties.Uncompress_dex { + if *j.dexProperties.Uncompress_dex { combinedAlignedJar := android.PathForModuleOut(ctx, "dex-withres-aligned", jarName) TransformZipAlign(ctx, combinedAlignedJar, combinedJar) dexOutputFile = combinedAlignedJar @@ -1937,11 +1927,11 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.checkSdkVersions(ctx) j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar") j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary - if j.deviceProperties.Uncompress_dex == nil { + if j.dexProperties.Uncompress_dex == nil { // If the value was not force-set by the user, use reasonable default based on the module. - j.deviceProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter)) + j.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter)) } - j.dexpreopter.uncompressedDex = *j.deviceProperties.Uncompress_dex + j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex j.compile(ctx, nil) exclusivelyForApex := android.InAnyApex(ctx.ModuleName()) && !j.IsForPlatform() @@ -2178,6 +2168,7 @@ type JavaTestImport struct { prebuiltTestProperties prebuiltTestProperties testConfig android.Path + dexJarFile android.Path } func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -2476,8 +2467,15 @@ type Import struct { // Functionality common to Module and Import. embeddableInModuleAndImport + hiddenAPI + dexer + dexpreopter + properties ImportProperties + // output file containing classes.dex and resources + dexJarFile android.Path + combinedClasspathFile android.Path exportedSdkLibs []string } @@ -2486,10 +2484,22 @@ func (j *Import) sdkVersion() sdkSpec { return sdkSpecFrom(String(j.properties.Sdk_version)) } +func (j *Import) makeSdkVersion() string { + return j.sdkVersion().raw +} + +func (j *Import) systemModules() string { + return "none" +} + func (j *Import) minSdkVersion() sdkSpec { return j.sdkVersion() } +func (j *Import) targetSdkVersion() sdkSpec { + return j.sdkVersion() +} + func (j *Import) MinSdkVersion() string { return j.minSdkVersion().version.String() } @@ -2514,8 +2524,16 @@ func (a *Import) JacocoReportClassesFile() android.Path { return nil } +func (j *Import) LintDepSets() LintDepSets { + return LintDepSets{} +} + func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...) + + if ctx.Device() && Bool(j.dexProperties.Compile_dex) { + sdkDeps(ctx, sdkContext(j), j.dexer) + } } func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -2538,6 +2556,8 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { // added to the Android manifest. j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...) + var flags javaBuilderFlags + ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) @@ -2546,12 +2566,16 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { case Dependency: switch tag { case libTag, staticLibTag: + flags.classpath = append(flags.classpath, dep.HeaderJars()...) // sdk lib names from dependencies are re-exported j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...) + case bootClasspathTag: + flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars()...) } case SdkLibraryDependency: switch tag { case libTag: + flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) // names of sdk libs that are directly depended are exported j.exportedSdkLibs = append(j.exportedSdkLibs, otherName) } @@ -2563,6 +2587,41 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"), jarName, outputFile) } + + if ctx.Device() && Bool(j.dexProperties.Compile_dex) { + sdkDep := decodeSdkDep(ctx, sdkContext(j)) + if sdkDep.invalidVersion { + ctx.AddMissingDependencies(sdkDep.bootclasspath) + ctx.AddMissingDependencies(sdkDep.java9Classpath) + } else if sdkDep.useFiles { + // sdkDep.jar is actually equivalent to turbine header.jar. + flags.classpath = append(flags.classpath, sdkDep.jars...) + } + + // Dex compilation + + j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", jarName) + if j.dexProperties.Uncompress_dex == nil { + // If the value was not force-set by the user, use reasonable default based on the module. + j.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter)) + } + j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex + + var dexOutputFile android.ModuleOutPath + dexOutputFile = j.dexer.compileDex(ctx, flags, j.minSdkVersion(), outputFile, jarName) + if ctx.Failed() { + return + } + + configurationName := j.BaseModuleName() + primary := j.Prebuilt().UsePrebuilt() + + // Hidden API CSV generation and dex encoding + dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, outputFile, + proptools.Bool(j.dexProperties.Uncompress_dex)) + + j.dexJarFile = dexOutputFile + } } var _ Dependency = (*Import)(nil) @@ -2593,7 +2652,7 @@ func (j *Import) ImplementationAndResourcesJars() android.Paths { } func (j *Import) DexJar() android.Path { - return nil + return j.dexJarFile } func (j *Import) AidlIncludeDirs() android.Paths { @@ -2642,6 +2701,12 @@ func (j *Import) IDECustomizedModuleName() string { var _ android.PrebuiltInterface = (*Import)(nil) +func (j *Import) IsInstallable() bool { + return Bool(j.properties.Installable) +} + +var _ dexpreopterInterface = (*Import)(nil) + // java_import imports one or more `.jar` files into the build graph as if they were built by a java_library module. // // By default, a java_import has a single variant that expects a `.jar` file containing `.class` files that were @@ -2652,10 +2717,15 @@ var _ android.PrebuiltInterface = (*Import)(nil) func ImportFactory() android.Module { module := &Import{} - module.AddProperties(&module.properties) + module.AddProperties( + &module.properties, + &module.dexer.dexProperties, + ) module.initModuleAndImport(&module.ModuleBase) + module.dexProperties.Optimize.EnabledByDefault = false + android.InitPrebuiltModule(module, &module.properties.Jars) android.InitApexModule(module) android.InitSdkAwareModule(module) @@ -2854,6 +2924,7 @@ func DefaultsFactory() android.Module { module.AddProperties( &CompilerProperties{}, &CompilerDeviceProperties{}, + &DexProperties{}, &DexpreoptProperties{}, &android.ProtoProperties{}, &aaptProperties{}, diff --git a/java/java_test.go b/java/java_test.go index 8797119b5..97ec42660 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -30,7 +30,6 @@ import ( "android/soong/android" "android/soong/cc" "android/soong/dexpreopt" - "android/soong/genrule" ) var buildDir string @@ -80,7 +79,6 @@ func testContext() *android.TestContext { RegisterSystemModulesBuildComponents(ctx) ctx.RegisterModuleType("java_plugin", PluginFactory) ctx.RegisterModuleType("filegroup", android.FileGroupFactory) - ctx.RegisterModuleType("genrule", genrule.GenRuleFactory) RegisterDocsBuildComponents(ctx) RegisterStubsBuildComponents(ctx) RegisterSdkLibraryBuildComponents(ctx) @@ -486,6 +484,8 @@ func TestPrebuilts(t *testing.T) { java_import { name: "baz", jars: ["b.jar"], + sdk_version: "current", + compile_dex: true, } dex_import { @@ -516,8 +516,10 @@ func TestPrebuilts(t *testing.T) { fooModule := ctx.ModuleForTests("foo", "android_common") javac := fooModule.Rule("javac") combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac") - barJar := ctx.ModuleForTests("bar", "android_common").Rule("combineJar").Output - bazJar := ctx.ModuleForTests("baz", "android_common").Rule("combineJar").Output + barModule := ctx.ModuleForTests("bar", "android_common") + barJar := barModule.Rule("combineJar").Output + bazModule := ctx.ModuleForTests("baz", "android_common") + bazJar := bazModule.Rule("combineJar").Output sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").Rule("combineJar").Output fooLibrary := fooModule.Module().(*Library) @@ -532,6 +534,11 @@ func TestPrebuilts(t *testing.T) { t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barJar.String()) } + barDexJar := barModule.Module().(*Import).DexJar() + if barDexJar != nil { + t.Errorf("bar dex jar build path expected to be nil, got %q", barDexJar) + } + if !strings.Contains(javac.Args["classpath"], sdklibStubsJar.String()) { t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], sdklibStubsJar.String()) } @@ -540,6 +547,12 @@ func TestPrebuilts(t *testing.T) { t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, bazJar.String()) } + bazDexJar := bazModule.Module().(*Import).DexJar().String() + expectedDexJar := buildDir + "/.intermediates/baz/android_common/dex/baz.jar" + if bazDexJar != expectedDexJar { + t.Errorf("baz dex jar build path expected %q, got %q", expectedDexJar, bazDexJar) + } + ctx.ModuleForTests("qux", "android_common").Rule("Cp") } diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go index 999c72f3c..bcc6cc0cf 100644 --- a/java/prebuilt_apis.go +++ b/java/prebuilt_apis.go @@ -34,6 +34,13 @@ func RegisterPrebuiltApisBuildComponents(ctx android.RegistrationContext) { type prebuiltApisProperties struct { // list of api version directories Api_dirs []string + + // The sdk_version of java_import modules generated based on jar files. + // Defaults to "current" + Imports_sdk_version *string + + // If set to true, compile dex for java_import modules. Defaults to false. + Imports_compile_dex *bool } type prebuiltApis struct { @@ -74,18 +81,19 @@ func prebuiltApiModuleName(mctx android.LoadHookContext, module string, scope st return mctx.ModuleName() + "_" + scope + "_" + apiver + "_" + module } -func createImport(mctx android.LoadHookContext, module string, scope string, apiver string, path string) { +func createImport(mctx android.LoadHookContext, module, scope, apiver, path, sdkVersion string, compileDex bool) { props := struct { Name *string Jars []string Sdk_version *string Installable *bool + Compile_dex *bool }{} props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, apiver)) props.Jars = append(props.Jars, path) - // TODO(hansson): change to scope after migration is done. - props.Sdk_version = proptools.StringPtr("current") + props.Sdk_version = proptools.StringPtr(sdkVersion) props.Installable = proptools.BoolPtr(false) + props.Compile_dex = proptools.BoolPtr(compileDex) mctx.CreateModule(ImportFactory, &props) } @@ -101,10 +109,10 @@ func createFilegroup(mctx android.LoadHookContext, module string, scope string, mctx.CreateModule(android.FileGroupFactory, &filegroupProps) } -func getPrebuiltFiles(mctx android.LoadHookContext, name string) []string { +func getPrebuiltFiles(mctx android.LoadHookContext, p *prebuiltApis, name string) []string { mydir := mctx.ModuleDir() + "/" var files []string - for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs { + for _, apiver := range p.properties.Api_dirs { for _, scope := range []string{"public", "system", "test", "core", "module-lib", "system-server"} { vfiles, err := mctx.GlobWithDeps(mydir+apiver+"/"+scope+"/"+name, nil) if err != nil { @@ -116,16 +124,19 @@ func getPrebuiltFiles(mctx android.LoadHookContext, name string) []string { return files } -func prebuiltSdkStubs(mctx android.LoadHookContext) { +func prebuiltSdkStubs(mctx android.LoadHookContext, p *prebuiltApis) { mydir := mctx.ModuleDir() + "/" // <apiver>/<scope>/<module>.jar - files := getPrebuiltFiles(mctx, "*.jar") + files := getPrebuiltFiles(mctx, p, "*.jar") + + sdkVersion := proptools.StringDefault(p.properties.Imports_sdk_version, "current") + compileDex := proptools.BoolDefault(p.properties.Imports_compile_dex, false) for _, f := range files { // create a Import module for each jar file localPath := strings.TrimPrefix(f, mydir) module, apiver, scope := parseJarPath(localPath) - createImport(mctx, module, scope, apiver, localPath) + createImport(mctx, module, scope, apiver, localPath, sdkVersion, compileDex) } } @@ -140,8 +151,8 @@ func createSystemModules(mctx android.LoadHookContext, apiver string) { mctx.CreateModule(SystemModulesFactory, &props) } -func prebuiltSdkSystemModules(mctx android.LoadHookContext) { - for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs { +func prebuiltSdkSystemModules(mctx android.LoadHookContext, p *prebuiltApis) { + for _, apiver := range p.properties.Api_dirs { jar := android.ExistentPathForSource(mctx, mctx.ModuleDir(), apiver, "public", "core-for-system-modules.jar") if jar.Valid() { @@ -150,10 +161,10 @@ func prebuiltSdkSystemModules(mctx android.LoadHookContext) { } } -func prebuiltApiFiles(mctx android.LoadHookContext) { +func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) { mydir := mctx.ModuleDir() + "/" // <apiver>/<scope>/api/<module>.txt - files := getPrebuiltFiles(mctx, "api/*.txt") + files := getPrebuiltFiles(mctx, p, "api/*.txt") if len(files) == 0 { mctx.ModuleErrorf("no api file found under %q", mydir) @@ -201,10 +212,10 @@ func prebuiltApiFiles(mctx android.LoadHookContext) { } func createPrebuiltApiModules(mctx android.LoadHookContext) { - if _, ok := mctx.Module().(*prebuiltApis); ok { - prebuiltApiFiles(mctx) - prebuiltSdkStubs(mctx) - prebuiltSdkSystemModules(mctx) + if p, ok := mctx.Module().(*prebuiltApis); ok { + prebuiltApiFiles(mctx, p) + prebuiltSdkStubs(mctx, p) + prebuiltSdkSystemModules(mctx, p) } } diff --git a/java/sdk_library.go b/java/sdk_library.go index f2a509ad2..7d973c4fb 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -1110,6 +1110,7 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) &module.properties, &module.protoProperties, &module.deviceProperties, + &module.dexProperties, &module.dexpreoptProperties, &module.linter.properties, &props, @@ -1174,8 +1175,8 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext // We compile the stubs for 1.8 in line with the main android.jar stubs, and potential // interop with older developer tools that don't support 1.9. props.Java_version = proptools.StringPtr("1.8") - if module.deviceProperties.Compile_dex != nil { - props.Compile_dex = module.deviceProperties.Compile_dex + if module.dexProperties.Compile_dex != nil { + props.Compile_dex = module.dexProperties.Compile_dex } // Dist the class jar artifact for sdk builds. diff --git a/java/testing.go b/java/testing.go index 48e449f34..500b8de7a 100644 --- a/java/testing.go +++ b/java/testing.go @@ -132,6 +132,7 @@ func GatherRequiredDepsForTest() string { srcs: ["a.java"], sdk_version: "none", system_modules: "core-platform-api-stubs-system-modules", + compile_dex: true, } `, extra) } diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go index 0bcdccb7b..e1123e088 100644 --- a/ui/build/cleanbuild.go +++ b/ui/build/cleanbuild.go @@ -104,6 +104,7 @@ func installClean(ctx Context, config Config, what int) { productOut("*.img"), productOut("*.zip"), productOut("android-info.txt"), + productOut("misc_info.txt"), productOut("apex"), productOut("kernel"), productOut("data"), diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go index 571740133..405f37969 100644 --- a/ui/build/paths/config.go +++ b/ui/build/paths/config.go @@ -74,6 +74,12 @@ func GetConfig(name string) PathConfig { } var Configuration = map[string]PathConfig{ + "aarch64-linux-android-ar": Log, + "aarch64-linux-android-gcc": Log, + "aarch64-linux-android-ld": Log, + "aarch64-linux-android-nm": Log, + "aarch64-linux-android-objcopy": Log, + "aarch64-linux-android-objdump": Log, "bash": Allowed, "dd": Allowed, "diff": Allowed, @@ -89,6 +95,8 @@ var Configuration = map[string]PathConfig{ "lsof": Allowed, "openssl": Allowed, "patch": Allowed, + "perl": Log, + "printf": Log, "pstree": Allowed, "rsync": Allowed, "sh": Allowed, @@ -110,10 +118,72 @@ var Configuration = map[string]PathConfig{ "ld.gold": Forbidden, "pkg-config": Forbidden, - // These are toybox tools that only work on Linux. - "pgrep": LinuxOnlyPrebuilt, - "pkill": LinuxOnlyPrebuilt, - "ps": LinuxOnlyPrebuilt, + // On Linux we'll use the toybox versions of these instead. + "basename": LinuxOnlyPrebuilt, + "cat": LinuxOnlyPrebuilt, + "chmod": LinuxOnlyPrebuilt, + // TODO (b/121282416): switch back to LinuxOnlyPrebuilt when build is hermetic + "cmp": Log, + // TODO (b/121282416): switch back to LinuxOnlyPrebuilt when build is hermetic + "cp": Log, + "comm": LinuxOnlyPrebuilt, + "cut": LinuxOnlyPrebuilt, + "date": LinuxOnlyPrebuilt, + // TODO (b/121282416): switch back to LinuxOnlyPrebuilt when build is hermetic + "dirname": Log, + "du": LinuxOnlyPrebuilt, + "echo": LinuxOnlyPrebuilt, + "egrep": LinuxOnlyPrebuilt, + "env": LinuxOnlyPrebuilt, + "getconf": LinuxOnlyPrebuilt, + "grep": LinuxOnlyPrebuilt, + "head": LinuxOnlyPrebuilt, + "hostname": LinuxOnlyPrebuilt, + "id": LinuxOnlyPrebuilt, + "ln": LinuxOnlyPrebuilt, + "ls": LinuxOnlyPrebuilt, + "md5sum": LinuxOnlyPrebuilt, + // TODO (b/121282416): switch back to LinuxOnlyPrebuilt when build is hermetic + "mkdir": Log, + "mktemp": LinuxOnlyPrebuilt, + "mv": LinuxOnlyPrebuilt, + "od": LinuxOnlyPrebuilt, + // TODO (b/121282416): switch back to LinuxOnlyPrebuilt when build is hermetic + "paste": Log, + "pgrep": LinuxOnlyPrebuilt, + "pkill": LinuxOnlyPrebuilt, + "ps": LinuxOnlyPrebuilt, + // TODO (b/121282416): switch back to LinuxOnlyPrebuilt when build is hermetic + "pwd": Log, + "readlink": LinuxOnlyPrebuilt, + "rm": LinuxOnlyPrebuilt, + // TODO (b/121282416): switch back to LinuxOnlyPrebuilt when build is hermetic + "rmdir": Log, + "sed": LinuxOnlyPrebuilt, + "seq": LinuxOnlyPrebuilt, + "setsid": LinuxOnlyPrebuilt, + "sha1sum": LinuxOnlyPrebuilt, + "sha256sum": LinuxOnlyPrebuilt, + "sha512sum": LinuxOnlyPrebuilt, + "sleep": LinuxOnlyPrebuilt, + "sort": LinuxOnlyPrebuilt, + "stat": LinuxOnlyPrebuilt, + // TODO (b/121282416): switch back to LinuxOnlyPrebuilt when build is hermetic + "tail": Log, + "tar": LinuxOnlyPrebuilt, + "tee": LinuxOnlyPrebuilt, + "timeout": LinuxOnlyPrebuilt, + // TODO (b/121282416): switch back to LinuxOnlyPrebuilt when build is hermetic + "touch": Log, + "true": LinuxOnlyPrebuilt, + "uname": LinuxOnlyPrebuilt, + "uniq": LinuxOnlyPrebuilt, + "unix2dos": LinuxOnlyPrebuilt, + "wc": LinuxOnlyPrebuilt, + "whoami": LinuxOnlyPrebuilt, + "which": LinuxOnlyPrebuilt, + // TODO (b/121282416): switch back to LinuxOnlyPrebuilt when build is hermetic + "xxd": Log, } func init() { diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go index 2de772b00..850ca3b1e 100644 --- a/ui/build/sandbox_linux.go +++ b/ui/build/sandbox_linux.go @@ -33,14 +33,14 @@ type Sandbox struct { var ( noSandbox = Sandbox{} basicSandbox = Sandbox{ - Enabled: true, + Enabled: false, } dumpvarsSandbox = basicSandbox katiSandbox = basicSandbox soongSandbox = basicSandbox ninjaSandbox = Sandbox{ - Enabled: true, + Enabled: false, DisableWhenUsingGoma: true, AllowBuildBrokenUsesNetwork: true, @@ -54,6 +54,9 @@ var sandboxConfig struct { working bool group string + srcDir string + outDir string + distDir string } func (c *Cmd) sandboxSupported() bool { @@ -72,15 +75,34 @@ func (c *Cmd) sandboxSupported() bool { sandboxConfig.group = "nobody" } - cmd := exec.CommandContext(c.ctx.Context, nsjailPath, + sandboxConfig.srcDir = absPath(c.ctx, ".") + sandboxConfig.outDir = absPath(c.ctx, c.config.OutDir()) + sandboxConfig.distDir = absPath(c.ctx, c.config.DistDir()) + + sandboxArgs := []string{ "-H", "android-build", "-e", "-u", "nobody", "-g", sandboxConfig.group, - "-B", "/", + "-R", "/", + "-B", sandboxConfig.srcDir, + "-B", "/tmp", + "-B", sandboxConfig.outDir, + } + + if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) { + //Mount dist dir as read-write if it already exists + sandboxArgs = append(sandboxArgs, "-B", + sandboxConfig.distDir) + } + + sandboxArgs = append(sandboxArgs, "--disable_clone_newcgroup", "--", "/bin/bash", "-c", `if [ $(hostname) == "android-build" ]; then echo "Android" "Success"; else echo Failure; fi`) + + cmd := exec.CommandContext(c.ctx.Context, nsjailPath, sandboxArgs...) + cmd.Env = c.config.Environment().Environ() c.ctx.Verboseln(cmd.Args) @@ -144,8 +166,17 @@ func (c *Cmd) wrapSandbox() { "--rlimit_fsize", "soft", "--rlimit_nofile", "soft", - // For now, just map everything. Eventually we should limit this, especially to make most things readonly. - "-B", "/", + // For now, just map everything. Make most things readonly. + "-R", "/", + + // Mount source are read-write + "-B", sandboxConfig.srcDir, + + //Mount out dir as read-write + "-B", sandboxConfig.outDir, + + // Mount a writable tmp dir + "-B", "/tmp", // Disable newcgroup for now, since it may require newer kernels // TODO: try out cgroups @@ -155,6 +186,11 @@ func (c *Cmd) wrapSandbox() { "-q", } + if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) { + //Mount dist dir as read-write if it already exists + sandboxArgs = append(sandboxArgs, "-B", sandboxConfig.distDir) + } + if c.Sandbox.AllowBuildBrokenUsesNetwork && c.config.BuildBrokenUsesNetwork() { c.ctx.Printf("AllowBuildBrokenUsesNetwork: %v", c.Sandbox.AllowBuildBrokenUsesNetwork) c.ctx.Printf("BuildBrokenUsesNetwork: %v", c.config.BuildBrokenUsesNetwork()) |