Implement mixed builds for apex modules, take 2.
* Add ApexCqueryInfo to obtain apex artifacts used by the makefile generator and downstream modules * Refactor code common to GenerateAndroidBuildActions and ProcessBazelQueryResponse * Implement android.MixedBuildBuildable for modules * Enable mixed build for apex modules with payload_type:"image" The first take6a2b7c40b
was setting compressed APEX suffix incorrectly, and was reverted in8a3c91494
. Fixes: 239925080 239695521 232085015 Test: treehugger Change-Id: I1720f8db3c7cc773183d25a815d9b7eeaf7c73ad
This commit is contained in:
259
apex/apex.go
259
apex/apex.go
@@ -17,6 +17,7 @@
|
||||
package apex
|
||||
|
||||
import (
|
||||
"android/soong/bazel/cquery"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
@@ -1803,6 +1804,184 @@ func (f fsType) string() string {
|
||||
}
|
||||
}
|
||||
|
||||
var _ android.MixedBuildBuildable = (*apexBundle)(nil)
|
||||
|
||||
func (a *apexBundle) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
|
||||
return ctx.ModuleType() == "apex" && a.properties.ApexType == imageApex
|
||||
}
|
||||
|
||||
func (a *apexBundle) QueueBazelCall(ctx android.BaseModuleContext) {
|
||||
bazelCtx := ctx.Config().BazelContext
|
||||
bazelCtx.QueueBazelRequest(a.GetBazelLabel(ctx, a), cquery.GetApexInfo, android.GetConfigKey(ctx))
|
||||
}
|
||||
|
||||
func (a *apexBundle) ProcessBazelQueryResponse(ctx android.ModuleContext) {
|
||||
if !a.commonBuildActions(ctx) {
|
||||
return
|
||||
}
|
||||
|
||||
a.setApexTypeAndSuffix(ctx)
|
||||
a.setPayloadFsType(ctx)
|
||||
a.setSystemLibLink(ctx)
|
||||
|
||||
if a.properties.ApexType != zipApex {
|
||||
a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, a.primaryApexType)
|
||||
}
|
||||
|
||||
bazelCtx := ctx.Config().BazelContext
|
||||
outputs, err := bazelCtx.GetApexInfo(a.GetBazelLabel(ctx, a), android.GetConfigKey(ctx))
|
||||
if err != nil {
|
||||
ctx.ModuleErrorf(err.Error())
|
||||
return
|
||||
}
|
||||
a.installDir = android.PathForModuleInstall(ctx, "apex")
|
||||
a.outputApexFile = android.PathForBazelOut(ctx, outputs.SignedOutput)
|
||||
a.outputFile = a.outputApexFile
|
||||
a.setCompression(ctx)
|
||||
|
||||
a.publicKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyPair[0])
|
||||
a.privateKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyPair[1])
|
||||
a.containerCertificateFile = android.PathForBazelOut(ctx, outputs.ContainerKeyPair[0])
|
||||
a.containerPrivateKeyFile = android.PathForBazelOut(ctx, outputs.ContainerKeyPair[1])
|
||||
apexType := a.properties.ApexType
|
||||
switch apexType {
|
||||
case imageApex:
|
||||
// TODO(asmundak): Bazel does not create these files yet.
|
||||
// b/190817312
|
||||
a.htmlGzNotice = android.PathForBazelOut(ctx, "NOTICE.html.gz")
|
||||
// b/239081457
|
||||
a.bundleModuleFile = android.PathForBazelOut(ctx, a.Name()+apexType.suffix()+"-base.zip")
|
||||
// b/239081455
|
||||
a.nativeApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_using.txt"))
|
||||
// b/239081456
|
||||
a.nativeApisBackedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_backing.txt"))
|
||||
// b/239084755
|
||||
a.javaApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_using.xml"))
|
||||
installSuffix := imageApexSuffix
|
||||
if a.isCompressed {
|
||||
installSuffix = imageCapexSuffix
|
||||
}
|
||||
a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile,
|
||||
a.compatSymlinks.Paths()...)
|
||||
default:
|
||||
panic(fmt.Errorf("unexpected apex_type for the ProcessBazelQuery: %v", a.properties.ApexType))
|
||||
}
|
||||
|
||||
/*
|
||||
TODO(asmundak): compared to building an APEX with Soong, building it with Bazel does not
|
||||
return filesInfo and requiredDeps fields (in the Soong build the latter is updated).
|
||||
Fix this, as these fields are subsequently used in apex/androidmk.go and in apex/builder/go
|
||||
To find out what Soong build puts there, run:
|
||||
vctx := visitorContext{handleSpecialLibs: !android.Bool(a.properties.Ignore_system_library_special_case)}
|
||||
ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
|
||||
return a.depVisitor(&vctx, ctx, child, parent)
|
||||
})
|
||||
vctx.normalizeFileInfo()
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
func (a *apexBundle) setCompression(ctx android.ModuleContext) {
|
||||
if a.properties.ApexType != imageApex {
|
||||
a.isCompressed = false
|
||||
} else if a.testOnlyShouldForceCompression() {
|
||||
a.isCompressed = true
|
||||
} else {
|
||||
a.isCompressed = ctx.Config().ApexCompressionEnabled() && a.isCompressable()
|
||||
}
|
||||
}
|
||||
|
||||
func (a *apexBundle) setSystemLibLink(ctx android.ModuleContext) {
|
||||
// Optimization. If we are building bundled APEX, for the files that are gathered due to the
|
||||
// transitive dependencies, don't place them inside the APEX, but place a symlink pointing
|
||||
// the same library in the system partition, thus effectively sharing the same libraries
|
||||
// across the APEX boundary. For unbundled APEX, all the gathered files are actually placed
|
||||
// in the APEX.
|
||||
a.linkToSystemLib = !ctx.Config().UnbundledBuild() && a.installable()
|
||||
|
||||
// APEXes targeting other than system/system_ext partitions use vendor/product variants.
|
||||
// So we can't link them to /system/lib libs which are core variants.
|
||||
if a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
|
||||
a.linkToSystemLib = false
|
||||
}
|
||||
|
||||
forced := ctx.Config().ForceApexSymlinkOptimization()
|
||||
updatable := a.Updatable() || a.FutureUpdatable()
|
||||
|
||||
// We don't need the optimization for updatable APEXes, as it might give false signal
|
||||
// to the system health when the APEXes are still bundled (b/149805758).
|
||||
if !forced && updatable && a.properties.ApexType == imageApex {
|
||||
a.linkToSystemLib = false
|
||||
}
|
||||
|
||||
// We also don't want the optimization for host APEXes, because it doesn't make sense.
|
||||
if ctx.Host() {
|
||||
a.linkToSystemLib = false
|
||||
}
|
||||
}
|
||||
|
||||
func (a *apexBundle) setPayloadFsType(ctx android.ModuleContext) {
|
||||
switch proptools.StringDefault(a.properties.Payload_fs_type, ext4FsType) {
|
||||
case ext4FsType:
|
||||
a.payloadFsType = ext4
|
||||
case f2fsFsType:
|
||||
a.payloadFsType = f2fs
|
||||
case erofsFsType:
|
||||
a.payloadFsType = erofs
|
||||
default:
|
||||
ctx.PropertyErrorf("payload_fs_type", "%q is not a valid filesystem for apex [ext4, f2fs, erofs]", *a.properties.Payload_fs_type)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *apexBundle) setApexTypeAndSuffix(ctx android.ModuleContext) {
|
||||
// Set suffix and primaryApexType depending on the ApexType
|
||||
buildFlattenedAsDefault := ctx.Config().FlattenApex()
|
||||
switch a.properties.ApexType {
|
||||
case imageApex:
|
||||
if buildFlattenedAsDefault {
|
||||
a.suffix = imageApexSuffix
|
||||
} else {
|
||||
a.suffix = ""
|
||||
a.primaryApexType = true
|
||||
|
||||
if ctx.Config().InstallExtraFlattenedApexes() {
|
||||
a.requiredDeps = append(a.requiredDeps, a.Name()+flattenedSuffix)
|
||||
}
|
||||
}
|
||||
case zipApex:
|
||||
if proptools.String(a.properties.Payload_type) == "zip" {
|
||||
a.suffix = ""
|
||||
a.primaryApexType = true
|
||||
} else {
|
||||
a.suffix = zipApexSuffix
|
||||
}
|
||||
case flattenedApex:
|
||||
if buildFlattenedAsDefault {
|
||||
a.suffix = ""
|
||||
a.primaryApexType = true
|
||||
} else {
|
||||
a.suffix = flattenedSuffix
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (a apexBundle) isCompressable() bool {
|
||||
return proptools.BoolDefault(a.overridableProperties.Compressible, false) && !a.testApex
|
||||
}
|
||||
|
||||
func (a *apexBundle) commonBuildActions(ctx android.ModuleContext) bool {
|
||||
a.checkApexAvailability(ctx)
|
||||
a.checkUpdatable(ctx)
|
||||
a.CheckMinSdkVersion(ctx)
|
||||
a.checkStaticLinkingToStubLibraries(ctx)
|
||||
a.checkStaticExecutables(ctx)
|
||||
if len(a.properties.Tests) > 0 && !a.testApex {
|
||||
ctx.PropertyErrorf("tests", "property allowed only in apex_test module type")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type visitorContext struct {
|
||||
// all the files that will be included in this APEX
|
||||
filesInfo []apexFile
|
||||
@@ -2188,16 +2367,9 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
|
||||
func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 1) do some validity checks such as apex_available, min_sdk_version, etc.
|
||||
a.checkApexAvailability(ctx)
|
||||
a.checkUpdatable(ctx)
|
||||
a.CheckMinSdkVersion(ctx)
|
||||
a.checkStaticLinkingToStubLibraries(ctx)
|
||||
a.checkStaticExecutables(ctx)
|
||||
if len(a.properties.Tests) > 0 && !a.testApex {
|
||||
ctx.PropertyErrorf("tests", "property allowed only in apex_test module type")
|
||||
if !a.commonBuildActions(ctx) {
|
||||
return
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 2) traverse the dependency tree to collect apexFile structs from them.
|
||||
|
||||
@@ -2219,74 +2391,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||
a.installDir = android.PathForModuleInstall(ctx, "apex")
|
||||
a.filesInfo = vctx.filesInfo
|
||||
|
||||
// Set suffix and primaryApexType depending on the ApexType
|
||||
buildFlattenedAsDefault := ctx.Config().FlattenApex()
|
||||
switch a.properties.ApexType {
|
||||
case imageApex:
|
||||
if buildFlattenedAsDefault {
|
||||
a.suffix = imageApexSuffix
|
||||
} else {
|
||||
a.suffix = ""
|
||||
a.primaryApexType = true
|
||||
|
||||
if ctx.Config().InstallExtraFlattenedApexes() {
|
||||
a.requiredDeps = append(a.requiredDeps, a.Name()+flattenedSuffix)
|
||||
}
|
||||
}
|
||||
case zipApex:
|
||||
if proptools.String(a.properties.Payload_type) == "zip" {
|
||||
a.suffix = ""
|
||||
a.primaryApexType = true
|
||||
} else {
|
||||
a.suffix = zipApexSuffix
|
||||
}
|
||||
case flattenedApex:
|
||||
if buildFlattenedAsDefault {
|
||||
a.suffix = ""
|
||||
a.primaryApexType = true
|
||||
} else {
|
||||
a.suffix = flattenedSuffix
|
||||
}
|
||||
}
|
||||
|
||||
switch proptools.StringDefault(a.properties.Payload_fs_type, ext4FsType) {
|
||||
case ext4FsType:
|
||||
a.payloadFsType = ext4
|
||||
case f2fsFsType:
|
||||
a.payloadFsType = f2fs
|
||||
case erofsFsType:
|
||||
a.payloadFsType = erofs
|
||||
default:
|
||||
ctx.PropertyErrorf("payload_fs_type", "%q is not a valid filesystem for apex [ext4, f2fs, erofs]", *a.properties.Payload_fs_type)
|
||||
}
|
||||
|
||||
// Optimization. If we are building bundled APEX, for the files that are gathered due to the
|
||||
// transitive dependencies, don't place them inside the APEX, but place a symlink pointing
|
||||
// the same library in the system partition, thus effectively sharing the same libraries
|
||||
// across the APEX boundary. For unbundled APEX, all the gathered files are actually placed
|
||||
// in the APEX.
|
||||
a.linkToSystemLib = !ctx.Config().UnbundledBuild() && a.installable()
|
||||
|
||||
// APEXes targeting other than system/system_ext partitions use vendor/product variants.
|
||||
// So we can't link them to /system/lib libs which are core variants.
|
||||
if a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
|
||||
a.linkToSystemLib = false
|
||||
}
|
||||
|
||||
forced := ctx.Config().ForceApexSymlinkOptimization()
|
||||
updatable := a.Updatable() || a.FutureUpdatable()
|
||||
|
||||
// We don't need the optimization for updatable APEXes, as it might give false signal
|
||||
// to the system health when the APEXes are still bundled (b/149805758).
|
||||
if !forced && updatable && a.properties.ApexType == imageApex {
|
||||
a.linkToSystemLib = false
|
||||
}
|
||||
|
||||
// We also don't want the optimization for host APEXes, because it doesn't make sense.
|
||||
if ctx.Host() {
|
||||
a.linkToSystemLib = false
|
||||
}
|
||||
|
||||
a.setApexTypeAndSuffix(ctx)
|
||||
a.setPayloadFsType(ctx)
|
||||
a.setSystemLibLink(ctx)
|
||||
if a.properties.ApexType != zipApex {
|
||||
a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, a.primaryApexType)
|
||||
}
|
||||
|
@@ -549,8 +549,6 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
|
||||
outHostBinDir := ctx.Config().HostToolPath(ctx, "").String()
|
||||
prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
|
||||
|
||||
// Figure out if we need to compress the apex.
|
||||
compressionEnabled := ctx.Config().CompressedApex() && proptools.BoolDefault(a.overridableProperties.Compressible, false) && !a.testApex && !ctx.Config().UnbundledBuildApps()
|
||||
if apexType == imageApex {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -635,10 +633,15 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
|
||||
implicitInputs = append(implicitInputs, noticeAssetPath)
|
||||
optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeAssetPath.String()))
|
||||
|
||||
if (moduleMinSdkVersion.GreaterThan(android.SdkVersion_Android10) && !a.shouldGenerateHashtree()) && !compressionEnabled {
|
||||
// Apexes which are supposed to be installed in builtin dirs(/system, etc)
|
||||
// don't need hashtree for activation. Therefore, by removing hashtree from
|
||||
// apex bundle (filesystem image in it, to be specific), we can save storage.
|
||||
// Apexes which are supposed to be installed in builtin dirs(/system, etc)
|
||||
// don't need hashtree for activation. Therefore, by removing hashtree from
|
||||
// apex bundle (filesystem image in it, to be specific), we can save storage.
|
||||
needHashTree := moduleMinSdkVersion.LessThanOrEqualTo(android.SdkVersion_Android10) ||
|
||||
a.shouldGenerateHashtree()
|
||||
if ctx.Config().ApexCompressionEnabled() && a.isCompressable() {
|
||||
needHashTree = true
|
||||
}
|
||||
if !needHashTree {
|
||||
optFlags = append(optFlags, "--no_hashtree")
|
||||
}
|
||||
|
||||
@@ -806,8 +809,9 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
|
||||
return
|
||||
}
|
||||
|
||||
if apexType == imageApex && (compressionEnabled || a.testOnlyShouldForceCompression()) {
|
||||
a.isCompressed = true
|
||||
installSuffix := suffix
|
||||
a.setCompression(ctx)
|
||||
if a.isCompressed {
|
||||
unsignedCompressedOutputFile := android.PathForModuleOut(ctx, a.Name()+imageCapexSuffix+".unsigned")
|
||||
|
||||
compressRule := android.NewRuleBuilder(pctx, ctx)
|
||||
@@ -835,10 +839,6 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
|
||||
Args: args,
|
||||
})
|
||||
a.outputFile = signedCompressedOutputFile
|
||||
}
|
||||
|
||||
installSuffix := suffix
|
||||
if a.isCompressed {
|
||||
installSuffix = imageCapexSuffix
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user