diff options
69 files changed, 2012 insertions, 711 deletions
@@ -419,7 +419,8 @@ soong_config_module_type { name: "acme_cc_defaults", module_type: "cc_defaults", config_namespace: "acme", - variables: ["board", "feature"], + variables: ["board"], + bool_variables: ["feature"], properties: ["cflags", "srcs"], } @@ -427,10 +428,6 @@ soong_config_string_variable { name: "board", values: ["soc_a", "soc_b"], } - -soong_config_bool_variable { - name: "feature", -} ``` This example describes a new `acme_cc_defaults` module type that extends the diff --git a/android/apex.go b/android/apex.go index eabe05944..9bf6fc717 100644 --- a/android/apex.go +++ b/android/apex.go @@ -19,6 +19,8 @@ import ( "sort" "strconv" "sync" + + "github.com/google/blueprint" ) const ( @@ -32,6 +34,14 @@ type ApexInfo struct { MinSdkVersion int } +// Extracted from ApexModule to make it easier to define custom subsets of the +// ApexModule interface and improve code navigation within the IDE. +type DepIsInSameApex interface { + // DepIsInSameApex tests if the other module 'dep' is installed to the same + // APEX as this module + DepIsInSameApex(ctx BaseModuleContext, dep Module) bool +} + // ApexModule is the interface that a module type is expected to implement if // the module has to be built differently depending on whether the module // is destined for an apex or not (installed to one of the regular partitions). @@ -49,6 +59,8 @@ type ApexInfo struct { // respectively. type ApexModule interface { Module + DepIsInSameApex + apexModuleBase() *ApexModuleBase // Marks that this module should be built for the specified APEXes. @@ -88,16 +100,10 @@ type ApexModule interface { // Tests if this module is available for the specified APEX or ":platform" AvailableFor(what string) bool - // 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 + // Returns the highest version which is <= maxSdkVersion. + // For example, with maxSdkVersion is 10 and versionList is [9,11] + // it returns 9 as string + ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error) } type ApexProperties struct { @@ -113,6 +119,15 @@ type ApexProperties struct { Info ApexInfo `blueprint:"mutated"` } +// Marker interface that identifies dependencies that are excluded from APEX +// contents. +type ExcludeFromApexContentsTag interface { + blueprint.DependencyTag + + // Method that differentiates this interface from others. + ExcludeFromApexContents() +} + // Provides default implementation for the ApexModule interface. APEX-aware // modules are expected to include this struct and call InitApexModule(). type ApexModuleBase struct { @@ -193,22 +208,14 @@ func (m *ApexModuleBase) DepIsInSameApex(ctx BaseModuleContext, dep Module) bool 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 +func (m *ApexModuleBase) ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error) { for i := range versionList { ver, _ := strconv.Atoi(versionList[len(versionList)-i-1]) - if ver <= minSdkVersion { + if ver <= maxSdkVersion { 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 <= SdkVersion_Android10) + return "", fmt.Errorf("not found a version(<=%d) in versionList: %v", maxSdkVersion, versionList) } func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) { diff --git a/android/config.go b/android/config.go index 795317030..558c828e0 100644 --- a/android/config.go +++ b/android/config.go @@ -1032,6 +1032,10 @@ func (c *deviceConfig) DeviceKernelHeaderDirs() []string { return c.config.productVariables.DeviceKernelHeaders } +func (c *deviceConfig) SamplingPGO() bool { + return Bool(c.config.productVariables.SamplingPGO) +} + func (c *config) NativeLineCoverage() bool { return Bool(c.productVariables.NativeLineCoverage) } diff --git a/android/defs.go b/android/defs.go index 5c815e64e..45522246f 100644 --- a/android/defs.go +++ b/android/defs.go @@ -100,6 +100,9 @@ var ( // Used only when USE_GOMA=true is set, to restrict non-goma jobs to the local parallelism value localPool = blueprint.NewBuiltinPool("local_pool") + // Used only by RuleBuilder to identify remoteable rules. Does not actually get created in ninja. + remotePool = blueprint.NewBuiltinPool("remote_pool") + // Used for processes that need significant RAM to ensure there are not too many running in parallel. highmemPool = blueprint.NewBuiltinPool("highmem_pool") ) diff --git a/android/module.go b/android/module.go index 057a5c71f..02b2c8926 100644 --- a/android/module.go +++ b/android/module.go @@ -128,6 +128,13 @@ type BaseModuleContext interface { // and returns a top-down dependency path from a start module to current child module. GetWalkPath() []Module + // GetTagPath is supposed to be called in visit function passed in WalkDeps() + // and returns a top-down dependency tags path from a start module to current child module. + // It has one less entry than GetWalkPath() as it contains the dependency tags that + // exist between each adjacent pair of modules in the GetWalkPath(). + // GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1] + GetTagPath() []blueprint.DependencyTag + AddMissingDependencies(missingDeps []string) Target() Target @@ -220,6 +227,7 @@ type Module interface { InstallBypassMake() bool InstallForceOS() *OsType SkipInstall() + IsSkipInstall() bool ExportedToMake() bool InitRc() Paths VintfFragments() Paths @@ -894,6 +902,40 @@ func (m *ModuleBase) SystemExtSpecific() bool { return Bool(m.commonProperties.System_ext_specific) } +func (m *ModuleBase) PartitionTag(config DeviceConfig) string { + partition := "system" + if m.SocSpecific() { + // A SoC-specific module could be on the vendor partition at + // "vendor" or the system partition at "system/vendor". + if config.VendorPath() == "vendor" { + partition = "vendor" + } + } else if m.DeviceSpecific() { + // A device-specific module could be on the odm partition at + // "odm", the vendor partition at "vendor/odm", or the system + // partition at "system/vendor/odm". + if config.OdmPath() == "odm" { + partition = "odm" + } else if strings.HasPrefix(config.OdmPath(), "vendor/") { + partition = "vendor" + } + } else if m.ProductSpecific() { + // A product-specific module could be on the product partition + // at "product" or the system partition at "system/product". + if config.ProductPath() == "product" { + partition = "product" + } + } else if m.SystemExtSpecific() { + // A system_ext-specific module could be on the system_ext + // partition at "system_ext" or the system partition at + // "system/system_ext". + if config.SystemExtPath() == "system_ext" { + partition = "system_ext" + } + } + return partition +} + func (m *ModuleBase) Enabled() bool { if m.commonProperties.Enabled == nil { return !m.Os().DefaultDisabled @@ -909,6 +951,10 @@ func (m *ModuleBase) SkipInstall() { m.commonProperties.SkipInstall = true } +func (m *ModuleBase) IsSkipInstall() bool { + return m.commonProperties.SkipInstall == true +} + func (m *ModuleBase) ExportedToMake() bool { return m.commonProperties.NamespaceExportedToMake } @@ -1366,6 +1412,7 @@ type baseModuleContext struct { debug bool walkPath []Module + tagPath []blueprint.DependencyTag strictVisitDeps bool // If true, enforce that all dependencies are enabled } @@ -1472,10 +1519,17 @@ func (m *moduleContext) Variable(pctx PackageContext, name, value string) { func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule { - if m.config.UseRemoteBuild() && params.Pool == nil { - // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict - // jobs to the local parallelism value - params.Pool = localPool + if m.config.UseRemoteBuild() { + if params.Pool == nil { + // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict + // jobs to the local parallelism value + params.Pool = localPool + } else if params.Pool == remotePool { + // remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's + // pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS + // parallelism. + params.Pool = nil + } } rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...) @@ -1655,6 +1709,7 @@ func (b *baseModuleContext) WalkDepsBlueprint(visit func(blueprint.Module, bluep func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) { b.walkPath = []Module{b.Module()} + b.tagPath = []blueprint.DependencyTag{} b.bp.WalkDeps(func(child, parent blueprint.Module) bool { childAndroidModule, _ := child.(Module) parentAndroidModule, _ := parent.(Module) @@ -1662,8 +1717,10 @@ func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) { // record walkPath before visit for b.walkPath[len(b.walkPath)-1] != parentAndroidModule { b.walkPath = b.walkPath[0 : len(b.walkPath)-1] + b.tagPath = b.tagPath[0 : len(b.tagPath)-1] } b.walkPath = append(b.walkPath, childAndroidModule) + b.tagPath = append(b.tagPath, b.OtherModuleDependencyTag(childAndroidModule)) return visit(childAndroidModule, parentAndroidModule) } else { return false @@ -1675,6 +1732,10 @@ func (b *baseModuleContext) GetWalkPath() []Module { return b.walkPath } +func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag { + return b.tagPath +} + func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) { m.bp.VisitAllModuleVariants(func(module blueprint.Module) { visit(module.(Module)) diff --git a/android/prebuilt.go b/android/prebuilt.go index c902ec826..82745a498 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -39,6 +39,12 @@ var PrebuiltDepTag prebuiltDependencyTag // Mark this tag so dependencies that use it are excluded from visibility enforcement. func (t prebuiltDependencyTag) ExcludeFromVisibilityEnforcement() {} +// Mark this tag so dependencies that use it are excluded from APEX contents. +func (t prebuiltDependencyTag) ExcludeFromApexContents() {} + +var _ ExcludeFromVisibilityEnforcementTag = PrebuiltDepTag +var _ ExcludeFromApexContentsTag = PrebuiltDepTag + type PrebuiltProperties struct { // When prefer is set to true the prebuilt will be used instead of any source module with // a matching name. diff --git a/android/rule_builder.go b/android/rule_builder.go index 9005f072a..6226548ba 100644 --- a/android/rule_builder.go +++ b/android/rule_builder.go @@ -446,7 +446,8 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string if ctx.Config().UseGoma() && r.remoteable.Goma { // When USE_GOMA=true is set and the rule is supported by goma, allow jobs to run outside the local pool. } else if ctx.Config().UseRBE() && r.remoteable.RBE { - // When USE_RBE=true is set and the rule is supported by RBE, allow jobs to run outside the local pool. + // When USE_RBE=true is set and the rule is supported by RBE, use the remotePool. + pool = remotePool } else if r.highmem { pool = highmemPool } else if ctx.Config().UseRemoteBuild() { diff --git a/android/sdk.go b/android/sdk.go index 66094cda0..6f62f552c 100644 --- a/android/sdk.go +++ b/android/sdk.go @@ -22,17 +22,30 @@ import ( "github.com/google/blueprint/proptools" ) +// Extracted from SdkAware to make it easier to define custom subsets of the +// SdkAware interface and improve code navigation within the IDE. +// +// In addition to its use in SdkAware this interface must also be implemented by +// APEX to specify the SDKs required by that module and its contents. e.g. APEX +// is expected to implement RequiredSdks() by reading its own properties like +// `uses_sdks`. +type RequiredSdks interface { + // The set of SDKs required by an APEX and its contents. + RequiredSdks() SdkRefs +} + // SdkAware is the interface that must be supported by any module to become a member of SDK or to be // built with SDK type SdkAware interface { Module + RequiredSdks + sdkBase() *SdkBase MakeMemberOf(sdk SdkRef) IsInAnySdk() bool ContainingSdk() SdkRef MemberName() string BuildWithSdks(sdks SdkRefs) - RequiredSdks() SdkRefs } // SdkRef refers to a version of an SDK diff --git a/android/singleton.go b/android/singleton.go index 45a9b8243..568398cdd 100644 --- a/android/singleton.go +++ b/android/singleton.go @@ -128,10 +128,17 @@ func (s *singletonContextAdaptor) Variable(pctx PackageContext, name, value stri } func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule { - if s.Config().UseRemoteBuild() && params.Pool == nil { - // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict - // jobs to the local parallelism value - params.Pool = localPool + if s.Config().UseRemoteBuild() { + if params.Pool == nil { + // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict + // jobs to the local parallelism value + params.Pool = localPool + } else if params.Pool == remotePool { + // remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's + // pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS + // parallelism. + params.Pool = nil + } } rule := s.SingletonContext.Rule(pctx.PackageContext, name, params, argNames...) if s.Config().captureBuild { diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go index 198108d65..6ce609a19 100644 --- a/android/soong_config_modules.go +++ b/android/soong_config_modules.go @@ -88,7 +88,8 @@ type soongConfigModuleTypeImportProperties struct { // name: "acme_cc_defaults", // module_type: "cc_defaults", // config_namespace: "acme", -// variables: ["board", "feature"], +// variables: ["board"], +// bool_variables: ["feature"], // properties: ["cflags", "srcs"], // } // @@ -97,10 +98,6 @@ type soongConfigModuleTypeImportProperties struct { // values: ["soc_a", "soc_b"], // } // -// soong_config_bool_variable { -// name: "feature", -// } -// // If an acme BoardConfig.mk file contained: // // SOONG_CONFIG_NAMESPACES += acme @@ -125,7 +122,10 @@ func soongConfigModuleTypeImportFactory() Module { } func (m *soongConfigModuleTypeImport) Name() string { - return "soong_config_module_type_import_" + soongconfig.CanonicalizeToProperty(m.properties.From) + // The generated name is non-deterministic, but it does not + // matter because this module does not emit any rules. + return soongconfig.CanonicalizeToProperty(m.properties.From) + + "soong_config_module_type_import_" + fmt.Sprintf("%p", m) } func (*soongConfigModuleTypeImport) Nameless() {} @@ -149,7 +149,8 @@ type soongConfigModuleTypeModule struct { // name: "acme_cc_defaults", // module_type: "cc_defaults", // config_namespace: "acme", -// variables: ["board", "feature"], +// variables: ["board"], +// bool_variables: ["feature"], // properties: ["cflags", "srcs"], // } // @@ -158,10 +159,6 @@ type soongConfigModuleTypeModule struct { // values: ["soc_a", "soc_b"], // } // -// soong_config_bool_variable { -// name: "feature", -// } -// // acme_cc_defaults { // name: "acme_defaults", // cflags: ["-DGENERIC"], diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go index 6ad88a2ee..1cf060dc0 100644 --- a/android/soong_config_modules_test.go +++ b/android/soong_config_modules_test.go @@ -43,7 +43,8 @@ func TestSoongConfigModule(t *testing.T) { name: "acme_test_defaults", module_type: "test_defaults", config_namespace: "acme", - variables: ["board", "feature1", "feature2", "FEATURE3"], + variables: ["board", "feature1", "FEATURE3"], + bool_variables: ["feature2"], properties: ["cflags", "srcs"], } @@ -57,10 +58,6 @@ func TestSoongConfigModule(t *testing.T) { } soong_config_bool_variable { - name: "feature2", - } - - soong_config_bool_variable { name: "FEATURE3", } ` diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go index aa4f5c5f1..2d6063d79 100644 --- a/android/soongconfig/modules.go +++ b/android/soongconfig/modules.go @@ -109,6 +109,9 @@ type ModuleTypeProperties struct { // the list of SOONG_CONFIG variables that this module type will read Variables []string + // the list of boolean SOONG_CONFIG variables that this module type will read + Bool_variables []string + // the list of properties that this module type will extend. Properties []string } @@ -146,6 +149,18 @@ func processModuleTypeDef(v *SoongConfigDefinition, def *parser.Module) (errs [] } v.ModuleTypes[props.Name] = mt + for _, name := range props.Bool_variables { + if name == "" { + return []error{fmt.Errorf("bool_variable name must not be blank")} + } + + mt.Variables = append(mt.Variables, &boolVariable{ + baseVariable: baseVariable{ + variable: name, + }, + }) + } + return nil } diff --git a/android/variable.go b/android/variable.go index 91de956bb..612d138c3 100644 --- a/android/variable.go +++ b/android/variable.go @@ -95,6 +95,9 @@ type variableProperties struct { Sanitize struct { Address *bool } + Optimize struct { + Enabled *bool + } } Pdk struct { @@ -252,6 +255,8 @@ type productVariables struct { ClangTidy *bool `json:",omitempty"` TidyChecks *string `json:",omitempty"` + SamplingPGO *bool `json:",omitempty"` + NativeLineCoverage *bool `json:",omitempty"` Native_coverage *bool `json:",omitempty"` ClangCoverage *bool `json:",omitempty"` diff --git a/android/vts_config.go b/android/vts_config.go index 9a1df7c99..77fb9fed9 100644 --- a/android/vts_config.go +++ b/android/vts_config.go @@ -53,7 +53,7 @@ func (me *VtsConfig) AndroidMk() AndroidMkData { fmt.Fprintf(w, "LOCAL_TEST_CONFIG := %s\n", *me.properties.Test_config) } - fmt.Fprintf(w, "LOCAL_COMPATIBILITY_SUITE := vts %s\n", + fmt.Fprintf(w, "LOCAL_COMPATIBILITY_SUITE := vts10 %s\n", strings.Join(me.properties.Test_suites, " ")) }, } @@ -64,7 +64,7 @@ func InitVtsConfigModule(me *VtsConfig) { me.AddProperties(&me.properties) } -// vts_config generates a Vendor Test Suite (VTS) configuration file from the +// vts_config generates a Vendor Test Suite (VTS10) configuration file from the // <test_config> xml file and stores it in a subdirectory of $(HOST_OUT). func VtsConfigFactory() Module { module := &VtsConfig{} diff --git a/apex/androidmk.go b/apex/androidmk.go index 5c15e8e8c..db1048e23 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -22,6 +22,7 @@ import ( "android/soong/android" "android/soong/cc" + "android/soong/java" "github.com/google/blueprint/proptools" ) @@ -181,6 +182,9 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo // we need to remove the suffix from LOCAL_MODULE_STEM, otherwise // we will have foo.apk.apk fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.builtFile.Base(), ".apk")) + if app, ok := fi.module.(*java.AndroidApp); ok && len(app.JniCoverageOutputs()) > 0 { + fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", strings.Join(app.JniCoverageOutputs().Strings(), " ")) + } fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_app_prebuilt.mk") } else if fi.class == nativeSharedLib || fi.class == nativeExecutable || fi.class == nativeTest { fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base()) diff --git a/apex/apex.go b/apex/apex.go index 46aaa8b5f..5a56185e8 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -18,6 +18,7 @@ import ( "fmt" "path" "path/filepath" + "regexp" "sort" "strconv" "strings" @@ -94,27 +95,9 @@ func makeApexAvailableWhitelist() map[string][]string { // Module separator // m["com.android.adbd"] = []string{ - "adbd", - "bcm_object", - "fmtlib", - "libadbconnection_server", - "libadbd", "libadbd_auth", - "libadbd_core", - "libadbd_services", - "libasyncio", - "libbacktrace_headers", - "libbase", - "libbase_headers", "libbuildversion", - "libc++", "libcap", - "libcrypto", - "libcrypto_utils", - "libcutils", - "libcutils_headers", - "libdiagnose_usb", - "liblog_headers", "libmdnssd", "libminijail", "libminijail_gen_constants", @@ -125,9 +108,6 @@ func makeApexAvailableWhitelist() map[string][]string { "libpackagelistparser", "libpcre2", "libprocessgroup_headers", - "libqemu_pipe", - "libsystem_headers", - "libutils_headers", } // // Module separator @@ -136,7 +116,6 @@ func makeApexAvailableWhitelist() map[string][]string { "art_cmdlineparser_headers", "art_disassembler_headers", "art_libartbase_headers", - "bcm_object", "bionic_libc_platform_headers", "core-repackaged-icu4j", "cpp-define-generator-asm-support", @@ -148,9 +127,7 @@ func makeApexAvailableWhitelist() map[string][]string { "conscrypt.module.intra.core.api.stubs", "dex2oat_headers", "dt_fd_forward_export", - "fmtlib", "icu4c_extra_headers", - "jacocoagent", "javavm_headers", "jni_platform_headers", "libPlatformProperties", @@ -160,15 +137,6 @@ func makeApexAvailableWhitelist() map[string][]string { "libart_runtime_headers_ndk", "libartd-disassembler", "libasync_safe", - "libbacktrace", - "libbase", - "libbase_headers", - "libc++", - "libc++_static", - "libc++abi", - "libc++demangle", - "libc_headers", - "libcrypto", "libdexfile_all_headers", "libdexfile_external_headers", "libdexfile_support", @@ -181,7 +149,6 @@ func makeApexAvailableWhitelist() map[string][]string { "libicuuc_headers", "libicuuc_stubdata", "libjdwp_headers", - "liblog_headers", "liblz4", "liblzma", "libmeminfo", @@ -192,7 +159,6 @@ func makeApexAvailableWhitelist() map[string][]string { "libopenjdkjvmti_headers", "libperfetto_client_experimental", "libprocinfo", - "libprotobuf-cpp-lite", "libunwind_llvm", "libunwindstack", "libv8", @@ -229,13 +195,10 @@ func makeApexAvailableWhitelist() map[string][]string { "android.hidl.token@1.0-utils", "avrcp-target-service", "avrcp_headers", - "bcm_object", "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", @@ -245,9 +208,6 @@ func makeApexAvailableWhitelist() map[string][]string { "libFraunhoferAAC", "libaudio-a2dp-hw-utils", "libaudio-hearing-aid-hw-utils", - "libbacktrace_headers", - "libbase", - "libbase_headers", "libbinder_headers", "libbluetooth", "libbluetooth-types", @@ -269,38 +229,23 @@ func makeApexAvailableWhitelist() map[string][]string { "libbtdevice", "libbte", "libbtif", - "libc++", "libchrome", - "libcrypto", - "libcutils", - "libcutils_headers", "libevent", "libfmq", "libg722codec", "libgtest_prod", "libgui_headers", - "libhidlbase", - "libhidlbase-impl-internal", - "libhidltransport-impl-internal", - "libhwbinder-impl-internal", - "libjsoncpp", - "liblog_headers", "libmedia_headers", "libmodpb64", "libosi", "libprocessgroup", "libprocessgroup_headers", - "libprotobuf-cpp-lite", - "libprotobuf-java-lite", - "libprotobuf-java-micro", "libstagefright_foundation_headers", "libstagefright_headers", "libstatslog", "libstatssocket", - "libsystem_headers", "libtinyxml2", "libudrv-uipc", - "libutils_headers", "libz", "media_plugin_headers", "net-utils-services-common", @@ -320,12 +265,8 @@ func makeApexAvailableWhitelist() map[string][]string { // Module separator // m["com.android.conscrypt"] = []string{ - "bcm_object", "boringssl_self_test", - "libc++", - "libcrypto", "libnativehelper_header_only", - "libssl", "unsupportedappusage", } // @@ -365,28 +306,11 @@ func makeApexAvailableWhitelist() map[string][]string { "android.hidl.memory.token@1.0", "android.hidl.memory@1.0", "android.hidl.safe_union@1.0", - "bcm_object", - "fmtlib", "gemmlowp_headers", "libarect", - "libbacktrace_headers", - "libbase", - "libbase_headers", "libbuildversion", - "libc++", - "libcrypto", - "libcrypto_static", - "libcutils", - "libcutils_headers", "libeigen", "libfmq", - "libhidlbase", - "libhidlbase-impl-internal", - "libhidlmemory", - "libhidltransport-impl-internal", - "libhwbinder-impl-internal", - "libjsoncpp", - "liblog_headers", "libmath", "libneuralnetworks_common", "libneuralnetworks_headers", @@ -394,12 +318,10 @@ func makeApexAvailableWhitelist() map[string][]string { "libprocessgroup_headers", "libprocpartition", "libsync", - "libsystem_headers", "libtextclassifier_hash", "libtextclassifier_hash_headers", "libtextclassifier_hash_static", "libtflite_kernel_utils", - "libutils_headers", "philox_random", "philox_random_headers", "tensorflow_headers", @@ -431,9 +353,7 @@ func makeApexAvailableWhitelist() map[string][]string { "android.hidl.memory@1.0", "android.hidl.token@1.0", "android.hidl.token@1.0-utils", - "bcm_object", "bionic_libc_platform_headers", - "fmtlib", "gl_headers", "libEGL", "libEGL_blobCache", @@ -455,23 +375,14 @@ func makeApexAvailableWhitelist() map[string][]string { "libaudiopolicy", "libaudioutils", "libaudioutils_fixedfft", - "libbacktrace", - "libbacktrace_headers", - "libbase", - "libbase_headers", "libbinder_headers", "libbluetooth-types-header", "libbufferhub", "libbufferhub_headers", "libbufferhubqueue", - "libc++", - "libc_headers", "libc_malloc_debug_backtrace", "libcamera_client", "libcamera_metadata", - "libcrypto", - "libcutils", - "libcutils_headers", "libdexfile_external_headers", "libdexfile_support", "libdvr_headers", @@ -483,14 +394,7 @@ func makeApexAvailableWhitelist() map[string][]string { "libgui", "libgui_headers", "libhardware_headers", - "libhidlbase", - "libhidlbase-impl-internal", - "libhidlmemory", - "libhidltransport-impl-internal", - "libhwbinder-impl-internal", "libinput", - "libjsoncpp", - "liblog_headers", "liblzma", "libmath", "libmedia", @@ -538,11 +442,9 @@ func makeApexAvailableWhitelist() map[string][]string { "libstagefright_mpeg2extractor", "libstagefright_mpeg2support", "libsync", - "libsystem_headers", "libui", "libui_headers", "libunwindstack", - "libutils_headers", "libvibrator", "libvorbisidec", "libwavextractor", @@ -582,7 +484,6 @@ func makeApexAvailableWhitelist() map[string][]string { "android.hidl.safe_union@1.0", "android.hidl.token@1.0", "android.hidl.token@1.0-utils", - "fmtlib", "libEGL", "libFLAC", "libFLAC-config", @@ -599,15 +500,10 @@ func makeApexAvailableWhitelist() map[string][]string { "libavcenc", "libavservices_minijail", "libavservices_minijail", - "libbacktrace", - "libbacktrace_headers", - "libbase", - "libbase_headers", "libbinder_headers", "libbinderthreadstateutils", "libbluetooth-types-header", "libbufferhub_headers", - "libc++", "libc_scudo", "libcap", "libcodec2", @@ -647,8 +543,6 @@ func makeApexAvailableWhitelist() map[string][]string { "libcodec2_soft_vp9dec", "libcodec2_soft_vp9enc", "libcodec2_vndk", - "libcutils", - "libcutils_headers", "libdexfile_support", "libdvr_headers", "libfmq", @@ -664,15 +558,8 @@ func makeApexAvailableWhitelist() map[string][]string { "libhardware_headers", "libhevcdec", "libhevcenc", - "libhidlbase", - "libhidlbase-impl-internal", - "libhidlmemory", - "libhidltransport-impl-internal", - "libhwbinder-impl-internal", "libion", "libjpeg", - "libjsoncpp", - "liblog_headers", "liblzma", "libmath", "libmedia_codecserviceregistrant", @@ -710,11 +597,9 @@ func makeApexAvailableWhitelist() map[string][]string { "libstagefright_m4vh263enc", "libstagefright_mp3dec", "libsync", - "libsystem_headers", "libui", "libui_headers", "libunwindstack", - "libutils_headers", "libvorbisidec", "libvpx", "libyuv", @@ -730,7 +615,6 @@ func makeApexAvailableWhitelist() map[string][]string { "MediaProvider", "MediaProviderGoogle", "fmtlib_ndk", - "guava", "libbase_ndk", "libfuse", "libfuse_jni", @@ -754,7 +638,6 @@ func makeApexAvailableWhitelist() map[string][]string { "kotlinx-coroutines-android-nodeps", "kotlinx-coroutines-core", "kotlinx-coroutines-core-nodeps", - "libprotobuf-java-lite", "permissioncontroller-statsd", } // @@ -762,14 +645,9 @@ func makeApexAvailableWhitelist() map[string][]string { // m["com.android.runtime"] = []string{ "bionic_libc_platform_headers", - "fmtlib", "libarm-optimized-routines-math", "libasync_safe", "libasync_safe_headers", - "libbacktrace_headers", - "libbase", - "libbase_headers", - "libc++", "libc_aeabi", "libc_bionic", "libc_bionic_ndk", @@ -783,7 +661,6 @@ func makeApexAvailableWhitelist() map[string][]string { "libc_freebsd", "libc_freebsd_large_stack", "libc_gdtoa", - "libc_headers", "libc_init_dynamic", "libc_init_static", "libc_jemalloc_wrapper", @@ -798,8 +675,6 @@ func makeApexAvailableWhitelist() map[string][]string { "libc_syscalls", "libc_tzcode", "libc_unwind_static", - "libcutils", - "libcutils_headers", "libdebuggerd", "libdebuggerd_common_headers", "libdebuggerd_handler_core", @@ -812,7 +687,6 @@ func makeApexAvailableWhitelist() map[string][]string { "libjemalloc5", "liblinker_main", "liblinker_malloc", - "liblog_headers", "liblz4", "liblzma", "libprocessgroup_headers", @@ -820,11 +694,9 @@ func makeApexAvailableWhitelist() map[string][]string { "libpropertyinfoparser", "libscudo", "libstdc++", - "libsystem_headers", "libsystemproperties", "libtombstoned_client_static", "libunwindstack", - "libutils_headers", "libz", "libziparchive", } @@ -832,34 +704,19 @@ func makeApexAvailableWhitelist() map[string][]string { // Module separator // m["com.android.resolv"] = []string{ - "bcm_object", "dnsresolver_aidl_interface-unstable-ndk_platform", - "fmtlib", - "libbacktrace_headers", - "libbase", - "libbase_headers", - "libc++", - "libcrypto", - "libcutils", - "libcutils_headers", "libgtest_prod", - "libjsoncpp", - "liblog_headers", "libnativehelper_header_only", "libnetd_client_headers", "libnetd_resolv", "libnetdutils", "libprocessgroup", "libprocessgroup_headers", - "libprotobuf-cpp-lite", - "libssl", "libstatslog_resolv", "libstatspush_compat", "libstatssocket", "libstatssocket_headers", - "libsystem_headers", "libsysutils", - "libutils_headers", "netd_event_listener_interface-ndk_platform", "server_configurable_flags", "stats_proto", @@ -868,28 +725,13 @@ func makeApexAvailableWhitelist() map[string][]string { // Module separator // m["com.android.tethering"] = []string{ - "libbase", - "libc++", "libnativehelper_compat_libc++", "android.hardware.tetheroffload.config@1.0", - "fmtlib", - "libbacktrace_headers", - "libbase_headers", "libcgrouprc", "libcgrouprc_format", - "libcutils", - "libcutils_headers", - "libhidlbase", - "libhidlbase-impl-internal", - "libhidltransport-impl-internal", - "libhwbinder-impl-internal", - "libjsoncpp", - "liblog_headers", "libprocessgroup", "libprocessgroup_headers", - "libsystem_headers", "libtetherutilsjni", - "libutils_headers", "libvndksupport", "tethering-aidl-interfaces-java", } @@ -925,20 +767,9 @@ func makeApexAvailableWhitelist() map[string][]string { "ipmemorystore-aidl-interfaces-V3-java", "ipmemorystore-aidl-interfaces-java", "ksoap2", - "libbacktrace_headers", - "libbase", - "libbase_headers", - "libc++", - "libcutils", - "libcutils_headers", - "liblog_headers", "libnanohttpd", "libprocessgroup", "libprocessgroup_headers", - "libprotobuf-java-lite", - "libprotobuf-java-nano", - "libsystem_headers", - "libutils_headers", "libwifi-jni", "net-utils-services-common", "netd_aidl_interface-V2-java", @@ -966,34 +797,14 @@ func makeApexAvailableWhitelist() map[string][]string { // Module separator // m["com.android.os.statsd"] = []string{ - "libbacktrace_headers", - "libbase_headers", - "libc++", - "libcutils", - "libcutils_headers", - "liblog_headers", "libprocessgroup_headers", "libstatssocket", - "libsystem_headers", - "libutils_headers", } // // Module separator // m[android.AvailableToAnyApex] = []string{ - "crtbegin_dynamic", - "crtbegin_dynamic1", - "crtbegin_so", - "crtbegin_so1", - "crtbegin_static", - "crtbrand", - "crtend_android", - "crtend_so", "libatomic", - "libc++_static", - "libc++abi", - "libc++demangle", - "libc_headers", "libclang_rt", "libgcc_stripped", "libprofile-clang-extras", @@ -1001,22 +812,6 @@ func makeApexAvailableWhitelist() map[string][]string { "libprofile-extras", "libprofile-extras_ndk", "libunwind_llvm", - "ndk_crtbegin_dynamic.27", - "ndk_crtbegin_so.16", - "ndk_crtbegin_so.19", - "ndk_crtbegin_so.21", - "ndk_crtbegin_so.24", - "ndk_crtbegin_so.27", - "ndk_crtend_android.27", - "ndk_crtend_so.16", - "ndk_crtend_so.19", - "ndk_crtend_so.21", - "ndk_crtend_so.24", - "ndk_crtend_so.27", - "ndk_libandroid_support", - "ndk_libc++_static", - "ndk_libc++abi", - "ndk_libunwind", } return m } @@ -1071,20 +866,28 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) { return } - cur := mctx.Module().(interface { - DepIsInSameApex(android.BaseModuleContext, android.Module) bool - }) + cur := mctx.Module().(android.DepIsInSameApex) mctx.VisitDirectDeps(func(child android.Module) { depName := mctx.OtherModuleName(child) if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && - cur.DepIsInSameApex(mctx, child) { + (cur.DepIsInSameApex(mctx, child) || inAnySdk(child)) { android.UpdateApexDependency(apexBundles, depName, directDep) am.BuildForApexes(apexBundles) } }) } +// If a module in an APEX depends on a module from an SDK then it needs an APEX +// specific variant created for it. Refer to sdk.sdkDepsReplaceMutator. +func inAnySdk(module android.Module) bool { + if sa, ok := module.(android.SdkAware); ok { + return sa.IsInAnySdk() + } + + return false +} + // Create apex variations if a module is included in APEX(s). func apexMutator(mctx android.BottomUpMutatorContext) { if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() { @@ -1973,10 +1776,14 @@ func (c *flattenedApexContext) InstallBypassMake() bool { return true } +// Function called while walking an APEX's payload dependencies. +// +// Return true if the `to` module should be visited, false otherwise. +type payloadDepsCallback func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool + // Visit dependencies that contributes to the payload of this APEX -func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext, - do func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool)) { - ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool { +func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext, do payloadDepsCallback) { + ctx.WalkDeps(func(child, parent android.Module) bool { am, ok := child.(android.ApexModule) if !ok || !am.CanHaveApexVariants() { return false @@ -1985,22 +1792,18 @@ func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext, // Check for the direct dependencies that contribute to the payload if dt, ok := ctx.OtherModuleDependencyTag(child).(dependencyTag); ok { if dt.payload { - do(ctx, parent, am, false /* externalDep */) - return true + return do(ctx, parent, am, false /* externalDep */) } + // As soon as the dependency graph crosses the APEX boundary, don't go further. return false } // Check for the indirect dependencies if it is considered as part of the APEX if am.ApexName() != "" { - do(ctx, parent, am, false /* externalDep */) - return true + return do(ctx, parent, am, false /* externalDep */) } - do(ctx, parent, am, true /* externalDep */) - - // As soon as the dependency graph crosses the APEX boundary, don't go further. - return false + return do(ctx, parent, am, true /* externalDep */) }) } @@ -2016,6 +1819,24 @@ func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) int { return android.FutureApiLevel } +// A regexp for removing boilerplate from BaseDependencyTag from the string representation of +// a dependency tag. +var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:blueprint.BaseDependencyTag{}\E(, )?`) + +func PrettyPrintTag(tag blueprint.DependencyTag) string { + // Use tag's custom String() method if available. + if stringer, ok := tag.(fmt.Stringer); ok { + return stringer.String() + } + + // Otherwise, get a default string representation of the tag's struct. + tagString := fmt.Sprintf("%#v", tag) + + // Remove the boilerplate from BaseDependencyTag as it adds no value. + tagString = tagCleaner.ReplaceAllString(tagString, "") + return tagString +} + // 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 @@ -2023,24 +1844,54 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { return } - a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) { + // Coverage build adds additional dependencies for the coverage-only runtime libraries. + // Requiring them and their transitive depencies with apex_available is not right + // because they just add noise. + if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") || a.IsNativeCoverageNeeded(ctx) { + return + } + + a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { + if externalDep { + // As soon as the dependency graph crosses the APEX boundary, don't go further. + return false + } + apexName := ctx.ModuleName() fromName := ctx.OtherModuleName(from) toName := ctx.OtherModuleName(to) - if externalDep || to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) { - return + + // If `to` is not actually in the same APEX as `from` then it does not need apex_available and neither + // do any of its dependencies. + if am, ok := from.(android.DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) { + // As soon as the dependency graph crosses the APEX boundary, don't go further. + return false } - ctx.ModuleErrorf("%q requires %q that is not available for the APEX.", fromName, toName) + + if to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) { + return true + } + message := "" + tagPath := ctx.GetTagPath() + // Skip the first module as that will be added at the start of the error message by ctx.ModuleErrorf(). + walkPath := ctx.GetWalkPath()[1:] + for i, m := range walkPath { + message = fmt.Sprintf("%s\n via tag %s\n -> %s", message, PrettyPrintTag(tagPath[i]), m.String()) + } + ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, message) + // Visit this module's dependencies to check and report any issues with their availability. + return true }) } // Collects the list of module names that directly or indirectly contributes to the payload of this APEX func (a *apexBundle) collectDepsInfo(ctx android.ModuleContext) { a.depInfos = make(map[string]depInfo) - a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) { + a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { if from.Name() == to.Name() { // This can happen for cc.reuseObjTag. We are not interested in tracking this. - return + // As soon as the dependency graph crosses the APEX boundary, don't go further. + return !externalDep } if info, exists := a.depInfos[to.Name()]; exists { @@ -2056,6 +1907,9 @@ func (a *apexBundle) collectDepsInfo(ctx android.ModuleContext) { isExternal: externalDep, } } + + // As soon as the dependency graph crosses the APEX boundary, don't go further. + return !externalDep }) } @@ -2132,6 +1986,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { // TODO(jiyong) do this using walkPayloadDeps ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool { depTag := ctx.OtherModuleDependencyTag(child) + if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok { + return false + } depName := ctx.OtherModuleName(child) if _, isDirectDep := parent.(*apexBundle); isDirectDep { switch depTag { @@ -2300,7 +2157,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName)) } } else if am.CanHaveApexVariants() && am.IsInstallableToApex() { - ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName) + ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", PrettyPrintTag(depTag), depName) } } } diff --git a/apex/apex_test.go b/apex/apex_test.go index dbccb9217..0c8937edd 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -27,6 +27,7 @@ import ( "android/soong/android" "android/soong/cc" + "android/soong/dexpreopt" "android/soong/java" ) @@ -158,6 +159,7 @@ func testApexContext(t *testing.T, bp string, handlers ...testCustomizer) (*andr "my_include": nil, "foo/bar/MyClass.java": nil, "prebuilt.jar": nil, + "prebuilt.so": nil, "vendor/foo/devkeys/test.x509.pem": nil, "vendor/foo/devkeys/test.pk8": nil, "testkey.x509.pem": nil, @@ -367,7 +369,7 @@ func TestBasicApex(t *testing.T) { apex_available: [ "myapex" ], } - cc_library { + cc_library_shared { name: "mylib2", srcs: ["mylib.cpp"], system_shared_libs: [], @@ -381,6 +383,16 @@ func TestBasicApex(t *testing.T) { ], } + cc_prebuilt_library_shared { + name: "mylib2", + srcs: ["prebuilt.so"], + // TODO: remove //apex_available:platform + apex_available: [ + "//apex_available:platform", + "myapex", + ], + } + cc_library_static { name: "libstatic", srcs: ["mylib.cpp"], @@ -874,58 +886,89 @@ func TestApexWithRuntimeLibsDependency(t *testing.T) { } -func TestApexDependencyToLLNDK(t *testing.T) { - ctx, _ := testApex(t, ` - apex { - name: "myapex", - key: "myapex.key", - use_vendor: true, - native_shared_libs: ["mylib"], - } - - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } - - cc_library { - name: "mylib", - srcs: ["mylib.cpp"], - vendor_available: true, - shared_libs: ["libbar"], - system_shared_libs: [], - stl: "none", - apex_available: [ "myapex" ], - } - - cc_library { - name: "libbar", - srcs: ["mylib.cpp"], - system_shared_libs: [], - stl: "none", - } - - llndk_library { - name: "libbar", - symbol_file: "", - } - `, func(fs map[string][]byte, config android.Config) { - setUseVendorWhitelistForTest(config, []string{"myapex"}) - }) +func TestApexDependsOnLLNDKTransitively(t *testing.T) { + testcases := []struct { + name string + minSdkVersion string + shouldLink string + shouldNotLink []string + }{ + { + name: "should link to the latest", + minSdkVersion: "current", + shouldLink: "30", + shouldNotLink: []string{"29"}, + }, + { + name: "should link to llndk#29", + minSdkVersion: "29", + shouldLink: "29", + shouldNotLink: []string{"30"}, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + ctx, _ := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + use_vendor: true, + native_shared_libs: ["mylib"], + min_sdk_version: "`+tc.minSdkVersion+`", + } - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") - copyCmds := apexRule.Args["copy_commands"] + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } - // Ensure that LLNDK dep is not included - ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so") + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + vendor_available: true, + shared_libs: ["libbar"], + system_shared_libs: [], + stl: "none", + apex_available: [ "myapex" ], + } - apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") - ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"])) + cc_library { + name: "libbar", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + stubs: { versions: ["29","30"] }, + } - // Ensure that LLNDK dep is required - ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so") + llndk_library { + name: "libbar", + symbol_file: "", + } + `, func(fs map[string][]byte, config android.Config) { + setUseVendorWhitelistForTest(config, []string{"myapex"}) + }, withUnbundledBuild) + + // Ensure that LLNDK dep is not included + ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + "lib64/mylib.so", + }) + + // Ensure that LLNDK dep is required + apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") + ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"])) + ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so") + + mylibLdFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"] + ensureContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+tc.shouldLink+"/libbar.so") + for _, ver := range tc.shouldNotLink { + ensureNotContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+ver+"/libbar.so") + } + mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] + ensureContains(t, mylibCFlags, "__LIBBAR_API__="+tc.shouldLink) + }) + } } func TestApexWithSystemLibsStubs(t *testing.T) { @@ -1191,7 +1234,7 @@ func TestPlatformUsesLatestStubsFromApexes(t *testing.T) { expectNoLink("libz", "shared", "libz", "shared") } -func TestQApexesUseLatestStubsInBundledBuilds(t *testing.T) { +func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) { ctx, _ := testApex(t, ` apex { name: "myapex", @@ -1218,16 +1261,18 @@ func TestQApexesUseLatestStubsInBundledBuilds(t *testing.T) { versions: ["29", "30"], }, } - `) + `, func(fs map[string][]byte, config android.Config) { + config.TestProductVariables.SanitizeDevice = []string{"hwaddress"} + }) 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") + expectLink("libx", "shared_hwasan_myapex", "libbar", "shared_30") } -func TestQTargetApexUseStaticUnwinder(t *testing.T) { +func TestQTargetApexUsesStaticUnwinder(t *testing.T) { ctx, _ := testApex(t, ` apex { name: "myapex", @@ -1246,8 +1291,7 @@ func TestQTargetApexUseStaticUnwinder(t *testing.T) { 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) @@ -1255,14 +1299,10 @@ func TestQTargetApexUseStaticUnwinder(t *testing.T) { // 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.*`, ` + testApexError(t, `"libz" .*: not found a version\(<=29\)`, ` apex { name: "myapex", key: "myapex.key", @@ -1292,9 +1332,9 @@ func TestInvalidMinSdkVersion(t *testing.T) { versions: ["30"], }, } - `, withUnbundledBuild) + `) - testApexError(t, `"myapex" .*: min_sdk_version: should be .*`, ` + testApexError(t, `"myapex" .*: min_sdk_version: should be "current" or <number>`, ` apex { name: "myapex", key: "myapex.key", @@ -1797,6 +1837,7 @@ func TestMacro(t *testing.T) { "myapex", "otherapex", ], + recovery_available: true, } cc_library { name: "mylib2", @@ -1814,7 +1855,7 @@ func TestMacro(t *testing.T) { // 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") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__") // APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] @@ -1846,6 +1887,11 @@ func TestMacro(t *testing.T) { ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") + + // recovery variant does not set __ANDROID_SDK_VERSION__ + mylibCFlags = ctx.ModuleForTests("mylib", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__") } func TestHeaderLibsDependency(t *testing.T) { @@ -3468,7 +3514,7 @@ func TestApexPropertiesShouldBeDefaultable(t *testing.T) { }`) } -func TestApexAvailable(t *testing.T) { +func TestApexAvailable_DirectDep(t *testing.T) { // libfoo is not available to myapex, but only to otherapex testApexError(t, "requires \"libfoo\" that is not available for the APEX", ` apex { @@ -3501,9 +3547,17 @@ func TestApexAvailable(t *testing.T) { system_shared_libs: [], apex_available: ["otherapex"], }`) +} +func TestApexAvailable_IndirectDep(t *testing.T) { // libbbaz is an indirect dep - testApexError(t, "requires \"libbaz\" that is not available for the APEX", ` + testApexError(t, `requires "libbaz" that is not available for the APEX. Dependency path: +.*via tag apex\.dependencyTag.*"sharedLib".* +.*-> libfoo.*link:shared.* +.*via tag cc\.DependencyTag.*"shared".* +.*-> libbar.*link:shared.* +.*via tag cc\.DependencyTag.*"shared".* +.*-> libbaz.*link:shared.*`, ` apex { name: "myapex", key: "myapex.key", @@ -3537,7 +3591,9 @@ func TestApexAvailable(t *testing.T) { stl: "none", system_shared_libs: [], }`) +} +func TestApexAvailable_InvalidApexName(t *testing.T) { testApexError(t, "\"otherapex\" is not a valid module name", ` apex { name: "myapex", @@ -3558,7 +3614,7 @@ func TestApexAvailable(t *testing.T) { apex_available: ["otherapex"], }`) - ctx, _ := testApex(t, ` + testApex(t, ` apex { name: "myapex", key: "myapex.key", @@ -3594,7 +3650,9 @@ func TestApexAvailable(t *testing.T) { versions: ["10", "20", "30"], }, }`) +} +func TestApexAvailable_CreatedForPlatform(t *testing.T) { // check that libfoo and libbar are created only for myapex, but not for the platform // TODO(jiyong) the checks for the platform variant are removed because we now create // the platform variant regardless of the apex_availability. Instead, we will make sure that @@ -3606,7 +3664,7 @@ func TestApexAvailable(t *testing.T) { // ensureListContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared_myapex") // ensureListNotContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared") - ctx, _ = testApex(t, ` + ctx, _ := testApex(t, ` apex { name: "myapex", key: "myapex.key", @@ -3628,8 +3686,10 @@ func TestApexAvailable(t *testing.T) { // check that libfoo is created only for the platform ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared_myapex") ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared") +} - ctx, _ = testApex(t, ` +func TestApexAvailable_CreatedForApex(t *testing.T) { + testApex(t, ` apex { name: "myapex", key: "myapex.key", @@ -4144,6 +4204,175 @@ func TestAppBundle(t *testing.T) { ensureContains(t, content, `"apex_config":{"apex_embedded_apk_config":[{"package_name":"com.android.foo","path":"app/AppFoo/AppFoo.apk"}]}`) } +func testNoUpdatableJarsInBootImage(t *testing.T, errmsg, bp string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) { + t.Helper() + + bp = bp + ` + filegroup { + name: "some-updatable-apex-file_contexts", + srcs: [ + "system/sepolicy/apex/some-updatable-apex-file_contexts", + ], + } + ` + bp += cc.GatherRequiredDepsForTest(android.Android) + bp += java.GatherRequiredDepsForTest() + bp += dexpreopt.BpToolModulesForTest() + + fs := map[string][]byte{ + "a.java": nil, + "a.jar": nil, + "build/make/target/product/security": nil, + "apex_manifest.json": nil, + "AndroidManifest.xml": nil, + "system/sepolicy/apex/some-updatable-apex-file_contexts": nil, + "system/sepolicy/apex/com.android.art.something-file_contexts": nil, + "framework/aidl/a.aidl": nil, + } + cc.GatherRequiredFilesForTest(fs) + + ctx := android.NewTestArchContext() + ctx.RegisterModuleType("apex", BundleFactory) + ctx.RegisterModuleType("apex_key", ApexKeyFactory) + ctx.RegisterModuleType("filegroup", android.FileGroupFactory) + cc.RegisterRequiredBuildComponentsForTest(ctx) + java.RegisterJavaBuildComponents(ctx) + java.RegisterSystemModulesBuildComponents(ctx) + java.RegisterAppBuildComponents(ctx) + java.RegisterDexpreoptBootJarsComponents(ctx) + ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) + ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators) + ctx.PreDepsMutators(RegisterPreDepsMutators) + ctx.PostDepsMutators(RegisterPostDepsMutators) + + config := android.TestArchConfig(buildDir, nil, bp, fs) + ctx.Register(config) + + _ = dexpreopt.GlobalSoongConfigForTests(config) + dexpreopt.RegisterToolModulesForTest(ctx) + pathCtx := android.PathContextForTesting(config) + dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx) + transformDexpreoptConfig(dexpreoptConfig) + dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig) + + _, errs := ctx.ParseBlueprintsFiles("Android.bp") + android.FailIfErrored(t, errs) + + _, errs = ctx.PrepareBuildActions(config) + if errmsg == "" { + android.FailIfErrored(t, errs) + } else if len(errs) > 0 { + android.FailIfNoMatchingErrors(t, errmsg, errs) + return + } else { + t.Fatalf("missing expected error %q (0 errors are returned)", errmsg) + } +} + +func TestNoUpdatableJarsInBootImage(t *testing.T) { + bp := ` + java_library { + name: "some-updatable-apex-lib", + srcs: ["a.java"], + apex_available: [ + "some-updatable-apex", + ], + } + + java_library { + name: "some-platform-lib", + srcs: ["a.java"], + installable: true, + } + + java_library { + name: "some-art-lib", + srcs: ["a.java"], + apex_available: [ + "com.android.art.something", + ], + hostdex: true, + } + + apex { + name: "some-updatable-apex", + key: "some-updatable-apex.key", + java_libs: ["some-updatable-apex-lib"], + } + + apex_key { + name: "some-updatable-apex.key", + } + + apex { + name: "com.android.art.something", + key: "com.android.art.something.key", + java_libs: ["some-art-lib"], + } + + apex_key { + name: "com.android.art.something.key", + } + ` + + var error string + var transform func(*dexpreopt.GlobalConfig) + + // updatable jar from ART apex in the ART boot image => ok + transform = func(config *dexpreopt.GlobalConfig) { + config.ArtApexJars = []string{"some-art-lib"} + } + testNoUpdatableJarsInBootImage(t, "", bp, transform) + + // updatable jar from ART apex in the framework boot image => error + error = "module 'some-art-lib' from updatable apex 'com.android.art.something' is not allowed in the framework boot image" + transform = func(config *dexpreopt.GlobalConfig) { + config.BootJars = []string{"some-art-lib"} + } + testNoUpdatableJarsInBootImage(t, error, bp, transform) + + // updatable jar from some other apex in the ART boot image => error + error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the ART boot image" + transform = func(config *dexpreopt.GlobalConfig) { + config.ArtApexJars = []string{"some-updatable-apex-lib"} + } + testNoUpdatableJarsInBootImage(t, error, bp, transform) + + // updatable jar from some other apex in the framework boot image => error + error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image" + transform = func(config *dexpreopt.GlobalConfig) { + config.BootJars = []string{"some-updatable-apex-lib"} + } + testNoUpdatableJarsInBootImage(t, error, bp, transform) + + // nonexistent jar in the ART boot image => error + error = "failed to find a dex jar path for module 'nonexistent'" + transform = func(config *dexpreopt.GlobalConfig) { + config.ArtApexJars = []string{"nonexistent"} + } + testNoUpdatableJarsInBootImage(t, error, bp, transform) + + // nonexistent jar in the framework boot image => error + error = "failed to find a dex jar path for module 'nonexistent'" + transform = func(config *dexpreopt.GlobalConfig) { + config.BootJars = []string{"nonexistent"} + } + testNoUpdatableJarsInBootImage(t, error, bp, transform) + + // platform jar in the ART boot image => error + error = "module 'some-platform-lib' is part of the platform and not allowed in the ART boot image" + transform = func(config *dexpreopt.GlobalConfig) { + config.ArtApexJars = []string{"some-platform-lib"} + } + testNoUpdatableJarsInBootImage(t, error, bp, transform) + + // platform jar in the framework boot image => ok + transform = func(config *dexpreopt.GlobalConfig) { + config.BootJars = []string{"some-platform-lib"} + } + testNoUpdatableJarsInBootImage(t, "", bp, transform) +} + func TestMain(m *testing.M) { run := func() int { setUp() diff --git a/apex/builder.go b/apex/builder.go index 67bc20603..5a2134a05 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -230,12 +230,16 @@ func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName string) android.NoticeOutputs { var noticeFiles android.Paths - a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) { + a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { if externalDep { - return + // As soon as the dependency graph crosses the APEX boundary, don't go further. + return false } + notices := to.NoticeFiles() noticeFiles = append(noticeFiles, notices...) + + return true }) if len(noticeFiles) == 0 { diff --git a/apex/key.go b/apex/key.go index ffde315f9..607cac57c 100644 --- a/apex/key.go +++ b/apex/key.go @@ -133,17 +133,18 @@ func (s *apexKeysText) GenerateBuildActions(ctx android.SingletonContext) { module := apexModulesMap[key] if m, ok := module.(*apexBundle); ok { fmt.Fprintf(&filecontent, - "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q\\n", + "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q\\n", m.Name()+".apex", m.public_key_file.String(), m.private_key_file.String(), m.container_certificate_file.String(), - m.container_private_key_file.String()) + m.container_private_key_file.String(), + m.PartitionTag(ctx.DeviceConfig())) } else if m, ok := module.(*Prebuilt); ok { fmt.Fprintf(&filecontent, - "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q\\n", + "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q\\n", m.InstallFilename(), - "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED") + "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED", m.PartitionTag(ctx.DeviceConfig())) } } diff --git a/bpf/bpf.go b/bpf/bpf.go index 59d1502ff..4cdfb315c 100644 --- a/bpf/bpf.go +++ b/bpf/bpf.go @@ -60,6 +60,10 @@ type bpf struct { func (bpf *bpf) GenerateAndroidBuildActions(ctx android.ModuleContext) { cflags := []string{ "-nostdlibinc", + + // Make paths in deps files relative + "-no-canonical-prefixes", + "-O2", "-isystem bionic/libc/include", "-isystem bionic/libc/kernel/uapi", diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go index 051627977..a1c5de122 100644 --- a/bpfix/bpfix/bpfix.go +++ b/bpfix/bpfix/bpfix.go @@ -124,6 +124,10 @@ var fixSteps = []FixStep{ Name: "removeHidlInterfaceTypes", Fix: removeHidlInterfaceTypes, }, + { + Name: "removeSoongConfigBoolVariable", + Fix: removeSoongConfigBoolVariable, + }, } func NewFixRequest() FixRequest { @@ -714,6 +718,78 @@ func removeHidlInterfaceTypes(f *Fixer) error { return nil } +func removeSoongConfigBoolVariable(f *Fixer) error { + found := map[string]bool{} + newDefs := make([]parser.Definition, 0, len(f.tree.Defs)) + for _, def := range f.tree.Defs { + if mod, ok := def.(*parser.Module); ok && mod.Type == "soong_config_bool_variable" { + if name, ok := getLiteralStringPropertyValue(mod, "name"); ok { + found[name] = true + } else { + return fmt.Errorf("Found soong_config_bool_variable without a name") + } + } else { + newDefs = append(newDefs, def) + } + } + f.tree.Defs = newDefs + + if len(found) == 0 { + return nil + } + + return runPatchListMod(func(mod *parser.Module, buf []byte, patchList *parser.PatchList) error { + if mod.Type != "soong_config_module_type" { + return nil + } + + variables, ok := getLiteralListProperty(mod, "variables") + if !ok { + return nil + } + + boolValues := strings.Builder{} + empty := true + for _, item := range variables.Values { + nameValue, ok := item.(*parser.String) + if !ok { + empty = false + continue + } + if found[nameValue.Value] { + patchList.Add(item.Pos().Offset, item.End().Offset+2, "") + + boolValues.WriteString(`"`) + boolValues.WriteString(nameValue.Value) + boolValues.WriteString(`",`) + } else { + empty = false + } + } + if empty { + *patchList = parser.PatchList{} + + prop, _ := mod.GetProperty("variables") + patchList.Add(prop.Pos().Offset, prop.End().Offset+2, "") + } + if boolValues.Len() == 0 { + return nil + } + + bool_variables, ok := getLiteralListProperty(mod, "bool_variables") + if ok { + patchList.Add(bool_variables.RBracePos.Offset, bool_variables.RBracePos.Offset, ","+boolValues.String()) + } else { + patchList.Add(variables.RBracePos.Offset+2, variables.RBracePos.Offset+2, + fmt.Sprintf(`bool_variables: [%s],`, boolValues.String())) + } + + return nil + })(f) + + return nil +} + // Converts the default source list property, 'srcs', to a single source property with a given name. // "LOCAL_MODULE" reference is also resolved during the conversion process. func convertToSingleSource(mod *parser.Module, srcPropertyName string) { diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go index 38cefdd6b..64a7b93b2 100644 --- a/bpfix/bpfix/bpfix_test.go +++ b/bpfix/bpfix/bpfix_test.go @@ -918,3 +918,67 @@ func TestRemoveHidlInterfaceTypes(t *testing.T) { }) } } + +func TestRemoveSoongConfigBoolVariable(t *testing.T) { + tests := []struct { + name string + in string + out string + }{ + { + name: "remove bool", + in: ` + soong_config_module_type { + name: "foo", + variables: ["bar", "baz"], + } + + soong_config_bool_variable { + name: "bar", + } + + soong_config_string_variable { + name: "baz", + } + `, + out: ` + soong_config_module_type { + name: "foo", + variables: [ + "baz" + ], + bool_variables: ["bar"], + } + + soong_config_string_variable { + name: "baz", + } + `, + }, + { + name: "existing bool_variables", + in: ` + soong_config_module_type { + name: "foo", + variables: ["baz"], + bool_variables: ["bar"], + } + + soong_config_bool_variable { + name: "baz", + } + `, + out: ` + soong_config_module_type { + name: "foo", + bool_variables: ["bar", "baz"], + } + `, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + runPass(t, test.in, test.out, removeSoongConfigBoolVariable) + }) + } +} diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go index 9b3235c5d..1d9cc54f8 100644 --- a/cc/binary_sdk_member.go +++ b/cc/binary_sdk_member.go @@ -18,6 +18,7 @@ import ( "path/filepath" "android/soong/android" + "github.com/google/blueprint" ) @@ -137,7 +138,9 @@ func (p *nativeBinaryInfoProperties) AddToPropertySet(ctx android.SdkMemberConte propertySet.AddPropertyWithTag("shared_libs", p.SharedLibs, builder.SdkMemberReferencePropertyTag(false)) } - if len(p.SystemSharedLibs) > 0 { + // SystemSharedLibs needs to be propagated if it's a list, even if it's empty, + // so check for non-nil instead of nonzero length. + if p.SystemSharedLibs != nil { propertySet.AddPropertyWithTag("system_shared_libs", p.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false)) } } @@ -393,7 +393,7 @@ type linker interface { type specifiedDeps struct { sharedLibs []string - systemSharedLibs []string + systemSharedLibs []string // Note nil and [] are semantically distinct. } type installer interface { @@ -503,6 +503,9 @@ type Module struct { makeLinkType string // Kythe (source file indexer) paths for this compilation module kytheFiles android.Paths + + // For apex variants, this is set as apex.min_sdk_version + apexSdkVersion int } func (c *Module) Toc() android.OptionalPath { @@ -644,6 +647,10 @@ func (c *Module) SetBuildStubs() { c.Properties.PreventInstall = true return } + if _, ok := c.linker.(*llndkStubDecorator); ok { + c.Properties.HideFromMake = true + return + } } panic(fmt.Errorf("SetBuildStubs called on non-library module: %q", c.BaseModuleName())) } @@ -663,6 +670,10 @@ func (c *Module) SetStubsVersions(version string) { library.MutatedProperties.StubsVersion = version return } + if llndk, ok := c.linker.(*llndkStubDecorator); ok { + llndk.libraryDecorator.MutatedProperties.StubsVersion = version + return + } } panic(fmt.Errorf("SetStubsVersions called on non-library module: %q", c.BaseModuleName())) } @@ -672,6 +683,9 @@ func (c *Module) StubsVersion() string { if library, ok := c.linker.(*libraryDecorator); ok { return library.MutatedProperties.StubsVersion } + if llndk, ok := c.linker.(*llndkStubDecorator); ok { + return llndk.libraryDecorator.MutatedProperties.StubsVersion + } } panic(fmt.Errorf("StubsVersion called on non-library module: %q", c.BaseModuleName())) } @@ -1228,7 +1242,7 @@ func (ctx *moduleContextImpl) apexName() string { } func (ctx *moduleContextImpl) apexSdkVersion() int { - return ctx.mod.ApexProperties.Info.MinSdkVersion + return ctx.mod.apexSdkVersion } func (ctx *moduleContextImpl) hasStubsVariants() bool { @@ -1868,7 +1882,10 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { }, depTag, lib) } - if deps.StaticUnwinderIfLegacy && ctx.Config().UnbundledBuild() { + // staticUnwinderDep is treated as staticDep for Q apexes + // so that native libraries/binaries are linked with static unwinder + // because Q libc doesn't have unwinder APIs + if deps.StaticUnwinderIfLegacy { actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, }, staticUnwinderDepTag, staticUnwinder(actx)) @@ -1883,7 +1900,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { addSharedLibDependencies := func(depTag DependencyTag, name string, version string) { var variations []blueprint.Variation variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"}) - versionVariantAvail := !ctx.useVndk() && !c.InRecovery() && !c.InRamdisk() + versionVariantAvail := !c.InRecovery() && !c.InRamdisk() if version != "" && versionVariantAvail { // Version is explicitly specified. i.e. libFoo#30 variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version}) @@ -2218,13 +2235,17 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { if depTag == android.ProtoPluginDepTag { return } + if depTag == llndkImplDep { + return + } if dep.Target().Os != ctx.Os() { ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName) return } if dep.Target().Arch.ArchType != ctx.Arch().ArchType { - ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName) + ctx.ModuleErrorf("Arch mismatch between %q(%v) and %q(%v)", + ctx.ModuleName(), ctx.Arch().ArchType, depName, dep.Target().Arch.ArchType) return } @@ -2248,9 +2269,22 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } } + // For the dependency from platform to apex, use the latest stubs + c.apexSdkVersion = android.FutureApiLevel + if !c.IsForPlatform() { + c.apexSdkVersion = c.ApexProperties.Info.MinSdkVersion + } + + if android.InList("hwaddress", ctx.Config().SanitizeDevice()) { + // In hwasan build, we override apexSdkVersion to the FutureApiLevel(10000) + // so that even Q(29/Android10) apexes could use the dynamic unwinder by linking the newer stubs(e.g libc(R+)). + // (b/144430859) + c.apexSdkVersion = android.FutureApiLevel + } + if depTag == staticUnwinderDepTag { - // Use static unwinder for legacy (min_sdk_version = 29) apexes (b/144430859) - if c.ShouldSupportAndroid10() { + // Use static unwinder for legacy (min_sdk_version = 29) apexes (b/144430859) + if c.apexSdkVersion <= android.SdkVersion_Android10 { depTag = StaticDepTag } else { return @@ -2304,8 +2338,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // 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) + versionToUse, err := c.ChooseSdkVersion(ccDep.StubsVersions(), c.apexSdkVersion) if err != nil { ctx.OtherModuleErrorf(dep, err.Error()) return @@ -2319,6 +2352,26 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return // stop processing this dep } } + if c.UseVndk() { + if m, ok := ccDep.(*Module); ok && m.IsStubs() { // LLNDK + // by default, use current version of LLNDK + versionToUse := "" + versions := stubsVersionsFor(ctx.Config())[depName] + if c.ApexName() != "" && len(versions) > 0 { + // if this is for use_vendor apex && dep has stubsVersions + // apply the same rule of apex sdk enforcement to choose right version + var err error + versionToUse, err = c.ChooseSdkVersion(versions, c.apexSdkVersion) + if err != nil { + ctx.OtherModuleErrorf(dep, err.Error()) + return + } + } + if versionToUse != ccDep.StubsVersion() { + return + } + } + } depPaths.IncludeDirs = append(depPaths.IncludeDirs, ccDep.IncludeDirs()...) diff --git a/cc/cc_test.go b/cc/cc_test.go index 9a9678f1d..67eb248d2 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -2398,6 +2398,34 @@ func checkEquals(t *testing.T, message string, expected, actual interface{}) { } } +func TestLlndkLibrary(t *testing.T) { + ctx := testCc(t, ` + cc_library { + name: "libllndk", + stubs: { versions: ["1", "2"] }, + } + llndk_library { + name: "libllndk", + } + `) + actual := ctx.ModuleVariantsForTests("libllndk.llndk") + expected := []string{ + "android_vendor.VER_arm64_armv8-a_shared", + "android_vendor.VER_arm64_armv8-a_shared_1", + "android_vendor.VER_arm64_armv8-a_shared_2", + "android_vendor.VER_arm_armv7-a-neon_shared", + "android_vendor.VER_arm_armv7-a-neon_shared_1", + "android_vendor.VER_arm_armv7-a-neon_shared_2", + } + checkEquals(t, "variants for llndk stubs", expected, actual) + + params := ctx.ModuleForTests("libllndk.llndk", "android_vendor.VER_arm_armv7-a-neon_shared").Description("generate stub") + checkEquals(t, "use VNDK version for default stubs", "current", params.Args["apiLevel"]) + + params = ctx.ModuleForTests("libllndk.llndk", "android_vendor.VER_arm_armv7-a-neon_shared_1").Description("generate stub") + checkEquals(t, "override apiLevel for versioned stubs", "1", params.Args["apiLevel"]) +} + func TestLlndkHeaders(t *testing.T) { ctx := testCc(t, ` llndk_headers { diff --git a/cc/compiler.go b/cc/compiler.go index fe81bd0a4..681b1ab90 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -315,18 +315,6 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps "-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__") } @@ -340,6 +328,9 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps if Bool(compiler.Properties.Use_apex_name_macro) { flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_"+makeDefineString(ctx.apexName())+"__") } + if ctx.Device() { + flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_SDK_VERSION__="+strconv.Itoa(ctx.apexSdkVersion())) + } } instructionSet := String(compiler.Properties.Instruction_set) diff --git a/cc/config/global.go b/cc/config/global.go index 29020ab24..5611a965e 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -127,8 +127,8 @@ var ( // prebuilts/clang default settings. ClangDefaultBase = "prebuilts/clang/host" - ClangDefaultVersion = "clang-r377782c" - ClangDefaultShortVersion = "10.0.5" + ClangDefaultVersion = "clang-r377782d" + ClangDefaultShortVersion = "10.0.6" // Directories with warnings from Android.bp files. WarningAllowedProjects = []string{ diff --git a/cc/config/x86_darwin_host.go b/cc/config/x86_darwin_host.go index 25225b5cb..8eb79e34e 100644 --- a/cc/config/x86_darwin_host.go +++ b/cc/config/x86_darwin_host.go @@ -15,9 +15,11 @@ package config import ( + "fmt" "os/exec" "path/filepath" "strings" + "sync" "android/soong/android" ) @@ -89,28 +91,20 @@ const ( ) func init() { - pctx.VariableFunc("macSdkPath", func(ctx android.PackageVarContext) string { - xcodeselect := ctx.Config().HostSystemTool("xcode-select") - bytes, err := exec.Command(xcodeselect, "--print-path").Output() - if err != nil { - ctx.Errorf("xcode-select failed with: %q", err.Error()) - } - return strings.TrimSpace(string(bytes)) - }) pctx.VariableFunc("macSdkRoot", func(ctx android.PackageVarContext) string { - return xcrunSdk(ctx, "--show-sdk-path") + return getMacTools(ctx).sdkRoot }) pctx.StaticVariable("macMinVersion", "10.10") pctx.VariableFunc("MacArPath", func(ctx android.PackageVarContext) string { - return xcrun(ctx, "--find", "ar") + return getMacTools(ctx).arPath }) pctx.VariableFunc("MacStripPath", func(ctx android.PackageVarContext) string { - return xcrun(ctx, "--find", "strip") + return getMacTools(ctx).stripPath }) pctx.VariableFunc("MacToolPath", func(ctx android.PackageVarContext) string { - return filepath.Dir(xcrun(ctx, "--find", "ld")) + return getMacTools(ctx).toolPath }) pctx.StaticVariable("DarwinGccVersion", darwinGccVersion) @@ -126,38 +120,66 @@ func init() { pctx.StaticVariable("DarwinYasmFlags", "-f macho -m amd64") } -func xcrun(ctx android.PackageVarContext, args ...string) string { - xcrun := ctx.Config().HostSystemTool("xcrun") - bytes, err := exec.Command(xcrun, args...).Output() - if err != nil { - ctx.Errorf("xcrun failed with: %q", err.Error()) - } - return strings.TrimSpace(string(bytes)) +type macPlatformTools struct { + once sync.Once + err error + + sdkRoot string + arPath string + stripPath string + toolPath string } -func xcrunSdk(ctx android.PackageVarContext, arg string) string { - xcrun := ctx.Config().HostSystemTool("xcrun") - if selected := ctx.Config().Getenv("MAC_SDK_VERSION"); selected != "" { - if !inList(selected, darwinSupportedSdkVersions) { - ctx.Errorf("MAC_SDK_VERSION %s isn't supported: %q", selected, darwinSupportedSdkVersions) - return "" - } +var macTools = &macPlatformTools{} - bytes, err := exec.Command(xcrun, "--sdk", "macosx"+selected, arg).Output() - if err != nil { - ctx.Errorf("MAC_SDK_VERSION %s is not installed", selected) - } - return strings.TrimSpace(string(bytes)) - } +func getMacTools(ctx android.PackageVarContext) *macPlatformTools { + macTools.once.Do(func() { + xcrunTool := ctx.Config().HostSystemTool("xcrun") + + xcrun := func(args ...string) string { + if macTools.err != nil { + return "" + } + + bytes, err := exec.Command(xcrunTool, args...).Output() + if err != nil { + macTools.err = fmt.Errorf("xcrun %q failed with: %q", args, err) + return "" + } - for _, sdk := range darwinSupportedSdkVersions { - bytes, err := exec.Command(xcrun, "--sdk", "macosx"+sdk, arg).Output() - if err == nil { return strings.TrimSpace(string(bytes)) } + + xcrunSdk := func(arg string) string { + if selected := ctx.Config().Getenv("MAC_SDK_VERSION"); selected != "" { + if !inList(selected, darwinSupportedSdkVersions) { + macTools.err = fmt.Errorf("MAC_SDK_VERSION %s isn't supported: %q", selected, darwinSupportedSdkVersions) + return "" + } + + return xcrun("--sdk", "macosx"+selected, arg) + } + + for _, sdk := range darwinSupportedSdkVersions { + bytes, err := exec.Command(xcrunTool, "--sdk", "macosx"+sdk, arg).Output() + if err == nil { + return strings.TrimSpace(string(bytes)) + } + } + macTools.err = fmt.Errorf("Could not find a supported mac sdk: %q", darwinSupportedSdkVersions) + return "" + } + + macTools.sdkRoot = xcrunSdk("--show-sdk-path") + + macTools.arPath = xcrun("--find", "ar") + macTools.stripPath = xcrun("--find", "strip") + macTools.toolPath = filepath.Dir(xcrun("--find", "ld")) + }) + if macTools.err != nil { + ctx.Errorf("%q", macTools.err) } - ctx.Errorf("Could not find a supported mac sdk: %q", darwinSupportedSdkVersions) - return "" + return macTools } type toolchainDarwin struct { diff --git a/cc/fuzz.go b/cc/fuzz.go index 6a9b7096a..b7173a30b 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -198,6 +198,11 @@ func sharedLibraryInstallLocation( return installLocation } +// Get the device-only shared library symbols install directory. +func sharedLibrarySymbolsInstallLocation(libraryPath android.Path, archString string) string { + return filepath.Join("$(PRODUCT_OUT)/symbols/data/fuzz/", archString, "/lib/", libraryPath.Base()) +} + func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) { fuzz.binaryDecorator.baseInstaller.dir = filepath.Join( "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName()) @@ -269,6 +274,12 @@ func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) { fuzz.installedSharedDeps = append(fuzz.installedSharedDeps, sharedLibraryInstallLocation( lib, ctx.Host(), ctx.Arch().ArchType.String())) + + // Also add the dependency on the shared library symbols dir. + if !ctx.Host() { + fuzz.installedSharedDeps = append(fuzz.installedSharedDeps, + sharedLibrarySymbolsInstallLocation(lib, ctx.Arch().ArchType.String())) + } } } @@ -419,12 +430,24 @@ func (s *fuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { continue } sharedLibraryInstalled[installDestination] = true + // Escape all the variables, as the install destination here will be called // via. $(eval) in Make. installDestination = strings.ReplaceAll( installDestination, "$", "$$") s.sharedLibInstallStrings = append(s.sharedLibInstallStrings, library.String()+":"+installDestination) + + // Ensure that on device, the library is also reinstalled to the /symbols/ + // dir. Symbolized DSO's are always installed to the device when fuzzing, but + // we want symbolization tools (like `stack`) to be able to find the symbols + // in $ANDROID_PRODUCT_OUT/symbols automagically. + if !ccModule.Host() { + symbolsInstallDestination := sharedLibrarySymbolsInstallLocation(library, archString) + symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$") + s.sharedLibInstallStrings = append(s.sharedLibInstallStrings, + library.String()+":"+symbolsInstallDestination) + } } // The executable. diff --git a/cc/library.go b/cc/library.go index 5ce854ed0..140f87a0a 100644 --- a/cc/library.go +++ b/cc/library.go @@ -376,7 +376,7 @@ type libraryDecorator struct { useCoreVariant bool checkSameCoreVariant bool - // Decorated interafaces + // Decorated interfaces *baseCompiler *baseLinker *baseInstaller @@ -749,10 +749,12 @@ func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { func (library *libraryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps { if library.static() { + // Compare with nil because an empty list needs to be propagated. if library.StaticProperties.Static.System_shared_libs != nil { library.baseLinker.Properties.System_shared_libs = library.StaticProperties.Static.System_shared_libs } } else if library.shared() { + // Compare with nil because an empty list needs to be propagated. if library.SharedProperties.Shared.System_shared_libs != nil { library.baseLinker.Properties.System_shared_libs = library.SharedProperties.Shared.System_shared_libs } @@ -828,10 +830,21 @@ func (library *libraryDecorator) linkerSpecifiedDeps(specifiedDeps specifiedDeps } specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, properties.Shared_libs...) - specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, properties.System_shared_libs...) + + // Must distinguish nil and [] in system_shared_libs - ensure that [] in + // either input list doesn't come out as nil. + if specifiedDeps.systemSharedLibs == nil { + specifiedDeps.systemSharedLibs = properties.System_shared_libs + } else { + specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, properties.System_shared_libs...) + } specifiedDeps.sharedLibs = android.FirstUniqueStrings(specifiedDeps.sharedLibs) - specifiedDeps.systemSharedLibs = android.FirstUniqueStrings(specifiedDeps.systemSharedLibs) + if len(specifiedDeps.systemSharedLibs) > 0 { + // Skip this if systemSharedLibs is either nil or [], to ensure they are + // retained. + specifiedDeps.systemSharedLibs = android.FirstUniqueStrings(specifiedDeps.systemSharedLibs) + } return specifiedDeps } @@ -1011,8 +1024,9 @@ func (library *libraryDecorator) coverageOutputFilePath() android.OptionalPath { } func getRefAbiDumpFile(ctx ModuleContext, vndkVersion, fileName string) android.Path { + // The logic must be consistent with classifySourceAbiDump. isNdk := ctx.isNdk() - isLlndkOrVndk := ctx.isLlndkPublic(ctx.Config()) || ctx.isVndk() + isLlndkOrVndk := ctx.isLlndkPublic(ctx.Config()) || (ctx.useVndk() && ctx.isVndk()) refAbiDumpTextFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isNdk, isLlndkOrVndk, false) refAbiDumpGzipFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isNdk, isLlndkOrVndk, true) @@ -1371,6 +1385,8 @@ func reuseStaticLibrary(mctx android.BottomUpMutatorContext, static, shared *Mod len(sharedCompiler.SharedProperties.Shared.Static_libs) == 0 && len(staticCompiler.StaticProperties.Static.Shared_libs) == 0 && len(sharedCompiler.SharedProperties.Shared.Shared_libs) == 0 && + // Compare System_shared_libs properties with nil because empty lists are + // semantically significant for them. staticCompiler.StaticProperties.Static.System_shared_libs == nil && sharedCompiler.SharedProperties.Shared.System_shared_libs == nil { @@ -1487,6 +1503,19 @@ func checkVersions(ctx android.BaseModuleContext, versions []string) { } } +func createVersionVariations(mctx android.BottomUpMutatorContext, versions []string) { + // "" is for the non-stubs variant + versions = append([]string{""}, versions...) + + modules := mctx.CreateVariations(versions...) + for i, m := range modules { + if versions[i] != "" { + m.(LinkableInterface).SetBuildStubs() + m.(LinkableInterface).SetStubsVersions(versions[i]) + } + } +} + // 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) { @@ -1498,24 +1527,30 @@ func VersionMutator(mctx android.BottomUpMutatorContext) { return } - // save the list of versions for later use stubsVersionsLock.Lock() defer stubsVersionsLock.Unlock() + // save the list of versions for later use stubsVersionsFor(mctx.Config())[mctx.ModuleName()] = versions - // "" is for the non-stubs variant - versions = append([]string{""}, versions...) + createVersionVariations(mctx, versions) + return + } - modules := mctx.CreateVariations(versions...) - for i, m := range modules { - if versions[i] != "" { - m.(LinkableInterface).SetBuildStubs() - m.(LinkableInterface).SetStubsVersions(versions[i]) - } - } - } else { - mctx.CreateVariations("") + if c, ok := library.(*Module); ok && c.IsStubs() { + stubsVersionsLock.Lock() + defer stubsVersionsLock.Unlock() + // For LLNDK llndk_library, we borrow vstubs.ersions from its implementation library. + // Since llndk_library has dependency to its implementation library, + // we can safely access stubsVersionsFor() with its baseModuleName. + versions := stubsVersionsFor(mctx.Config())[c.BaseModuleName()] + // save the list of versions for later use + stubsVersionsFor(mctx.Config())[mctx.ModuleName()] = versions + + createVersionVariations(mctx, versions) + return } + + mctx.CreateVariations("") return } if genrule, ok := mctx.Module().(*genrule.Module); ok { diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go index 49674552f..754b96a98 100644 --- a/cc/library_sdk_member.go +++ b/cc/library_sdk_member.go @@ -212,7 +212,9 @@ func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, b outputProperties.AddPropertyWithTag("shared_libs", libInfo.SharedLibs, builder.SdkMemberReferencePropertyTag(false)) } - if len(libInfo.SystemSharedLibs) > 0 { + // SystemSharedLibs needs to be propagated if it's a list, even if it's empty, + // so check for non-nil instead of nonzero length. + if libInfo.SystemSharedLibs != nil { outputProperties.AddPropertyWithTag("system_shared_libs", libInfo.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false)) } @@ -267,6 +269,11 @@ func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, b for property, dirs := range includeDirs { outputProperties.AddProperty(property, dirs) } + + if len(libInfo.StubsVersion) > 0 { + stubsSet := outputProperties.AddPropertySet("stubs") + stubsSet.AddProperty("versions", []string{libInfo.StubsVersion}) + } } const ( @@ -327,11 +334,16 @@ type nativeLibInfoProperties struct { // This field is exported as its contents may not be arch specific. SharedLibs []string - // The set of system shared libraries + // The set of system shared libraries. Note nil and [] are semantically + // distinct - see BaseLinkerProperties.System_shared_libs. // // This field is exported as its contents may not be arch specific. SystemSharedLibs []string + // The specific stubs version for the lib variant, or empty string if stubs + // are not in use. + StubsVersion string + // outputFile is not exported as it is always arch specific. outputFile android.Path } @@ -367,6 +379,10 @@ func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberConte p.SystemSharedLibs = specifiedDeps.systemSharedLibs } p.exportedGeneratedHeaders = ccModule.ExportedGeneratedHeaders() + + if ccModule.HasStubsVariants() { + p.StubsVersion = ccModule.StubsVersion() + } } func (p *nativeLibInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { diff --git a/cc/linker.go b/cc/linker.go index 385e04e16..57a0c016a 100644 --- a/cc/linker.go +++ b/cc/linker.go @@ -502,7 +502,15 @@ func (linker *baseLinker) link(ctx ModuleContext, 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...) + + // Must distinguish nil and [] in system_shared_libs - ensure that [] in + // either input list doesn't come out as nil. + if specifiedDeps.systemSharedLibs == nil { + specifiedDeps.systemSharedLibs = linker.Properties.System_shared_libs + } else { + specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, linker.Properties.System_shared_libs...) + } + return specifiedDeps } diff --git a/cc/llndk_library.go b/cc/llndk_library.go index 3dee6920a..09050aa34 100644 --- a/cc/llndk_library.go +++ b/cc/llndk_library.go @@ -19,8 +19,14 @@ import ( "strings" "android/soong/android" + + "github.com/google/blueprint" ) +var llndkImplDep = struct { + blueprint.DependencyTag +}{} + var ( llndkLibrarySuffix = ".llndk" llndkHeadersSuffix = ".llndk" @@ -81,6 +87,9 @@ func (stub *llndkStubDecorator) compile(ctx ModuleContext, flags Flags, deps Pat // For non-enforcing devices, vndkVer is empty. Use "current" in that case, too. vndkVer = "current" } + if stub.stubsVersion() != "" { + vndkVer = stub.stubsVersion() + } objs, versionScript := compileStubLibrary(ctx, flags, String(stub.Properties.Symbol_file), vndkVer, "--llndk") stub.versionScriptPath = versionScript return objs @@ -154,6 +163,10 @@ func (stub *llndkStubDecorator) link(ctx ModuleContext, flags Flags, deps PathDe stub.libraryDecorator.flagExporter.Properties.Export_include_dirs = []string{} } + if stub.stubsVersion() != "" { + stub.reexportFlags("-D" + versioningMacroName(ctx.baseModuleName()) + "=" + stub.stubsVersion()) + } + return stub.libraryDecorator.link(ctx, flags, deps, objs) } diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go index f909add43..c4d770837 100644 --- a/cc/ndk_prebuilt.go +++ b/cc/ndk_prebuilt.go @@ -92,6 +92,11 @@ func (c *ndkPrebuiltObjectLinker) link(ctx ModuleContext, flags Flags, return ndkPrebuiltModuleToPath(ctx, flags.Toolchain, objectExtension, ctx.sdkVersion()) } +func (*ndkPrebuiltObjectLinker) availableFor(what string) bool { + // ndk prebuilt objects are available to everywhere + return true +} + type ndkPrebuiltStlLinker struct { *libraryDecorator } @@ -105,6 +110,11 @@ func (*ndkPrebuiltStlLinker) linkerDeps(ctx DepsContext, deps Deps) Deps { return deps } +func (*ndkPrebuiltStlLinker) availableFor(what string) bool { + // ndk prebuilt objects are available to everywhere + return true +} + // ndk_prebuilt_shared_stl exports a precompiled ndk shared standard template // library (stl) library for linking operation. The soong's module name format // is ndk_<NAME>.so where the library is located under @@ -88,20 +88,21 @@ func (pgo *pgo) props() []interface{} { return []interface{}{&pgo.Properties} } -func (props *PgoProperties) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags { +func (props *PgoProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags { flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...) - if props.isInstrumentation() { - flags.Local.CFlags = append(flags.Local.CFlags, profileInstrumentFlag) - // The profile runtime is added below in deps(). Add the below - // flag, which is the only other link-time action performed by - // the Clang driver during link. - flags.Local.LdFlags = append(flags.Local.LdFlags, "-u__llvm_profile_runtime") - } - if props.isSampling() { - flags.Local.CFlags = append(flags.Local.CFlags, profileSamplingFlag) - flags.Local.LdFlags = append(flags.Local.LdFlags, profileSamplingFlag) - } + flags.Local.CFlags = append(flags.Local.CFlags, profileInstrumentFlag) + // The profile runtime is added below in deps(). Add the below + // flag, which is the only other link-time action performed by + // the Clang driver during link. + flags.Local.LdFlags = append(flags.Local.LdFlags, "-u__llvm_profile_runtime") + return flags +} +func (props *PgoProperties) addSamplingProfileGatherFlags(ctx ModuleContext, flags Flags) Flags { + flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...) + + flags.Local.CFlags = append(flags.Local.CFlags, profileSamplingFlag) + flags.Local.LdFlags = append(flags.Local.LdFlags, profileSamplingFlag) return flags } @@ -286,8 +287,12 @@ func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags { props := pgo.Properties // Add flags to profile this module based on its profile_kind - if props.ShouldProfileModule { - return props.addProfileGatherFlags(ctx, flags) + if props.ShouldProfileModule && props.isInstrumentation() { + return props.addInstrumentationProfileGatherFlags(ctx, flags) + } else if props.ShouldProfileModule && props.isSampling() { + return props.addSamplingProfileGatherFlags(ctx, flags) + } else if ctx.DeviceConfig().SamplingPGO() { + return props.addSamplingProfileGatherFlags(ctx, flags) } if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") { diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go index 242d835e9..0b018c10d 100644 --- a/cc/prebuilt_test.go +++ b/cc/prebuilt_test.go @@ -22,6 +22,25 @@ import ( "github.com/google/blueprint" ) +func testPrebuilt(t *testing.T, bp string, fs map[string][]byte) *android.TestContext { + config := TestConfig(buildDir, android.Android, nil, bp, fs) + ctx := CreateTestContext() + + // Enable androidmk support. + // * Register the singleton + // * Configure that we are inside make + // * Add CommonOS to ensure that androidmk processing works. + android.RegisterAndroidMkBuildComponents(ctx) + android.SetInMakeForTests(config) + + ctx.Register(config) + _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + return ctx +} + func TestPrebuilt(t *testing.T) { bp := ` cc_library { @@ -84,7 +103,15 @@ func TestPrebuilt(t *testing.T) { } ` - ctx := testPrebuilt(t, bp) + ctx := testPrebuilt(t, bp, map[string][]byte{ + "liba.so": nil, + "libb.a": nil, + "libd.so": nil, + "libe.a": nil, + "libf.a": nil, + "libf.so": nil, + "crtx.o": nil, + }) // Verify that all the modules exist and that their dependencies were connected correctly liba := ctx.ModuleForTests("liba", "android_arm64_armv8-a_shared").Module() @@ -143,35 +170,6 @@ func TestPrebuilt(t *testing.T) { } } -func testPrebuilt(t *testing.T, bp string) *android.TestContext { - - fs := map[string][]byte{ - "liba.so": nil, - "libb.a": nil, - "libd.so": nil, - "libe.a": nil, - "libf.a": nil, - "libf.so": nil, - "crtx.o": nil, - } - config := TestConfig(buildDir, android.Android, nil, bp, fs) - ctx := CreateTestContext() - - // Enable androidmk support. - // * Register the singleton - // * Configure that we are inside make - // * Add CommonOS to ensure that androidmk processing works. - android.RegisterAndroidMkBuildComponents(ctx) - android.SetInMakeForTests(config) - - ctx.Register(config) - _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) - android.FailIfErrored(t, errs) - return ctx -} - func TestPrebuiltLibraryShared(t *testing.T) { ctx := testPrebuilt(t, ` cc_prebuilt_library_shared { @@ -181,7 +179,9 @@ func TestPrebuiltLibraryShared(t *testing.T) { none: true, }, } - `) + `, map[string][]byte{ + "libf.so": nil, + }) shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module) assertString(t, shared.OutputFile().String(), "libf.so") @@ -193,7 +193,9 @@ func TestPrebuiltLibraryStatic(t *testing.T) { name: "libtest", srcs: ["libf.a"], } - `) + `, map[string][]byte{ + "libf.a": nil, + }) static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module) assertString(t, static.OutputFile().String(), "libf.a") @@ -213,7 +215,10 @@ func TestPrebuiltLibrary(t *testing.T) { none: true, }, } - `) + `, map[string][]byte{ + "libf.a": nil, + "libf.so": nil, + }) shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module) assertString(t, shared.OutputFile().String(), "libf.so") diff --git a/cc/testing.go b/cc/testing.go index 89a9c36dc..53f09955a 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -67,6 +67,20 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { src: "", } + cc_prebuilt_library_shared { + name: "libclang_rt.hwasan-aarch64-android", + nocrt: true, + vendor_available: true, + recovery_available: true, + system_shared_libs: [], + stl: "none", + srcs: [""], + check_elf_files: false, + sanitize: { + never: true, + }, + } + toolchain_library { name: "libclang_rt.builtins-i686-android", vendor_available: true, @@ -220,6 +234,10 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { vendor_available: true, recovery_available: true, host_supported: true, + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], } cc_library { name: "libc++", @@ -248,6 +266,10 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { host_supported: false, vendor_available: true, recovery_available: true, + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], } cc_library { name: "libunwind_llvm", @@ -259,8 +281,21 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { recovery_available: true, } + cc_defaults { + name: "crt_defaults", + recovery_available: true, + vendor_available: true, + native_bridge_supported: true, + stl: "none", + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], + } + cc_object { name: "crtbegin_so", + defaults: ["crt_defaults"], recovery_available: true, vendor_available: true, native_bridge_supported: true, @@ -269,6 +304,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { cc_object { name: "crtbegin_dynamic", + defaults: ["crt_defaults"], recovery_available: true, vendor_available: true, native_bridge_supported: true, @@ -277,6 +313,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { cc_object { name: "crtbegin_static", + defaults: ["crt_defaults"], recovery_available: true, vendor_available: true, native_bridge_supported: true, @@ -285,6 +322,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { cc_object { name: "crtend_so", + defaults: ["crt_defaults"], recovery_available: true, vendor_available: true, native_bridge_supported: true, @@ -293,6 +331,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { cc_object { name: "crtend_android", + defaults: ["crt_defaults"], recovery_available: true, vendor_available: true, native_bridge_supported: true, diff --git a/cc/vndk.go b/cc/vndk.go index e02e7b534..4888dcf07 100644 --- a/cc/vndk.go +++ b/cc/vndk.go @@ -297,6 +297,9 @@ func processLlndkLibrary(mctx android.BottomUpMutatorContext, m *Module) { if !Bool(lib.Properties.Vendor_available) { vndkPrivateLibraries(mctx.Config())[name] = filename } + if mctx.OtherModuleExists(name) { + mctx.AddFarVariationDependencies(m.Target().Variations(), llndkImplDep, name) + } } func processVndkLibrary(mctx android.BottomUpMutatorContext, m *Module) { diff --git a/cmd/zipsync/zipsync.go b/cmd/zipsync/zipsync.go index a6023d3bf..294e5ef0a 100644 --- a/cmd/zipsync/zipsync.go +++ b/cmd/zipsync/zipsync.go @@ -115,7 +115,7 @@ func main() { filename := filepath.Join(*outputDir, name) if f.FileInfo().IsDir() { - must(os.MkdirAll(filename, f.FileInfo().Mode())) + must(os.MkdirAll(filename, 0777)) } else { must(os.MkdirAll(filepath.Dir(filename), 0777)) in, err := f.Open() diff --git a/cuj/cuj.go b/cuj/cuj.go index c7ff8ffa8..333301268 100644 --- a/cuj/cuj.go +++ b/cuj/cuj.go @@ -33,8 +33,9 @@ import ( ) type Test struct { - name string - args []string + name string + args []string + before func() error results TestResults } @@ -119,6 +120,15 @@ func (t *Test) Run(logsDir string) { t.results.metrics = met } +// Touch the Intent.java file to cause a rebuild of the frameworks to monitor the +// incremental build speed as mentioned b/152046247. Intent.java file was chosen +// as it is a key component of the framework and is often modified. +func touchIntentFile() error { + const intentFileName = "frameworks/base/core/java/android/content/Intent.java" + currentTime := time.Now().Local() + return os.Chtimes(intentFileName, currentTime, currentTime) +} + func main() { outDir := os.Getenv("OUT_DIR") if outDir == "" { @@ -170,6 +180,36 @@ func main() { name: "framework_rebuild_twice", args: []string{"framework"}, }, + { + // Scenario major_inc_build (b/152046247): tracking build speed of major incremental build. + name: "major_inc_build_droid", + args: []string{"droid"}, + }, + { + name: "major_inc_build_framework_minus_apex_after_droid_build", + args: []string{"framework-minus-apex"}, + before: touchIntentFile, + }, + { + name: "major_inc_build_framework_after_droid_build", + args: []string{"framework"}, + before: touchIntentFile, + }, + { + name: "major_inc_build_sync_after_droid_build", + args: []string{"sync"}, + before: touchIntentFile, + }, + { + name: "major_inc_build_droid_rebuild", + args: []string{"droid"}, + before: touchIntentFile, + }, + { + name: "major_inc_build_update_api_after_droid_rebuild", + args: []string{"update-api"}, + before: touchIntentFile, + }, } cujMetrics := metrics.NewCriticalUserJourneysMetrics() @@ -178,6 +218,12 @@ func main() { for i, t := range tests { logsSubDir := fmt.Sprintf("%02d_%s", i, t.name) logsDir := filepath.Join(cujDir, "logs", logsSubDir) + if t.before != nil { + if err := t.before(); err != nil { + fmt.Printf("error running before function on test %q: %v\n", t.name, err) + break + } + } t.Run(logsDir) if t.results.err != nil { fmt.Printf("error running test %q: %s\n", t.name, t.results.err) diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go index 02e54b3ee..0e1bfc615 100644 --- a/dexpreopt/dexpreopt.go +++ b/dexpreopt/dexpreopt.go @@ -589,7 +589,7 @@ func NonUpdatableSystemServerJars(ctx android.PathContext, global *GlobalConfig) // at that time (Soong processes the jars in dependency order, which may be different from the // the system server classpath order). func SystemServerDexJarHostPath(ctx android.PathContext, jar string) android.OutputPath { - return android.PathForOutput(ctx, ctx.Config().BuildDir(), "system_server_dexjars", jar+".jar") + return android.PathForOutput(ctx, "system_server_dexjars", jar+".jar") } func contains(l []string, s string) bool { diff --git a/java/androidmk.go b/java/androidmk.go index d76e29b21..136bb36ca 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -72,6 +72,7 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { if !hideFromMake { mainEntries = android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", + DistFile: android.OptionalPathForPath(library.distFile), OutputFile: android.OptionalPathForPath(library.outputFile), Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk", ExtraEntries: []android.AndroidMkExtraEntriesFunc{ @@ -275,7 +276,7 @@ func (binary *Binary) AndroidMkEntries() []android.AndroidMkEntries { } func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { - if !app.IsForPlatform() { + if !app.IsForPlatform() || app.appProperties.HideFromMake { return []android.AndroidMkEntries{android.AndroidMkEntries{ Disabled: true, }} @@ -288,6 +289,7 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { func(entries *android.AndroidMkEntries) { // App module names can be overridden. entries.SetString("LOCAL_MODULE", app.installApkName) + entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", app.appProperties.PreventInstall) entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", app.exportPackage) if app.dexJarFile != nil { entries.SetPath("LOCAL_SOONG_DEX_JAR", app.dexJarFile) @@ -347,6 +349,9 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { for _, jniLib := range app.installJniLibs { entries.AddStrings("LOCAL_SOONG_JNI_LIBS_"+jniLib.target.Arch.ArchType.String(), jniLib.name) } + if len(app.jniCoverageOutputs) > 0 { + entries.AddStrings("LOCAL_PREBUILT_COVERAGE_ARCHIVE", app.jniCoverageOutputs.Strings()...) + } if len(app.dexpreopter.builtInstalled) > 0 { entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", app.dexpreopter.builtInstalled) } @@ -542,6 +547,7 @@ func (ddoc *Droiddoc) AndroidMkEntries() []android.AndroidMkEntries { func (dstubs *Droidstubs) AndroidMkEntries() []android.AndroidMkEntries { return []android.AndroidMkEntries{android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", + DistFile: android.OptionalPathForPath(dstubs.apiFile), OutputFile: android.OptionalPathForPath(dstubs.stubsSrcJar), Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk", ExtraEntries: []android.AndroidMkExtraEntriesFunc{ diff --git a/java/androidmk_test.go b/java/androidmk_test.go index acc6bf039..7daa6244f 100644 --- a/java/androidmk_test.go +++ b/java/androidmk_test.go @@ -16,6 +16,7 @@ package java import ( "reflect" + "strings" "testing" "android/soong/android" @@ -133,3 +134,38 @@ func TestHostdexSpecificRequired(t *testing.T) { t.Errorf("Unexpected required modules - expected: %q, actual: %q", expected, actual) } } + +func TestDistWithTag(t *testing.T) { + ctx, config := testJava(t, ` + java_library { + name: "foo_without_tag", + srcs: ["a.java"], + compile_dex: true, + dist: { + targets: ["hi"], + }, + } + java_library { + name: "foo_with_tag", + srcs: ["a.java"], + compile_dex: true, + dist: { + targets: ["hi"], + tag: ".jar", + }, + } + `) + + without_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_without_tag", "android_common").Module()) + with_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_with_tag", "android_common").Module()) + + if len(without_tag_entries) != 2 || len(with_tag_entries) != 2 { + t.Errorf("two mk entries per module expected, got %d and %d", len(without_tag_entries), len(with_tag_entries)) + } + if !with_tag_entries[0].DistFile.Valid() || !strings.Contains(with_tag_entries[0].DistFile.String(), "/javac/foo_with_tag.jar") { + t.Errorf("expected classes.jar DistFile, got %v", with_tag_entries[0].DistFile) + } + if without_tag_entries[0].DistFile.Valid() { + t.Errorf("did not expect explicit DistFile, got %v", without_tag_entries[0].DistFile) + } +} diff --git a/java/app.go b/java/app.go index 346f1551d..6a0aa8f41 100755 --- a/java/app.go +++ b/java/app.go @@ -105,6 +105,11 @@ type appProperties struct { // If set, find and merge all NOTICE files that this module and its dependencies have and store // it in the APK as an asset. Embed_notices *bool + + // cc.Coverage related properties + PreventInstall bool `blueprint:"mutated"` + HideFromMake bool `blueprint:"mutated"` + IsCoverageVariant bool `blueprint:"mutated"` } // android_app properties that can be overridden by override_android_app @@ -133,7 +138,8 @@ type AndroidApp struct { overridableAppProperties overridableAppProperties - installJniLibs []jniLib + installJniLibs []jniLib + jniCoverageOutputs android.Paths bundleFile android.Path @@ -171,6 +177,10 @@ func (a *AndroidApp) Certificate() Certificate { return a.certificate } +func (a *AndroidApp) JniCoverageOutputs() android.Paths { + return a.jniCoverageOutputs +} + var _ AndroidLibraryDependency = (*AndroidApp)(nil) type Certificate struct { @@ -380,6 +390,11 @@ func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, ctx android.ModuleContext if a.shouldEmbedJnis(ctx) { jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip") TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.useEmbeddedNativeLibs(ctx)) + for _, jni := range jniLibs { + if jni.coverageFile.Valid() { + a.jniCoverageOutputs = append(a.jniCoverageOutputs, jni.coverageFile.Path()) + } + } } else { a.installJniLibs = jniLibs } @@ -521,14 +536,28 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { // Build a final signed app package. packageFile := android.PathForModuleOut(ctx, a.installApkName+".apk") - CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps) + v4SigningRequested := Bool(a.Module.deviceProperties.V4_signature) + var v4SignatureFile android.WritablePath = nil + if v4SigningRequested { + v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+".apk.idsig") + } + CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile) a.outputFile = packageFile + if v4SigningRequested { + a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile) + } for _, split := range a.aapt.splits { // Sign the split APKs packageFile := android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk") - CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps) + if v4SigningRequested { + v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk.idsig") + } + CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile) a.extraOutputFiles = append(a.extraOutputFiles, packageFile) + if v4SigningRequested { + a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile) + } } // Build an app bundle. @@ -582,9 +611,10 @@ func collectAppDeps(ctx android.ModuleContext, shouldCollectRecursiveNativeDeps if lib.Valid() { jniLibs = append(jniLibs, jniLib{ - name: ctx.OtherModuleName(module), - path: path, - target: module.Target(), + name: ctx.OtherModuleName(module), + path: path, + target: module.Target(), + coverageFile: dep.CoverageOutputFile(), }) } else { ctx.ModuleErrorf("dependency %q missing output file", otherName) @@ -638,6 +668,24 @@ func (a *AndroidApp) Privileged() bool { return Bool(a.appProperties.Privileged) } +func (a *AndroidApp) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool { + return ctx.Device() && (ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled()) +} + +func (a *AndroidApp) PreventInstall() { + a.appProperties.PreventInstall = true +} + +func (a *AndroidApp) HideFromMake() { + a.appProperties.HideFromMake = true +} + +func (a *AndroidApp) MarkAsCoverageVariant(coverage bool) { + a.appProperties.IsCoverageVariant = coverage +} + +var _ cc.Coverage = (*AndroidApp)(nil) + // android_app compiles sources and Android resources into an Android application package `.apk` file. func AndroidAppFactory() android.Module { module := &AndroidApp{} @@ -1129,7 +1177,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext } a.certificate = certificates[0] signed := android.PathForModuleOut(ctx, "signed", ctx.ModuleName()+".apk") - SignAppPackage(ctx, signed, dexOutput, certificates) + SignAppPackage(ctx, signed, dexOutput, certificates, nil) a.outputFile = signed } else { alignedApk := android.PathForModuleOut(ctx, "zip-aligned", ctx.ModuleName()+".apk") @@ -1334,7 +1382,7 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC _, certificates := collectAppDeps(ctx, false, false) certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx) signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk") - SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates) + SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil) r.certificate = certificates[0] r.outputFile = signed diff --git a/java/app_builder.go b/java/app_builder.go index 5e7fbe6de..b2780bc90 100644 --- a/java/app_builder.go +++ b/java/app_builder.go @@ -45,7 +45,7 @@ var combineApk = pctx.AndroidStaticRule("combineApk", }) func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath, - packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths) { + packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath) { unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk" unsignedApk := android.PathForModuleOut(ctx, unsignedApkName) @@ -66,10 +66,10 @@ func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.Writa Implicits: deps, }) - SignAppPackage(ctx, outputFile, unsignedApk, certificates) + SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile) } -func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate) { +func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate, v4SignatureFile android.WritablePath) { var certificateArgs []string var deps android.Paths @@ -78,14 +78,22 @@ func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, u deps = append(deps, c.Pem, c.Key) } + outputFiles := android.WritablePaths{signedApk} + var flag string = "" + if v4SignatureFile != nil { + outputFiles = append(outputFiles, v4SignatureFile) + flag = "--enable-v4" + } + ctx.Build(pctx, android.BuildParams{ Rule: Signapk, Description: "signapk", - Output: signedApk, + Outputs: outputFiles, Input: unsignedApk, Implicits: deps, Args: map[string]string{ "certificates": strings.Join(certificateArgs, " "), + "flags": flag, }, }) } diff --git a/java/app_test.go b/java/app_test.go index fa18e9dac..f2ec4837f 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -1079,6 +1079,66 @@ func TestCertificates(t *testing.T) { } } +func TestRequestV4SigningFlag(t *testing.T) { + testCases := []struct { + name string + bp string + expected string + }{ + { + name: "default", + bp: ` + android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "current", + } + `, + expected: "", + }, + { + name: "default", + bp: ` + android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "current", + v4_signature: false, + } + `, + expected: "", + }, + { + name: "module certificate property", + bp: ` + android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "current", + v4_signature: true, + } + `, + expected: "--enable-v4", + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + config := testAppConfig(nil, test.bp, nil) + ctx := testContext() + + run(t, ctx, config) + foo := ctx.ModuleForTests("foo", "android_common") + + signapk := foo.Output("foo.apk") + signFlags := signapk.Args["flags"] + if test.expected != signFlags { + t.Errorf("Incorrect signing flags, expected: %q, got: %q", test.expected, signFlags) + } + }) + } +} + func TestPackageNameOverride(t *testing.T) { testCases := []struct { name string diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 40cfe4f5d..fba0b97fb 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -127,7 +127,8 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo global := dexpreopt.GetGlobalConfig(ctx) bootImage := defaultBootImageConfig(ctx) dexFiles := bootImage.dexPathsDeps.Paths() - dexLocations := bootImage.dexLocationsDeps + // The dex locations for all Android variants are identical. + dexLocations := bootImage.getAnyAndroidVariant().dexLocationsDeps if global.UseArtImage { bootImage = artBootImageConfig(ctx) } @@ -155,6 +156,8 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo images = append(images, variant.images) imagesDeps = append(imagesDeps, variant.imagesDeps) } + // The image locations for all Android variants are identical. + imageLocations := bootImage.getAnyAndroidVariant().imageLocations() dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath) @@ -198,7 +201,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo Archs: archs, DexPreoptImages: images, DexPreoptImagesDeps: imagesDeps, - DexPreoptImageLocations: bootImage.imageLocations, + DexPreoptImageLocations: imageLocations, PreoptBootClassPathDexFiles: dexFiles, PreoptBootClassPathDexLocations: dexLocations, diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index a3b264ed8..543b2333c 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -16,6 +16,7 @@ package java import ( "path/filepath" + "sort" "strings" "android/soong/android" @@ -25,31 +26,13 @@ import ( ) func init() { - android.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory) + RegisterDexpreoptBootJarsComponents(android.InitRegistrationContext) } -// The image "location" is a symbolic path that with multiarchitecture -// support doesn't really exist on the device. Typically it is -// /system/framework/boot.art and should be the same for all supported -// architectures on the device. The concrete architecture specific -// content actually ends up in a "filename" that contains an -// architecture specific directory name such as arm, arm64, x86, x86_64. -// -// Here are some example values for an x86_64 / x86 configuration: -// -// bootImages["x86_64"] = "out/soong/generic_x86_64/dex_bootjars/system/framework/x86_64/boot.art" -// dexpreopt.PathToLocation(bootImages["x86_64"], "x86_64") = "out/soong/generic_x86_64/dex_bootjars/system/framework/boot.art" -// -// bootImages["x86"] = "out/soong/generic_x86_64/dex_bootjars/system/framework/x86/boot.art" -// dexpreopt.PathToLocation(bootImages["x86"])= "out/soong/generic_x86_64/dex_bootjars/system/framework/boot.art" -// -// The location is passed as an argument to the ART tools like dex2oat instead of the real path. The ART tools -// will then reconstruct the real path, so the rules must have a dependency on the real path. - // Target-independent description of pre-compiled boot image. type bootImageConfig struct { - // Whether this image is an extension. - extension bool + // If this image is an extension, the image that it extends. + extends *bootImageConfig // Image name (used in directory names and ninja rule names). name string @@ -69,17 +52,10 @@ type bootImageConfig struct { // The names of jars that constitute this image. modules []string - // The "locations" of jars. - dexLocations []string // for this image - dexLocationsDeps []string // for the dependency images and in this image - // File paths to jars. dexPaths android.WritablePaths // for this image dexPathsDeps android.WritablePaths // for the dependency images and in this image - // The "locations" of the dependency images and in this image. - imageLocations []string - // File path to a zip archive with all image files (or nil, if not needed). zip android.WritablePath @@ -97,6 +73,10 @@ type bootImageVariant struct { // Target for which the image is generated. target android.Target + // The "locations" of jars. + dexLocations []string // for this image + dexLocationsDeps []string // for the dependency images and in this image + // Paths to image files. images android.OutputPath // first image file imagesDeps android.OutputPaths // all files @@ -119,13 +99,23 @@ func (image bootImageConfig) getVariant(target android.Target) *bootImageVariant return nil } +// Return any (the first) variant which is for the device (as opposed to for the host) +func (image bootImageConfig) getAnyAndroidVariant() *bootImageVariant { + for _, variant := range image.variants { + if variant.target.Os == android.Android { + return variant + } + } + return nil +} + func (image bootImageConfig) moduleName(idx int) string { // Dexpreopt on the boot class path produces multiple files. The first dex file // is converted into 'name'.art (to match the legacy assumption that 'name'.art // exists), and the rest are converted to 'name'-<jar>.art. m := image.modules[idx] name := image.stem - if idx != 0 || image.extension { + if idx != 0 || image.extends != nil { name += "-" + stemOf(m) } return name @@ -150,6 +140,24 @@ func (image bootImageConfig) moduleFiles(ctx android.PathContext, dir android.Ou return ret } +// The image "location" is a symbolic path that, with multiarchitecture support, doesn't really +// exist on the device. Typically it is /apex/com.android.art/javalib/boot.art and should be the +// same for all supported architectures on the device. The concrete architecture specific files +// actually end up in architecture-specific sub-directory such as arm, arm64, x86, or x86_64. +// +// For example a physical file +// "/apex/com.android.art/javalib/x86/boot.art" has "image location" +// "/apex/com.android.art/javalib/boot.art" (which is not an actual file). +// +// The location is passed as an argument to the ART tools like dex2oat instead of the real path. +// ART tools will then reconstruct the architecture-specific real path. +func (image *bootImageVariant) imageLocations() (imageLocations []string) { + if image.extends != nil { + imageLocations = image.extends.getVariant(image.target).imageLocations() + } + return append(imageLocations, dexpreopt.PathToLocation(image.images, image.target.Arch.ArchType)) +} + func concat(lists ...[]string) []string { var size int for _, l := range lists { @@ -166,6 +174,10 @@ func dexpreoptBootJarsFactory() android.Singleton { return &dexpreoptBootJars{} } +func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) { + ctx.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory) +} + func skipDexpreoptBootJars(ctx android.PathContext) bool { if dexpreopt.GetGlobalConfig(ctx).DisablePreopt { return true @@ -234,16 +246,66 @@ func (d *dexpreoptBootJars) GenerateBuildActions(ctx android.SingletonContext) { dumpOatRules(ctx, d.defaultBootImage) } +// Inspect this module to see if it contains a bootclasspath dex jar. +// Note that the same jar may occur in multiple modules. +// This logic is tested in the apex package to avoid import cycle apex <-> java. +func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, module android.Module) (int, android.Path) { + // All apex Java libraries have non-installable platform variants, skip them. + if module.IsSkipInstall() { + return -1, nil + } + + jar, hasJar := module.(interface{ DexJar() android.Path }) + if !hasJar { + return -1, nil + } + + name := ctx.ModuleName(module) + index := android.IndexList(name, image.modules) + if index == -1 { + return -1, nil + } + + // Check that this module satisfies constraints for a particular boot image. + apex, isApexModule := module.(android.ApexModule) + if image.name == artBootImageName { + if isApexModule && strings.HasPrefix(apex.ApexName(), "com.android.art.") { + // ok, found the jar in the ART apex + } else if isApexModule && !apex.IsForPlatform() { + // this jar is part of an updatable apex other than ART, fail immediately + ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the ART boot image", name, apex.ApexName()) + } else if isApexModule && apex.IsForPlatform() && Bool(module.(*Library).deviceProperties.Hostdex) { + // this is a special "hostdex" variant, skip it and resume search + return -1, nil + } else if name == "jacocoagent" && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") { + // this is Jacoco platform variant for a coverage build, skip it and resume search + return -1, nil + } else { + // this (installable) jar is part of the platform, fail immediately + ctx.Errorf("module '%s' is part of the platform and not allowed in the ART boot image", name) + } + } else if image.name == frameworkBootImageName { + if !isApexModule || apex.IsForPlatform() { + // ok, this jar is part of the platform + } else { + // this jar is part of an updatable apex, fail immediately + ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the framework boot image", name, apex.ApexName()) + } + } else { + panic("unknown boot image: " + image.name) + } + + return index, jar.DexJar() +} + // buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image. func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig { + // Collect dex jar paths for the boot image modules. + // This logic is tested in the apex package to avoid import cycle apex <-> java. bootDexJars := make(android.Paths, len(image.modules)) ctx.VisitAllModules(func(module android.Module) { - // Collect dex jar paths for the modules listed above. - if j, ok := module.(interface{ DexJar() android.Path }); ok { - name := ctx.ModuleName(module) - if i := android.IndexList(name, image.modules); i != -1 { - bootDexJars[i] = j.DexJar() - } + if i, j := getBootImageJar(ctx, image, module); i != -1 { + bootDexJars[i] = j } }) @@ -255,7 +317,8 @@ func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootI missingDeps = append(missingDeps, image.modules[i]) bootDexJars[i] = android.PathForOutput(ctx, "missing") } else { - ctx.Errorf("failed to find dex jar path for module %q", + ctx.Errorf("failed to find a dex jar path for module '%s'"+ + ", note that some jars may be filtered out by module constraints", image.modules[i]) } } @@ -274,6 +337,7 @@ func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootI profile := bootImageProfileRule(ctx, image, missingDeps) bootFrameworkProfileRule(ctx, image, missingDeps) + updatableBcpPackagesRule(ctx, image, missingDeps) var allFiles android.Paths for _, variant := range image.variants { @@ -351,7 +415,7 @@ func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant cmd.FlagWithInput("--dirty-image-objects=", global.DirtyImageObjects.Path()) } - if image.extension { + if image.extends != nil { artImage := image.primaryImages cmd. Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", image.dexPathsDeps.Paths(), ":"). @@ -478,7 +542,7 @@ func bootImageProfileRule(ctx android.SingletonContext, image *bootImageConfig, Tool(globalSoong.Profman). FlagWithInput("--create-profile-from=", bootImageProfile). FlagForEachInput("--apk=", image.dexPathsDeps.Paths()). - FlagForEachArg("--dex-location=", image.dexLocationsDeps). + FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps). FlagWithOutput("--reference-profile-file=", profile) rule.Install(profile, "/system/etc/boot-image.prof") @@ -529,7 +593,7 @@ func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImageConf Flag("--generate-boot-profile"). FlagWithInput("--create-profile-from=", bootFrameworkProfile). FlagForEachInput("--apk=", image.dexPathsDeps.Paths()). - FlagForEachArg("--dex-location=", image.dexLocationsDeps). + FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps). FlagWithOutput("--reference-profile-file=", profile) rule.Install(profile, "/system/etc/boot-image.bprof") @@ -542,6 +606,61 @@ func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImageConf var bootFrameworkProfileRuleKey = android.NewOnceKey("bootFrameworkProfileRule") +func updatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConfig, missingDeps []string) android.WritablePath { + if ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() { + return nil + } + + return ctx.Config().Once(updatableBcpPackagesRuleKey, func() interface{} { + global := dexpreopt.GetGlobalConfig(ctx) + updatableModules := dexpreopt.GetJarsFromApexJarPairs(global.UpdatableBootJars) + + // Collect `permitted_packages` for updatable boot jars. + var updatablePackages []string + ctx.VisitAllModules(func(module android.Module) { + if j, ok := module.(*Library); ok { + name := ctx.ModuleName(module) + if i := android.IndexList(name, updatableModules); i != -1 { + pp := j.properties.Permitted_packages + if len(pp) > 0 { + updatablePackages = append(updatablePackages, pp...) + } else { + ctx.Errorf("Missing permitted_packages for %s", name) + } + // Do not match the same library repeatedly. + updatableModules = append(updatableModules[:i], updatableModules[i+1:]...) + } + } + }) + + // Sort updatable packages to ensure deterministic ordering. + sort.Strings(updatablePackages) + + updatableBcpPackagesName := "updatable-bcp-packages.txt" + updatableBcpPackages := image.dir.Join(ctx, updatableBcpPackagesName) + + ctx.Build(pctx, android.BuildParams{ + Rule: android.WriteFile, + Output: updatableBcpPackages, + Args: map[string]string{ + // WriteFile automatically adds the last end-of-line. + "content": strings.Join(updatablePackages, "\\n"), + }, + }) + + rule := android.NewRuleBuilder() + rule.MissingDeps(missingDeps) + rule.Install(updatableBcpPackages, "/system/etc/"+updatableBcpPackagesName) + // TODO: Rename `profileInstalls` to `extraInstalls`? + // Maybe even move the field out of the bootImageConfig into some higher level type? + image.profileInstalls = append(image.profileInstalls, rule.Installs()...) + + return updatableBcpPackages + }).(android.WritablePath) +} + +var updatableBcpPackagesRuleKey = android.NewOnceKey("updatableBcpPackagesRule") + func dumpOatRules(ctx android.SingletonContext, image *bootImageConfig) { var allPhonies android.Paths for _, image := range image.variants { @@ -559,7 +678,7 @@ func dumpOatRules(ctx android.SingletonContext, image *bootImageConfig) { BuiltTool(ctx, "oatdumpd"). FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":"). FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocationsDeps, ":"). - FlagWithArg("--image=", strings.Join(image.imageLocations, ":")).Implicits(image.imagesDeps.Paths()). + 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-"+suffix, "dump oat boot "+arch.String()) @@ -573,10 +692,7 @@ func dumpOatRules(ctx android.SingletonContext, image *bootImageConfig) { Text("echo").FlagWithArg("Output in ", output.String()) rule.Build(pctx, ctx, "phony-dump-oat-boot-"+suffix, "dump oat boot "+arch.String()) - // TODO: We need to make imageLocations per-variant to make oatdump work on host. - if image.target.Os == android.Android { - allPhonies = append(allPhonies, phony) - } + allPhonies = append(allPhonies, phony) } phony := android.PathForPhony(ctx, "dump-oat-boot") @@ -612,25 +728,25 @@ func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) { if image != nil { ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", image.profileInstalls.String()) ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(image.dexPathsDeps.Strings(), " ")) - ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.dexLocationsDeps, " ")) + ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.getAnyAndroidVariant().dexLocationsDeps, " ")) var imageNames []string for _, current := range append(d.otherImages, image) { imageNames = append(imageNames, current.name) - for _, current := range current.variants { + for _, variant := range current.variants { suffix := "" - if current.target.Os.Class == android.Host { + if variant.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(), " ")) - ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, current.installs.String()) - ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, current.unstrippedInstalls.String()) + sfx := variant.name + suffix + "_" + variant.target.Arch.ArchType.String() + ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+sfx, variant.vdexInstalls.String()) + ctx.Strict("DEXPREOPT_IMAGE_"+sfx, variant.images.String()) + ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(variant.imagesDeps.Strings(), " ")) + ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, variant.installs.String()) + ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, variant.unstrippedInstalls.String()) } - - ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_"+current.name, strings.Join(current.imageLocations, ":")) + imageLocations := current.getAnyAndroidVariant().imageLocations() + ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_"+current.name, strings.Join(imageLocations, ":")) ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+current.name, current.zip.String()) } ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(imageNames, " ")) diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go index 94ca8bb97..127c20159 100644 --- a/java/dexpreopt_bootjars_test.go +++ b/java/dexpreopt_bootjars_test.go @@ -53,7 +53,7 @@ func TestDexpreoptBootJars(t *testing.T) { ctx := testContext() - ctx.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory) + RegisterDexpreoptBootJarsComponents(ctx) run(t, ctx, config) diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go index ffce2a9ff..066694cc3 100644 --- a/java/dexpreopt_config.go +++ b/java/dexpreopt_config.go @@ -79,6 +79,14 @@ func stemOf(moduleName string) string { return moduleName } +func getDexLocation(ctx android.PathContext, target android.Target, subdir string, name string) string { + if target.Os.Class == android.Host { + return filepath.Join(ctx.Config().Getenv("OUT_DIR"), "host", ctx.Config().PrebuiltOS(), subdir, name) + } else { + return filepath.Join("/", subdir, name) + } +} + var ( bootImageConfigKey = android.NewOnceKey("bootImageConfig") artBootImageName = "art" @@ -104,36 +112,23 @@ func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig { artSubdir := "apex/com.android.art/javalib" frameworkSubdir := "system/framework" - var artLocations, frameworkLocations []string - for _, m := range artModules { - artLocations = append(artLocations, filepath.Join("/"+artSubdir, stemOf(m)+".jar")) - } - for _, m := range frameworkModules { - frameworkLocations = append(frameworkLocations, filepath.Join("/"+frameworkSubdir, stemOf(m)+".jar")) - } - // ART config for the primary boot image in the ART apex. // It includes the Core Libraries. artCfg := bootImageConfig{ - extension: false, - name: artBootImageName, - stem: "boot", - installSubdir: artSubdir, - modules: artModules, - dexLocations: artLocations, - dexLocationsDeps: artLocations, + name: artBootImageName, + stem: "boot", + installSubdir: artSubdir, + modules: artModules, } // Framework config for the boot image extension. // It includes framework libraries and depends on the ART config. frameworkCfg := bootImageConfig{ - extension: true, - name: frameworkBootImageName, - stem: "boot", - installSubdir: frameworkSubdir, - modules: frameworkModules, - dexLocations: frameworkLocations, - dexLocationsDeps: append(artLocations, frameworkLocations...), + extends: &artCfg, + name: frameworkBootImageName, + stem: "boot", + installSubdir: frameworkSubdir, + modules: frameworkModules, } configs := map[string]*bootImageConfig{ @@ -149,8 +144,6 @@ func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig { // 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, "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. // Set up known paths for them, the singleton rules will copy them there. @@ -171,6 +164,10 @@ func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig { images: imageDir.Join(ctx, imageName), imagesDeps: c.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex"), } + for _, m := range c.modules { + variant.dexLocations = append(variant.dexLocations, getDexLocation(ctx, target, c.installSubdir, stemOf(m)+".jar")) + } + variant.dexLocationsDeps = variant.dexLocations c.variants = append(c.variants, variant) } @@ -181,8 +178,8 @@ func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig { frameworkCfg.dexPathsDeps = append(artCfg.dexPathsDeps, frameworkCfg.dexPathsDeps...) for i := range targets { frameworkCfg.variants[i].primaryImages = artCfg.variants[i].images + frameworkCfg.variants[i].dexLocationsDeps = append(artCfg.variants[i].dexLocations, frameworkCfg.variants[i].dexLocationsDeps...) } - frameworkCfg.imageLocations = append(artCfg.imageLocations, frameworkCfg.imageLocations...) return configs }).(map[string]*bootImageConfig) @@ -206,7 +203,7 @@ func defaultBootclasspath(ctx android.PathContext) []string { updatableBootclasspath[i] = dexpreopt.GetJarLocationFromApexJarPair(p) } - bootclasspath := append(copyOf(image.dexLocationsDeps), updatableBootclasspath...) + bootclasspath := append(copyOf(image.getAnyAndroidVariant().dexLocationsDeps), updatableBootclasspath...) return bootclasspath }) } @@ -221,7 +218,7 @@ func init() { func dexpreoptConfigMakevars(ctx android.MakeVarsContext) { ctx.Strict("PRODUCT_BOOTCLASSPATH", strings.Join(defaultBootclasspath(ctx), ":")) - ctx.Strict("PRODUCT_DEX2OAT_BOOTCLASSPATH", strings.Join(defaultBootImageConfig(ctx).dexLocationsDeps, ":")) + ctx.Strict("PRODUCT_DEX2OAT_BOOTCLASSPATH", strings.Join(defaultBootImageConfig(ctx).getAnyAndroidVariant().dexLocationsDeps, ":")) ctx.Strict("PRODUCT_SYSTEM_SERVER_CLASSPATH", strings.Join(systemServerClasspath(ctx), ":")) ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules, ":")) diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index 7e7e955f5..c7f7cbdfe 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -211,23 +211,30 @@ func stubFlagsRule(ctx android.SingletonContext) { // the greylists. func flagsRule(ctx android.SingletonContext) android.Path { var flagsCSV android.Paths - - var greylistIgnoreConflicts android.Path + var greylistRemovedApis android.Paths ctx.VisitAllModules(func(module android.Module) { if h, ok := module.(hiddenAPIIntf); ok { if csv := h.flagsCSV(); csv != nil { flagsCSV = append(flagsCSV, csv) } - } else if ds, ok := module.(*Droidstubs); ok && ctx.ModuleName(module) == "hiddenapi-lists-docs" { - greylistIgnoreConflicts = ds.removedDexApiFile + } else if ds, ok := module.(*Droidstubs); ok { + // Track @removed public and system APIs via corresponding droidstubs targets. + // These APIs are not present in the stubs, however, we have to keep allowing access + // to them at runtime. + if m := ctx.ModuleName(module); m == "api-stubs-docs" || m == "system-api-stubs-docs" { + greylistRemovedApis = append(greylistRemovedApis, ds.removedDexApiFile) + } } }) - if greylistIgnoreConflicts == nil { - ctx.Errorf("failed to find removed_dex_api_filename from hiddenapi-lists-docs module") - return nil - } + combinedRemovedApis := android.PathForOutput(ctx, "hiddenapi", "combined-removed-dex.txt") + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cat, + Inputs: greylistRemovedApis, + Output: combinedRemovedApis, + Description: "Combine removed apis for " + combinedRemovedApis.String(), + }) rule := android.NewRuleBuilder() @@ -242,8 +249,7 @@ func flagsRule(ctx android.SingletonContext) android.Path { Inputs(flagsCSV). FlagWithInput("--greylist ", android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist.txt")). - FlagWithInput("--greylist-ignore-conflicts ", - greylistIgnoreConflicts). + FlagWithInput("--greylist-ignore-conflicts ", combinedRemovedApis). FlagWithInput("--greylist-max-q ", android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-q.txt")). FlagWithInput("--greylist-max-p ", diff --git a/java/java.go b/java/java.go index 22d14ecfe..a8ca3ffef 100644 --- a/java/java.go +++ b/java/java.go @@ -325,6 +325,10 @@ type CompilerDeviceProperties struct { UncompressDex bool `blueprint:"mutated"` IsSDKLibrary bool `blueprint:"mutated"` + + // If true, generate the signature file of APK Signing Scheme V4, along side the signed APK file. + // Defaults to false. + V4_signature *bool } func (me *CompilerDeviceProperties) EffectiveOptimizeEnabled() bool { @@ -421,6 +425,8 @@ type Module struct { // list of the xref extraction files kytheFiles android.Paths + + distFile android.Path } func (j *Module) OutputFiles(tag string) (android.Paths, error) { @@ -540,9 +546,10 @@ func (s sdkDep) hasFrameworkLibs() bool { } type jniLib struct { - name string - path android.Path - target android.Target + name string + path android.Path + target android.Target + coverageFile android.OptionalPath } func (j *Module) shouldInstrument(ctx android.BaseModuleContext) bool { @@ -800,7 +807,7 @@ func (m *Module) getLinkType(name string) (ret linkType, stubs bool) { return javaModule, true case ver.kind == sdkModule: return javaModule, false - case name == "services-stubs": + case name == "android_system_server_stubs_current": return javaSystemServer, true case ver.kind == sdkSystemServer: return javaSystemServer, false @@ -1753,11 +1760,6 @@ func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu 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. - if sa, ok := dep.(android.SdkAware); ok && sa.IsInAnySdk() { - return true - } return false } @@ -1777,9 +1779,18 @@ func (j *Module) IsInstallable() bool { // Java libraries (.jar file) // +type LibraryProperties struct { + Dist struct { + // The tag of the output of this module that should be output. + Tag *string `android:"arch_variant"` + } `android:"arch_variant"` +} + type Library struct { Module + libraryProperties LibraryProperties + InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths) } @@ -1823,6 +1834,15 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"), ctx.ModuleName()+".jar", j.outputFile, extraInstallDeps...) } + + // Verify Dist.Tag is set to a supported output + if j.libraryProperties.Dist.Tag != nil { + distFiles, err := j.OutputFiles(*j.libraryProperties.Dist.Tag) + if err != nil { + ctx.PropertyErrorf("dist.tag", "%s", err.Error()) + } + j.distFile = distFiles[0] + } } func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) { @@ -1943,7 +1963,8 @@ func LibraryFactory() android.Module { &module.Module.properties, &module.Module.deviceProperties, &module.Module.dexpreoptProperties, - &module.Module.protoProperties) + &module.Module.protoProperties, + &module.libraryProperties) android.InitApexModule(module) android.InitSdkAwareModule(module) @@ -2338,6 +2359,12 @@ type ImportProperties struct { // set the name of the output Stem *string + + Aidl struct { + // directories that should be added as include directories for any aidl sources of modules + // that depend on this module, as well as to aidl for this module. + Export_include_dirs []string + } } type Import struct { @@ -2351,6 +2378,7 @@ type Import struct { combinedClasspathFile android.Path exportedSdkLibs []string + exportAidlIncludeDirs android.Paths } func (j *Import) sdkVersion() sdkSpec { @@ -2424,6 +2452,8 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"), jarName, outputFile) } + + j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs) } var _ Dependency = (*Import)(nil) @@ -2458,7 +2488,7 @@ func (j *Import) DexJar() android.Path { } func (j *Import) AidlIncludeDirs() android.Paths { - return nil + return j.exportAidlIncludeDirs } func (j *Import) ExportedSdkLibs() []string { @@ -2478,11 +2508,6 @@ func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu 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. - if sa, ok := dep.(android.SdkAware); ok && sa.IsInAnySdk() { - return true - } return false } diff --git a/java/java_test.go b/java/java_test.go index 6d972bebd..e8a1a7c83 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -1491,3 +1491,27 @@ func checkBootClasspathForSystemModule(t *testing.T, ctx *android.TestContext, m t.Errorf("bootclasspath of %q must start with --system and end with %q, but was %#v.", moduleName, expectedSuffix, bootClasspath) } } + +func TestAidlExportIncludeDirsFromImports(t *testing.T) { + ctx, _ := testJava(t, ` + java_library { + name: "foo", + srcs: ["aidl/foo/IFoo.aidl"], + libs: ["bar"], + } + + java_import { + name: "bar", + jars: ["a.jar"], + aidl: { + export_include_dirs: ["aidl/bar"], + }, + } + `) + + aidlCommand := ctx.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command + expectedAidlFlag := "-Iaidl/bar" + if !strings.Contains(aidlCommand, expectedAidlFlag) { + t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag) + } +} diff --git a/java/sdk.go b/java/sdk.go index ded2a061b..0e132d399 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -406,7 +406,7 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep return toModule([]string{"android_module_lib_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx)) case sdkSystemServer: // TODO(146757305): provide .apk and .aidl that have more APIs for modules - return toModule([]string{"android_module_lib_stubs_current", "services-stubs"}, "framework-res", sdkFrameworkAidlPath(ctx)) + return toModule([]string{"android_system_server_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx)) default: panic(fmt.Errorf("invalid sdk %q", sdkVersion.raw)) } diff --git a/java/sdk_library.go b/java/sdk_library.go index 6921114bf..efee7da23 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -18,7 +18,6 @@ import ( "android/soong/android" "fmt" - "io" "path" "path/filepath" "sort" @@ -87,6 +86,9 @@ type apiScope struct { // *current. Older stubs library built with a numbered SDK version is created from // the prebuilt jar. sdkVersion string + + // Extra arguments to pass to droidstubs for this scope. + droidstubsArgs []string } // Initialize a scope, creating and adding appropriate dependency tags @@ -132,6 +134,7 @@ var ( moduleSuffix: sdkSystemApiSuffix, apiFileMakeVariableSuffix: "_SYSTEM", sdkVersion: "system_current", + droidstubsArgs: []string{"-showAnnotation android.annotation.SystemApi"}, }) apiScopeTest = initApiScope(&apiScope{ name: "test", @@ -139,6 +142,7 @@ var ( moduleSuffix: sdkTestApiSuffix, apiFileMakeVariableSuffix: "_TEST", sdkVersion: "test_current", + droidstubsArgs: []string{"-showAnnotation android.annotation.TestApi"}, }) allApiScopes = apiScopes{ apiScopePublic, @@ -328,41 +332,6 @@ func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries { entriesList := module.Library.AndroidMkEntries() entries := &entriesList[0] entries.Required = append(entries.Required, module.xmlFileName()) - - entries.ExtraFooters = []android.AndroidMkExtraFootersFunc{ - func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) { - if !Bool(module.sdkLibraryProperties.No_dist) { - // Create a phony module that installs the impl library, for the case when this lib is - // in PRODUCT_PACKAGES. - owner := module.ModuleBase.Owner() - if owner == "" { - if Bool(module.sdkLibraryProperties.Core_lib) { - owner = "core" - } else { - owner = "android" - } - } - - // Create dist rules to install the stubs libs and api files to the dist dir - for _, apiScope := range module.getActiveApiScopes() { - if scopePaths, ok := module.scopePaths[apiScope]; ok { - if len(scopePaths.stubsHeaderPath) == 1 { - fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ - scopePaths.stubsImplPath.Strings()[0]+ - ":"+path.Join("apistubs", owner, apiScope.name, - module.BaseModuleName()+".jar")+")") - } - if scopePaths.apiFilePath != nil { - fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ - scopePaths.apiFilePath.String()+ - ":"+path.Join("apistubs", owner, apiScope.name, "api", - module.BaseModuleName()+".txt")+")") - } - } - } - } - }, - } return entriesList } @@ -386,6 +355,17 @@ func (module *SdkLibrary) xmlFileName() string { return module.BaseModuleName() + sdkXmlFileSuffix } +// The dist path of the stub artifacts +func (module *SdkLibrary) apiDistPath(apiScope *apiScope) string { + if module.ModuleBase.Owner() != "" { + return path.Join("apistubs", module.ModuleBase.Owner(), apiScope.name) + } else if Bool(module.sdkLibraryProperties.Core_lib) { + return path.Join("apistubs", "core", apiScope.name) + } else { + return path.Join("apistubs", "android", apiScope.name) + } +} + // Get the sdk version for use when compiling the stubs library. func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.LoadHookContext, apiScope *apiScope) string { sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library)) @@ -438,6 +418,12 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.LoadHookContext, apiSc Srcs []string Javacflags []string } + Dist struct { + Targets []string + Dest *string + Dir *string + Tag *string + } }{} props.Name = proptools.StringPtr(module.stubsName(apiScope)) @@ -466,11 +452,18 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.LoadHookContext, apiSc } else if module.SystemExtSpecific() { props.System_ext_specific = proptools.BoolPtr(true) } + // Dist the class jar artifact for sdk builds. + if !Bool(module.sdkLibraryProperties.No_dist) { + props.Dist.Targets = []string{"sdk", "win_sdk"} + props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.BaseModuleName())) + props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope)) + props.Dist.Tag = proptools.StringPtr(".jar") + } mctx.CreateModule(LibraryFactory, &props) } -// Creates a droiddoc module that creates stubs source files from the given full source +// Creates a droidstubs module that creates stubs source files from the given full source // files func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiScope *apiScope) { props := struct { @@ -497,6 +490,11 @@ func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiSc Include_dirs []string Local_include_dirs []string } + Dist struct { + Targets []string + Dest *string + Dir *string + } }{} sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library)) @@ -523,15 +521,15 @@ func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiSc props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs - droiddocArgs := []string{} + droidstubsArgs := []string{} if len(module.sdkLibraryProperties.Api_packages) != 0 { - droiddocArgs = append(droiddocArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":")) + droidstubsArgs = append(droidstubsArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":")) } if len(module.sdkLibraryProperties.Hidden_api_packages) != 0 { - droiddocArgs = append(droiddocArgs, + droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(module.sdkLibraryProperties.Hidden_api_packages, " --hide-package ")) } - droiddocArgs = append(droiddocArgs, module.sdkLibraryProperties.Droiddoc_options...) + droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...) disabledWarnings := []string{ "MissingPermission", "BroadcastBehavior", @@ -543,16 +541,12 @@ func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiSc "Todo", "Typo", } - droiddocArgs = append(droiddocArgs, android.JoinWithPrefix(disabledWarnings, "--hide ")) + droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide ")) - switch apiScope { - case apiScopeSystem: - droiddocArgs = append(droiddocArgs, "-showAnnotation android.annotation.SystemApi") - case apiScopeTest: - droiddocArgs = append(droiddocArgs, " -showAnnotation android.annotation.TestApi") - } + // Add in scope specific arguments. + droidstubsArgs = append(droidstubsArgs, apiScope.droidstubsArgs...) props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files - props.Args = proptools.StringPtr(strings.Join(droiddocArgs, " ")) + props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " ")) // List of APIs identified from the provided source files are created. They are later // compared against to the not-yet-released (a.k.a current) list of APIs and to the @@ -578,6 +572,13 @@ func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiSc module.latestRemovedApiFilegroupName(apiScope)) props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true) + // Dist the api txt artifact for sdk builds. + if !Bool(module.sdkLibraryProperties.No_dist) { + props.Dist.Targets = []string{"sdk", "win_sdk"} + props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.txt", module.BaseModuleName())) + props.Dist.Dir = proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api")) + } + mctx.CreateModule(DroidstubsFactory, &props) } diff --git a/java/sdk_test.go b/java/sdk_test.go index ea6733d86..088db9e70 100644 --- a/java/sdk_test.go +++ b/java/sdk_test.go @@ -222,9 +222,9 @@ func TestClasspath(t *testing.T) { { name: "system_server_current", properties: `sdk_version: "system_server_current",`, - bootclasspath: []string{"android_module_lib_stubs_current", "services-stubs", "core-lambda-stubs"}, + bootclasspath: []string{"android_system_server_stubs_current", "core-lambda-stubs"}, system: "core-current-stubs-system-modules", - java9classpath: []string{"android_module_lib_stubs_current", "services-stubs"}, + java9classpath: []string{"android_system_server_stubs_current"}, aidl: "-p" + buildDir + "/framework.aidl", }, } diff --git a/java/testing.go b/java/testing.go index 5b6a39b2a..6929bb724 100644 --- a/java/testing.go +++ b/java/testing.go @@ -50,6 +50,8 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string "api/test-current.txt": nil, "api/test-removed.txt": nil, "framework/aidl/a.aidl": nil, + "aidl/foo/IFoo.aidl": nil, + "aidl/bar/IBar.aidl": nil, "assets_a/a": nil, "assets_b/b": nil, @@ -148,7 +150,7 @@ func GatherRequiredDepsForTest() string { "android_system_stubs_current", "android_test_stubs_current", "android_module_lib_stubs_current", - "services-stubs", + "android_system_server_stubs_current", "core.current.stubs", "core.platform.api.stubs", "kotlin-stdlib", diff --git a/rust/compiler.go b/rust/compiler.go index 4593165f4..81b258c1e 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -222,7 +222,10 @@ func (compiler *baseCompiler) installDir(ctx ModuleContext) android.InstallPath if ctx.toolchain().Is64Bit() && compiler.dir64 != "" { dir = compiler.dir64 } - if !ctx.Host() || ctx.Target().NativeBridge == android.NativeBridgeEnabled { + if ctx.Target().NativeBridge == android.NativeBridgeEnabled { + dir = filepath.Join(dir, ctx.Target().NativeBridgeRelativePath) + } + if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) { dir = filepath.Join(dir, ctx.Arch().ArchType.String()) } return android.PathForModuleInstall(ctx, dir, compiler.subDir, diff --git a/rust/library.go b/rust/library.go index 0cf2dd045..bf863bb67 100644 --- a/rust/library.go +++ b/rust/library.go @@ -318,6 +318,8 @@ func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { if ctx.toolchain().Bionic() && (library.dylib() || library.shared()) { deps = library.baseCompiler.bionicDeps(ctx, deps) + deps.CrtBegin = "crtbegin_so" + deps.CrtEnd = "crtend_so" } return deps diff --git a/scripts/OWNERS b/scripts/OWNERS index 9e97a6011..dd0966fa5 100644 --- a/scripts/OWNERS +++ b/scripts/OWNERS @@ -1,2 +1,3 @@ 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 +per-file build-aml-prebuilts.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com diff --git a/scripts/build-aml-prebuilts.sh b/scripts/build-aml-prebuilts.sh index 7e3a82c17..35a6ff337 100755 --- a/scripts/build-aml-prebuilts.sh +++ b/scripts/build-aml-prebuilts.sh @@ -58,6 +58,7 @@ cat > ${SOONG_VARS}.new << EOF "DeviceName": "generic_arm64", "HostArch": "x86_64", + "HostSecondaryArch": "x86", "Aml_abis": true, "UseGoma": ${USE_GOMA} diff --git a/scripts/transitive-deps.sh b/scripts/transitive-deps.sh index 23121c6b7..c6f8b76e4 100755 --- a/scripts/transitive-deps.sh +++ b/scripts/transitive-deps.sh @@ -469,7 +469,9 @@ case "${notices_out}" in fi readonly hashedNotice="${tmpFiles}/hashednotices" ( # md5sum outputs checksum space indicator(space or *) filename newline + set +e sort -u "${allNotice}" | tr '\n' '\0' | xargs -0 -r md5sum 2>/dev/null + set -e # use sed to replace space and indicator with separator ) > "${hashedNotice}" if ${showProgress}; then diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go index ca40afd04..780da9fc3 100644 --- a/sdk/cc_sdk_test.go +++ b/sdk/cc_sdk_test.go @@ -32,6 +32,7 @@ func testSdkWithCc(t *testing.T, bp string) *testSdkResult { "arm64/include/Arm64Test.h": nil, "libfoo.so": nil, "aidl/foo/bar/Test.aidl": nil, + "some/where/stubslib.map.txt": nil, } return testSdkWithFs(t, bp, fs) } @@ -48,7 +49,6 @@ func TestSdkIsCompileMultilibBoth(t *testing.T) { cc_library_shared { name: "sdkmember", srcs: ["Test.cpp"], - system_shared_libs: [], stl: "none", } `) @@ -178,13 +178,11 @@ func TestHostSdkWithCc(t *testing.T) { cc_library_host_shared { name: "sdkshared", - system_shared_libs: [], stl: "none", } cc_library_host_static { name: "sdkstatic", - system_shared_libs: [], stl: "none", } `) @@ -201,25 +199,21 @@ func TestSdkWithCc(t *testing.T) { cc_library_shared { name: "sdkshared", - system_shared_libs: [], stl: "none", } cc_library_static { name: "sdkstatic", - system_shared_libs: [], stl: "none", } cc_library { name: "sdkboth1", - system_shared_libs: [], stl: "none", } cc_library { name: "sdkboth2", - system_shared_libs: [], stl: "none", } `) @@ -295,7 +289,6 @@ func TestSnapshotWithCcDuplicateHeaders(t *testing.T) { "Test.cpp", ], export_include_dirs: ["include"], - system_shared_libs: [], stl: "none", } @@ -305,7 +298,6 @@ func TestSnapshotWithCcDuplicateHeaders(t *testing.T) { "Test.cpp", ], export_include_dirs: ["include"], - system_shared_libs: [], stl: "none", } `) @@ -342,7 +334,6 @@ func TestSnapshotWithCcSharedLibraryCommonProperties(t *testing.T) { export_system_include_dirs: ["arm64/include"], }, }, - system_shared_libs: [], stl: "none", } `) @@ -410,7 +401,6 @@ func TestSnapshotWithCcBinary(t *testing.T) { "Test.cpp", ], compile_multilib: "both", - system_shared_libs: [], stl: "none", } `) @@ -485,7 +475,6 @@ func TestMultipleHostOsTypesSnapshotWithCcBinary(t *testing.T) { "Test.cpp", ], compile_multilib: "both", - system_shared_libs: [], stl: "none", target: { windows: { @@ -586,7 +575,6 @@ func TestSnapshotWithCcSharedLibrary(t *testing.T) { aidl: { export_aidl_headers: true, }, - system_shared_libs: [], stl: "none", } `) @@ -673,7 +661,6 @@ func TestSnapshotWithCcSharedLibrarySharedLibs(t *testing.T) { srcs: [ "Test.cpp", ], - system_shared_libs: [], stl: "none", } @@ -714,7 +701,6 @@ func TestSnapshotWithCcSharedLibrarySharedLibs(t *testing.T) { }, }, }, - system_shared_libs: [], stl: "none", } `) @@ -864,7 +850,6 @@ func TestHostSnapshotWithCcSharedLibrary(t *testing.T) { aidl: { export_aidl_headers: true, }, - system_shared_libs: [], stl: "none", sdk_version: "minimum", } @@ -960,7 +945,6 @@ func TestMultipleHostOsTypesSnapshotWithCcSharedLibrary(t *testing.T) { srcs: [ "Test.cpp", ], - system_shared_libs: [], stl: "none", target: { windows: { @@ -1050,7 +1034,6 @@ func TestSnapshotWithCcStaticLibrary(t *testing.T) { aidl: { export_aidl_headers: true, }, - system_shared_libs: [], stl: "none", } `) @@ -1137,7 +1120,6 @@ func TestHostSnapshotWithCcStaticLibrary(t *testing.T) { aidl: { export_aidl_headers: true, }, - system_shared_libs: [], stl: "none", } `) @@ -1219,7 +1201,6 @@ func TestSnapshotWithCcLibrary(t *testing.T) { "Test.cpp", ], export_include_dirs: ["include"], - system_shared_libs: [], stl: "none", } `) @@ -1322,7 +1303,6 @@ func TestHostSnapshotWithMultiLib64(t *testing.T) { aidl: { export_aidl_headers: true, }, - system_shared_libs: [], stl: "none", } `) @@ -1393,7 +1373,6 @@ func TestSnapshotWithCcHeadersLibrary(t *testing.T) { cc_library_headers { name: "mynativeheaders", export_include_dirs: ["include"], - system_shared_libs: [], stl: "none", } `) @@ -1444,7 +1423,6 @@ func TestHostSnapshotWithCcHeadersLibrary(t *testing.T) { device_supported: false, host_supported: true, export_include_dirs: ["include"], - system_shared_libs: [], stl: "none", } `) @@ -1498,7 +1476,6 @@ func TestDeviceAndHostSnapshotWithCcHeadersLibrary(t *testing.T) { cc_library_headers { name: "mynativeheaders", host_supported: true, - system_shared_libs: [], stl: "none", export_system_include_dirs: ["include"], target: { @@ -1561,3 +1538,265 @@ include-host/HostTest.h -> include/include-host/HostTest.h `), ) } + +func TestSystemSharedLibPropagation(t *testing.T) { + // b/145598135 - Generating host snapshots for anything other than linux is not supported. + SkipIfNotLinux(t) + + result := testSdkWithCc(t, ` + sdk { + name: "mysdk", + native_shared_libs: ["sslnil", "sslempty", "sslnonempty"], + } + + cc_library { + name: "sslnil", + host_supported: true, + } + + cc_library { + name: "sslempty", + system_shared_libs: [], + } + + cc_library { + name: "sslnonempty", + system_shared_libs: ["sslnil"], + } + `) + + result.CheckSnapshot("mysdk", "", + checkAndroidBpContents(` +// This is auto-generated. DO NOT EDIT. + +cc_prebuilt_library_shared { + name: "mysdk_sslnil@current", + sdk_member_name: "sslnil", + installable: false, + arch: { + arm64: { + srcs: ["arm64/lib/sslnil.so"], + }, + arm: { + srcs: ["arm/lib/sslnil.so"], + }, + }, +} + +cc_prebuilt_library_shared { + name: "sslnil", + prefer: false, + arch: { + arm64: { + srcs: ["arm64/lib/sslnil.so"], + }, + arm: { + srcs: ["arm/lib/sslnil.so"], + }, + }, +} + +cc_prebuilt_library_shared { + name: "mysdk_sslempty@current", + sdk_member_name: "sslempty", + installable: false, + system_shared_libs: [], + arch: { + arm64: { + srcs: ["arm64/lib/sslempty.so"], + }, + arm: { + srcs: ["arm/lib/sslempty.so"], + }, + }, +} + +cc_prebuilt_library_shared { + name: "sslempty", + prefer: false, + system_shared_libs: [], + arch: { + arm64: { + srcs: ["arm64/lib/sslempty.so"], + }, + arm: { + srcs: ["arm/lib/sslempty.so"], + }, + }, +} + +cc_prebuilt_library_shared { + name: "mysdk_sslnonempty@current", + sdk_member_name: "sslnonempty", + installable: false, + system_shared_libs: ["mysdk_sslnil@current"], + arch: { + arm64: { + srcs: ["arm64/lib/sslnonempty.so"], + }, + arm: { + srcs: ["arm/lib/sslnonempty.so"], + }, + }, +} + +cc_prebuilt_library_shared { + name: "sslnonempty", + prefer: false, + system_shared_libs: ["sslnil"], + arch: { + arm64: { + srcs: ["arm64/lib/sslnonempty.so"], + }, + arm: { + srcs: ["arm/lib/sslnonempty.so"], + }, + }, +} + +sdk_snapshot { + name: "mysdk@current", + native_shared_libs: [ + "mysdk_sslnil@current", + "mysdk_sslempty@current", + "mysdk_sslnonempty@current", + ], +} +`)) + + result = testSdkWithCc(t, ` + sdk { + name: "mysdk", + host_supported: true, + native_shared_libs: ["sslvariants"], + } + + cc_library { + name: "sslvariants", + host_supported: true, + target: { + android: { + system_shared_libs: [], + }, + }, + } + `) + + result.CheckSnapshot("mysdk", "", + checkAndroidBpContents(` +// This is auto-generated. DO NOT EDIT. + +cc_prebuilt_library_shared { + name: "mysdk_sslvariants@current", + sdk_member_name: "sslvariants", + host_supported: true, + installable: false, + target: { + android: { + system_shared_libs: [], + }, + android_arm64: { + srcs: ["android/arm64/lib/sslvariants.so"], + }, + android_arm: { + srcs: ["android/arm/lib/sslvariants.so"], + }, + linux_glibc_x86_64: { + srcs: ["linux_glibc/x86_64/lib/sslvariants.so"], + }, + linux_glibc_x86: { + srcs: ["linux_glibc/x86/lib/sslvariants.so"], + }, + }, +} + +cc_prebuilt_library_shared { + name: "sslvariants", + prefer: false, + host_supported: true, + target: { + android: { + system_shared_libs: [], + }, + android_arm64: { + srcs: ["android/arm64/lib/sslvariants.so"], + }, + android_arm: { + srcs: ["android/arm/lib/sslvariants.so"], + }, + linux_glibc_x86_64: { + srcs: ["linux_glibc/x86_64/lib/sslvariants.so"], + }, + linux_glibc_x86: { + srcs: ["linux_glibc/x86/lib/sslvariants.so"], + }, + }, +} + +sdk_snapshot { + name: "mysdk@current", + host_supported: true, + native_shared_libs: ["mysdk_sslvariants@current"], +} +`)) +} + +func TestStubsLibrary(t *testing.T) { + result := testSdkWithCc(t, ` + sdk { + name: "mysdk", + native_shared_libs: ["stubslib"], + } + + cc_library { + name: "stubslib", + stubs: { + symbol_file: "some/where/stubslib.map.txt", + versions: ["1", "2", "3"], + }, + } + `) + + result.CheckSnapshot("mysdk", "", + checkAndroidBpContents(` +// This is auto-generated. DO NOT EDIT. + +cc_prebuilt_library_shared { + name: "mysdk_stubslib@current", + sdk_member_name: "stubslib", + installable: false, + stubs: { + versions: ["3"], + }, + arch: { + arm64: { + srcs: ["arm64/lib/stubslib.so"], + }, + arm: { + srcs: ["arm/lib/stubslib.so"], + }, + }, +} + +cc_prebuilt_library_shared { + name: "stubslib", + prefer: false, + stubs: { + versions: ["3"], + }, + arch: { + arm64: { + srcs: ["arm64/lib/stubslib.so"], + }, + arm: { + srcs: ["arm/lib/stubslib.so"], + }, + }, +} + +sdk_snapshot { + name: "mysdk@current", + native_shared_libs: ["mysdk_stubslib@current"], +} +`)) +} diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go index cbffb501b..4a2c05387 100644 --- a/sdk/java_sdk_test.go +++ b/sdk/java_sdk_test.go @@ -53,30 +53,18 @@ func TestBasicSdkWithJavaLibrary(t *testing.T) { system_modules: "none", sdk_version: "none", host_supported: true, - apex_available: [ - "//apex_available:platform", - "//apex_available:anyapex", - ], } java_import { name: "sdkmember_mysdk_1", sdk_member_name: "sdkmember", host_supported: true, - apex_available: [ - "//apex_available:platform", - "//apex_available:anyapex", - ], } java_import { name: "sdkmember_mysdk_2", sdk_member_name: "sdkmember", host_supported: true, - apex_available: [ - "//apex_available:platform", - "//apex_available:anyapex", - ], } java_library { diff --git a/sdk/sdk.go b/sdk/sdk.go index dabdf851e..cb5a6053d 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -312,7 +312,7 @@ func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) { ctx.BottomUp("SdkMemberInterVersion", memberInterVersionMutator).Parallel() } -// RegisterPostDepshMutators registers post-deps mutators to support modules implementing SdkAware +// RegisterPostDepsMutators registers post-deps mutators to support modules implementing SdkAware // interface and the sdk module type. This function has been made public to be called by tests // outside of the sdk package func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) { @@ -431,23 +431,31 @@ func sdkDepsReplaceMutator(mctx android.BottomUpMutatorContext) { } } -// Step 6: ensure that the dependencies from outside of the APEX are all from the required SDKs +// Step 6: ensure that the dependencies outside of the APEX are all from the required SDKs func sdkRequirementsMutator(mctx android.TopDownMutatorContext) { if m, ok := mctx.Module().(interface { - DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool - RequiredSdks() android.SdkRefs + android.DepIsInSameApex + android.RequiredSdks }); ok { requiredSdks := m.RequiredSdks() if len(requiredSdks) == 0 { return } mctx.VisitDirectDeps(func(dep android.Module) { - if mctx.OtherModuleDependencyTag(dep) == android.DefaultsDepTag { + tag := mctx.OtherModuleDependencyTag(dep) + if tag == android.DefaultsDepTag { // dependency to defaults is always okay return } - // If the dep is from outside of the APEX, but is not in any of the + // Ignore the dependency from the unversioned member to any versioned members as an + // apex that depends on the unversioned member will not also be depending on a versioned + // member. + if _, ok := tag.(sdkMemberVersionedDepTag); ok { + return + } + + // If the dep is outside of the APEX, but is not in any of the // required SDKs, we know that the dep is a violation. if sa, ok := dep.(android.SdkAware); ok { if !m.DepIsInSameApex(mctx, dep) && !requiredSdks.Contains(sa.ContainingSdk()) { diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go index 65dbb22a9..a2e35d9b0 100644 --- a/sysprop/sysprop_library.go +++ b/sysprop/sysprop_library.go @@ -18,6 +18,7 @@ import ( "fmt" "io" "path" + "sync" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -115,6 +116,7 @@ func syspropJavaGenFactory() android.Module { type syspropLibrary struct { android.ModuleBase + android.ApexModuleBase properties syspropLibraryProperties @@ -154,8 +156,21 @@ type syspropLibraryProperties struct { var ( pctx = android.NewPackageContext("android/soong/sysprop") syspropCcTag = dependencyTag{name: "syspropCc"} + + syspropLibrariesKey = android.NewOnceKey("syspropLibraries") + syspropLibrariesLock sync.Mutex ) +func syspropLibraries(config android.Config) *[]string { + return config.Once(syspropLibrariesKey, func() interface{} { + return &[]string{} + }).(*[]string) +} + +func SyspropLibraries(config android.Config) []string { + return append([]string{}, *syspropLibraries(config)...) +} + func init() { android.RegisterModuleType("sysprop_library", syspropLibraryFactory) } @@ -195,6 +210,10 @@ func (m *syspropLibrary) HasPublicStub() bool { return proptools.Bool(m.properties.Public_stub) } +func (m *syspropLibrary) CurrentSyspropApiFile() android.Path { + return m.currentApiFile +} + func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { baseModuleName := m.BaseModuleName() @@ -296,6 +315,7 @@ func syspropLibraryFactory() android.Module { &m.properties, ) android.InitAndroidModule(m) + android.InitApexModule(m) android.AddLoadHook(m, func(ctx android.LoadHookContext) { syspropLibraryHook(ctx, m) }) return m } @@ -323,6 +343,7 @@ type ccLibraryProperties struct { Recovery_available *bool Vendor_available *bool Host_supported *bool + Apex_available []string } type javaLibraryProperties struct { @@ -411,6 +432,7 @@ func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { ccProps.Recovery_available = m.properties.Recovery_available ccProps.Vendor_available = m.properties.Vendor_available ccProps.Host_supported = m.properties.Host_supported + ccProps.Apex_available = m.ApexProperties.Apex_available ctx.CreateModule(cc.LibraryFactory, &ccProps) scope := "internal" @@ -463,6 +485,12 @@ func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { Stem: proptools.StringPtr(m.BaseModuleName()), }) } + + syspropLibrariesLock.Lock() + defer syspropLibrariesLock.Unlock() + + libraries := syspropLibraries(ctx.Config()) + *libraries = append(*libraries, ctx.ModuleName()) } func syspropDepsMutator(ctx android.BottomUpMutatorContext) { diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go index 51da22205..850338675 100644 --- a/sysprop/sysprop_test.go +++ b/sysprop/sysprop_test.go @@ -15,6 +15,8 @@ package sysprop import ( + "reflect" + "android/soong/android" "android/soong/cc" "android/soong/java" @@ -157,6 +159,7 @@ func TestSyspropLibrary(t *testing.T) { ctx := test(t, ` sysprop_library { name: "sysprop-platform", + apex_available: ["//apex_available:platform"], srcs: ["android/sysprop/PlatformProperties.sysprop"], api_packages: ["android.sysprop"], property_owner: "Platform", @@ -305,7 +308,12 @@ func TestSyspropLibrary(t *testing.T) { "android_arm64_armv8-a_shared", "android_arm64_armv8-a_static", } { - ctx.ModuleForTests("libsysprop-platform", variant) + library := ctx.ModuleForTests("libsysprop-platform", variant).Module().(*cc.Module) + expectedApexAvailableOnLibrary := []string{"//apex_available:platform"} + if !reflect.DeepEqual(library.ApexProperties.Apex_available, expectedApexAvailableOnLibrary) { + t.Errorf("apex available property on libsysprop-platform must be %#v, but was %#v.", + expectedApexAvailableOnLibrary, library.ApexProperties.Apex_available) + } // core variant of vendor-owned sysprop_library is for product ctx.ModuleForTests("libsysprop-vendor", variant) diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go index 95d049aed..0bcdccb7b 100644 --- a/ui/build/cleanbuild.go +++ b/ui/build/cleanbuild.go @@ -99,6 +99,7 @@ func installClean(ctx Context, config Config, what int) { hostOut("sdk_addon"), hostOut("testcases"), hostOut("vts"), + hostOut("vts10"), hostOut("vts-core"), productOut("*.img"), productOut("*.zip"), diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go index 2de772b00..4c3bac307 100644 --- a/ui/build/sandbox_linux.go +++ b/ui/build/sandbox_linux.go @@ -54,6 +54,9 @@ var sandboxConfig struct { working bool group string + srcDir string + outDir string + distDir string } func (c *Cmd) sandboxSupported() bool { @@ -72,15 +75,34 @@ func (c *Cmd) sandboxSupported() bool { sandboxConfig.group = "nobody" } - cmd := exec.CommandContext(c.ctx.Context, nsjailPath, + sandboxConfig.srcDir = absPath(c.ctx, ".") + sandboxConfig.outDir = absPath(c.ctx, c.config.OutDir()) + sandboxConfig.distDir = absPath(c.ctx, c.config.DistDir()) + + sandboxArgs := []string{ "-H", "android-build", "-e", "-u", "nobody", "-g", sandboxConfig.group, - "-B", "/", + "-R", "/", + "-B", sandboxConfig.srcDir, + "-B", "/tmp", + "-B", sandboxConfig.outDir, + } + + if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) { + //Mount dist dir as read-write if it already exists + sandboxArgs = append(sandboxArgs, "-B", + sandboxConfig.distDir) + } + + sandboxArgs = append(sandboxArgs, "--disable_clone_newcgroup", "--", "/bin/bash", "-c", `if [ $(hostname) == "android-build" ]; then echo "Android" "Success"; else echo Failure; fi`) + + cmd := exec.CommandContext(c.ctx.Context, nsjailPath, sandboxArgs...) + cmd.Env = c.config.Environment().Environ() c.ctx.Verboseln(cmd.Args) @@ -144,8 +166,17 @@ func (c *Cmd) wrapSandbox() { "--rlimit_fsize", "soft", "--rlimit_nofile", "soft", - // For now, just map everything. Eventually we should limit this, especially to make most things readonly. - "-B", "/", + // For now, just map everything. Make most things readonly. + "-R", "/", + + // Mount source are read-write + "-B", sandboxConfig.srcDir, + + //Mount out dir as read-write + "-B", sandboxConfig.outDir, + + // Mount a writable tmp dir + "-B", "/tmp", // Disable newcgroup for now, since it may require newer kernels // TODO: try out cgroups @@ -155,6 +186,11 @@ func (c *Cmd) wrapSandbox() { "-q", } + if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) { + //Mount dist dir as read-write if it already exists + sandboxArgs = append(sandboxArgs, "-B", sandboxConfig.distDir) + } + if c.Sandbox.AllowBuildBrokenUsesNetwork && c.config.BuildBrokenUsesNetwork() { c.ctx.Printf("AllowBuildBrokenUsesNetwork: %v", c.Sandbox.AllowBuildBrokenUsesNetwork) c.ctx.Printf("BuildBrokenUsesNetwork: %v", c.config.BuildBrokenUsesNetwork()) |