Merge "Disable CFI only on incompatible variants."
diff --git a/android/apex.go b/android/apex.go
index 026d685..eb79123 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -15,7 +15,9 @@
package android
import (
+ "fmt"
"sort"
+ "strconv"
"sync"
)
@@ -25,6 +27,8 @@
// Whether this apex variant needs to target Android 10
LegacyAndroid10Support bool
+
+ MinSdkVersion int
}
// ApexModule is the interface that a module type is expected to implement if
@@ -86,6 +90,13 @@
// DepIsInSameApex tests if the other module 'dep' is installed to the same
// APEX as this module
DepIsInSameApex(ctx BaseModuleContext, dep Module) bool
+
+ // Returns the highest version which is <= min_sdk_version.
+ // For example, with min_sdk_version is 10 and versionList is [9,11]
+ // it returns 9.
+ ChooseSdkVersion(versionList []string, useLatest bool) (string, error)
+
+ ShouldSupportAndroid10() bool
}
type ApexProperties struct {
@@ -157,7 +168,7 @@
const (
AvailableToPlatform = "//apex_available:platform"
- availableToAnyApex = "//apex_available:anyapex"
+ AvailableToAnyApex = "//apex_available:anyapex"
)
func CheckAvailableForApex(what string, apex_available []string) bool {
@@ -167,7 +178,7 @@
return what == AvailableToPlatform
}
return InList(what, apex_available) ||
- (what != AvailableToPlatform && InList(availableToAnyApex, apex_available))
+ (what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available))
}
func (m *ApexModuleBase) AvailableFor(what string) bool {
@@ -181,9 +192,27 @@
return true
}
+func (m *ApexModuleBase) ChooseSdkVersion(versionList []string, useLatest bool) (string, error) {
+ if useLatest {
+ return versionList[len(versionList)-1], nil
+ }
+ minSdkVersion := m.ApexProperties.Info.MinSdkVersion
+ for i := range versionList {
+ ver, _ := strconv.Atoi(versionList[len(versionList)-i-1])
+ if ver <= minSdkVersion {
+ return versionList[len(versionList)-i-1], nil
+ }
+ }
+ return "", fmt.Errorf("min_sdk_version is set %v, but not found in %v", minSdkVersion, versionList)
+}
+
+func (m *ApexModuleBase) ShouldSupportAndroid10() bool {
+ return !m.IsForPlatform() && (m.ApexProperties.Info.MinSdkVersion <= 29 || m.ApexProperties.Info.LegacyAndroid10Support)
+}
+
func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
for _, n := range m.ApexProperties.Apex_available {
- if n == AvailableToPlatform || n == availableToAnyApex {
+ if n == AvailableToPlatform || n == AvailableToAnyApex {
continue
}
if !mctx.OtherModuleExists(n) && !mctx.Config().AllowMissingDependencies() {
diff --git a/android/arch.go b/android/arch.go
index 922548e..e440486 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -596,7 +596,7 @@
}()
var (
- osTypeList []OsType
+ OsTypeList []OsType
commonTargetMap = make(map[string]Target)
NoOsType OsType
@@ -672,7 +672,7 @@
DefaultDisabled: defDisabled,
}
- osTypeList = append(osTypeList, os)
+ OsTypeList = append(OsTypeList, os)
if _, found := commonTargetMap[name]; found {
panic(fmt.Errorf("Found Os type duplicate during OsType registration: %q", name))
@@ -684,7 +684,7 @@
}
func osByName(name string) OsType {
- for _, os := range osTypeList {
+ for _, os := range OsTypeList {
if os.Name == name {
return os
}
@@ -750,7 +750,7 @@
var moduleOSList []OsType
- for _, os := range osTypeList {
+ for _, os := range OsTypeList {
supportedClass := false
for _, osClass := range osClasses {
if os.Class == osClass {
@@ -1071,7 +1071,7 @@
"Arm_on_x86",
"Arm_on_x86_64",
}
- for _, os := range osTypeList {
+ for _, os := range OsTypeList {
targets = append(targets, os.Field)
for _, archType := range osArchTypeMap[os] {
diff --git a/android/sdk.go b/android/sdk.go
index d13ad7d..32d9921 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -186,9 +186,33 @@
// is correctly output for both versioned and unversioned prebuilts in the
// snapshot.
//
+ // "required: true" means that the property must only contain references
+ // to other members of the sdk. Passing a reference to a module that is not a
+ // member of the sdk will result in a build error.
+ //
+ // "required: false" means that the property can contain references to modules
+ // that are either members or not members of the sdk. If a reference is to a
+ // module that is a non member then the reference is left unchanged, i.e. it
+ // is not transformed as references to members are.
+ //
+ // The handling of the member names is dependent on whether it is an internal or
+ // exported member. An exported member is one whose name is specified in one of
+ // the member type specific properties. An internal member is one that is added
+ // due to being a part of an exported (or other internal) member and is not itself
+ // an exported member.
+ //
+ // Member names are handled as follows:
+ // * When creating the unversioned form of the module the name is left unchecked
+ // unless the member is internal in which case it is transformed into an sdk
+ // specific name, i.e. by prefixing with the sdk name.
+ //
+ // * When creating the versioned form of the module the name is transformed into
+ // a versioned sdk specific name, i.e. by prefixing with the sdk name and
+ // suffixing with the version.
+ //
// e.g.
- // bpPropertySet.AddPropertyWithTag("libs", []string{"member1", "member2"}, builder.SdkMemberReferencePropertyTag())
- SdkMemberReferencePropertyTag() BpPropertyTag
+ // bpPropertySet.AddPropertyWithTag("libs", []string{"member1", "member2"}, builder.SdkMemberReferencePropertyTag(true))
+ SdkMemberReferencePropertyTag(required bool) BpPropertyTag
}
type BpPropertyTag interface{}
@@ -302,7 +326,47 @@
//
// The SdkMember is guaranteed to contain variants for which the
// IsInstance(Module) method returned true.
+ //
+ // deprecated Use AddPrebuiltModule() instead.
BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember)
+
+ // Add a prebuilt module that the sdk will populate.
+ //
+ // Returning nil from this will cause the sdk module type to use the deprecated BuildSnapshot
+ // method to build the snapshot. That method is deprecated because it requires the SdkMemberType
+ // implementation to do all the word.
+ //
+ // Otherwise, returning a non-nil value from this will cause the sdk module type to do the
+ // majority of the work to generate the snapshot. The sdk module code generates the snapshot
+ // as follows:
+ //
+ // * A properties struct of type SdkMemberProperties is created for each variant and
+ // populated with information from the variant by calling PopulateFromVariant(SdkAware)
+ // on the struct.
+ //
+ // * An additional properties struct is created into which the common properties will be
+ // added.
+ //
+ // * The variant property structs are analysed to find exported (capitalized) fields which
+ // have common values. Those fields are cleared and the common value added to the common
+ // properties. A field annotated with a tag of `sdk:"keep"` will be treated as if it
+ // was not capitalized, i.e. not optimized for common values.
+ //
+ // * The sdk module type populates the BpModule structure, creating the arch specific
+ // structure and calls AddToPropertySet(...) on the properties struct to add the member
+ // specific properties in the correct place in the structure.
+ //
+ // * Finally, the FinalizeModule(...) method is called to add any additional properties.
+ // This was created to allow the property ordering in existing tests to be maintained so
+ // as to avoid having to change tests while refactoring.
+ //
+ AddPrebuiltModule(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember) BpModule
+
+ // Add any additional properties to the end of the module.
+ FinalizeModule(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember, bpModule BpModule)
+
+ // Create a structure into which variant specific properties can be added.
+ CreateVariantPropertiesStruct() SdkMemberProperties
}
// Base type for SdkMemberType implementations.
@@ -324,6 +388,23 @@
return b.TransitiveSdkMembers
}
+func (b *SdkMemberTypeBase) BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember) {
+ panic("override AddPrebuiltModule")
+}
+
+func (b *SdkMemberTypeBase) AddPrebuiltModule(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember) BpModule {
+ // Returning nil causes the legacy BuildSnapshot method to be used.
+ return nil
+}
+
+func (b *SdkMemberTypeBase) FinalizeModule(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember, module BpModule) {
+ // Do nothing by default
+}
+
+func (b *SdkMemberTypeBase) CreateVariantPropertiesStruct() SdkMemberProperties {
+ panic("override me")
+}
+
// Encapsulates the information about registered SdkMemberTypes.
type SdkMemberTypesRegistry struct {
// The list of types sorted by property name.
@@ -389,3 +470,50 @@
SdkMemberTypes = SdkMemberTypes.copyAndAppend(memberType)
}
}
+
+// Base structure for all implementations of SdkMemberProperties.
+//
+// Contains common properties that apply across many different member types. These
+// are not affected by the optimization to extract common values.
+type SdkMemberPropertiesBase struct {
+ // The setting to use for the compile_multilib property.
+ Compile_multilib string `sdk:"keep"`
+
+ // The number of unique os types supported by the member variants.
+ Os_count int `sdk:"keep"`
+
+ // The os type for which these properties refer.
+ Os OsType `sdk:"keep"`
+}
+
+// The os prefix to use for any file paths in the sdk.
+//
+// Is an empty string if the member only provides variants for a single os type, otherwise
+// is the OsType.Name.
+func (b *SdkMemberPropertiesBase) OsPrefix() string {
+ if b.Os_count == 1 {
+ return ""
+ } else {
+ return b.Os.Name
+ }
+}
+
+func (b *SdkMemberPropertiesBase) Base() *SdkMemberPropertiesBase {
+ return b
+}
+
+// Interface to be implemented on top of a structure that contains variant specific
+// information.
+//
+// Struct fields that are capitalized are examined for common values to extract. Fields
+// that are not capitalized are assumed to be arch specific.
+type SdkMemberProperties interface {
+ // Access the base structure.
+ Base() *SdkMemberPropertiesBase
+
+ // Populate the structure with information from the variant.
+ PopulateFromVariant(variant SdkAware)
+
+ // Add the information from the structure to the property set.
+ AddToPropertySet(sdkModuleContext ModuleContext, builder SnapshotBuilder, propertySet BpPropertySet)
+}
diff --git a/apex/apex.go b/apex/apex.go
index bef4e42..cddd72b 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -19,6 +19,7 @@
"path"
"path/filepath"
"sort"
+ "strconv"
"strings"
"sync"
@@ -62,8 +63,26 @@
usesTag = dependencyTag{name: "uses"}
androidAppTag = dependencyTag{name: "androidApp", payload: true}
apexAvailWl = makeApexAvailableWhitelist()
+
+ inverseApexAvailWl = invertApexWhiteList(apexAvailWl)
)
+// Transform the map of apex -> modules to module -> apexes.
+func invertApexWhiteList(m map[string][]string) map[string][]string {
+ r := make(map[string][]string)
+ for apex, modules := range m {
+ for _, module := range modules {
+ r[module] = append(r[module], apex)
+ }
+ }
+ return r
+}
+
+// Retrieve the while list of apexes to which the supplied module belongs.
+func WhitelistedApexAvailable(moduleName string) []string {
+ return inverseApexAvailWl[normalizeModuleName(moduleName)]
+}
+
// This is a map from apex to modules, which overrides the
// apex_available setting for that particular module to make
// it available for the apex regardless of its setting.
@@ -114,14 +133,7 @@
//
// Module separator
//
- m["com.android.appsearch"] = []string{
- "icing-java-proto-lite",
- "libprotobuf-java-lite",
- }
- //
- // Module separator
- //
- m["com.android.art"] = []string{
+ artApexContents := []string{
"art_cmdlineparser_headers",
"art_disassembler_headers",
"art_libartbase_headers",
@@ -196,6 +208,8 @@
"libziparchive",
"perfetto_trace_protos",
}
+ m["com.android.art.debug"] = artApexContents
+ m["com.android.art.release"] = artApexContents
//
// Module separator
//
@@ -220,8 +234,11 @@
"bluetooth-protos-lite",
"bluetooth.mapsapi",
"com.android.vcard",
+ "dnsresolver_aidl_interface-V2-java",
"fmtlib",
"guava",
+ "ipmemorystore-aidl-interfaces-V5-java",
+ "ipmemorystore-aidl-interfaces-java",
"internal_include_headers",
"lib-bt-packets",
"lib-bt-packets-avrcp",
@@ -287,6 +304,12 @@
"libutils_headers",
"libz",
"media_plugin_headers",
+ "net-utils-services-common",
+ "netd_aidl_interface-unstable-java",
+ "netd_event_listener_interface-java",
+ "netlink-client",
+ "networkstack-aidl-interfaces-unstable-java",
+ "networkstack-client",
"sap-api-java-static",
"services.net",
}
@@ -304,6 +327,7 @@
"libcrypto",
"libnativehelper_header_only",
"libssl",
+ "unsupportedappusage",
}
//
// Module separator
@@ -327,6 +351,7 @@
"cronet_impl_platform_java",
"libcronet.80.0.3986.0",
"org.chromium.net.cronet",
+ "org.chromium.net.cronet.xml",
"prebuilt_libcronet.80.0.3986.0",
}
//
@@ -565,6 +590,7 @@
"libFLAC-config",
"libFLAC-headers",
"libFraunhoferAAC",
+ "libLibGuiProperties",
"libarect",
"libasync_safe",
"libaudio_system_headers",
@@ -580,6 +606,7 @@
"libbase",
"libbase_headers",
"libbinder_headers",
+ "libbinderthreadstateutils",
"libbluetooth-types-header",
"libbufferhub_headers",
"libc++",
@@ -782,6 +809,7 @@
"libdexfile_external_headers",
"libdexfile_support",
"libdexfile_support_static",
+ "libdl_static",
"libgtest_prod",
"libjemalloc5",
"liblinker_main",
@@ -873,6 +901,7 @@
m["com.android.wifi"] = []string{
"PlatformProperties",
"android.hardware.wifi-V1.0-java",
+ "android.hardware.wifi-V1.0-java-constants",
"android.hardware.wifi-V1.1-java",
"android.hardware.wifi-V1.2-java",
"android.hardware.wifi-V1.3-java",
@@ -893,6 +922,8 @@
"bouncycastle-unbundled",
"dnsresolver_aidl_interface-V2-java",
"error_prone_annotations",
+ "framework-wifi-pre-jarjar",
+ "framework-wifi-util-lib",
"ipmemorystore-aidl-interfaces-V3-java",
"ipmemorystore-aidl-interfaces-java",
"ksoap2",
@@ -951,7 +982,7 @@
//
// Module separator
//
- m["//any"] = []string{
+ m[android.AvailableToAnyApex] = []string{
"crtbegin_dynamic",
"crtbegin_dynamic1",
"crtbegin_so",
@@ -1028,7 +1059,12 @@
var apexBundles []android.ApexInfo
var directDep bool
if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex {
- apexBundles = []android.ApexInfo{{mctx.ModuleName(), proptools.Bool(a.properties.Legacy_android10_support)}}
+ minSdkVersion := a.minSdkVersion(mctx)
+ apexBundles = []android.ApexInfo{android.ApexInfo{
+ ApexName: mctx.ModuleName(),
+ LegacyAndroid10Support: proptools.Bool(a.properties.Legacy_android10_support),
+ MinSdkVersion: minSdkVersion,
+ }}
directDep = true
} else if am, ok := mctx.Module().(android.ApexModule); ok {
apexBundles = am.ApexVariations()
@@ -1039,10 +1075,14 @@
return
}
+ cur := mctx.Module().(interface {
+ DepIsInSameApex(android.BaseModuleContext, android.Module) bool
+ })
+
mctx.VisitDirectDeps(func(child android.Module) {
depName := mctx.OtherModuleName(child)
if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() &&
- (directDep || am.DepIsInSameApex(mctx, child)) {
+ cur.DepIsInSameApex(mctx, child) {
android.UpdateApexDependency(apexBundles, depName, directDep)
am.BuildForApexes(apexBundles)
}
@@ -1816,10 +1856,10 @@
case "lib64":
dirInApex = "lib64"
}
- dirInApex = filepath.Join(dirInApex, ccMod.RelativeInstallPath())
if ccMod.Target().NativeBridge == android.NativeBridgeEnabled {
dirInApex = filepath.Join(dirInApex, ccMod.Target().NativeBridgeRelativePath)
}
+ dirInApex = filepath.Join(dirInApex, ccMod.RelativeInstallPath())
if handleSpecialLibs && cc.InstallToBootstrap(ccMod.BaseModuleName(), ctx.Config()) {
// Special case for Bionic libs and other libs installed with them. This is
// to prevent those libs from being included in the search path
@@ -1839,10 +1879,11 @@
}
func apexFileForExecutable(ctx android.BaseModuleContext, cc *cc.Module) apexFile {
- dirInApex := filepath.Join("bin", cc.RelativeInstallPath())
+ dirInApex := "bin"
if cc.Target().NativeBridge == android.NativeBridgeEnabled {
dirInApex = filepath.Join(dirInApex, cc.Target().NativeBridgeRelativePath)
}
+ dirInApex = filepath.Join(dirInApex, cc.RelativeInstallPath())
fileToCopy := cc.OutputFile().Path()
af := newApexFile(ctx, fileToCopy, cc.Name(), dirInApex, nativeExecutable, cc)
af.symlinks = cc.Symlinks()
@@ -1955,7 +1996,7 @@
}
// Check for the indirect dependencies if it is considered as part of the APEX
- if am.DepIsInSameApex(ctx, am) {
+ if am.ApexName() != "" {
do(ctx, parent, am, false /* externalDep */)
return true
}
@@ -1967,6 +2008,18 @@
})
}
+func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) int {
+ ver := proptools.StringDefault(a.properties.Min_sdk_version, "current")
+ if ver != "current" {
+ minSdkVersion, err := strconv.Atoi(ver)
+ if err != nil {
+ ctx.PropertyErrorf("min_sdk_version", "should be \"current\" or <number>, but %q", ver)
+ }
+ return minSdkVersion
+ }
+ return android.FutureApiLevel
+}
+
// Ensures that the dependencies are marked as available for this APEX
func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) {
// Let's be practical. Availability for test, host, and the VNDK apex isn't important
@@ -1976,10 +2029,12 @@
a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
apexName := ctx.ModuleName()
- if externalDep || to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, to) {
+ fromName := ctx.OtherModuleName(from)
+ toName := ctx.OtherModuleName(to)
+ if externalDep || to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) {
return
}
- ctx.ModuleErrorf("requires %q that is not available for the APEX.", to.Name())
+ ctx.ModuleErrorf("%q requires %q that is not available for the APEX.", fromName, toName)
})
}
@@ -2356,13 +2411,23 @@
a.buildApexDependencyInfo(ctx)
}
-func whitelistedApexAvailable(apex string, module android.Module) bool {
+func whitelistedApexAvailable(apex, moduleName string) bool {
key := apex
- key = strings.Replace(key, "test_", "", 1)
- key = strings.Replace(key, "com.android.art.debug", "com.android.art", 1)
- key = strings.Replace(key, "com.android.art.release", "com.android.art", 1)
+ moduleName = normalizeModuleName(moduleName)
- moduleName := module.Name()
+ if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
+ return true
+ }
+
+ key = android.AvailableToAnyApex
+ if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
+ return true
+ }
+
+ return false
+}
+
+func normalizeModuleName(moduleName string) string {
// Prebuilt modules (e.g. java_import, etc.) have "prebuilt_" prefix added by the build
// system. Trim the prefix for the check since they are confusing
moduleName = strings.TrimPrefix(moduleName, "prebuilt_")
@@ -2371,17 +2436,7 @@
// We don't want to list them all
moduleName = "libclang_rt"
}
-
- if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
- return true
- }
-
- key = "//any"
- if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
- return true
- }
-
- return false
+ return moduleName
}
func newApexBundle() *apexBundle {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 674446a..ad91878 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -87,6 +87,24 @@
}
}
+// withNativeBridgeTargets sets configuration with targets including:
+// - X86_64 (primary)
+// - X86 (secondary)
+// - Arm64 on X86_64 (native bridge)
+// - Arm on X86 (native bridge)
+func withNativeBridgeEnabled(fs map[string][]byte, config android.Config) {
+ config.Targets[android.Android] = []android.Target{
+ {Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}},
+ NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+ {Os: android.Android, Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}},
+ NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+ {Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}},
+ NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86_64", NativeBridgeRelativePath: "arm64"},
+ {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}},
+ NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86", NativeBridgeRelativePath: "arm"},
+ }
+}
+
func withManifestPackageNameOverrides(specs []string) testCustomizer {
return func(fs map[string][]byte, config android.Config) {
config.TestProductVariables.ManifestPackageNameOverrides = specs
@@ -984,6 +1002,297 @@
ensureContains(t, libFlags, "libdl/android_arm64_armv8-a_shared/libdl.so")
}
+func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) {
+ // there are three links between liba --> libz
+ // 1) myapex -> libx -> liba -> libz : this should be #2 link, but fallback to #1
+ // 2) otherapex -> liby -> liba -> libz : this should be #3 link
+ // 3) (platform) -> liba -> libz : this should be non-stub link
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libx"],
+ min_sdk_version: "2",
+ }
+
+ apex {
+ name: "otherapex",
+ key: "myapex.key",
+ native_shared_libs: ["liby"],
+ min_sdk_version: "3",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libx",
+ shared_libs: ["liba"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+
+ cc_library {
+ name: "liby",
+ shared_libs: ["liba"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "otherapex" ],
+ }
+
+ cc_library {
+ name: "liba",
+ shared_libs: ["libz"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
+ }
+
+ cc_library {
+ name: "libz",
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["1", "3"],
+ },
+ }
+ `, withUnbundledBuild)
+
+ expectLink := func(from, from_variant, to, to_variant string) {
+ ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+ ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ expectNoLink := func(from, from_variant, to, to_variant string) {
+ ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+ ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ // platform liba is linked to non-stub version
+ expectLink("liba", "shared", "libz", "shared")
+ // liba in myapex is linked to #1
+ expectLink("liba", "shared_myapex", "libz", "shared_1")
+ expectNoLink("liba", "shared_myapex", "libz", "shared_3")
+ expectNoLink("liba", "shared_myapex", "libz", "shared")
+ // liba in otherapex is linked to #3
+ expectLink("liba", "shared_otherapex", "libz", "shared_3")
+ expectNoLink("liba", "shared_otherapex", "libz", "shared_1")
+ expectNoLink("liba", "shared_otherapex", "libz", "shared")
+}
+
+func TestApexMinSdkVersionDefaultsToLatest(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libx"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libx",
+ shared_libs: ["libz"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+
+ cc_library {
+ name: "libz",
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["1", "2"],
+ },
+ }
+ `)
+
+ expectLink := func(from, from_variant, to, to_variant string) {
+ ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+ ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ expectNoLink := func(from, from_variant, to, to_variant string) {
+ ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+ ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ expectLink("libx", "shared_myapex", "libz", "shared_2")
+ expectNoLink("libx", "shared_myapex", "libz", "shared_1")
+ expectNoLink("libx", "shared_myapex", "libz", "shared")
+}
+
+func TestPlatformUsesLatestStubsFromApexes(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libx"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libx",
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ stubs: {
+ versions: ["1", "2"],
+ },
+ }
+
+ cc_library {
+ name: "libz",
+ shared_libs: ["libx"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ expectLink := func(from, from_variant, to, to_variant string) {
+ ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+ ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ expectNoLink := func(from, from_variant, to, to_variant string) {
+ ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+ ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ expectLink("libz", "shared", "libx", "shared_2")
+ expectNoLink("libz", "shared", "libz", "shared_1")
+ expectNoLink("libz", "shared", "libz", "shared")
+}
+
+func TestQApexesUseLatestStubsInBundledBuilds(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libx"],
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libx",
+ shared_libs: ["libbar"],
+ apex_available: [ "myapex" ],
+ }
+
+ cc_library {
+ name: "libbar",
+ stubs: {
+ versions: ["29", "30"],
+ },
+ }
+ `)
+ expectLink := func(from, from_variant, to, to_variant string) {
+ ld := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld")
+ libFlags := ld.Args["libFlags"]
+ ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ expectLink("libx", "shared_myapex", "libbar", "shared_30")
+}
+
+func TestQTargetApexUseStaticUnwinder(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libx"],
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libx",
+ apex_available: [ "myapex" ],
+ }
+
+ `, withUnbundledBuild)
+
+ // ensure apex variant of c++ is linked with static unwinder
+ cm := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module)
+ ensureListContains(t, cm.Properties.AndroidMkStaticLibs, "libgcc_stripped")
+ // note that platform variant is not.
+ cm = ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared").Module().(*cc.Module)
+ ensureListNotContains(t, cm.Properties.AndroidMkStaticLibs, "libgcc_stripped")
+
+ libFlags := ctx.ModuleForTests("libx", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"]
+ ensureContains(t, libFlags, "android_arm64_armv8-a_shared_myapex/libc++.so")
+ ensureContains(t, libFlags, "android_arm64_armv8-a_shared_29/libc.so") // min_sdk_version applied
+}
+
+func TestInvalidMinSdkVersion(t *testing.T) {
+ testApexError(t, `"libz" .*: min_sdk_version is set 29.*`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libx"],
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libx",
+ shared_libs: ["libz"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+
+ cc_library {
+ name: "libz",
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["30"],
+ },
+ }
+ `, withUnbundledBuild)
+
+ testApexError(t, `"myapex" .*: min_sdk_version: should be .*`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ min_sdk_version: "R",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `)
+}
+
func TestFilesInSubDir(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -1046,6 +1355,64 @@
ensureListContains(t, dirs, "bin/foo/bar")
}
+func TestFilesInSubDirWhenNativeBridgeEnabled(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ multilib: {
+ both: {
+ native_shared_libs: ["mylib"],
+ binaries: ["mybin"],
+ },
+ },
+ compile_multilib: "both",
+ native_bridge_supported: true,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ relative_install_path: "foo/bar",
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ native_bridge_supported: true,
+ }
+
+ cc_binary {
+ name: "mybin",
+ relative_install_path: "foo/bar",
+ system_shared_libs: [],
+ static_executable: true,
+ stl: "none",
+ apex_available: [ "myapex" ],
+ native_bridge_supported: true,
+ compile_multilib: "both", // default is "first" for binary
+ multilib: {
+ lib64: {
+ suffix: "64",
+ },
+ },
+ }
+ `, withNativeBridgeEnabled)
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+ "bin/foo/bar/mybin",
+ "bin/foo/bar/mybin64",
+ "bin/arm/foo/bar/mybin",
+ "bin/arm64/foo/bar/mybin64",
+ "lib/foo/bar/mylib.so",
+ "lib/arm/foo/bar/mylib.so",
+ "lib64/foo/bar/mylib.so",
+ "lib64/arm64/foo/bar/mylib.so",
+ })
+}
+
func TestUseVendor(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -1396,6 +1763,7 @@
name: "otherapex",
key: "myapex.key",
native_shared_libs: ["mylib", "mylib2"],
+ min_sdk_version: "29",
}
apex_key {
@@ -1430,15 +1798,18 @@
// non-APEX variant does not have __ANDROID_APEX__ defined
mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+ ensureContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=10000")
- // APEX variant has __ANDROID_APEX__ defined
+ // APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined
mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+ ensureContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=10000")
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
- // APEX variant has __ANDROID_APEX__ defined
+ // APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined
mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"]
ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+ ensureContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=29")
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
// When cc_library sets use_apex_name_macro: true
@@ -1909,15 +2280,7 @@
stl: "none",
apex_available: [ "myapex" ],
}
- `+vndkLibrariesTxtFiles("current"),
- withTargets(map[android.OsType][]android.Target{
- android.Android: []android.Target{
- {Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
- {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
- {Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "arm64", NativeBridgeRelativePath: "x86_64"},
- {Os: android.Android, Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "arm", NativeBridgeRelativePath: "x86"},
- },
- }))
+ `+vndkLibrariesTxtFiles("current"), withNativeBridgeEnabled)
ensureExactContents(t, ctx, "myapex", "android_common_image", []string{
"lib/libvndk.so",
@@ -2012,7 +2375,8 @@
withBinder32bit,
withTargets(map[android.OsType][]android.Target{
android.Android: []android.Target{
- {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+ {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}},
+ NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
},
}),
)
@@ -2873,6 +3237,7 @@
stl: "none",
system_shared_libs: [],
enabled: false,
+ apex_available: ["myapex"],
}
`)
testApexError(t, `module "myapex" .* depends on disabled module "myjar"`, `
@@ -2894,6 +3259,7 @@
sdk_version: "none",
system_modules: "none",
enabled: false,
+ apex_available: ["myapex"],
}
`)
}
@@ -3054,7 +3420,7 @@
func TestApexPropertiesShouldBeDefaultable(t *testing.T) {
// libfoo's apex_available comes from cc_defaults
- testApexError(t, `"myapex" .*: requires "libfoo" that is not available for the APEX`, `
+ testApexError(t, `requires "libfoo" that is not available for the APEX`, `
apex {
name: "myapex",
key: "myapex.key",
@@ -3120,8 +3486,8 @@
apex_available: ["otherapex"],
}`)
- // libbar is an indirect dep
- testApexError(t, "requires \"libbar\" that is not available for the APEX", `
+ // libbbaz is an indirect dep
+ testApexError(t, "requires \"libbaz\" that is not available for the APEX", `
apex {
name: "myapex",
key: "myapex.key",
@@ -3134,31 +3500,26 @@
private_key: "testkey.pem",
}
- apex {
- name: "otherapex",
- key: "otherapex.key",
- native_shared_libs: ["libfoo"],
- }
-
- apex_key {
- name: "otherapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
cc_library {
name: "libfoo",
stl: "none",
shared_libs: ["libbar"],
system_shared_libs: [],
- apex_available: ["myapex", "otherapex"],
+ apex_available: ["myapex"],
}
cc_library {
name: "libbar",
stl: "none",
+ shared_libs: ["libbaz"],
system_shared_libs: [],
- apex_available: ["otherapex"],
+ apex_available: ["myapex"],
+ }
+
+ cc_library {
+ name: "libbaz",
+ stl: "none",
+ system_shared_libs: [],
}`)
testApexError(t, "\"otherapex\" is not a valid module name", `
@@ -3505,6 +3866,7 @@
sdk_version: "none",
system_modules: "none",
compile_dex: false,
+ apex_available: ["myapex"],
}
`)
}
diff --git a/apex/builder.go b/apex/builder.go
index 279445b..464d843 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -453,21 +453,18 @@
targetSdkVersion := ctx.Config().DefaultAppTargetSdk()
minSdkVersion := ctx.Config().DefaultAppTargetSdk()
+ // TODO: this should be based on min_sdk_version property of an APEX.
if proptools.Bool(a.properties.Legacy_android10_support) {
- if !java.UseApiFingerprint(ctx, targetSdkVersion) {
- targetSdkVersion = "29"
- }
- if !java.UseApiFingerprint(ctx, minSdkVersion) {
- minSdkVersion = "29"
- }
+ targetSdkVersion = "29"
+ minSdkVersion = "29"
}
- if java.UseApiFingerprint(ctx, targetSdkVersion) {
- targetSdkVersion += fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
+ if java.UseApiFingerprint(ctx) {
+ targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
}
- if java.UseApiFingerprint(ctx, minSdkVersion) {
- minSdkVersion += fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
+ if java.UseApiFingerprint(ctx) {
+ minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
}
optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion)
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 81004da..ef695b0 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -244,6 +244,9 @@
if library.shared() && !library.buildStubs() {
ctx.subAndroidMk(entries, library.baseInstaller)
} else {
+ if library.buildStubs() {
+ entries.SubName = "." + library.stubsVersion()
+ }
entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
if library.buildStubs() {
@@ -254,6 +257,10 @@
if len(library.Properties.Stubs.Versions) > 0 &&
android.DirectlyInAnyApex(ctx, ctx.Name()) && !ctx.InRamdisk() && !ctx.InRecovery() && !ctx.UseVndk() &&
!ctx.static() {
+ if library.buildStubs() && library.isLatestStubVersion() {
+ // reference the latest version via its name without suffix when it is provided by apex
+ entries.SubName = ""
+ }
if !library.buildStubs() {
entries.SubName = ".bootstrap"
}
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index 58d6ad0..2778ebd 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -16,7 +16,6 @@
import (
"path/filepath"
- "strings"
"android/soong/android"
"github.com/google/blueprint"
@@ -64,65 +63,13 @@
return false
}
-func (mt *binarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
- info := mt.organizeVariants(member)
- buildSharedNativeBinarySnapshot(info, builder, member)
-}
-
-// Organize the variants by architecture.
-func (mt *binarySdkMemberType) organizeVariants(member android.SdkMember) *nativeBinaryInfo {
- memberName := member.Name()
- info := &nativeBinaryInfo{
- name: memberName,
- memberType: mt,
- }
-
- for _, variant := range member.Variants() {
- ccModule := variant.(*Module)
-
- info.archVariantProperties = append(info.archVariantProperties, nativeBinaryInfoProperties{
- name: memberName,
- archType: ccModule.Target().Arch.ArchType.String(),
- outputFile: ccModule.OutputFile().Path(),
- })
- }
-
- // Initialize the unexported properties that will not be set during the
- // extraction process.
- info.commonProperties.name = memberName
-
- // Extract common properties from the arch specific properties.
- extractCommonProperties(&info.commonProperties, info.archVariantProperties)
-
- return info
-}
-
-func buildSharedNativeBinarySnapshot(info *nativeBinaryInfo, builder android.SnapshotBuilder, member android.SdkMember) {
+func (mt *binarySdkMemberType) AddPrebuiltModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) android.BpModule {
pbm := builder.AddPrebuiltModule(member, "cc_prebuilt_binary")
- archVariantCount := len(info.archVariantProperties)
+ return pbm
+}
- // Choose setting for compile_multilib that is appropriate for the arch variants supplied.
- var multilib string
- if archVariantCount == 2 {
- multilib = "both"
- } else if archVariantCount == 1 {
- if strings.HasSuffix(info.archVariantProperties[0].archType, "64") {
- multilib = "64"
- } else {
- multilib = "32"
- }
- }
- if multilib != "" {
- pbm.AddProperty("compile_multilib", multilib)
- }
-
- archProperties := pbm.AddPropertySet("arch")
- for _, av := range info.archVariantProperties {
- archTypeProperties := archProperties.AddPropertySet(av.archType)
- archTypeProperties.AddProperty("srcs", []string{nativeBinaryPathFor(av)})
-
- builder.CopyToSnapshot(av.outputFile, nativeBinaryPathFor(av))
- }
+func (mt *binarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &nativeBinaryInfoProperties{}
}
const (
@@ -131,7 +78,7 @@
// path to the native binary. Relative to <sdk_root>/<api_dir>
func nativeBinaryPathFor(lib nativeBinaryInfoProperties) string {
- return filepath.Join(lib.archType,
+ return filepath.Join(lib.OsPrefix(), lib.archType,
nativeBinaryDir, lib.outputFile.Base())
}
@@ -140,8 +87,7 @@
// The exported (capitalized) fields will be examined and may be changed during common value extraction.
// The unexported fields will be left untouched.
type nativeBinaryInfoProperties struct {
- // The name of the library, is not exported as this must not be changed during optimization.
- name string
+ android.SdkMemberPropertiesBase
// archType is not exported as if set (to a non default value) it is always arch specific.
// This is "" for common properties.
@@ -149,12 +95,49 @@
// outputFile is not exported as it is always arch specific.
outputFile android.Path
+
+ // The set of shared libraries
+ //
+ // This field is exported as its contents may not be arch specific.
+ SharedLibs []string
+
+ // The set of system shared libraries
+ //
+ // This field is exported as its contents may not be arch specific.
+ SystemSharedLibs []string
}
-// nativeBinaryInfo represents a collection of arch-specific modules having the same name
-type nativeBinaryInfo struct {
- name string
- memberType *binarySdkMemberType
- archVariantProperties []nativeBinaryInfoProperties
- commonProperties nativeBinaryInfoProperties
+func (p *nativeBinaryInfoProperties) PopulateFromVariant(variant android.SdkAware) {
+ ccModule := variant.(*Module)
+
+ p.archType = ccModule.Target().Arch.ArchType.String()
+ p.outputFile = ccModule.OutputFile().Path()
+
+ if ccModule.linker != nil {
+ specifiedDeps := specifiedDeps{}
+ specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps)
+
+ p.SharedLibs = specifiedDeps.sharedLibs
+ p.SystemSharedLibs = specifiedDeps.systemSharedLibs
+ }
+}
+
+func (p *nativeBinaryInfoProperties) AddToPropertySet(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, propertySet android.BpPropertySet) {
+ if p.Compile_multilib != "" {
+ propertySet.AddProperty("compile_multilib", p.Compile_multilib)
+ }
+
+ if p.outputFile != nil {
+ propertySet.AddProperty("srcs", []string{nativeBinaryPathFor(*p)})
+
+ builder.CopyToSnapshot(p.outputFile, nativeBinaryPathFor(*p))
+ }
+
+ if len(p.SharedLibs) > 0 {
+ propertySet.AddPropertyWithTag("shared_libs", p.SharedLibs, builder.SdkMemberReferencePropertyTag(false))
+ }
+
+ if len(p.SystemSharedLibs) > 0 {
+ propertySet.AddPropertyWithTag("system_shared_libs", p.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false))
+ }
}
diff --git a/cc/cc.go b/cc/cc.go
index e5e724e..61ae10a 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -250,6 +250,8 @@
// Used by vendor snapshot to record dependencies from snapshot modules.
SnapshotSharedLibs []string `blueprint:"mutated"`
SnapshotRuntimeLibs []string `blueprint:"mutated"`
+
+ Installable *bool
}
type VendorProperties struct {
@@ -290,6 +292,7 @@
staticBinary() bool
header() bool
toolchain() config.Toolchain
+ canUseSdk() bool
useSdk() bool
sdkVersion() string
useVndk() bool
@@ -313,6 +316,7 @@
useClangLld(actx ModuleContext) bool
isForPlatform() bool
apexName() string
+ apexSdkVersion() int
hasStubsVariants() bool
isStubs() bool
bootstrap() bool
@@ -366,11 +370,21 @@
nativeCoverage() bool
coverageOutputFilePath() android.OptionalPath
+
+ // Get the deps that have been explicitly specified in the properties.
+ // Only updates the
+ linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps
+}
+
+type specifiedDeps struct {
+ sharedLibs []string
+ systemSharedLibs []string
}
type installer interface {
installerProps() []interface{}
install(ctx ModuleContext, path android.Path)
+ everInstallable() bool
inData() bool
inSanitizerDir() bool
hostToolPath() android.OptionalPath
@@ -631,6 +645,15 @@
panic(fmt.Errorf("SetStubsVersions called on non-library module: %q", c.BaseModuleName()))
}
+func (c *Module) StubsVersion() string {
+ if c.linker != nil {
+ if library, ok := c.linker.(*libraryDecorator); ok {
+ return library.MutatedProperties.StubsVersion
+ }
+ }
+ panic(fmt.Errorf("StubsVersion called on non-library module: %q", c.BaseModuleName()))
+}
+
func (c *Module) SetStatic() {
if c.linker != nil {
if library, ok := c.linker.(libraryInterface); ok {
@@ -1036,8 +1059,12 @@
return ctx.mod.header()
}
+func (ctx *moduleContextImpl) canUseSdk() bool {
+ return ctx.ctx.Device() && !ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && !ctx.ctx.Fuchsia()
+}
+
func (ctx *moduleContextImpl) useSdk() bool {
- if ctx.ctx.Device() && !ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && !ctx.ctx.Fuchsia() {
+ if ctx.canUseSdk() {
return String(ctx.mod.Properties.Sdk_version) != ""
}
return false
@@ -1170,6 +1197,10 @@
return ctx.mod.ApexName()
}
+func (ctx *moduleContextImpl) apexSdkVersion() int {
+ return ctx.mod.ApexProperties.Info.MinSdkVersion
+}
+
func (ctx *moduleContextImpl) hasStubsVariants() bool {
return ctx.mod.HasStubsVariants()
}
@@ -1479,6 +1510,13 @@
if ctx.Failed() {
return
}
+ } else if !proptools.BoolDefault(c.Properties.Installable, true) {
+ // If the module has been specifically configure to not be installed then
+ // skip the installation as otherwise it will break when running inside make
+ // as the output path to install will not be specified. Not all uninstallable
+ // modules can skip installation as some are needed for resolving make side
+ // dependencies.
+ c.SkipInstall()
}
}
@@ -1821,16 +1859,17 @@
}
actx.AddVariationDependencies(variations, depTag, name)
- // If the version is not specified, add dependency to the latest stubs library.
+ // If the version is not specified, add dependency to all stubs libraries.
// The stubs library will be used when the depending module is built for APEX and
// the dependent module is not in the same APEX.
- latestVersion := LatestStubsVersionFor(actx.Config(), name)
- if version == "" && latestVersion != "" && versionVariantAvail {
- actx.AddVariationDependencies([]blueprint.Variation{
- {Mutator: "link", Variation: "shared"},
- {Mutator: "version", Variation: latestVersion},
- }, depTag, name)
- // Note that depTag.ExplicitlyVersioned is false in this case.
+ if version == "" && versionVariantAvail {
+ for _, ver := range stubsVersionsFor(actx.Config())[name] {
+ // Note that depTag.ExplicitlyVersioned is false in this case.
+ actx.AddVariationDependencies([]blueprint.Variation{
+ {Mutator: "link", Variation: "shared"},
+ {Mutator: "version", Variation: ver},
+ }, depTag, name)
+ }
}
}
@@ -2178,7 +2217,8 @@
}
if depTag == staticUnwinderDepTag {
- if c.ApexProperties.Info.LegacyAndroid10Support {
+ // Use static unwinder for legacy (min_sdk_version = 29) apexes (b/144430859)
+ if c.ShouldSupportAndroid10() {
depTag = StaticDepTag
} else {
return
@@ -2230,6 +2270,19 @@
useThisDep = (depInSameApex != depIsStubs)
}
+ // when to use (unspecified) stubs, check min_sdk_version and choose the right one
+ if useThisDep && depIsStubs && !explicitlyVersioned {
+ useLatest := c.IsForPlatform() || (c.ShouldSupportAndroid10() && !ctx.Config().UnbundledBuild())
+ versionToUse, err := c.ChooseSdkVersion(ccDep.StubsVersions(), useLatest)
+ if err != nil {
+ ctx.OtherModuleErrorf(dep, err.Error())
+ return
+ }
+ if versionToUse != ccDep.StubsVersion() {
+ useThisDep = false
+ }
+ }
+
if !useThisDep {
return // stop processing this dep
}
@@ -2605,8 +2658,18 @@
}
}
+// Return true if the module is ever installable.
+func (c *Module) EverInstallable() bool {
+ return c.installer != nil &&
+ // Check to see whether the module is actually ever installable.
+ c.installer.everInstallable()
+}
+
func (c *Module) installable() bool {
- ret := c.installer != nil && !c.Properties.PreventInstall && c.outputFile.Valid()
+ ret := c.EverInstallable() &&
+ // Check to see whether the module has been configured to not be installed.
+ proptools.BoolDefault(c.Properties.Installable, true) &&
+ !c.Properties.PreventInstall && c.outputFile.Valid()
// The platform variant doesn't need further condition. Apex variants however might not
// be installable because it will likely to be included in the APEX and won't appear
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 8acc817..56b36df 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -2530,6 +2530,7 @@
}
func checkStaticLibs(t *testing.T, expected []string, module *Module) {
+ t.Helper()
actual := module.Properties.AndroidMkStaticLibs
if !reflect.DeepEqual(actual, expected) {
t.Errorf("incorrect static_libs"+
diff --git a/cc/compiler.go b/cc/compiler.go
index 3a87b69..fe81bd0 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -315,6 +315,18 @@
"-isystem "+getCurrentIncludePath(ctx).Join(ctx, config.NDKTriple(tc)).String())
}
+ if ctx.canUseSdk() {
+ sdkVersion := ctx.sdkVersion()
+ if sdkVersion == "" || sdkVersion == "current" {
+ if ctx.isForPlatform() {
+ sdkVersion = strconv.Itoa(android.FutureApiLevel)
+ } else {
+ sdkVersion = strconv.Itoa(ctx.apexSdkVersion())
+ }
+ }
+ flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_SDK_VERSION__="+sdkVersion)
+ }
+
if ctx.useVndk() {
flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_VNDK__")
}
diff --git a/cc/installer.go b/cc/installer.go
index 2f55ac5..200d59e 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -86,6 +86,11 @@
installer.path = ctx.InstallFile(installer.installDir(ctx), file.Base(), file)
}
+func (installer *baseInstaller) everInstallable() bool {
+ // Most cc modules are installable.
+ return true
+}
+
func (installer *baseInstaller) inData() bool {
return installer.location == InstallInData
}
diff --git a/cc/library.go b/cc/library.go
index 0159cee..6bd93f9 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -817,6 +817,23 @@
return deps
}
+func (library *libraryDecorator) linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps {
+ specifiedDeps = library.baseLinker.linkerSpecifiedDeps(specifiedDeps)
+ var properties StaticOrSharedProperties
+ if library.static() {
+ properties = library.StaticProperties.Static
+ } else if library.shared() {
+ properties = library.SharedProperties.Shared
+ }
+
+ specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, properties.Shared_libs...)
+ specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, properties.System_shared_libs...)
+
+ specifiedDeps.sharedLibs = android.FirstUniqueStrings(specifiedDeps.sharedLibs)
+ specifiedDeps.systemSharedLibs = android.FirstUniqueStrings(specifiedDeps.systemSharedLibs)
+ return specifiedDeps
+}
+
func (library *libraryDecorator) linkStatic(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
@@ -1220,6 +1237,12 @@
}
}
+func (library *libraryDecorator) everInstallable() bool {
+ // Only shared and static libraries are installed. Header libraries (which are
+ // neither static or shared) are not installed.
+ return library.shared() || library.static()
+}
+
func (library *libraryDecorator) static() bool {
return library.MutatedProperties.VariantIsStatic
}
@@ -1273,6 +1296,11 @@
return library.MutatedProperties.StubsVersion
}
+func (library *libraryDecorator) isLatestStubVersion() bool {
+ versions := library.Properties.Stubs.Versions
+ return versions[len(versions)-1] == library.stubsVersion()
+}
+
func (library *libraryDecorator) availableFor(what string) bool {
var list []string
if library.static() {
@@ -1444,30 +1472,35 @@
return ""
}
+func checkVersions(ctx android.BaseModuleContext, versions []string) {
+ numVersions := make([]int, len(versions))
+ for i, v := range versions {
+ numVer, err := strconv.Atoi(v)
+ if err != nil {
+ ctx.PropertyErrorf("versions", "%q is not a number", v)
+ }
+ numVersions[i] = numVer
+ }
+ if !sort.IsSorted(sort.IntSlice(numVersions)) {
+ ctx.PropertyErrorf("versions", "not sorted: %v", versions)
+ }
+}
+
// Version mutator splits a module into the mandatory non-stubs variant
// (which is unnamed) and zero or more stubs variants.
func VersionMutator(mctx android.BottomUpMutatorContext) {
if library, ok := mctx.Module().(LinkableInterface); ok && !library.InRecovery() {
if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 {
- versions := []string{}
- for _, v := range library.StubsVersions() {
- if _, err := strconv.Atoi(v); err != nil {
- mctx.PropertyErrorf("versions", "%q is not a number", v)
- }
- versions = append(versions, v)
+ versions := library.StubsVersions()
+ checkVersions(mctx, versions)
+ if mctx.Failed() {
+ return
}
- sort.Slice(versions, func(i, j int) bool {
- left, _ := strconv.Atoi(versions[i])
- right, _ := strconv.Atoi(versions[j])
- return left < right
- })
// save the list of versions for later use
- copiedVersions := make([]string, len(versions))
- copy(copiedVersions, versions)
stubsVersionsLock.Lock()
defer stubsVersionsLock.Unlock()
- stubsVersionsFor(mctx.Config())[mctx.ModuleName()] = copiedVersions
+ stubsVersionsFor(mctx.Config())[mctx.ModuleName()] = versions
// "" is for the non-stubs variant
versions = append([]string{""}, versions...)
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index a36917e..f1b0975 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -16,10 +16,10 @@
import (
"path/filepath"
- "reflect"
"android/soong/android"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
)
// This file contains support for using cc library modules within an sdk.
@@ -96,48 +96,28 @@
return false
}
-// copy exported header files and stub *.so files
-func (mt *librarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
- info := mt.organizeVariants(member)
- info.generatePrebuiltLibrary(sdkModuleContext, builder, member)
+func (mt *librarySdkMemberType) AddPrebuiltModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) android.BpModule {
+ pbm := builder.AddPrebuiltModule(member, mt.prebuiltModuleType)
+
+ ccModule := member.Variants()[0].(*Module)
+
+ sdkVersion := ccModule.SdkVersion()
+ if sdkVersion != "" {
+ pbm.AddProperty("sdk_version", sdkVersion)
+ }
+ return pbm
}
-// Organize the variants by architecture.
-func (mt *librarySdkMemberType) organizeVariants(member android.SdkMember) *nativeLibInfo {
- memberName := member.Name()
- info := &nativeLibInfo{
- name: memberName,
- memberType: mt,
+func (mt *librarySdkMemberType) FinalizeModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember, bpModule android.BpModule) {
+ ccModule := (member.Variants()[0]).(*Module)
+ stl := ccModule.stl.Properties.Stl
+ if stl != nil {
+ bpModule.AddProperty("stl", proptools.String(stl))
}
+}
- for _, variant := range member.Variants() {
- ccModule := variant.(*Module)
-
- // Separate out the generated include dirs (which are arch specific) from the
- // include dirs (which may not be).
- exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate(
- ccModule.ExportedIncludeDirs(), isGeneratedHeaderDirectory)
-
- info.archVariantProperties = append(info.archVariantProperties, nativeLibInfoProperties{
- name: memberName,
- archType: ccModule.Target().Arch.ArchType.String(),
- ExportedIncludeDirs: exportedIncludeDirs,
- exportedGeneratedIncludeDirs: exportedGeneratedIncludeDirs,
- ExportedSystemIncludeDirs: ccModule.ExportedSystemIncludeDirs(),
- ExportedFlags: ccModule.ExportedFlags(),
- exportedGeneratedHeaders: ccModule.ExportedGeneratedHeaders(),
- outputFile: ccModule.OutputFile().Path(),
- })
- }
-
- // Initialize the unexported properties that will not be set during the
- // extraction process.
- info.commonProperties.name = memberName
-
- // Extract common properties from the arch specific properties.
- extractCommonProperties(&info.commonProperties, info.archVariantProperties)
-
- return info
+func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &nativeLibInfoProperties{memberType: mt}
}
func isGeneratedHeaderDirectory(p android.Path) bool {
@@ -145,94 +125,9 @@
return gen
}
-// Extract common properties from a slice of property structures of the same type.
-//
-// All the property structures must be of the same type.
-// commonProperties - must be a pointer to the structure into which common properties will be added.
-// inputPropertiesSlice - must be a slice of input properties structures.
-//
-// Iterates over each exported field (capitalized name) and checks to see whether they
-// have the same value (using DeepEquals) across all the input properties. If it does not then no
-// change is made. Otherwise, the common value is stored in the field in the commonProperties
-// and the field in each of the input properties structure is set to its default value.
-func extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) {
- commonStructValue := reflect.ValueOf(commonProperties).Elem()
- propertiesStructType := commonStructValue.Type()
-
- // Create an empty structure from which default values for the field can be copied.
- emptyStructValue := reflect.New(propertiesStructType).Elem()
-
- for f := 0; f < propertiesStructType.NumField(); f++ {
- // Check to see if all the structures have the same value for the field. The commonValue
- // is nil on entry to the loop and if it is nil on exit then there is no common value,
- // otherwise it points to the common value.
- var commonValue *reflect.Value
- sliceValue := reflect.ValueOf(inputPropertiesSlice)
-
- for i := 0; i < sliceValue.Len(); i++ {
- structValue := sliceValue.Index(i)
- fieldValue := structValue.Field(f)
- if !fieldValue.CanInterface() {
- // The field is not exported so ignore it.
- continue
- }
-
- if commonValue == nil {
- // Use the first value as the commonProperties value.
- commonValue = &fieldValue
- } else {
- // If the value does not match the current common value then there is
- // no value in common so break out.
- if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
- commonValue = nil
- break
- }
- }
- }
-
- // If the fields all have a common value then store it in the common struct field
- // and set the input struct's field to the empty value.
- if commonValue != nil {
- emptyValue := emptyStructValue.Field(f)
- commonStructValue.Field(f).Set(*commonValue)
- for i := 0; i < sliceValue.Len(); i++ {
- structValue := sliceValue.Index(i)
- fieldValue := structValue.Field(f)
- fieldValue.Set(emptyValue)
- }
- }
- }
-}
-
-func (info *nativeLibInfo) generatePrebuiltLibrary(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
-
- pbm := builder.AddPrebuiltModule(member, info.memberType.prebuiltModuleType)
-
- addPossiblyArchSpecificProperties(sdkModuleContext, builder, info.commonProperties, pbm)
-
- archProperties := pbm.AddPropertySet("arch")
- for _, av := range info.archVariantProperties {
- archTypeProperties := archProperties.AddPropertySet(av.archType)
-
- // If the library has some link types then it produces an output binary file, otherwise it
- // is header only.
- if info.memberType.linkTypes != nil {
- // Copy the generated library to the snapshot and add a reference to it in the .bp module.
- nativeLibraryPath := nativeLibraryPathFor(av)
- builder.CopyToSnapshot(av.outputFile, nativeLibraryPath)
- archTypeProperties.AddProperty("srcs", []string{nativeLibraryPath})
- }
-
- // Add any arch specific properties inside the appropriate arch: {<arch>: {...}} block
- addPossiblyArchSpecificProperties(sdkModuleContext, builder, av, archTypeProperties)
- }
- pbm.AddProperty("stl", "none")
- pbm.AddProperty("system_shared_libs", []string{})
-}
-
type includeDirsProperty struct {
// Accessor to retrieve the paths
- pathsGetter func(libInfo nativeLibInfoProperties) android.Paths
+ pathsGetter func(libInfo *nativeLibInfoProperties) android.Paths
// The name of the property in the prebuilt library, "" means there is no property.
propertyName string
@@ -252,7 +147,7 @@
// ExportedIncludeDirs lists directories that contains some header files to be
// copied into a directory in the snapshot. The snapshot directories must be added to
// the export_include_dirs property in the prebuilt module in the snapshot.
- pathsGetter: func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.ExportedIncludeDirs },
+ pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedIncludeDirs },
propertyName: "export_include_dirs",
snapshotDir: nativeIncludeDir,
copy: true,
@@ -262,7 +157,7 @@
// ExportedSystemIncludeDirs lists directories that contains some system header files to
// be copied into a directory in the snapshot. The snapshot directories must be added to
// the export_system_include_dirs property in the prebuilt module in the snapshot.
- pathsGetter: func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.ExportedSystemIncludeDirs },
+ pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedSystemIncludeDirs },
propertyName: "export_system_include_dirs",
snapshotDir: nativeIncludeDir,
copy: true,
@@ -273,7 +168,7 @@
// that are explicitly listed in the exportedGeneratedHeaders property. So, the contents
// of these directories do not need to be copied, but these directories do need adding to
// the export_include_dirs property in the prebuilt module in the snapshot.
- pathsGetter: func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedIncludeDirs },
+ pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedIncludeDirs },
propertyName: "export_include_dirs",
snapshotDir: nativeGeneratedIncludeDir,
copy: false,
@@ -284,7 +179,7 @@
// specified in exportedGeneratedIncludeDirs must be copied into the snapshot.
// As they are in a directory in exportedGeneratedIncludeDirs they do not need adding to a
// property in the prebuilt module in the snapshot.
- pathsGetter: func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedHeaders },
+ pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedHeaders },
propertyName: "",
snapshotDir: nativeGeneratedIncludeDir,
copy: true,
@@ -293,7 +188,22 @@
}
// Add properties that may, or may not, be arch specific.
-func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo nativeLibInfoProperties, outputProperties android.BpPropertySet) {
+func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo *nativeLibInfoProperties, outputProperties android.BpPropertySet) {
+
+ // Copy the generated library to the snapshot and add a reference to it in the .bp module.
+ if libInfo.outputFile != nil {
+ nativeLibraryPath := nativeLibraryPathFor(libInfo)
+ builder.CopyToSnapshot(libInfo.outputFile, nativeLibraryPath)
+ outputProperties.AddProperty("srcs", []string{nativeLibraryPath})
+ }
+
+ if len(libInfo.SharedLibs) > 0 {
+ outputProperties.AddPropertyWithTag("shared_libs", libInfo.SharedLibs, builder.SdkMemberReferencePropertyTag(false))
+ }
+
+ if len(libInfo.SystemSharedLibs) > 0 {
+ outputProperties.AddPropertyWithTag("system_shared_libs", libInfo.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false))
+ }
// Map from property name to the include dirs to add to the prebuilt module in the snapshot.
includeDirs := make(map[string][]string)
@@ -355,8 +265,8 @@
)
// path to the native library. Relative to <sdk_root>/<api_dir>
-func nativeLibraryPathFor(lib nativeLibInfoProperties) string {
- return filepath.Join(lib.archType,
+func nativeLibraryPathFor(lib *nativeLibInfoProperties) string {
+ return filepath.Join(lib.OsPrefix(), lib.archType,
nativeStubDir, lib.outputFile.Base())
}
@@ -365,6 +275,10 @@
// The exported (capitalized) fields will be examined and may be changed during common value extraction.
// The unexported fields will be left untouched.
type nativeLibInfoProperties struct {
+ android.SdkMemberPropertiesBase
+
+ memberType *librarySdkMemberType
+
// The name of the library, is not exported as this must not be changed during optimization.
name string
@@ -397,14 +311,50 @@
// This field is exported as its contents may not be arch specific.
ExportedFlags []string
+ // The set of shared libraries
+ //
+ // This field is exported as its contents may not be arch specific.
+ SharedLibs []string
+
+ // The set of system shared libraries
+ //
+ // This field is exported as its contents may not be arch specific.
+ SystemSharedLibs []string
+
// outputFile is not exported as it is always arch specific.
outputFile android.Path
}
-// nativeLibInfo represents a collection of arch-specific modules having the same name
-type nativeLibInfo struct {
- name string
- memberType *librarySdkMemberType
- archVariantProperties []nativeLibInfoProperties
- commonProperties nativeLibInfoProperties
+func (p *nativeLibInfoProperties) PopulateFromVariant(variant android.SdkAware) {
+ ccModule := variant.(*Module)
+
+ // If the library has some link types then it produces an output binary file, otherwise it
+ // is header only.
+ if p.memberType.linkTypes != nil {
+ p.outputFile = ccModule.OutputFile().Path()
+ }
+
+ // Separate out the generated include dirs (which are arch specific) from the
+ // include dirs (which may not be).
+ exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate(
+ ccModule.ExportedIncludeDirs(), isGeneratedHeaderDirectory)
+
+ p.name = variant.Name()
+ p.archType = ccModule.Target().Arch.ArchType.String()
+ p.ExportedIncludeDirs = exportedIncludeDirs
+ p.exportedGeneratedIncludeDirs = exportedGeneratedIncludeDirs
+ p.ExportedSystemIncludeDirs = ccModule.ExportedSystemIncludeDirs()
+ p.ExportedFlags = ccModule.ExportedFlags()
+ if ccModule.linker != nil {
+ specifiedDeps := specifiedDeps{}
+ specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps)
+
+ p.SharedLibs = specifiedDeps.sharedLibs
+ p.SystemSharedLibs = specifiedDeps.systemSharedLibs
+ }
+ p.exportedGeneratedHeaders = ccModule.ExportedGeneratedHeaders()
+}
+
+func (p *nativeLibInfoProperties) AddToPropertySet(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, propertySet android.BpPropertySet) {
+ addPossiblyArchSpecificProperties(sdkModuleContext, builder, p, propertySet)
}
diff --git a/cc/linkable.go b/cc/linkable.go
index e4f034c..80cd6b8 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -26,6 +26,7 @@
BuildStubs() bool
SetBuildStubs()
SetStubsVersions(string)
+ StubsVersion() string
HasStubsVariants() bool
SelectedStl() string
ApiLevel() string
diff --git a/cc/linker.go b/cc/linker.go
index a7b621a..aa2d0ab 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -490,6 +490,12 @@
panic(fmt.Errorf("baseLinker doesn't know how to link"))
}
+func (linker *baseLinker) linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps {
+ specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, linker.Properties.Shared_libs...)
+ specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, linker.Properties.System_shared_libs...)
+ return specifiedDeps
+}
+
// Injecting version symbols
// Some host modules want a version number, but we don't want to rebuild it every time. Optionally add a step
// after linking that injects a constant placeholder with the current version number.
diff --git a/cc/sanitize.go b/cc/sanitize.go
index a342cd2..f12edc6 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -900,6 +900,11 @@
c.sanitize.Properties.Sanitizers = sanitizers
c.sanitize.Properties.DiagSanitizers = diagSanitizers
+ // TODO(b/150822854) Hosts have a different default behavior and assume the runtime library is used.
+ if c.Host() {
+ diagSanitizers = sanitizers
+ }
+
// Determine the runtime library required
runtimeLibrary := ""
var extraStaticDeps []string
diff --git a/cc/stl.go b/cc/stl.go
index eda8a4f..8113f72 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -235,11 +235,6 @@
flags.Local.CppFlags = append(flags.Local.CppFlags, "-nostdinc++")
flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++")
if ctx.Windows() {
- if stl.Properties.SelectedStl == "libc++_static" {
- // These are transitively needed by libc++_static.
- flags.extraLibFlags = append(flags.extraLibFlags,
- "-lmsvcrt", "-lucrt")
- }
// Use SjLj exceptions for 32-bit. libgcc_eh implements SjLj
// exception model for 32-bit.
if ctx.Arch().ArchType == android.X86 {
diff --git a/cc/testing.go b/cc/testing.go
index a22763a..b8a7eab 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -34,7 +34,7 @@
ctx.RegisterModuleType("ndk_prebuilt_object", NdkPrebuiltObjectFactory)
}
-func GatherRequiredDepsForTest(os android.OsType) string {
+func GatherRequiredDepsForTest(oses ...android.OsType) string {
ret := `
toolchain_library {
name: "libatomic",
@@ -341,8 +341,9 @@
}
`
- if os == android.Fuchsia {
- ret += `
+ for _, os := range oses {
+ if os == android.Fuchsia {
+ ret += `
cc_library {
name: "libbioniccompat",
stl: "none",
@@ -352,6 +353,22 @@
stl: "none",
}
`
+ }
+ if os == android.Windows {
+ ret += `
+ toolchain_library {
+ name: "libwinpthread",
+ host_supported: true,
+ enabled: false,
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ src: "",
+ }
+ `
+ }
}
return ret
}
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 9a71be2..8280cb1 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -99,8 +99,8 @@
if err != nil {
ctx.ModuleErrorf("invalid targetSdkVersion: %s", err)
}
- if UseApiFingerprint(ctx, targetSdkVersion) {
- targetSdkVersion += fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
+ if UseApiFingerprint(ctx) {
+ targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
deps = append(deps, ApiFingerprintPath(ctx))
}
@@ -108,8 +108,8 @@
if err != nil {
ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
}
- if UseApiFingerprint(ctx, minSdkVersion) {
- minSdkVersion += fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
+ if UseApiFingerprint(ctx) {
+ minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
deps = append(deps, ApiFingerprintPath(ctx))
}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index d7adb40..7ccf828 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -176,11 +176,6 @@
return true
}
- if len(ctx.Config().Targets[android.Android]) == 0 {
- // Host-only build
- return true
- }
-
return false
}
@@ -199,7 +194,10 @@
// Include dexpreopt files for the primary boot image.
files := map[android.ArchType]android.OutputPaths{}
for _, variant := range artBootImageConfig(ctx).variants {
- files[variant.target.Arch.ArchType] = variant.imagesDeps
+ // We also generate boot images for host (for testing), but we don't need those in the apex.
+ if variant.target.Os == android.Android {
+ files[variant.target.Arch.ArchType] = variant.imagesDeps
+ }
}
return files
}
@@ -305,9 +303,10 @@
global := dexpreopt.GetGlobalConfig(ctx)
arch := image.target.Arch.ArchType
- symbolsDir := image.symbolsDir.Join(ctx, image.installSubdir, arch.String())
+ os := image.target.Os.String() // We need to distinguish host-x86 and device-x86.
+ symbolsDir := image.symbolsDir.Join(ctx, os, image.installSubdir, arch.String())
symbolsFile := symbolsDir.Join(ctx, image.stem+".oat")
- outputDir := image.dir.Join(ctx, image.installSubdir, arch.String())
+ outputDir := image.dir.Join(ctx, os, image.installSubdir, arch.String())
outputPath := outputDir.Join(ctx, image.stem+".oat")
oatLocation := dexpreopt.PathToLocation(outputPath, arch)
imagePath := outputPath.ReplaceExtension(ctx, "art")
@@ -375,12 +374,18 @@
FlagWithArg("--oat-location=", oatLocation).
FlagWithArg("--image=", imagePath.String()).
FlagWithArg("--instruction-set=", arch.String()).
- FlagWithArg("--instruction-set-variant=", global.CpuVariant[arch]).
- FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch]).
FlagWithArg("--android-root=", global.EmptyDirectory).
FlagWithArg("--no-inline-from=", "core-oj.jar").
+ Flag("--force-determinism").
Flag("--abort-on-hard-verifier-error")
+ // Use the default variant/features for host builds.
+ // The map below contains only device CPU info (which might be x86 on some devices).
+ if image.target.Os == android.Android {
+ cmd.FlagWithArg("--instruction-set-variant=", global.CpuVariant[arch])
+ cmd.FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch])
+ }
+
if global.BootFlags != "" {
cmd.Flag(global.BootFlags)
}
@@ -392,7 +397,6 @@
cmd.Textf(`|| ( echo %s ; false )`, proptools.ShellEscape(failureMessage))
installDir := filepath.Join("/", image.installSubdir, arch.String())
- vdexInstallDir := filepath.Join("/", image.installSubdir)
var vdexInstalls android.RuleBuilderInstalls
var unstrippedInstalls android.RuleBuilderInstalls
@@ -411,11 +415,10 @@
cmd.ImplicitOutput(vdex)
zipFiles = append(zipFiles, vdex)
- // The vdex files are identical between architectures, install them to a shared location. The Make rules will
- // only use the install rules for one architecture, and will create symlinks into the architecture-specific
- // directories.
+ // Note that the vdex files are identical between architectures.
+ // Make rules will create symlinks to share them between architectures.
vdexInstalls = append(vdexInstalls,
- android.RuleBuilderInstall{vdex, filepath.Join(vdexInstallDir, vdex.Base())})
+ android.RuleBuilderInstall{vdex, filepath.Join(installDir, vdex.Base())})
}
for _, unstrippedOat := range image.moduleFiles(ctx, symbolsDir, ".oat") {
@@ -426,7 +429,7 @@
android.RuleBuilderInstall{unstrippedOat, filepath.Join(installDir, unstrippedOat.Base())})
}
- rule.Build(pctx, ctx, image.name+"JarsDexpreopt_"+arch.String(), "dexpreopt "+image.name+" jars "+arch.String())
+ rule.Build(pctx, ctx, image.name+"JarsDexpreopt_"+image.target.String(), "dexpreopt "+image.name+" jars "+arch.String())
// save output and installed files for makevars
image.installs = rule.Installs()
@@ -544,8 +547,9 @@
var allPhonies android.Paths
for _, image := range image.variants {
arch := image.target.Arch.ArchType
+ suffix := image.target.String()
// Create a rule to call oatdump.
- output := android.PathForOutput(ctx, "boot."+arch.String()+".oatdump.txt")
+ output := android.PathForOutput(ctx, "boot."+suffix+".oatdump.txt")
rule := android.NewRuleBuilder()
rule.Command().
// TODO: for now, use the debug version for better error reporting
@@ -555,16 +559,16 @@
FlagWithArg("--image=", strings.Join(image.imageLocations, ":")).Implicits(image.imagesDeps.Paths()).
FlagWithOutput("--output=", output).
FlagWithArg("--instruction-set=", arch.String())
- rule.Build(pctx, ctx, "dump-oat-boot-"+arch.String(), "dump oat boot "+arch.String())
+ rule.Build(pctx, ctx, "dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
// Create a phony rule that depends on the output file and prints the path.
- phony := android.PathForPhony(ctx, "dump-oat-boot-"+arch.String())
+ phony := android.PathForPhony(ctx, "dump-oat-boot-"+suffix)
rule = android.NewRuleBuilder()
rule.Command().
Implicit(output).
ImplicitOutput(phony).
Text("echo").FlagWithArg("Output in ", output.String())
- rule.Build(pctx, ctx, "phony-dump-oat-boot-"+arch.String(), "dump oat boot "+arch.String())
+ rule.Build(pctx, ctx, "phony-dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
allPhonies = append(allPhonies, phony)
}
@@ -608,7 +612,11 @@
for _, current := range append(d.otherImages, image) {
imageNames = append(imageNames, current.name)
for _, current := range current.variants {
- sfx := current.name + "_" + current.target.Arch.ArchType.String()
+ suffix := ""
+ if current.target.Os.Class == android.Host {
+ suffix = "_host"
+ }
+ sfx := current.name + suffix + "_" + current.target.Arch.ArchType.String()
ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+sfx, current.vdexInstalls.String())
ctx.Strict("DEXPREOPT_IMAGE_"+sfx, current.images.String())
ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(current.imagesDeps.Strings(), " "))
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index c3b2133..94ca8bb 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -62,7 +62,7 @@
bootArt := dexpreoptBootJars.Output("boot-foo.art")
expectedInputs := []string{
- "dex_artjars/apex/com.android.art/javalib/arm64/boot.art",
+ "dex_artjars/android/apex/com.android.art/javalib/arm64/boot.art",
"dex_bootjars_input/foo.jar",
"dex_bootjars_input/bar.jar",
"dex_bootjars_input/baz.jar",
@@ -81,23 +81,23 @@
}
expectedOutputs := []string{
- "dex_bootjars/system/framework/arm64/boot.invocation",
+ "dex_bootjars/android/system/framework/arm64/boot.invocation",
- "dex_bootjars/system/framework/arm64/boot-foo.art",
- "dex_bootjars/system/framework/arm64/boot-bar.art",
- "dex_bootjars/system/framework/arm64/boot-baz.art",
+ "dex_bootjars/android/system/framework/arm64/boot-foo.art",
+ "dex_bootjars/android/system/framework/arm64/boot-bar.art",
+ "dex_bootjars/android/system/framework/arm64/boot-baz.art",
- "dex_bootjars/system/framework/arm64/boot-foo.oat",
- "dex_bootjars/system/framework/arm64/boot-bar.oat",
- "dex_bootjars/system/framework/arm64/boot-baz.oat",
+ "dex_bootjars/android/system/framework/arm64/boot-foo.oat",
+ "dex_bootjars/android/system/framework/arm64/boot-bar.oat",
+ "dex_bootjars/android/system/framework/arm64/boot-baz.oat",
- "dex_bootjars/system/framework/arm64/boot-foo.vdex",
- "dex_bootjars/system/framework/arm64/boot-bar.vdex",
- "dex_bootjars/system/framework/arm64/boot-baz.vdex",
+ "dex_bootjars/android/system/framework/arm64/boot-foo.vdex",
+ "dex_bootjars/android/system/framework/arm64/boot-bar.vdex",
+ "dex_bootjars/android/system/framework/arm64/boot-baz.vdex",
- "dex_bootjars_unstripped/system/framework/arm64/boot-foo.oat",
- "dex_bootjars_unstripped/system/framework/arm64/boot-bar.oat",
- "dex_bootjars_unstripped/system/framework/arm64/boot-baz.oat",
+ "dex_bootjars_unstripped/android/system/framework/arm64/boot-foo.oat",
+ "dex_bootjars_unstripped/android/system/framework/arm64/boot-bar.oat",
+ "dex_bootjars_unstripped/android/system/framework/arm64/boot-baz.oat",
}
for i := range expectedOutputs {
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index a06aec4..d77d3e1 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -68,6 +68,10 @@
targets = append(targets, target)
}
}
+ // We may also need the images on host in order to run host-based tests.
+ for _, target := range ctx.Config().Targets[android.BuildOs] {
+ targets = append(targets, target)
+ }
return targets
}
@@ -152,7 +156,7 @@
// expands to <stem>.art for primary image and <stem>-<1st module>.art for extension
imageName := c.firstModuleNameOrStem() + ".art"
- c.imageLocations = []string{c.dir.Join(ctx, c.installSubdir, imageName).String()}
+ c.imageLocations = []string{c.dir.Join(ctx, "android", c.installSubdir, imageName).String()}
// The path to bootclasspath dex files needs to be known at module
// GenerateAndroidBuildAction time, before the bootclasspath modules have been compiled.
@@ -167,7 +171,7 @@
// Create target-specific variants.
for _, target := range targets {
arch := target.Arch.ArchType
- imageDir := c.dir.Join(ctx, c.installSubdir, arch.String())
+ imageDir := c.dir.Join(ctx, target.Os.String(), c.installSubdir, arch.String())
variant := &bootImageVariant{
bootImageConfig: c,
target: target,
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 5437499..1ac7444 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -1345,6 +1345,7 @@
cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
} else {
cmd.FlagWithArg("--stubs ", stubsDir.String())
+ cmd.Flag("--exclude-documentation-from-stubs")
}
}
diff --git a/java/java.go b/java/java.go
index 135ae51..8c779f5 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1796,11 +1796,16 @@
}
func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
- depTag := ctx.OtherModuleDependencyTag(dep)
// Dependencies other than the static linkage are all considered crossing APEX boundary
+ if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
+ return true
+ }
// Also, a dependency to an sdk member is also considered as such. This is required because
// sdk members should be mutated into APEXes. Refer to sdk.sdkDepsReplaceMutator.
- return depTag == staticLibTag || j.IsInAnySdk()
+ if sa, ok := dep.(android.SdkAware); ok && sa.IsInAnySdk() {
+ return true
+ }
+ return false
}
func (j *Module) Stem() string {
@@ -1879,12 +1884,12 @@
)
// path to the jar file of a java library. Relative to <sdk_root>/<api_dir>
-func sdkSnapshotFilePathForJar(member android.SdkMember) string {
- return sdkSnapshotFilePathForMember(member, jarFileSuffix)
+func sdkSnapshotFilePathForJar(osPrefix, name string) string {
+ return sdkSnapshotFilePathForMember(osPrefix, name, jarFileSuffix)
}
-func sdkSnapshotFilePathForMember(member android.SdkMember, suffix string) string {
- return filepath.Join(javaDir, member.Name()+suffix)
+func sdkSnapshotFilePathForMember(osPrefix, name string, suffix string) string {
+ return filepath.Join(javaDir, osPrefix, name+suffix)
}
type librarySdkMemberType struct {
@@ -1904,32 +1909,46 @@
return ok
}
-func (mt *librarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
+func (mt *librarySdkMemberType) AddPrebuiltModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) android.BpModule {
+ return builder.AddPrebuiltModule(member, "java_import")
+}
- variants := member.Variants()
- if len(variants) != 1 {
- sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
- for _, variant := range variants {
- sdkModuleContext.ModuleErrorf(" %q", variant)
- }
- }
- variant := variants[0]
+func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &librarySdkMemberProperties{memberType: mt}
+}
+
+type librarySdkMemberProperties struct {
+ android.SdkMemberPropertiesBase
+
+ memberType *librarySdkMemberType
+
+ library *Library
+ jarToExport android.Path
+}
+
+func (p *librarySdkMemberProperties) PopulateFromVariant(variant android.SdkAware) {
j := variant.(*Library)
- exportedJar := mt.jarToExportGetter(j)
- snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(member)
- builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
+ p.library = j
+ p.jarToExport = p.memberType.jarToExportGetter(j)
+}
- for _, dir := range j.AidlIncludeDirs() {
- // TODO(jiyong): copy parcelable declarations only
- aidlFiles, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
- for _, file := range aidlFiles {
- builder.CopyToSnapshot(android.PathForSource(sdkModuleContext, file), filepath.Join(aidlIncludeDir, file))
+func (p *librarySdkMemberProperties) AddToPropertySet(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, propertySet android.BpPropertySet) {
+ if p.jarToExport != nil {
+ exportedJar := p.jarToExport
+ snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), p.library.Name())
+ builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
+
+ for _, dir := range p.library.AidlIncludeDirs() {
+ // TODO(jiyong): copy parcelable declarations only
+ aidlFiles, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
+ for _, file := range aidlFiles {
+ builder.CopyToSnapshot(android.PathForSource(sdkModuleContext, file), filepath.Join(aidlIncludeDir, file))
+ }
}
- }
- module := builder.AddPrebuiltModule(member, "java_import")
- module.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+ propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+ }
}
var javaHeaderLibsSdkMemberType android.SdkMemberType = &librarySdkMemberType{
@@ -2094,31 +2113,44 @@
return ok
}
-func (mt *testSdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
- variants := member.Variants()
- if len(variants) != 1 {
- sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
- for _, variant := range variants {
- sdkModuleContext.ModuleErrorf(" %q", variant)
- }
- }
- variant := variants[0]
- j := variant.(*Test)
+func (mt *testSdkMemberType) AddPrebuiltModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) android.BpModule {
+ return builder.AddPrebuiltModule(member, "java_test_import")
+}
- implementationJars := j.ImplementationJars()
+func (mt *testSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &testSdkMemberProperties{}
+}
+
+type testSdkMemberProperties struct {
+ android.SdkMemberPropertiesBase
+
+ test *Test
+ jarToExport android.Path
+}
+
+func (p *testSdkMemberProperties) PopulateFromVariant(variant android.SdkAware) {
+ test := variant.(*Test)
+
+ implementationJars := test.ImplementationJars()
if len(implementationJars) != 1 {
- panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
+ panic(fmt.Errorf("there must be only one implementation jar from %q", test.Name()))
}
- snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(member)
- builder.CopyToSnapshot(implementationJars[0], snapshotRelativeJavaLibPath)
+ p.test = test
+ p.jarToExport = implementationJars[0]
+}
- snapshotRelativeTestConfigPath := sdkSnapshotFilePathForMember(member, testConfigSuffix)
- builder.CopyToSnapshot(j.testConfig, snapshotRelativeTestConfigPath)
+func (p *testSdkMemberProperties) AddToPropertySet(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, propertySet android.BpPropertySet) {
+ if p.jarToExport != nil {
+ snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), p.test.Name())
+ builder.CopyToSnapshot(p.jarToExport, snapshotRelativeJavaLibPath)
- module := builder.AddPrebuiltModule(member, "java_test_import")
- module.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
- module.AddProperty("test_config", snapshotRelativeTestConfigPath)
+ snapshotRelativeTestConfigPath := sdkSnapshotFilePathForMember(p.OsPrefix(), p.test.Name(), testConfigSuffix)
+ builder.CopyToSnapshot(p.test.testConfig, snapshotRelativeTestConfigPath)
+
+ propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+ propertySet.AddProperty("test_config", snapshotRelativeTestConfigPath)
+ }
}
// java_test builds a and links sources into a `.jar` file for the device, and possibly for the host as well, and
@@ -2321,7 +2353,7 @@
//
type ImportProperties struct {
- Jars []string `android:"path"`
+ Jars []string `android:"path,arch_variant"`
Sdk_version *string
@@ -2477,11 +2509,16 @@
}
func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
- depTag := ctx.OtherModuleDependencyTag(dep)
// dependencies other than the static linkage are all considered crossing APEX boundary
+ if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
+ return true
+ }
// Also, a dependency to an sdk member is also considered as such. This is required because
// sdk members should be mutated into APEXes. Refer to sdk.sdkDepsReplaceMutator.
- return depTag == staticLibTag || j.IsInAnySdk()
+ if sa, ok := dep.(android.SdkAware); ok && sa.IsInAnySdk() {
+ return true
+ }
+ return false
}
// Add compile time check for interface implementation
diff --git a/java/sdk.go b/java/sdk.go
index 1e60d67..ded2a06 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -50,9 +50,8 @@
targetSdkVersion() sdkSpec
}
-func UseApiFingerprint(ctx android.BaseModuleContext, v string) bool {
- if v == ctx.Config().PlatformSdkCodename() &&
- ctx.Config().UnbundledBuild() &&
+func UseApiFingerprint(ctx android.BaseModuleContext) bool {
+ if ctx.Config().UnbundledBuild() &&
!ctx.Config().UnbundledBuildUsePrebuiltSdks() &&
ctx.Config().IsEnvTrue("UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT") {
return true
@@ -283,6 +282,28 @@
}
}
+func (s sdkSpec) validateSystemSdk(ctx android.EarlyModuleContext) bool {
+ // Ensures that the specified system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor/product Java module)
+ // Assuming that BOARD_SYSTEMSDK_VERSIONS := 28 29,
+ // sdk_version of the modules in vendor/product that use system sdk must be either system_28, system_29 or system_current
+ if s.kind != sdkSystem || !s.version.isNumbered() {
+ return true
+ }
+ allowedVersions := ctx.DeviceConfig().PlatformSystemSdkVersions()
+ if ctx.DeviceSpecific() || ctx.SocSpecific() || (ctx.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
+ systemSdkVersions := ctx.DeviceConfig().SystemSdkVersions()
+ if len(systemSdkVersions) > 0 {
+ allowedVersions = systemSdkVersions
+ }
+ }
+ if len(allowedVersions) > 0 && !android.InList(s.version.String(), allowedVersions) {
+ ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
+ s.raw, allowedVersions)
+ return false
+ }
+ return true
+}
+
func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep {
sdkVersion := sdkContext.sdkVersion()
if !sdkVersion.valid() {
@@ -293,6 +314,9 @@
if ctx.Config().IsPdkBuild() {
sdkVersion = sdkVersion.forPdkBuild(ctx)
}
+ if !sdkVersion.validateSystemSdk(ctx) {
+ return sdkDep{}
+ }
if sdkVersion.usePrebuilt(ctx) {
dir := filepath.Join("prebuilts", "sdk", sdkVersion.version.String(), sdkVersion.kind.String())
@@ -340,21 +364,6 @@
}
}
- // Ensures that the specificed system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor apks)
- // or PRODUCT_SYSTEMSDK_VERSIONS (for other apks or when BOARD_SYSTEMSDK_VERSIONS is not set)
- if sdkVersion.kind == sdkSystem && sdkVersion.version.isNumbered() {
- allowed_versions := ctx.DeviceConfig().PlatformSystemSdkVersions()
- if ctx.DeviceSpecific() || ctx.SocSpecific() {
- if len(ctx.DeviceConfig().SystemSdkVersions()) > 0 {
- allowed_versions = ctx.DeviceConfig().SystemSdkVersions()
- }
- }
- if len(allowed_versions) > 0 && !android.InList(sdkVersion.version.String(), allowed_versions) {
- ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
- sdkVersion.raw, allowed_versions)
- }
- }
-
switch sdkVersion.kind {
case sdkPrivate:
return sdkDep{
diff --git a/java/sdk_library.go b/java/sdk_library.go
index a8edf1d..6921114 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -581,6 +581,14 @@
mctx.CreateModule(DroidstubsFactory, &props)
}
+func (module *SdkLibrary) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool {
+ depTag := mctx.OtherModuleDependencyTag(dep)
+ if depTag == xmlPermissionsFileTag {
+ return true
+ }
+ return module.Library.DepIsInSameApex(mctx, dep)
+}
+
// Creates the xml file that publicizes the runtime library
func (module *SdkLibrary) createXmlFile(mctx android.LoadHookContext) {
props := struct {
@@ -590,9 +598,11 @@
Device_specific *bool
Product_specific *bool
System_ext_specific *bool
+ Apex_available []string
}{
- Name: proptools.StringPtr(module.xmlFileName()),
- Lib_name: proptools.StringPtr(module.BaseModuleName()),
+ Name: proptools.StringPtr(module.xmlFileName()),
+ Lib_name: proptools.StringPtr(module.BaseModuleName()),
+ Apex_available: module.ApexProperties.Apex_available,
}
if module.SocSpecific() {
diff --git a/java/system_modules.go b/java/system_modules.go
index 47de6e3..40031cb 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -255,5 +255,5 @@
pbm := builder.AddPrebuiltModule(member, "java_system_modules_import")
// Add the references to the libraries that form the system module.
- pbm.AddPropertyWithTag("libs", systemModule.properties.Libs, builder.SdkMemberReferencePropertyTag())
+ pbm.AddPropertyWithTag("libs", systemModule.properties.Libs, builder.SdkMemberReferencePropertyTag(true))
}
diff --git a/python/androidmk.go b/python/androidmk.go
index 8e8e8ef..d293d52 100644
--- a/python/androidmk.go
+++ b/python/androidmk.go
@@ -100,5 +100,6 @@
fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES := "+strings.Join(installer.androidMkSharedLibs, " "))
+ fmt.Fprintln(w, "LOCAL_CHECK_ELF_FILES := false")
})
}
diff --git a/rust/rust.go b/rust/rust.go
index de6512c..f446ef0 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -325,6 +325,10 @@
panic("SetStubsVersions not yet implemented for rust modules")
}
+func (mod *Module) StubsVersion() string {
+ panic("SetStubsVersions not yet implemented for rust modules")
+}
+
func (mod *Module) BuildStaticVariant() bool {
if mod.compiler != nil {
if library, ok := mod.compiler.(libraryInterface); ok {
diff --git a/scripts/OWNERS b/scripts/OWNERS
index 076b3f5..9e97a60 100644
--- a/scripts/OWNERS
+++ b/scripts/OWNERS
@@ -1 +1,2 @@
per-file system-clang-format,system-clang-format-2 = enh@google.com,smoreland@google.com
+per-file build-mainline-modules.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh
new file mode 100755
index 0000000..79e40dd
--- /dev/null
+++ b/scripts/build-mainline-modules.sh
@@ -0,0 +1,63 @@
+#!/bin/bash -ex
+
+# Non exhaustive list of modules where we want prebuilts. More can be added as
+# needed.
+MAINLINE_MODULES=(
+ com.android.art.debug
+ com.android.art.release
+ com.android.art.testing
+ com.android.conscrypt
+ com.android.runtime
+ com.android.tzdata
+ com.android.i18n
+)
+
+# List of SDKs and module exports we know of.
+MODULES_SDK_AND_EXPORTS=(
+ art-module-sdk
+ art-module-test-exports
+ conscrypt-module-sdk
+ conscrypt-module-test-exports
+)
+
+# We want to create apex modules for all supported architectures.
+PRODUCTS=(
+ aosp_arm
+ aosp_arm64
+ aosp_x86
+ aosp_x86_64
+)
+
+if [ ! -e "build/make/core/Makefile" ]; then
+ echo "$0 must be run from the top of the tree"
+ exit 1
+fi
+
+OUT_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var OUT_DIR)
+DIST_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var DIST_DIR)
+
+for product in "${PRODUCTS[@]}"; do
+ build/soong/soong_ui.bash --make-mode $@ \
+ TARGET_PRODUCT=${product} \
+ ${MAINLINE_MODULES[@]}
+
+ PRODUCT_OUT=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var PRODUCT_OUT)
+ TARGET_ARCH=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var TARGET_ARCH)
+ rm -rf ${DIST_DIR}/${TARGET_ARCH}/
+ mkdir -p ${DIST_DIR}/${TARGET_ARCH}/
+ for module in "${MAINLINE_MODULES[@]}"; do
+ cp ${PWD}/${PRODUCT_OUT}/system/apex/${module}.apex ${DIST_DIR}/${TARGET_ARCH}/
+ done
+done
+
+
+# Create multi-archs SDKs in a different out directory. The multi-arch script
+# uses soong directly and therefore needs its own directory that doesn't clash
+# with make.
+export OUT_DIR=${OUT_DIR}/aml/
+for sdk in "${MODULES_SDK_AND_EXPORTS[@]}"; do
+ build/soong/scripts/build-aml-prebuilts.sh ${sdk}
+done
+
+rm -rf ${DIST_DIR}/mainline-sdks
+cp -R ${OUT_DIR}/soong/mainline-sdks ${DIST_DIR}
diff --git a/scripts/reverse-deps.sh b/scripts/reverse-deps.sh
new file mode 100755
index 0000000..02b7dcb
--- /dev/null
+++ b/scripts/reverse-deps.sh
@@ -0,0 +1,246 @@
+#!/bin/bash
+
+set -eu
+
+# 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.
+
+# Tool to evaluate the transitive closure of the ninja dependency graph of the
+# files and targets depending on a given target.
+#
+# i.e. the list of things that could change after changing a target.
+
+readonly me=$(basename "${0}")
+
+readonly usage="usage: ${me} {options} target [target...]
+
+Evaluate the reverse transitive closure of ninja targets depending on one or
+more targets.
+
+Options:
+
+ -(no)quiet Suppresses progress output to stderr and interactive
+ alias -(no)q prompts. By default, when stderr is a tty, progress gets
+ reported to stderr; when both stderr and stdin are tty,
+ the script asks user whether to delete intermediate files.
+ When suppressed or not prompted, script always deletes the
+ temporary / intermediate files.
+ -sep=<delim> Use 'delim' as output field separator between notice
+ checksum and notice filename in notice output.
+ e.g. sep='\t'
+ (Default space)
+ -csv Shorthand for -sep=','
+
+At minimum, before running this script, you must first run:
+$ source build/envsetup.sh
+$ lunch
+$ m nothing
+to setup the build environment, choose a target platform, and build the ninja
+dependency graph.
+"
+
+function die() { echo -e "${*}" >&2; exit 2; }
+
+# Reads one input target per line from stdin; outputs (isnotice target) tuples.
+#
+# output target is a ninja target that the input target depends on
+# isnotice in {0,1} with 1 for output targets believed to be license or notice
+#
+# only argument is the dependency depth indicator
+function getDeps() {
+ (tr '\n' '\0' | xargs -0 "${ninja_bin}" -f "${ninja_file}" -t query) \
+ | awk -v depth="${1}" '
+ BEGIN {
+ inoutput = 0
+ }
+ $0 ~ /^\S\S*:$/ {
+ inoutput = 0
+ }
+ inoutput != 0 {
+ print gensub(/^\s*/, "", "g")" "depth
+ }
+ $1 == "outputs:" {
+ inoutput = 1
+ }
+ '
+}
+
+
+if [ -z "${ANDROID_BUILD_TOP}" ]; then
+ die "${me}: Run 'lunch' to configure the build environment"
+fi
+
+if [ -z "${TARGET_PRODUCT}" ]; then
+ die "${me}: Run 'lunch' to configure the build environment"
+fi
+
+ninja_file="${ANDROID_BUILD_TOP}/out/combined-${TARGET_PRODUCT}.ninja"
+if [ ! -f "${ninja_file}" ]; then
+ die "${me}: Run 'm nothing' to build the dependency graph"
+fi
+
+ninja_bin="${ANDROID_BUILD_TOP}/prebuilts/build-tools/linux-x86/bin/ninja"
+if [ ! -x "${ninja_bin}" ]; then
+ die "${me}: Cannot find ninja executable expected at ${ninja_bin}"
+fi
+
+
+# parse the command-line
+
+declare -a targets # one or more targets to evaluate
+
+quiet=false # whether to suppress progress
+
+sep=" " # output separator between depth and target
+
+use_stdin=false # whether to read targets from stdin i.e. target -
+
+while [ $# -gt 0 ]; do
+ case "${1:-}" in
+ -)
+ use_stdin=true
+ ;;
+ -*)
+ flag=$(expr "${1}" : '^-*\(.*\)$')
+ case "${flag:-}" in
+ q) ;&
+ quiet)
+ quiet=true;;
+ noq) ;&
+ noquiet)
+ quiet=false;;
+ csv)
+ sep=",";;
+ sep)
+ sep="${2?"${usage}"}"; shift;;
+ sep=*)
+ sep=$(expr "${flag}" : '^sep=\(.*\)$';;
+ *)
+ die "Unknown flag ${1}"
+ ;;
+ esac
+ ;;
+ *)
+ targets+=("${1:-}")
+ ;;
+ esac
+ shift
+done
+
+if [ ! -v targets[0] ] && ! ${use_stdin}; then
+ die "${usage}\n\nNo target specified."
+fi
+
+# showProgress when stderr is a tty
+if [ -t 2 ] && ! ${quiet}; then
+ showProgress=true
+else
+ showProgress=false
+fi
+
+# interactive when both stderr and stdin are tty
+if ${showProgress} && [ -t 0 ]; then
+ interactive=true
+else
+ interactive=false
+fi
+
+
+readonly tmpFiles=$(mktemp -d "${TMPDIR}.tdeps.XXXXXXXXX")
+if [ -z "${tmpFiles}" ]; then
+ die "${me}: unable to create temporary directory"
+fi
+
+# The deps files contain unique (isnotice target) tuples where
+# isnotice in {0,1} with 1 when ninja target `target` is a license or notice.
+readonly oldDeps="${tmpFiles}/old"
+readonly newDeps="${tmpFiles}/new"
+readonly allDeps="${tmpFiles}/all"
+
+if ${use_stdin}; then # start deps by reading 1 target per line from stdin
+ awk '
+ NF > 0 {
+ print gensub(/\s*$/, "", "g", gensub(/^\s*/, "", "g"))" "0
+ }
+ ' >"${newDeps}"
+else # start with no deps by clearing file
+ : >"${newDeps}"
+fi
+
+# extend deps by appending targets from command-line
+for idx in "${!targets[*]}"; do
+ echo "${targets[${idx}]} 0" >>"${newDeps}"
+done
+
+# remove duplicates and start with new, old and all the same
+sort -u <"${newDeps}" >"${allDeps}"
+cp "${allDeps}" "${newDeps}"
+cp "${allDeps}" "${oldDeps}"
+
+# report depth of dependenciens when showProgress
+depth=0
+
+while [ $(wc -l < "${newDeps}") -gt 0 ]; do
+ if ${showProgress}; then
+ echo "depth ${depth} has "$(wc -l < "${newDeps}")" targets" >&2
+ fi
+ depth=$(expr ${depth} + 1)
+ ( # recalculate dependencies by combining unique inputs of new deps w. old
+ cut -d\ -f1 "${newDeps}" | getDeps "${depth}"
+ cat "${oldDeps}"
+ ) | sort -n | awk '
+ BEGIN {
+ prev = ""
+ }
+ {
+ depth = $NF
+ $NF = ""
+ gsub(/\s*$/, "")
+ if ($0 != prev) {
+ print gensub(/\s*$/, "", "g")" "depth
+ }
+ prev = $0
+ }
+ ' >"${allDeps}"
+ # recalculate new dependencies as net additions to old dependencies
+ set +e
+ diff "${oldDeps}" "${allDeps}" --old-line-format='' \
+ --new-line-format='%L' --unchanged-line-format='' > "${newDeps}"
+ set -e
+ # recalculate old dependencies for next iteration
+ cp "${allDeps}" "${oldDeps}"
+done
+
+# found all deps -- clean up last iteration of old and new
+rm -f "${oldDeps}"
+rm -f "${newDeps}"
+
+if ${showProgress}; then
+ echo $(wc -l < "${allDeps}")" targets" >&2
+fi
+
+awk -v sep="${sep}" '{
+ depth = $NF
+ $NF = ""
+ gsub(/\s*$/, "")
+ print depth sep $0
+}' "${allDeps}" | sort -n
+
+if ${interactive}; then
+ echo -n "$(date '+%F %-k:%M:%S') Delete ${tmpFiles} ? [n] " >&2
+ read answer
+ case "${answer}" in [yY]*) rm -fr "${tmpFiles}";; esac
+else
+ rm -fr "${tmpFiles}"
+fi
diff --git a/scripts/transitive-deps.sh b/scripts/transitive-deps.sh
new file mode 100755
index 0000000..34e2ecf
--- /dev/null
+++ b/scripts/transitive-deps.sh
@@ -0,0 +1,483 @@
+#!/bin/bash
+
+set -eu
+
+# 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.
+
+# Tool to evaluate the transitive closure of the ninja dependency graph of the
+# files and targets a given target depends on.
+#
+# i.e. the list of things that, if changed, could cause a change to a target.
+
+readonly me=$(basename "${0}")
+
+readonly usage="usage: ${me} {options} target [target...]
+
+Evaluate the transitive closure of files and ninja targets that one or more
+targets depend on.
+
+Dependency Options:
+
+ -(no)order_deps Whether to include order-only dependencies. (Default false)
+ -(no)implicit Whether to include implicit dependencies. (Default true)
+ -(no)explicit Whether to include regular / explicit deps. (Default true)
+
+ -nofollow Unanchored regular expression. Matching paths and targets
+ always get reported. Their dependencies do not get reported
+ unless first encountered in a 'container' file type.
+ Multiple allowed and combined using '|'.
+ e.g. -nofollow='*.so' not -nofollow='.so$'
+ -nofollow='*.so|*.dex' or -nofollow='*.so' -nofollow='.dex'
+ (Defaults to no matches)
+ -container Unanchored regular expression. Matching file extensions get
+ treated as 'container' files for -nofollow option.
+ Multiple allowed and combines using '|'
+ (Default 'apex|apk|zip|jar|tar|tgz')
+
+Output Options:
+
+ -(no)quiet Suppresses progress output to stderr and interactive
+ alias -(no)q prompts. By default, when stderr is a tty, progress gets
+ reported to stderr; when both stderr and stdin are tty,
+ the script asks user whether to delete intermediate files.
+ When suppressed or not prompted, script always deletes the
+ temporary / intermediate files.
+ -sep=<delim> Use 'delim' as output field separator between notice
+ checksum and notice filename in notice output.
+ e.g. sep='\t'
+ (Default space)
+ -csv Shorthand for -sep=','
+ -directories=<f> Output directory names of dependencies to 'f'.
+ alias -d User '/dev/stdout' to send directories to stdout. Defaults
+ to no directory output.
+ -notices=<file> Output license and notice file paths to 'file'.
+ alias -n Use '/dev/stdout' to send notices to stdout. Defaults to no
+ license/notice output.
+ -projects=<file> Output git project names to 'file'. Use '/dev/stdout' to
+ alias -p send projects to stdout. Defaults to no project output.
+ -targets=<fils> Output target dependencies to 'file'. Use '/dev/stdout' to
+ alias -t send targets to stdout.
+ When no directory, notice, project or target output options
+ given, defaults to stdout. Otherwise, defaults to no target
+ output.
+
+At minimum, before running this script, you must first run:
+$ source build/envsetup.sh
+$ lunch
+$ m nothing
+to setup the build environment, choose a target platform, and build the ninja
+dependency graph.
+"
+
+function die() { echo -e "${*}" >&2; exit 2; }
+
+# Reads one input target per line from stdin; outputs (isnotice target) tuples.
+#
+# output target is a ninja target that the input target depends on
+# isnotice in {0,1} with 1 for output targets believed to be license or notice
+function getDeps() {
+ (tr '\n' '\0' | xargs -0 -r "${ninja_bin}" -f "${ninja_file}" -t query) \
+ | awk -v include_order="${include_order_deps}" \
+ -v include_implicit="${include_implicit_deps}" \
+ -v include_explicit="${include_deps}" \
+ -v containers="${container_types}" \
+ '
+ BEGIN {
+ ininput = 0
+ isnotice = 0
+ currFileName = ""
+ currExt = ""
+ }
+ $1 == "outputs:" {
+ ininput = 0
+ }
+ ininput == 0 && $0 ~ /^\S\S*:$/ {
+ isnotice = ($0 ~ /.*NOTICE.*[.]txt:$/)
+ currFileName = gensub(/^.*[/]([^/]*)[:]$/, "\\1", "g")
+ currExt = gensub(/^.*[.]([^./]*)[:]$/, "\\1", "g")
+ }
+ ininput != 0 && $1 !~ /^[|][|]?/ {
+ if (include_explicit == "true") {
+ fileName = gensub(/^.*[/]([^/]*)$/, "\\1", "g")
+ print ( \
+ (isnotice && $0 !~ /^\s*build[/]soong[/]scripts[/]/) \
+ || $0 ~ /NOTICE|LICEN[CS]E/ \
+ || $0 ~ /(notice|licen[cs]e)[.]txt/ \
+ )" "(fileName == currFileName||currExt ~ "^(" containers ")$")" "gensub(/^\s*/, "", "g")
+ }
+ }
+ ininput != 0 && $1 == "|" {
+ if (include_implicit == "true") {
+ fileName = gensub(/^.*[/]([^/]*)$/, "\\1", "g")
+ $1 = ""
+ print ( \
+ (isnotice && $0 !~ /^\s*build[/]soong[/]scripts[/]/) \
+ || $0 ~ /NOTICE|LICEN[CS]E/ \
+ || $0 ~ /(notice|licen[cs]e)[.]txt/ \
+ )" "(fileName == currFileName||currExt ~ "^(" containers ")$")" "gensub(/^\s*/, "", "g")
+ }
+ }
+ ininput != 0 && $1 == "||" {
+ if (include_order == "true") {
+ fileName = gensub(/^.*[/]([^/]*)$/, "\\1", "g")
+ $1 = ""
+ print ( \
+ (isnotice && $0 !~ /^\s*build[/]soong[/]scripts[/]/) \
+ || $0 ~ /NOTICE|LICEN[CS]E/ \
+ || $0 ~ /(notice|licen[cs]e)[.]txt/ \
+ )" "(fileName == currFileName||currExt ~ "^(" containers ")$")" "gensub(/^\s*/, "", "g")
+ }
+ }
+ $1 == "input:" {
+ ininput = 1
+ }
+ '
+}
+
+# Reads one input directory per line from stdin; outputs unique git projects.
+function getProjects() {
+ while read d; do
+ while [ "${d}" != '.' ] && [ "${d}" != '/' ]; do
+ if [ -d "${d}/.git/" ]; then
+ echo "${d}"
+ break
+ fi
+ d=$(dirname "${d}")
+ done
+ done | sort -u
+}
+
+
+if [ -z "${ANDROID_BUILD_TOP}" ]; then
+ die "${me}: Run 'lunch' to configure the build environment"
+fi
+
+if [ -z "${TARGET_PRODUCT}" ]; then
+ die "${me}: Run 'lunch' to configure the build environment"
+fi
+
+readonly ninja_file="${ANDROID_BUILD_TOP}/out/combined-${TARGET_PRODUCT}.ninja"
+if [ ! -f "${ninja_file}" ]; then
+ die "${me}: Run 'm nothing' to build the dependency graph"
+fi
+
+readonly ninja_bin="${ANDROID_BUILD_TOP}/prebuilts/build-tools/linux-x86/bin/ninja"
+if [ ! -x "${ninja_bin}" ]; then
+ die "${me}: Cannot find ninja executable expected at ${ninja_bin}"
+fi
+
+
+# parse the command-line
+
+declare -a targets # one or more targets to evaluate
+
+include_order_deps=false # whether to trace through || "order dependencies"
+include_implicit_deps=true # whether to trace through | "implicit deps"
+include_deps=true # whether to trace through regular explicit deps
+quiet=false # whether to suppress progress
+
+projects_out='' # where to output the list of projects
+directories_out='' # where to output the list of directories
+targets_out='' # where to output the list of targets/source files
+notices_out='' # where to output the list of license/notice files
+
+sep=" " # separator between md5sum and notice filename
+
+nofollow='' # regularexp must fully match targets to skip
+
+container_types='' # regularexp must full match file extension
+ # defaults to 'apex|apk|zip|jar|tar|tgz' below.
+
+use_stdin=false # whether to read targets from stdin i.e. target -
+
+while [ $# -gt 0 ]; do
+ case "${1:-}" in
+ -)
+ use_stdin=true
+ ;;
+ -*)
+ flag=$(expr "${1}" : '^-*\(.*\)$')
+ case "${flag:-}" in
+ order_deps)
+ include_order_deps=true;;
+ noorder_deps)
+ include_order_deps=false;;
+ implicit)
+ include_implicit_deps=true;;
+ noimplicit)
+ include_implicit_deps=false;;
+ explicit)
+ include_deps=true;;
+ noexplicit)
+ include_deps=false;;
+ csv)
+ sep=",";;
+ sep)
+ sep="${2?"${usage}"}"; shift;;
+ sep=)
+ sep=$(expr "${flag}" : '^sep=\(.*\)$');;
+ q) ;&
+ quiet)
+ quiet=true;;
+ noq) ;&
+ noquiet)
+ quiet=false;;
+ nofollow)
+ case "${nofollow}" in
+ '')
+ nofollow="${2?"${usage}"}";;
+ *)
+ nofollow="${nofollow}|${2?"${usage}"}";;
+ esac
+ shift
+ ;;
+ nofollow=*)
+ case "${nofollow}" in
+ '')
+ nofollow=$(expr "${flag}" : '^nofollow=\(.*\)$');;
+ *)
+ nofollow="${nofollow}|"$(expr "${flag}" : '^nofollow=\(.*\)$');;
+ esac
+ ;;
+ container)
+ container_types="${container_types}|${2?"${usage}"}";;
+ container=*)
+ container_types="${container_types}|"$(expr "${flag}" : '^container=\(.*\)$');;
+ p) ;&
+ projects)
+ projects_out="${2?"${usage}"}"; shift;;
+ p=*) ;&
+ projects=*)
+ projects_out=$(expr "${flag}" : '^.*=\(.*\)$');;
+ d) ;&
+ directores)
+ directories_out="${2?"${usage}"}"; shift;;
+ d=*) ;&
+ directories=*)
+ directories_out=$(expr "${flag}" : '^.*=\(.*\)$');;
+ t) ;&
+ targets)
+ targets_out="${2?"${usage}"}"; shift;;
+ t=*) ;&
+ targets=)
+ targets_out=$(expr "${flag}" : '^.*=\(.*\)$');;
+ n) ;&
+ notices)
+ notices_out="${2?"${usage}"}"; shift;;
+ n=*) ;&
+ notices=)
+ notices_out=$(expr "${flag}" : '^.*=\(.*\)$');;
+ *)
+ die "Unknown flag ${1}";;
+ esac
+ ;;
+ *)
+ targets+=("${1:-}")
+ ;;
+ esac
+ shift
+done
+
+
+# fail fast if command-line arguments are invalid
+
+if [ ! -v targets[0] ] && ! ${use_stdin}; then
+ die "${usage}\n\nNo target specified."
+fi
+
+if [ -z "${projects_out}" ] \
+ && [ -z "${directories_out}" ] \
+ && [ -z "${targets_out}" ] \
+ && [ -z "${notices_out}" ]
+then
+ targets_out='/dev/stdout'
+fi
+
+if [ -z "${container_types}" ]; then
+ container_types='apex|apk|zip|jar|tar|tgz'
+fi
+
+# showProgress when stderr is a tty
+if [ -t 2 ] && ! ${quiet}; then
+ showProgress=true
+else
+ showProgress=false
+fi
+
+# interactive when both stderr and stdin are tty
+if ${showProgress} && [ -t 0 ]; then
+ interactive=true
+else
+ interactive=false
+fi
+
+
+readonly tmpFiles=$(mktemp -d "${TMPDIR}.tdeps.XXXXXXXXX")
+if [ -z "${tmpFiles}" ]; then
+ die "${me}: unable to create temporary directory"
+fi
+
+# The deps files contain unique (isnotice target) tuples where
+# isnotice in {0,1} with 1 when ninja target 'target' is a license or notice.
+readonly oldDeps="${tmpFiles}/old"
+readonly newDeps="${tmpFiles}/new"
+readonly allDeps="${tmpFiles}/all"
+
+if ${use_stdin}; then # start deps by reading 1 target per line from stdin
+ awk '
+ NF > 0 {
+ print ( \
+ $0 ~ /NOTICE|LICEN[CS]E/ \
+ || $0 ~ /(notice|licen[cs]e)[.]txt/ \
+ )" "gensub(/\s*$/, "", "g", gensub(/^\s*/, "", "g"))
+ }
+ ' > "${newDeps}"
+else # start with no deps by clearing file
+ : > "${newDeps}"
+fi
+
+# extend deps by appending targets from command-line
+for idx in "${!targets[*]}"; do
+ isnotice='0'
+ case "${targets[${idx}]}" in
+ *NOTICE*) ;&
+ *LICEN[CS]E*) ;&
+ *notice.txt) ;&
+ *licen[cs]e.txt)
+ isnotice='1';;
+ esac
+ echo "${isnotice} 1 ${targets[${idx}]}" >> "${newDeps}"
+done
+
+# remove duplicates and start with new, old and all the same
+sort -u < "${newDeps}" > "${allDeps}"
+cp "${allDeps}" "${newDeps}"
+cp "${allDeps}" "${oldDeps}"
+
+# report depth of dependenciens when showProgress
+depth=0
+
+# 1st iteration always unfiltered
+filter='cat'
+while [ $(wc -l < "${newDeps}") -gt 0 ]; do
+ if ${showProgress}; then
+ echo "depth ${depth} has "$(wc -l < "${newDeps}")" targets" >&2
+ depth=$(expr ${depth} + 1)
+ fi
+ ( # recalculate dependencies by combining unique inputs of new deps w. old
+ sh -c "${filter}" < "${newDeps}" | cut -d\ -f3- | getDeps
+ cat "${oldDeps}"
+ ) | sort -u > "${allDeps}"
+ # recalculate new dependencies as net additions to old dependencies
+ set +e
+ diff "${oldDeps}" "${allDeps}" --old-line-format='' --new-line-format='%L' \
+ --unchanged-line-format='' > "${newDeps}"
+ set -e
+ # apply filters on subsequent iterations
+ case "${nofollow}" in
+ '')
+ filter='cat';;
+ *)
+ filter="egrep -v '^[01] 0 (${nofollow})$'"
+ ;;
+ esac
+ # recalculate old dependencies for next iteration
+ cp "${allDeps}" "${oldDeps}"
+done
+
+# found all deps -- clean up last iteration of old and new
+rm -f "${oldDeps}"
+rm -f "${newDeps}"
+
+if ${showProgress}; then
+ echo $(wc -l < "${allDeps}")" targets" >&2
+fi
+
+if [ -n "${targets_out}" ]; then
+ cut -d\ -f3- "${allDeps}" | sort -u > "${targets_out}"
+fi
+
+if [ -n "${directories_out}" ] \
+ || [ -n "${projects_out}" ] \
+ || [ -n "${notices_out}" ]
+then
+ readonly allDirs="${tmpFiles}/dirs"
+ (
+ cut -d\ -f3- "${allDeps}" | tr '\n' '\0' | xargs -0 dirname
+ ) | sort -u > "${allDirs}"
+ if ${showProgress}; then
+ echo $(wc -l < "${allDirs}")" directories" >&2
+ fi
+
+ case "${directories_out}" in
+ '') : do nothing;;
+ *)
+ cat "${allDirs}" > "${directories_out}"
+ ;;
+ esac
+fi
+
+if [ -n "${projects_out}" ] \
+ || [ -n "${notices_out}" ]
+then
+ readonly allProj="${tmpFiles}/projects"
+ egrep -v '^out[/]' "${allDirs}" | getProjects > "${allProj}"
+ if ${showProgress}; then
+ echo $(wc -l < "${allProj}")" projects" >&2
+ fi
+
+ case "${projects_out}" in
+ '') : do nothing;;
+ *)
+ cat "${allProj}" > "${projects_out}"
+ ;;
+ esac
+fi
+
+case "${notices_out}" in
+ '') : do nothing;;
+ *)
+ readonly allNotice="${tmpFiles}/notices"
+ egrep '^1' "${allDeps}" | cut -d\ -f3- | egrep -v '^out/' > "${allNotice}"
+ cat "${allProj}" | while read proj; do
+ for f in LICENSE LICENCE NOTICE license.txt notice.txt; do
+ if [ -f "${proj}/${f}" ]; then
+ echo "${proj}/${f}"
+ fi
+ done
+ done >> "${allNotice}"
+ if ${showProgress}; then
+ echo $(cat "${allNotice}" | sort -u | wc -l)" notice targets" >&2
+ fi
+ readonly hashedNotice="${tmpFiles}/hashednotices"
+ ( # md5sum outputs checksum space indicator(space or *) filename newline
+ sort -u "${allNotice}" | tr '\n' '\0' | xargs -0 -r md5sum 2>/dev/null
+ # use sed to replace space and indicator with separator
+ ) > "${hashedNotice}"
+ if ${showProgress}; then
+ echo $(cut -d\ -f2- "${hashedNotice}" | sort -u | wc -l)" notice files" >&2
+ echo $(cut -d\ -f1 "${hashedNotice}" | sort -u | wc -l)" distinct notices" >&2
+ fi
+ sed 's/^\([^ ]*\) [* ]/\1'"${sep}"'/g' "${hashedNotice}" | sort > "${notices_out}"
+ ;;
+esac
+
+if ${interactive}; then
+ echo -n "$(date '+%F %-k:%M:%S') Delete ${tmpFiles} ? [n] " >&2
+ read answer
+ case "${answer}" in [yY]*) rm -fr "${tmpFiles}";; esac
+else
+ rm -fr "${tmpFiles}"
+fi
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index a14890e..0f84c4c 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -25,11 +25,13 @@
t.Helper()
fs := map[string][]byte{
- "Test.cpp": nil,
- "include/Test.h": nil,
- "arm64/include/Arm64Test.h": nil,
- "libfoo.so": nil,
- "aidl/foo/bar/Test.aidl": nil,
+ "Test.cpp": nil,
+ "include/Test.h": nil,
+ "include-android/AndroidTest.h": nil,
+ "include-host/HostTest.h": nil,
+ "arm64/include/Arm64Test.h": nil,
+ "libfoo.so": nil,
+ "aidl/foo/bar/Test.aidl": nil,
}
return testSdkWithFs(t, bp, fs)
}
@@ -295,6 +297,7 @@
cc_prebuilt_library_shared {
name: "mysdk_mynativelib@current",
sdk_member_name: "mynativelib",
+ installable: false,
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -306,7 +309,6 @@
},
},
stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_shared {
@@ -323,7 +325,6 @@
},
},
stl: "none",
- system_shared_libs: [],
}
sdk_snapshot {
@@ -364,6 +365,7 @@
cc_prebuilt_binary {
name: "mymodule_exports_mynativebinary@current",
sdk_member_name: "mynativebinary",
+ installable: false,
compile_multilib: "both",
arch: {
arm64: {
@@ -401,6 +403,109 @@
)
}
+func TestMultipleHostOsTypesSnapshotWithCcBinary(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithCc(t, `
+ module_exports {
+ name: "myexports",
+ device_supported: false,
+ host_supported: true,
+ native_binaries: ["mynativebinary"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }
+
+ cc_binary {
+ name: "mynativebinary",
+ device_supported: false,
+ host_supported: true,
+ srcs: [
+ "Test.cpp",
+ ],
+ compile_multilib: "both",
+ system_shared_libs: [],
+ stl: "none",
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }
+ `)
+
+ result.CheckSnapshot("myexports", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_binary {
+ name: "myexports_mynativebinary@current",
+ sdk_member_name: "mynativebinary",
+ device_supported: false,
+ host_supported: true,
+ installable: false,
+ target: {
+ linux_glibc: {
+ compile_multilib: "both",
+ },
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/bin/mynativebinary"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/bin/mynativebinary"],
+ },
+ windows: {
+ compile_multilib: "64",
+ },
+ windows_x86_64: {
+ srcs: ["windows/x86_64/bin/mynativebinary.exe"],
+ },
+ },
+}
+
+cc_prebuilt_binary {
+ name: "mynativebinary",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ target: {
+ linux_glibc: {
+ compile_multilib: "both",
+ },
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/bin/mynativebinary"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/bin/mynativebinary"],
+ },
+ windows: {
+ compile_multilib: "64",
+ },
+ windows_x86_64: {
+ srcs: ["windows/x86_64/bin/mynativebinary.exe"],
+ },
+ },
+}
+
+module_exports_snapshot {
+ name: "myexports@current",
+ device_supported: false,
+ host_supported: true,
+ native_binaries: ["myexports_mynativebinary@current"],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/mynativebinary/linux_glibc_x86_64/mynativebinary -> linux_glibc/x86_64/bin/mynativebinary
+.intermediates/mynativebinary/linux_glibc_x86/mynativebinary -> linux_glibc/x86/bin/mynativebinary
+.intermediates/mynativebinary/windows_x86_64/mynativebinary.exe -> windows/x86_64/bin/mynativebinary.exe
+`),
+ )
+}
+
func TestSnapshotWithCcSharedLibrary(t *testing.T) {
result := testSdkWithCc(t, `
sdk {
@@ -435,6 +540,7 @@
"apex1",
"apex2",
],
+ installable: false,
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -447,7 +553,6 @@
},
},
stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_shared {
@@ -469,7 +574,6 @@
},
},
stl: "none",
- system_shared_libs: [],
}
sdk_snapshot {
@@ -491,6 +595,189 @@
)
}
+func TestSnapshotWithCcSharedLibrarySharedLibs(t *testing.T) {
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ native_shared_libs: [
+ "mynativelib",
+ "myothernativelib",
+ "mysystemnativelib",
+ ],
+ }
+
+ cc_library {
+ name: "mysystemnativelib",
+ srcs: [
+ "Test.cpp",
+ ],
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ cc_library_shared {
+ name: "myothernativelib",
+ srcs: [
+ "Test.cpp",
+ ],
+ system_shared_libs: [
+ // A reference to a library that is not an sdk member. Uses libm as that
+ // is in the default set of modules available to this test and so is available
+ // both here and also when the generated Android.bp file is tested in
+ // CheckSnapshot(). This ensures that the system_shared_libs property correctly
+ // handles references to modules that are not sdk members.
+ "libm",
+ ],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "mynativelib",
+ srcs: [
+ "Test.cpp",
+ ],
+ shared_libs: [
+ // A reference to another sdk member.
+ "myothernativelib",
+ ],
+ target: {
+ android: {
+ shared: {
+ shared_libs: [
+ // A reference to a library that is not an sdk member. The libc library
+ // is used here to check that the shared_libs property is handled correctly
+ // in a similar way to how libm is used to check system_shared_libs above.
+ "libc",
+ ],
+ },
+ },
+ },
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+ name: "mysdk_mynativelib@current",
+ sdk_member_name: "mynativelib",
+ installable: false,
+ shared_libs: [
+ "mysdk_myothernativelib@current",
+ "libc",
+ ],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/mynativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/mynativelib.so"],
+ },
+ },
+ stl: "none",
+}
+
+cc_prebuilt_library_shared {
+ name: "mynativelib",
+ prefer: false,
+ shared_libs: [
+ "myothernativelib",
+ "libc",
+ ],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/mynativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/mynativelib.so"],
+ },
+ },
+ stl: "none",
+}
+
+cc_prebuilt_library_shared {
+ name: "mysdk_myothernativelib@current",
+ sdk_member_name: "myothernativelib",
+ installable: false,
+ system_shared_libs: ["libm"],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/myothernativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/myothernativelib.so"],
+ },
+ },
+ stl: "none",
+}
+
+cc_prebuilt_library_shared {
+ name: "myothernativelib",
+ prefer: false,
+ system_shared_libs: ["libm"],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/myothernativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/myothernativelib.so"],
+ },
+ },
+ stl: "none",
+}
+
+cc_prebuilt_library_shared {
+ name: "mysdk_mysystemnativelib@current",
+ sdk_member_name: "mysystemnativelib",
+ installable: false,
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/mysystemnativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/mysystemnativelib.so"],
+ },
+ },
+ stl: "none",
+}
+
+cc_prebuilt_library_shared {
+ name: "mysystemnativelib",
+ prefer: false,
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/mysystemnativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/mysystemnativelib.so"],
+ },
+ },
+ stl: "none",
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ native_shared_libs: [
+ "mysdk_mynativelib@current",
+ "mysdk_myothernativelib@current",
+ "mysdk_mysystemnativelib@current",
+ ],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/mynativelib/android_arm64_armv8-a_shared/mynativelib.so -> arm64/lib/mynativelib.so
+.intermediates/mynativelib/android_arm_armv7-a-neon_shared/mynativelib.so -> arm/lib/mynativelib.so
+.intermediates/myothernativelib/android_arm64_armv8-a_shared/myothernativelib.so -> arm64/lib/myothernativelib.so
+.intermediates/myothernativelib/android_arm_armv7-a-neon_shared/myothernativelib.so -> arm/lib/myothernativelib.so
+.intermediates/mysystemnativelib/android_arm64_armv8-a_shared/mysystemnativelib.so -> arm64/lib/mysystemnativelib.so
+.intermediates/mysystemnativelib/android_arm_armv7-a-neon_shared/mysystemnativelib.so -> arm/lib/mysystemnativelib.so
+`),
+ )
+}
+
func TestHostSnapshotWithCcSharedLibrary(t *testing.T) {
// b/145598135 - Generating host snapshots for anything other than linux is not supported.
SkipIfNotLinux(t)
@@ -517,6 +804,7 @@
},
system_shared_libs: [],
stl: "none",
+ sdk_version: "minimum",
}
`)
@@ -529,6 +817,8 @@
sdk_member_name: "mynativelib",
device_supported: false,
host_supported: true,
+ installable: false,
+ sdk_version: "minimum",
export_include_dirs: ["include/include"],
arch: {
x86_64: {
@@ -541,7 +831,6 @@
},
},
stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_shared {
@@ -549,6 +838,7 @@
prefer: false,
device_supported: false,
host_supported: true,
+ sdk_version: "minimum",
export_include_dirs: ["include/include"],
arch: {
x86_64: {
@@ -561,7 +851,6 @@
},
},
stl: "none",
- system_shared_libs: [],
}
sdk_snapshot {
@@ -585,6 +874,98 @@
)
}
+func TestMultipleHostOsTypesSnapshotWithCcSharedLibrary(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ device_supported: false,
+ host_supported: true,
+ native_shared_libs: ["mynativelib"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }
+
+ cc_library_shared {
+ name: "mynativelib",
+ device_supported: false,
+ host_supported: true,
+ srcs: [
+ "Test.cpp",
+ ],
+ system_shared_libs: [],
+ stl: "none",
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+ name: "mysdk_mynativelib@current",
+ sdk_member_name: "mynativelib",
+ device_supported: false,
+ host_supported: true,
+ installable: false,
+ target: {
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/lib/mynativelib.so"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/lib/mynativelib.so"],
+ },
+ windows_x86_64: {
+ srcs: ["windows/x86_64/lib/mynativelib.dll"],
+ },
+ },
+ stl: "none",
+}
+
+cc_prebuilt_library_shared {
+ name: "mynativelib",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ target: {
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/lib/mynativelib.so"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/lib/mynativelib.so"],
+ },
+ windows_x86_64: {
+ srcs: ["windows/x86_64/lib/mynativelib.dll"],
+ },
+ },
+ stl: "none",
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ device_supported: false,
+ host_supported: true,
+ native_shared_libs: ["mysdk_mynativelib@current"],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/mynativelib/linux_glibc_x86_64_shared/mynativelib.so -> linux_glibc/x86_64/lib/mynativelib.so
+.intermediates/mynativelib/linux_glibc_x86_shared/mynativelib.so -> linux_glibc/x86/lib/mynativelib.so
+.intermediates/mynativelib/windows_x86_64_shared/mynativelib.dll -> windows/x86_64/lib/mynativelib.dll
+`),
+ )
+}
+
func TestSnapshotWithCcStaticLibrary(t *testing.T) {
result := testSdkWithCc(t, `
module_exports {
@@ -614,6 +995,7 @@
cc_prebuilt_library_static {
name: "myexports_mynativelib@current",
sdk_member_name: "mynativelib",
+ installable: false,
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -626,7 +1008,6 @@
},
},
stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_static {
@@ -644,7 +1025,6 @@
},
},
stl: "none",
- system_shared_libs: [],
}
module_exports_snapshot {
@@ -704,6 +1084,7 @@
sdk_member_name: "mynativelib",
device_supported: false,
host_supported: true,
+ installable: false,
export_include_dirs: ["include/include"],
arch: {
x86_64: {
@@ -716,7 +1097,6 @@
},
},
stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_static {
@@ -736,7 +1116,6 @@
},
},
stl: "none",
- system_shared_libs: [],
}
module_exports_snapshot {
@@ -803,6 +1182,7 @@
sdk_member_name: "mynativelib",
device_supported: false,
host_supported: true,
+ installable: false,
export_include_dirs: ["include/include"],
arch: {
x86_64: {
@@ -811,7 +1191,6 @@
},
},
stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_static {
@@ -827,7 +1206,6 @@
},
},
stl: "none",
- system_shared_libs: [],
}
module_exports_snapshot {
@@ -875,7 +1253,6 @@
sdk_member_name: "mynativeheaders",
export_include_dirs: ["include/include"],
stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_headers {
@@ -883,7 +1260,6 @@
prefer: false,
export_include_dirs: ["include/include"],
stl: "none",
- system_shared_libs: [],
}
sdk_snapshot {
@@ -930,7 +1306,6 @@
host_supported: true,
export_include_dirs: ["include/include"],
stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_headers {
@@ -940,7 +1315,6 @@
host_supported: true,
export_include_dirs: ["include/include"],
stl: "none",
- system_shared_libs: [],
}
sdk_snapshot {
@@ -955,3 +1329,81 @@
`),
)
}
+
+func TestDeviceAndHostSnapshotWithCcHeadersLibrary(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ host_supported: true,
+ native_header_libs: ["mynativeheaders"],
+ }
+
+ cc_library_headers {
+ name: "mynativeheaders",
+ host_supported: true,
+ system_shared_libs: [],
+ stl: "none",
+ export_system_include_dirs: ["include"],
+ target: {
+ android: {
+ export_include_dirs: ["include-android"],
+ },
+ host: {
+ export_include_dirs: ["include-host"],
+ },
+ },
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_headers {
+ name: "mysdk_mynativeheaders@current",
+ sdk_member_name: "mynativeheaders",
+ host_supported: true,
+ export_system_include_dirs: ["include/include"],
+ target: {
+ android: {
+ export_include_dirs: ["include/include-android"],
+ },
+ linux_glibc: {
+ export_include_dirs: ["include/include-host"],
+ },
+ },
+ stl: "none",
+}
+
+cc_prebuilt_library_headers {
+ name: "mynativeheaders",
+ prefer: false,
+ host_supported: true,
+ export_system_include_dirs: ["include/include"],
+ target: {
+ android: {
+ export_include_dirs: ["include/include-android"],
+ },
+ linux_glibc: {
+ export_include_dirs: ["include/include-host"],
+ },
+ },
+ stl: "none",
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ host_supported: true,
+ native_header_libs: ["mysdk_mynativeheaders@current"],
+}
+`),
+ checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+include-android/AndroidTest.h -> include/include-android/AndroidTest.h
+include-host/HostTest.h -> include/include-host/HostTest.h
+`),
+ )
+}
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 9046eec..c60002b 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -230,6 +230,72 @@
)
}
+func TestDeviceAndHostSnapshotWithJavaHeaderLibrary(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithJava(t, `
+ sdk {
+ name: "mysdk",
+ host_supported: true,
+ java_header_libs: ["myjavalib"],
+ }
+
+ java_library {
+ name: "myjavalib",
+ host_supported: true,
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "mysdk_myjavalib@current",
+ sdk_member_name: "myjavalib",
+ host_supported: true,
+ target: {
+ android: {
+ jars: ["java/android/myjavalib.jar"],
+ },
+ linux_glibc: {
+ jars: ["java/linux_glibc/myjavalib.jar"],
+ },
+ },
+}
+
+java_import {
+ name: "myjavalib",
+ prefer: false,
+ host_supported: true,
+ target: {
+ android: {
+ jars: ["java/android/myjavalib.jar"],
+ },
+ linux_glibc: {
+ jars: ["java/linux_glibc/myjavalib.jar"],
+ },
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ host_supported: true,
+ java_header_libs: ["mysdk_myjavalib@current"],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/myjavalib/android_common/turbine-combined/myjavalib.jar -> java/android/myjavalib.jar
+.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/linux_glibc/myjavalib.jar
+`),
+ )
+}
+
func TestSnapshotWithJavaImplLibrary(t *testing.T) {
result := testSdkWithJava(t, `
module_exports {
@@ -750,3 +816,126 @@
checkAllCopyRules(".intermediates/system-module/linux_glibc_common/javac/system-module.jar -> java/system-module.jar"),
)
}
+
+func TestDeviceAndHostSnapshotWithOsSpecificMembers(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithJava(t, `
+ module_exports {
+ name: "myexports",
+ host_supported: true,
+ java_libs: ["myjavalib"],
+ target: {
+ android: {
+ java_header_libs: ["androidjavalib"],
+ },
+ host: {
+ java_header_libs: ["hostjavalib"],
+ },
+ },
+ }
+
+ java_library {
+ name: "myjavalib",
+ host_supported: true,
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ }
+
+ java_library {
+ name: "androidjavalib",
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ }
+
+ java_library_host {
+ name: "hostjavalib",
+ srcs: ["Test.java"],
+ }
+ `)
+
+ result.CheckSnapshot("myexports", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "myexports_hostjavalib@current",
+ sdk_member_name: "hostjavalib",
+ device_supported: false,
+ host_supported: true,
+ jars: ["java/hostjavalib.jar"],
+}
+
+java_import {
+ name: "hostjavalib",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ jars: ["java/hostjavalib.jar"],
+}
+
+java_import {
+ name: "myexports_androidjavalib@current",
+ sdk_member_name: "androidjavalib",
+ jars: ["java/androidjavalib.jar"],
+}
+
+java_import {
+ name: "androidjavalib",
+ prefer: false,
+ jars: ["java/androidjavalib.jar"],
+}
+
+java_import {
+ name: "myexports_myjavalib@current",
+ sdk_member_name: "myjavalib",
+ host_supported: true,
+ target: {
+ android: {
+ jars: ["java/android/myjavalib.jar"],
+ },
+ linux_glibc: {
+ jars: ["java/linux_glibc/myjavalib.jar"],
+ },
+ },
+}
+
+java_import {
+ name: "myjavalib",
+ prefer: false,
+ host_supported: true,
+ target: {
+ android: {
+ jars: ["java/android/myjavalib.jar"],
+ },
+ linux_glibc: {
+ jars: ["java/linux_glibc/myjavalib.jar"],
+ },
+ },
+}
+
+module_exports_snapshot {
+ name: "myexports@current",
+ host_supported: true,
+ target: {
+ android: {
+ java_header_libs: ["myexports_androidjavalib@current"],
+ },
+ linux_glibc: {
+ java_header_libs: ["myexports_hostjavalib@current"],
+ },
+ },
+ java_libs: ["myexports_myjavalib@current"],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/hostjavalib/linux_glibc_common/javac/hostjavalib.jar -> java/hostjavalib.jar
+.intermediates/androidjavalib/android_common/turbine-combined/androidjavalib.jar -> java/androidjavalib.jar
+.intermediates/myjavalib/android_common/javac/myjavalib.jar -> java/android/myjavalib.jar
+.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/linux_glibc/myjavalib.jar
+`),
+ )
+}
diff --git a/sdk/sdk.go b/sdk/sdk.go
index db71575..984ed7a 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -50,9 +50,6 @@
// list properties, e.g. java_libs.
dynamicMemberTypeListProperties interface{}
- // The set of exported members.
- exportedMembers map[string]struct{}
-
// Information about the OsType specific member variants associated with this variant.
//
// Set by OsType specific variants when their GenerateAndroidBuildActions is invoked
@@ -150,6 +147,7 @@
fields = append(fields, reflect.StructField{
Name: proptools.FieldNameForProperty(p),
Type: reflect.TypeOf([]string{}),
+ Tag: `android:"arch_variant"`,
})
// Copy the field index for use in the getter func as using the loop variable directly will
@@ -232,26 +230,19 @@
}
func (s *sdk) getExportedMembers() map[string]struct{} {
- if s.exportedMembers == nil {
- // Collect all the exported members.
- s.exportedMembers = make(map[string]struct{})
+ // Collect all the exported members.
+ exportedMembers := make(map[string]struct{})
- for _, memberListProperty := range s.memberListProperties() {
- names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
+ for _, memberListProperty := range s.memberListProperties() {
+ names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
- // Every member specified explicitly in the properties is exported by the sdk.
- for _, name := range names {
- s.exportedMembers[name] = struct{}{}
- }
+ // Every member specified explicitly in the properties is exported by the sdk.
+ for _, name := range names {
+ exportedMembers[name] = struct{}{}
}
}
- return s.exportedMembers
-}
-
-func (s *sdk) isInternalMember(memberName string) bool {
- _, ok := s.getExportedMembers()[memberName]
- return !ok
+ return exportedMembers
}
func (s *sdk) snapshot() bool {
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 243b976..fde9230 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -16,6 +16,8 @@
import (
"testing"
+
+ "github.com/google/blueprint/proptools"
)
// Needed in an _test.go file in this package to ensure tests run correctly, particularly in IDE.
@@ -58,6 +60,7 @@
sdk_version: "none",
compile_dex: true,
host_supported: true,
+ apex_available: ["myapex"],
}
// this lib is no in mysdk
@@ -113,7 +116,7 @@
java_defaults {
name: "java-defaults",
- visibility: ["//other/bar"],
+ visibility: ["//other/bar"],
}
java_library {
@@ -221,3 +224,106 @@
checkAllOtherCopyRules(`.intermediates/mysdk/common_os/mysdk-current.zip -> mysdk-current.zip`),
)
}
+
+type EmbeddedPropertiesStruct struct {
+ S_Embedded_Common string
+ S_Embedded_Different string
+}
+
+type testPropertiesStruct struct {
+ private string
+ Public_Kept string `sdk:"keep"`
+ S_Common string
+ S_Different string
+ A_Common []string
+ A_Different []string
+ F_Common *bool
+ F_Different *bool
+ EmbeddedPropertiesStruct
+}
+
+func TestCommonValueOptimization(t *testing.T) {
+ common := &testPropertiesStruct{}
+ structs := []*testPropertiesStruct{
+ &testPropertiesStruct{
+ private: "common",
+ Public_Kept: "common",
+ S_Common: "common",
+ S_Different: "upper",
+ A_Common: []string{"first", "second"},
+ A_Different: []string{"alpha", "beta"},
+ F_Common: proptools.BoolPtr(false),
+ F_Different: proptools.BoolPtr(false),
+ EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+ S_Embedded_Common: "embedded_common",
+ S_Embedded_Different: "embedded_upper",
+ },
+ },
+ &testPropertiesStruct{
+ private: "common",
+ Public_Kept: "common",
+ S_Common: "common",
+ S_Different: "lower",
+ A_Common: []string{"first", "second"},
+ A_Different: []string{"alpha", "delta"},
+ F_Common: proptools.BoolPtr(false),
+ F_Different: proptools.BoolPtr(true),
+ EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+ S_Embedded_Common: "embedded_common",
+ S_Embedded_Different: "embedded_lower",
+ },
+ },
+ }
+
+ extractor := newCommonValueExtractor(common)
+ extractor.extractCommonProperties(common, structs)
+
+ h := TestHelper{t}
+ h.AssertDeepEquals("common properties not correct", common,
+ &testPropertiesStruct{
+ private: "",
+ Public_Kept: "",
+ S_Common: "common",
+ S_Different: "",
+ A_Common: []string{"first", "second"},
+ A_Different: []string(nil),
+ F_Common: proptools.BoolPtr(false),
+ F_Different: nil,
+ EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+ S_Embedded_Common: "embedded_common",
+ S_Embedded_Different: "",
+ },
+ })
+
+ h.AssertDeepEquals("updated properties[0] not correct", structs[0],
+ &testPropertiesStruct{
+ private: "common",
+ Public_Kept: "common",
+ S_Common: "",
+ S_Different: "upper",
+ A_Common: nil,
+ A_Different: []string{"alpha", "beta"},
+ F_Common: nil,
+ F_Different: proptools.BoolPtr(false),
+ EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+ S_Embedded_Common: "",
+ S_Embedded_Different: "embedded_upper",
+ },
+ })
+
+ h.AssertDeepEquals("updated properties[1] not correct", structs[1],
+ &testPropertiesStruct{
+ private: "common",
+ Public_Kept: "common",
+ S_Common: "",
+ S_Different: "lower",
+ A_Common: nil,
+ A_Different: []string{"alpha", "delta"},
+ F_Common: nil,
+ F_Different: proptools.BoolPtr(true),
+ EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+ S_Embedded_Common: "",
+ S_Embedded_Different: "embedded_lower",
+ },
+ })
+}
diff --git a/sdk/testing.go b/sdk/testing.go
index 41333cd..00245ce 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -19,6 +19,7 @@
"io/ioutil"
"os"
"path/filepath"
+ "reflect"
"strings"
"testing"
@@ -40,7 +41,7 @@
name: "myapex.cert",
certificate: "myapex",
}
- ` + cc.GatherRequiredDepsForTest(android.Android)
+ ` + cc.GatherRequiredDepsForTest(android.Android, android.Windows)
mockFS := map[string][]byte{
"build/make/target/product/security": nil,
@@ -176,6 +177,13 @@
h.AssertStringEquals(message, strings.TrimSpace(expected), strings.TrimSpace(actual))
}
+func (h *TestHelper) AssertDeepEquals(message string, expected interface{}, actual interface{}) {
+ h.t.Helper()
+ if !reflect.DeepEqual(actual, expected) {
+ h.t.Errorf("%s: expected %#v, actual %#v", message, expected, actual)
+ }
+}
+
// Encapsulates result of processing an SDK definition. Provides support for
// checking the state of the build structures.
type testSdkResult struct {
diff --git a/sdk/update.go b/sdk/update.go
index b335777..a95d06a 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -17,8 +17,10 @@
import (
"fmt"
"reflect"
+ "sort"
"strings"
+ "android/soong/apex"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -224,9 +226,22 @@
// the contents (header files, stub libraries, etc) into the zip file.
func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) android.OutputPath {
+ allMembersByName := make(map[string]struct{})
+ exportedMembersByName := make(map[string]struct{})
var memberRefs []sdkMemberRef
for _, sdkVariant := range sdkVariants {
memberRefs = append(memberRefs, sdkVariant.memberRefs...)
+
+ // Record the names of all the members, both explicitly specified and implicitly
+ // included.
+ for _, memberRef := range sdkVariant.memberRefs {
+ allMembersByName[memberRef.variant.Name()] = struct{}{}
+ }
+
+ // Merge the exported member sets from all sdk variants.
+ for key, _ := range sdkVariant.getExportedMembers() {
+ exportedMembersByName[key] = struct{}{}
+ }
}
snapshotDir := android.PathForModuleOut(ctx, "snapshot")
@@ -238,20 +253,29 @@
}
builder := &snapshotBuilder{
- ctx: ctx,
- sdk: s,
- version: "current",
- snapshotDir: snapshotDir.OutputPath,
- copies: make(map[string]string),
- filesToZip: []android.Path{bp.path},
- bpFile: bpFile,
- prebuiltModules: make(map[string]*bpModule),
+ ctx: ctx,
+ sdk: s,
+ version: "current",
+ snapshotDir: snapshotDir.OutputPath,
+ copies: make(map[string]string),
+ filesToZip: []android.Path{bp.path},
+ bpFile: bpFile,
+ prebuiltModules: make(map[string]*bpModule),
+ allMembersByName: allMembersByName,
+ exportedMembersByName: exportedMembersByName,
}
s.builderForTests = builder
members, multilib := s.organizeMembers(ctx, memberRefs)
for _, member := range members {
- member.memberType.BuildSnapshot(ctx, builder, member)
+ memberType := member.memberType
+ prebuiltModule := memberType.AddPrebuiltModule(ctx, builder, member)
+ if prebuiltModule == nil {
+ // Fall back to legacy method of building a snapshot
+ memberType.BuildSnapshot(ctx, builder, member)
+ } else {
+ s.createMemberSnapshot(ctx, builder, member, prebuiltModule)
+ }
}
// Create a transformer that will transform an unversioned module into a versioned module.
@@ -294,23 +318,44 @@
snapshotModule.AddProperty("visibility", visibility)
}
- addHostDeviceSupportedProperties(&s.ModuleBase, snapshotModule)
+ addHostDeviceSupportedProperties(s.ModuleBase.DeviceSupported(), s.ModuleBase.HostSupported(), snapshotModule)
// Compile_multilib defaults to both and must always be set to both on the
// device and so only needs to be set when targeted at the host and is neither
// unspecified or both.
+ targetPropertySet := snapshotModule.AddPropertySet("target")
if s.HostSupported() && multilib != "" && multilib != "both" {
- targetSet := snapshotModule.AddPropertySet("target")
- hostSet := targetSet.AddPropertySet("host")
+ hostSet := targetPropertySet.AddPropertySet("host")
hostSet.AddProperty("compile_multilib", multilib)
}
- for _, memberListProperty := range s.memberListProperties() {
- names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
- if len(names) > 0 {
- snapshotModule.AddProperty(memberListProperty.propertyName(), builder.versionedSdkMemberNames(names))
+ var dynamicMemberPropertiesList []interface{}
+ osTypeToMemberProperties := make(map[android.OsType]*sdk)
+ for _, sdkVariant := range sdkVariants {
+ properties := sdkVariant.dynamicMemberTypeListProperties
+ osTypeToMemberProperties[sdkVariant.Target().Os] = sdkVariant
+ dynamicMemberPropertiesList = append(dynamicMemberPropertiesList, properties)
+ }
+
+ // Extract the common lists of members into a separate struct.
+ commonDynamicMemberProperties := s.dynamicSdkMemberTypes.createMemberListProperties()
+ extractor := newCommonValueExtractor(commonDynamicMemberProperties)
+ extractor.extractCommonProperties(commonDynamicMemberProperties, dynamicMemberPropertiesList)
+
+ // Add properties common to all os types.
+ s.addMemberPropertiesToPropertySet(builder, snapshotModule, commonDynamicMemberProperties)
+
+ // Iterate over the os types in a fixed order.
+ for _, osType := range s.getPossibleOsTypes() {
+ if sdkVariant, ok := osTypeToMemberProperties[osType]; ok {
+ osPropertySet := targetPropertySet.AddPropertySet(sdkVariant.Target().Os.Name)
+ s.addMemberPropertiesToPropertySet(builder, osPropertySet, sdkVariant.dynamicMemberTypeListProperties)
}
}
+
+ // Prune any empty property sets.
+ snapshotModule.transform(pruneEmptySetTransformer{})
+
bpFile.AddModule(snapshotModule)
// generate Android.bp
@@ -361,11 +406,37 @@
return outputZipFile
}
+func (s *sdk) addMemberPropertiesToPropertySet(builder *snapshotBuilder, propertySet android.BpPropertySet, dynamicMemberTypeListProperties interface{}) {
+ for _, memberListProperty := range s.memberListProperties() {
+ names := memberListProperty.getter(dynamicMemberTypeListProperties)
+ if len(names) > 0 {
+ propertySet.AddProperty(memberListProperty.propertyName(), builder.versionedSdkMemberNames(names, false))
+ }
+ }
+}
+
type propertyTag struct {
name string
}
-var sdkMemberReferencePropertyTag = propertyTag{"sdkMemberReferencePropertyTag"}
+// A BpPropertyTag to add to a property that contains references to other sdk members.
+//
+// This will cause the references to be rewritten to a versioned reference in the version
+// specific instance of a snapshot module.
+var requiredSdkMemberReferencePropertyTag = propertyTag{"requiredSdkMemberReferencePropertyTag"}
+
+// A BpPropertyTag to add to a property that contains references to other sdk members.
+//
+// This will cause the references to be rewritten to a versioned reference in the version
+// specific instance of a snapshot module.
+var optionalSdkMemberReferencePropertyTag = propertyTag{"optionalSdkMemberReferencePropertyTag"}
+
+// A BpPropertyTag that indicates the property should only be present in the versioned
+// module.
+//
+// This will cause the property to be removed from the unversioned instance of a
+// snapshot module.
+var sdkVersionedOnlyPropertyTag = propertyTag{"sdkVersionedOnlyPropertyTag"}
type unversionedToVersionedTransformation struct {
identityTransformation
@@ -376,14 +447,15 @@
// Use a versioned name for the module but remember the original name for the
// snapshot.
name := module.getValue("name").(string)
- module.setProperty("name", t.builder.versionedSdkMemberName(name))
+ module.setProperty("name", t.builder.versionedSdkMemberName(name, true))
module.insertAfter("name", "sdk_member_name", name)
return module
}
func (t unversionedToVersionedTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
- if tag == sdkMemberReferencePropertyTag {
- return t.builder.versionedSdkMemberNames(value.([]string)), tag
+ if tag == requiredSdkMemberReferencePropertyTag || tag == optionalSdkMemberReferencePropertyTag {
+ required := tag == requiredSdkMemberReferencePropertyTag
+ return t.builder.versionedSdkMemberNames(value.([]string), required), tag
} else {
return value, tag
}
@@ -397,7 +469,7 @@
func (t unversionedTransformation) transformModule(module *bpModule) *bpModule {
// If the module is an internal member then use a unique name for it.
name := module.getValue("name").(string)
- module.setProperty("name", t.builder.unversionedSdkMemberName(name))
+ module.setProperty("name", t.builder.unversionedSdkMemberName(name, true))
// Set prefer: false - this is not strictly required as that is the default.
module.insertAfter("name", "prefer", false)
@@ -406,8 +478,12 @@
}
func (t unversionedTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
- if tag == sdkMemberReferencePropertyTag {
- return t.builder.unversionedSdkMemberNames(value.([]string)), tag
+ if tag == requiredSdkMemberReferencePropertyTag || tag == optionalSdkMemberReferencePropertyTag {
+ required := tag == requiredSdkMemberReferencePropertyTag
+ return t.builder.unversionedSdkMemberNames(value.([]string), required), tag
+ } else if tag == sdkVersionedOnlyPropertyTag {
+ // The property is not allowed in the unversioned module so remove it.
+ return nil, nil
} else {
return value, tag
}
@@ -499,6 +575,12 @@
prebuiltModules map[string]*bpModule
prebuiltOrder []*bpModule
+
+ // The set of all members by name.
+ allMembersByName map[string]struct{}
+
+ // The set of exported members by name.
+ exportedMembersByName map[string]struct{}
}
func (s *snapshotBuilder) CopyToSnapshot(src android.Path, dest string) {
@@ -552,7 +634,7 @@
variant := member.Variants()[0]
- if s.sdk.isInternalMember(name) {
+ if s.isInternalMember(name) {
// An internal member is only referenced from the sdk snapshot which is in the
// same package so can be marked as private.
m.AddProperty("visibility", []string{"//visibility:private"})
@@ -565,64 +647,117 @@
}
}
- addHostDeviceSupportedProperties(&s.sdk.ModuleBase, m)
+ deviceSupported := false
+ hostSupported := false
+
+ for _, variant := range member.Variants() {
+ osClass := variant.Target().Os.Class
+ if osClass == android.Host || osClass == android.HostCross {
+ hostSupported = true
+ } else if osClass == android.Device {
+ deviceSupported = true
+ }
+ }
+
+ addHostDeviceSupportedProperties(deviceSupported, hostSupported, m)
// Where available copy apex_available properties from the member.
if apexAware, ok := variant.(interface{ ApexAvailable() []string }); ok {
apexAvailable := apexAware.ApexAvailable()
+
+ // Add in any white listed apex available settings.
+ apexAvailable = append(apexAvailable, apex.WhitelistedApexAvailable(member.Name())...)
+
if len(apexAvailable) > 0 {
+ // Remove duplicates and sort.
+ apexAvailable = android.FirstUniqueStrings(apexAvailable)
+ sort.Strings(apexAvailable)
+
m.AddProperty("apex_available", apexAvailable)
}
}
+ // Disable installation in the versioned module of those modules that are ever installable.
+ if installable, ok := variant.(interface{ EverInstallable() bool }); ok {
+ if installable.EverInstallable() {
+ m.AddPropertyWithTag("installable", false, sdkVersionedOnlyPropertyTag)
+ }
+ }
+
s.prebuiltModules[name] = m
s.prebuiltOrder = append(s.prebuiltOrder, m)
return m
}
-func addHostDeviceSupportedProperties(module *android.ModuleBase, bpModule *bpModule) {
- if !module.DeviceSupported() {
+func addHostDeviceSupportedProperties(deviceSupported bool, hostSupported bool, bpModule *bpModule) {
+ if !deviceSupported {
bpModule.AddProperty("device_supported", false)
}
- if module.HostSupported() {
+ if hostSupported {
bpModule.AddProperty("host_supported", true)
}
}
-func (s *snapshotBuilder) SdkMemberReferencePropertyTag() android.BpPropertyTag {
- return sdkMemberReferencePropertyTag
+func (s *snapshotBuilder) SdkMemberReferencePropertyTag(required bool) android.BpPropertyTag {
+ if required {
+ return requiredSdkMemberReferencePropertyTag
+ } else {
+ return optionalSdkMemberReferencePropertyTag
+ }
+}
+
+func (s *snapshotBuilder) OptionalSdkMemberReferencePropertyTag() android.BpPropertyTag {
+ return optionalSdkMemberReferencePropertyTag
}
// Get a versioned name appropriate for the SDK snapshot version being taken.
-func (s *snapshotBuilder) versionedSdkMemberName(unversionedName string) string {
+func (s *snapshotBuilder) versionedSdkMemberName(unversionedName string, required bool) string {
+ if _, ok := s.allMembersByName[unversionedName]; !ok {
+ if required {
+ s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", unversionedName)
+ }
+ return unversionedName
+ }
return versionedSdkMemberName(s.ctx, unversionedName, s.version)
}
-func (s *snapshotBuilder) versionedSdkMemberNames(members []string) []string {
+func (s *snapshotBuilder) versionedSdkMemberNames(members []string, required bool) []string {
var references []string = nil
for _, m := range members {
- references = append(references, s.versionedSdkMemberName(m))
+ references = append(references, s.versionedSdkMemberName(m, required))
}
return references
}
// Get an internal name unique to the sdk.
-func (s *snapshotBuilder) unversionedSdkMemberName(unversionedName string) string {
- if s.sdk.isInternalMember(unversionedName) {
+func (s *snapshotBuilder) unversionedSdkMemberName(unversionedName string, required bool) string {
+ if _, ok := s.allMembersByName[unversionedName]; !ok {
+ if required {
+ s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", unversionedName)
+ }
+ return unversionedName
+ }
+
+ if s.isInternalMember(unversionedName) {
return s.ctx.ModuleName() + "_" + unversionedName
} else {
return unversionedName
}
}
-func (s *snapshotBuilder) unversionedSdkMemberNames(members []string) []string {
+func (s *snapshotBuilder) unversionedSdkMemberNames(members []string, required bool) []string {
var references []string = nil
for _, m := range members {
- references = append(references, s.unversionedSdkMemberName(m))
+ references = append(references, s.unversionedSdkMemberName(m, required))
}
return references
}
+func (s *snapshotBuilder) isInternalMember(memberName string) bool {
+ _, ok := s.exportedMembersByName[memberName]
+ return !ok
+}
+
type sdkMemberRef struct {
memberType android.SdkMemberType
variant android.SdkAware
@@ -643,3 +778,363 @@
func (m *sdkMember) Variants() []android.SdkAware {
return m.variants
}
+
+type baseInfo struct {
+ Properties android.SdkMemberProperties
+}
+
+type osTypeSpecificInfo struct {
+ baseInfo
+
+ // The list of arch type specific info for this os type.
+ archTypes []*archTypeSpecificInfo
+
+ // True if the member has common arch variants for this os type.
+ commonArch bool
+}
+
+type archTypeSpecificInfo struct {
+ baseInfo
+
+ archType android.ArchType
+}
+
+func (s *sdk) createMemberSnapshot(sdkModuleContext android.ModuleContext, builder *snapshotBuilder, member *sdkMember, bpModule android.BpModule) {
+
+ memberType := member.memberType
+
+ // Group the variants by os type.
+ variantsByOsType := make(map[android.OsType][]android.SdkAware)
+ variants := member.Variants()
+ for _, variant := range variants {
+ osType := variant.Target().Os
+ variantsByOsType[osType] = append(variantsByOsType[osType], variant)
+ }
+
+ osCount := len(variantsByOsType)
+ createVariantPropertiesStruct := func(os android.OsType) android.SdkMemberProperties {
+ properties := memberType.CreateVariantPropertiesStruct()
+ base := properties.Base()
+ base.Os_count = osCount
+ base.Os = os
+ return properties
+ }
+
+ osTypeToInfo := make(map[android.OsType]*osTypeSpecificInfo)
+
+ // The set of properties that are common across all architectures and os types.
+ commonProperties := createVariantPropertiesStruct(android.CommonOS)
+
+ // Create common value extractor that can be used to optimize the properties.
+ commonValueExtractor := newCommonValueExtractor(commonProperties)
+
+ // The list of property structures which are os type specific but common across
+ // architectures within that os type.
+ var osSpecificPropertiesList []android.SdkMemberProperties
+
+ for osType, osTypeVariants := range variantsByOsType {
+ // Group the properties for each variant by arch type within the os.
+ osInfo := &osTypeSpecificInfo{}
+ osTypeToInfo[osType] = osInfo
+
+ // Create a structure into which properties common across the architectures in
+ // this os type will be stored. Add it to the list of os type specific yet
+ // architecture independent properties structs.
+ osInfo.Properties = createVariantPropertiesStruct(osType)
+ osSpecificPropertiesList = append(osSpecificPropertiesList, osInfo.Properties)
+
+ commonArch := false
+ for _, variant := range osTypeVariants {
+ var properties android.SdkMemberProperties
+
+ // Get the info associated with the arch type inside the os info.
+ archType := variant.Target().Arch.ArchType
+
+ if archType.Name == "common" {
+ // The arch type is common so populate the common properties directly.
+ properties = osInfo.Properties
+
+ commonArch = true
+ } else {
+ archInfo := &archTypeSpecificInfo{archType: archType}
+ properties = createVariantPropertiesStruct(osType)
+ archInfo.Properties = properties
+
+ osInfo.archTypes = append(osInfo.archTypes, archInfo)
+ }
+
+ properties.PopulateFromVariant(variant)
+ }
+
+ if commonArch {
+ if len(osTypeVariants) != 1 {
+ panic("Expected to only have 1 variant when arch type is common but found " + string(len(variants)))
+ }
+ } else {
+ var archPropertiesList []android.SdkMemberProperties
+ for _, archInfo := range osInfo.archTypes {
+ archPropertiesList = append(archPropertiesList, archInfo.Properties)
+ }
+
+ commonValueExtractor.extractCommonProperties(osInfo.Properties, archPropertiesList)
+
+ // Choose setting for compile_multilib that is appropriate for the arch variants supplied.
+ var multilib string
+ archVariantCount := len(osInfo.archTypes)
+ if archVariantCount == 2 {
+ multilib = "both"
+ } else if archVariantCount == 1 {
+ if strings.HasSuffix(osInfo.archTypes[0].archType.Name, "64") {
+ multilib = "64"
+ } else {
+ multilib = "32"
+ }
+ }
+
+ osInfo.commonArch = commonArch
+ osInfo.Properties.Base().Compile_multilib = multilib
+ }
+ }
+
+ // Extract properties which are common across all architectures and os types.
+ commonValueExtractor.extractCommonProperties(commonProperties, osSpecificPropertiesList)
+
+ // Add the common properties to the module.
+ commonProperties.AddToPropertySet(sdkModuleContext, builder, bpModule)
+
+ // Create a target property set into which target specific properties can be
+ // added.
+ targetPropertySet := bpModule.AddPropertySet("target")
+
+ // Iterate over the os types in a fixed order.
+ for _, osType := range s.getPossibleOsTypes() {
+ osInfo := osTypeToInfo[osType]
+ if osInfo == nil {
+ continue
+ }
+
+ var osPropertySet android.BpPropertySet
+ var archOsPrefix string
+ if len(osTypeToInfo) == 1 {
+ // There is only one os type present in the variants sp don't bother
+ // with adding target specific properties.
+
+ // Create a structure that looks like:
+ // module_type {
+ // name: "...",
+ // ...
+ // <common properties>
+ // ...
+ // <single os type specific properties>
+ //
+ // arch: {
+ // <arch specific sections>
+ // }
+ //
+ osPropertySet = bpModule
+
+ // Arch specific properties need to be added to an arch specific section
+ // within arch.
+ archOsPrefix = ""
+ } else {
+ // Create a structure that looks like:
+ // module_type {
+ // name: "...",
+ // ...
+ // <common properties>
+ // ...
+ // target: {
+ // <arch independent os specific sections, e.g. android>
+ // ...
+ // <arch and os specific sections, e.g. android_x86>
+ // }
+ //
+ osPropertySet = targetPropertySet.AddPropertySet(osType.Name)
+
+ // Arch specific properties need to be added to an os and arch specific
+ // section prefixed with <os>_.
+ archOsPrefix = osType.Name + "_"
+ }
+
+ osInfo.Properties.AddToPropertySet(sdkModuleContext, builder, osPropertySet)
+ if !osInfo.commonArch {
+ // Either add the arch specific sections into the target or arch sections
+ // depending on whether they will also be os specific.
+ var archPropertySet android.BpPropertySet
+ if archOsPrefix == "" {
+ archPropertySet = osPropertySet.AddPropertySet("arch")
+ } else {
+ archPropertySet = targetPropertySet
+ }
+
+ // Add arch (and possibly os) specific sections for each set of
+ // arch (and possibly os) specific properties.
+ for _, av := range osInfo.archTypes {
+ archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + av.archType.Name)
+
+ av.Properties.AddToPropertySet(sdkModuleContext, builder, archTypePropertySet)
+ }
+ }
+ }
+
+ memberType.FinalizeModule(sdkModuleContext, builder, member, bpModule)
+}
+
+// Compute the list of possible os types that this sdk could support.
+func (s *sdk) getPossibleOsTypes() []android.OsType {
+ var osTypes []android.OsType
+ for _, osType := range android.OsTypeList {
+ if s.DeviceSupported() {
+ if osType.Class == android.Device && osType != android.Fuchsia {
+ osTypes = append(osTypes, osType)
+ }
+ }
+ if s.HostSupported() {
+ if osType.Class == android.Host || osType.Class == android.HostCross {
+ osTypes = append(osTypes, osType)
+ }
+ }
+ }
+ sort.SliceStable(osTypes, func(i, j int) bool { return osTypes[i].Name < osTypes[j].Name })
+ return osTypes
+}
+
+// Given a struct value, access a field within that struct (or one of its embedded
+// structs).
+type fieldAccessorFunc func(structValue reflect.Value) reflect.Value
+
+// Supports extracting common values from a number of instances of a properties
+// structure into a separate common set of properties.
+type commonValueExtractor struct {
+ // The getters for every field from which common values can be extracted.
+ fieldGetters []fieldAccessorFunc
+}
+
+// Create a new common value extractor for the structure type for the supplied
+// properties struct.
+//
+// The returned extractor can be used on any properties structure of the same type
+// as the supplied set of properties.
+func newCommonValueExtractor(propertiesStruct interface{}) *commonValueExtractor {
+ structType := getStructValue(reflect.ValueOf(propertiesStruct)).Type()
+ extractor := &commonValueExtractor{}
+ extractor.gatherFields(structType, nil)
+ return extractor
+}
+
+// Gather the fields from the supplied structure type from which common values will
+// be extracted.
+//
+// This is recursive function. If it encounters an embedded field (no field name)
+// that is a struct then it will recurse into that struct passing in the accessor
+// for the field. That will then be used in the accessors for the fields in the
+// embedded struct.
+func (e *commonValueExtractor) gatherFields(structType reflect.Type, containingStructAccessor fieldAccessorFunc) {
+ for f := 0; f < structType.NumField(); f++ {
+ field := structType.Field(f)
+ if field.PkgPath != "" {
+ // Ignore unexported fields.
+ continue
+ }
+
+ // Ignore fields whose value should be kept.
+ if proptools.HasTag(field, "sdk", "keep") {
+ continue
+ }
+
+ // Save a copy of the field index for use in the function.
+ fieldIndex := f
+ fieldGetter := func(value reflect.Value) reflect.Value {
+ if containingStructAccessor != nil {
+ // This is an embedded structure so first access the field for the embedded
+ // structure.
+ value = containingStructAccessor(value)
+ }
+
+ // Skip through interface and pointer values to find the structure.
+ value = getStructValue(value)
+
+ // Return the field.
+ return value.Field(fieldIndex)
+ }
+
+ if field.Type.Kind() == reflect.Struct && field.Anonymous {
+ // Gather fields from the embedded structure.
+ e.gatherFields(field.Type, fieldGetter)
+ } else {
+ e.fieldGetters = append(e.fieldGetters, fieldGetter)
+ }
+ }
+}
+
+func getStructValue(value reflect.Value) reflect.Value {
+foundStruct:
+ for {
+ kind := value.Kind()
+ switch kind {
+ case reflect.Interface, reflect.Ptr:
+ value = value.Elem()
+ case reflect.Struct:
+ break foundStruct
+ default:
+ panic(fmt.Errorf("expecting struct, interface or pointer, found %v of kind %s", value, kind))
+ }
+ }
+ return value
+}
+
+// Extract common properties from a slice of property structures of the same type.
+//
+// All the property structures must be of the same type.
+// commonProperties - must be a pointer to the structure into which common properties will be added.
+// inputPropertiesSlice - must be a slice of input properties structures.
+//
+// Iterates over each exported field (capitalized name) and checks to see whether they
+// have the same value (using DeepEquals) across all the input properties. If it does not then no
+// change is made. Otherwise, the common value is stored in the field in the commonProperties
+// and the field in each of the input properties structure is set to its default value.
+func (e *commonValueExtractor) extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) {
+ commonPropertiesValue := reflect.ValueOf(commonProperties)
+ commonStructValue := commonPropertiesValue.Elem()
+ propertiesStructType := commonStructValue.Type()
+
+ // Create an empty structure from which default values for the field can be copied.
+ emptyStructValue := reflect.New(propertiesStructType).Elem()
+
+ for _, fieldGetter := range e.fieldGetters {
+ // Check to see if all the structures have the same value for the field. The commonValue
+ // is nil on entry to the loop and if it is nil on exit then there is no common value,
+ // otherwise it points to the common value.
+ var commonValue *reflect.Value
+ sliceValue := reflect.ValueOf(inputPropertiesSlice)
+
+ for i := 0; i < sliceValue.Len(); i++ {
+ itemValue := sliceValue.Index(i)
+ fieldValue := fieldGetter(itemValue)
+
+ if commonValue == nil {
+ // Use the first value as the commonProperties value.
+ commonValue = &fieldValue
+ } else {
+ // If the value does not match the current common value then there is
+ // no value in common so break out.
+ if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
+ commonValue = nil
+ break
+ }
+ }
+ }
+
+ // If the fields all have a common value then store it in the common struct field
+ // and set the input struct's field to the empty value.
+ if commonValue != nil {
+ emptyValue := fieldGetter(emptyStructValue)
+ fieldGetter(commonStructValue).Set(*commonValue)
+ for i := 0; i < sliceValue.Len(); i++ {
+ itemValue := sliceValue.Index(i)
+ fieldValue := fieldGetter(itemValue)
+ fieldValue.Set(emptyValue)
+ }
+ }
+ }
+}
diff --git a/ui/build/kati.go b/ui/build/kati.go
index a845c5b..8796a4f 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -104,17 +104,20 @@
envFunc(cmd.Environment)
if _, ok := cmd.Environment.Get("BUILD_USERNAME"); !ok {
- u, err := user.Current()
- if err != nil {
- ctx.Println("Failed to get current user")
+ username := "unknown"
+ if u, err := user.Current(); err == nil {
+ username = u.Username
+ } else {
+ ctx.Println("Failed to get current user:", err)
}
- cmd.Environment.Set("BUILD_USERNAME", u.Username)
+ cmd.Environment.Set("BUILD_USERNAME", username)
}
if _, ok := cmd.Environment.Get("BUILD_HOSTNAME"); !ok {
hostname, err := os.Hostname()
if err != nil {
- ctx.Println("Failed to read hostname")
+ ctx.Println("Failed to read hostname:", err)
+ hostname = "unknown"
}
cmd.Environment.Set("BUILD_HOSTNAME", hostname)
}
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 0749fe3..4fc1f01 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -38,6 +38,7 @@
executable := config.PrebuiltBuildTool("ninja")
args := []string{
"-d", "keepdepfile",
+ "-d", "keeprsp",
"--frontend_file", fifo,
}
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index bfe662d..5717401 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -74,28 +74,27 @@
}
var Configuration = map[string]PathConfig{
- "bash": Allowed,
- "dd": Allowed,
- "diff": Allowed,
- "dlv": Allowed,
- "expr": Allowed,
- "fuser": Allowed,
- "getopt": Allowed,
- "git": Allowed,
- "hexdump": Allowed,
- "jar": Allowed,
- "java": Allowed,
- "javap": Allowed,
- "lsof": Allowed,
- "openssl": Allowed,
- "patch": Allowed,
- "pstree": Allowed,
- "python3": Allowed,
- "rsync": Allowed,
- "sh": Allowed,
- "tr": Allowed,
- "unzip": Allowed,
- "zip": Allowed,
+ "bash": Allowed,
+ "dd": Allowed,
+ "diff": Allowed,
+ "dlv": Allowed,
+ "expr": Allowed,
+ "fuser": Allowed,
+ "getopt": Allowed,
+ "git": Allowed,
+ "hexdump": Allowed,
+ "jar": Allowed,
+ "java": Allowed,
+ "javap": Allowed,
+ "lsof": Allowed,
+ "openssl": Allowed,
+ "patch": Allowed,
+ "pstree": Allowed,
+ "rsync": Allowed,
+ "sh": Allowed,
+ "tr": Allowed,
+ "unzip": Allowed,
+ "zip": Allowed,
// Host toolchain is removed. In-tree toolchain should be used instead.
// GCC also can't find cc1 with this implementation.
diff --git a/ui/status/completion_proto/build_completion.pb.go b/ui/status/completion_proto/build_completion.pb.go
new file mode 100644
index 0000000..526e19a
--- /dev/null
+++ b/ui/status/completion_proto/build_completion.pb.go
@@ -0,0 +1,105 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: build_completion.proto
+
+package soong_build_completion_status_proto
+
+import (
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+type BuildCompletionStatus struct {
+ // Total number of actions in a build. The total actions will increase
+ // and might decrease during the course of a build.
+ TotalActions *uint64 `protobuf:"varint,1,opt,name=total_actions,json=totalActions" json:"total_actions,omitempty"`
+ // Total number of completed build actions. This value will never decrease
+ // and finished_actions <= total_actions. At one point of the build, the
+ // finished_actions will be equal to total_actions. This may not represent
+ // that the build is completed as the total_actions may be increased for
+ // additional counted work or is doing non-counted work.
+ FinishedActions *uint64 `protobuf:"varint,2,opt,name=finished_actions,json=finishedActions" json:"finished_actions,omitempty"`
+ // Total number of current actions being executed during a course of a
+ // build and current_actions + finished_actions <= total_actions.
+ CurrentActions *uint64 `protobuf:"varint,3,opt,name=current_actions,json=currentActions" json:"current_actions,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *BuildCompletionStatus) Reset() { *m = BuildCompletionStatus{} }
+func (m *BuildCompletionStatus) String() string { return proto.CompactTextString(m) }
+func (*BuildCompletionStatus) ProtoMessage() {}
+func (*BuildCompletionStatus) Descriptor() ([]byte, []int) {
+ return fileDescriptor_7f03c01d09a4e764, []int{0}
+}
+
+func (m *BuildCompletionStatus) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_BuildCompletionStatus.Unmarshal(m, b)
+}
+func (m *BuildCompletionStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_BuildCompletionStatus.Marshal(b, m, deterministic)
+}
+func (m *BuildCompletionStatus) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_BuildCompletionStatus.Merge(m, src)
+}
+func (m *BuildCompletionStatus) XXX_Size() int {
+ return xxx_messageInfo_BuildCompletionStatus.Size(m)
+}
+func (m *BuildCompletionStatus) XXX_DiscardUnknown() {
+ xxx_messageInfo_BuildCompletionStatus.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_BuildCompletionStatus proto.InternalMessageInfo
+
+func (m *BuildCompletionStatus) GetTotalActions() uint64 {
+ if m != nil && m.TotalActions != nil {
+ return *m.TotalActions
+ }
+ return 0
+}
+
+func (m *BuildCompletionStatus) GetFinishedActions() uint64 {
+ if m != nil && m.FinishedActions != nil {
+ return *m.FinishedActions
+ }
+ return 0
+}
+
+func (m *BuildCompletionStatus) GetCurrentActions() uint64 {
+ if m != nil && m.CurrentActions != nil {
+ return *m.CurrentActions
+ }
+ return 0
+}
+
+func init() {
+ proto.RegisterType((*BuildCompletionStatus)(nil), "soong_build_completion_status.BuildCompletionStatus")
+}
+
+func init() { proto.RegisterFile("build_completion.proto", fileDescriptor_7f03c01d09a4e764) }
+
+var fileDescriptor_7f03c01d09a4e764 = []byte{
+ // 158 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4b, 0x2a, 0xcd, 0xcc,
+ 0x49, 0x89, 0x4f, 0xce, 0xcf, 0x2d, 0xc8, 0x49, 0x2d, 0xc9, 0xcc, 0xcf, 0xd3, 0x2b, 0x28, 0xca,
+ 0x2f, 0xc9, 0x17, 0x92, 0x2d, 0xce, 0xcf, 0xcf, 0x4b, 0x8f, 0x47, 0x97, 0x8d, 0x2f, 0x2e, 0x49,
+ 0x2c, 0x29, 0x2d, 0x56, 0x9a, 0xc0, 0xc8, 0x25, 0xea, 0x04, 0x92, 0x73, 0x86, 0x4b, 0x05, 0x83,
+ 0x65, 0x84, 0x94, 0xb9, 0x78, 0x4b, 0xf2, 0x4b, 0x12, 0x73, 0xe2, 0x13, 0x93, 0x41, 0xa2, 0xc5,
+ 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x2c, 0x41, 0x3c, 0x60, 0x41, 0x47, 0x88, 0x98, 0x90, 0x26, 0x97,
+ 0x40, 0x5a, 0x66, 0x5e, 0x66, 0x71, 0x46, 0x6a, 0x0a, 0x5c, 0x1d, 0x13, 0x58, 0x1d, 0x3f, 0x4c,
+ 0x1c, 0xa6, 0x54, 0x9d, 0x8b, 0x3f, 0xb9, 0xb4, 0xa8, 0x28, 0x35, 0xaf, 0x04, 0xae, 0x92, 0x19,
+ 0xac, 0x92, 0x0f, 0x2a, 0x0c, 0x55, 0xe8, 0xa4, 0x1a, 0xa5, 0x8c, 0xd7, 0xcd, 0xf1, 0x60, 0x8f,
+ 0x01, 0x02, 0x00, 0x00, 0xff, 0xff, 0x13, 0x08, 0x7b, 0x38, 0xf1, 0x00, 0x00, 0x00,
+}
diff --git a/ui/status/completion_proto/build_completion.proto b/ui/status/completion_proto/build_completion.proto
new file mode 100644
index 0000000..939545e
--- /dev/null
+++ b/ui/status/completion_proto/build_completion.proto
@@ -0,0 +1,35 @@
+// 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.
+
+syntax = "proto2";
+
+package soong_build_completion_status;
+option go_package = "soong_build_completion_status_proto";
+
+message BuildCompletionStatus {
+ // Total number of actions in a build. The total actions will increase
+ // and might decrease during the course of a build.
+ optional uint64 total_actions = 1;
+
+ // Total number of completed build actions. This value will never decrease
+ // and finished_actions <= total_actions. At one point of the build, the
+ // finished_actions will be equal to total_actions. This may not represent
+ // that the build is completed as the total_actions may be increased for
+ // additional counted work or is doing non-counted work.
+ optional uint64 finished_actions = 2;
+
+ // Total number of current actions being executed during a course of a
+ // build and current_actions + finished_actions <= total_actions.
+ optional uint64 current_actions = 3;
+}
diff --git a/ui/status/completion_proto/regen.sh b/ui/status/completion_proto/regen.sh
new file mode 100755
index 0000000..652df08
--- /dev/null
+++ b/ui/status/completion_proto/regen.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Generates the golang source file of build_completion.proto file.
+
+set -e
+
+function die() { echo "ERROR: $1" >&2; exit 1; }
+
+readonly error_msg="Maybe you need to run 'lunch aosp_arm-eng && m aprotoc blueprint_tools'?"
+
+if ! hash aprotoc &>/dev/null; then
+ die "could not find aprotoc. ${error_msg}"
+fi
+
+if ! aprotoc --go_out=paths=source_relative:. build_completion.proto; then
+ die "build failed. ${error_msg}"
+fi