Store dex files uncompressed and unstripped in privileged APKs

Privileged APKs need to store their dex files uncompressed so they
can be verified and mapped directly out of the APK.

Also track whether the module will be dexpreopted or not in order
to determine if the dex file should be stripped before signing.

Test: SystemUI.apk contains an uncompressed dex file
Change-Id: I4dca86c7f8778595882405b34adcf2a7bae03c67
This commit is contained in:
Colin Cross
2018-10-05 14:20:06 -07:00
parent 1e30905f65
commit 5a0dcd5acf
6 changed files with 90 additions and 16 deletions

View File

@@ -708,6 +708,22 @@ func (c *config) HostStaticBinaries() bool {
return Bool(c.productVariables.HostStaticBinaries) return Bool(c.productVariables.HostStaticBinaries)
} }
func (c *config) UncompressPrivAppDex() bool {
return Bool(c.productVariables.UncompressPrivAppDex)
}
func (c *config) ModulesLoadedByPrivilegedModules() []string {
return c.productVariables.ModulesLoadedByPrivilegedModules
}
func (c *config) DefaultStripDex() bool {
return Bool(c.productVariables.DefaultStripDex)
}
func (c *config) DisableDexPreopt(name string) bool {
return Bool(c.productVariables.DisableDexPreopt) || InList(name, c.productVariables.DisableDexPreoptModules)
}
func (c *deviceConfig) Arches() []Arch { func (c *deviceConfig) Arches() []Arch {
var arches []Arch var arches []Arch
for _, target := range c.config.Targets[Android] { for _, target := range c.config.Targets[Android] {

View File

@@ -190,6 +190,12 @@ type productVariables struct {
Arc *bool `json:",omitempty"` Arc *bool `json:",omitempty"`
MinimizeJavaDebugInfo *bool `json:",omitempty"` MinimizeJavaDebugInfo *bool `json:",omitempty"`
UncompressPrivAppDex *bool `json:",omitempty"`
ModulesLoadedByPrivilegedModules []string `json:",omitempty"`
DefaultStripDex *bool `json:",omitempty"`
DisableDexPreopt *bool `json:",omitempty"`
DisableDexPreoptModules []string `json:",omitempty"`
IntegerOverflowExcludePaths *[]string `json:",omitempty"` IntegerOverflowExcludePaths *[]string `json:",omitempty"`
EnableCFI *bool `json:",omitempty"` EnableCFI *bool `json:",omitempty"`

View File

@@ -67,7 +67,9 @@ type appProperties struct {
// list of native libraries that will be provided in or alongside the resulting jar // list of native libraries that will be provided in or alongside the resulting jar
Jni_libs []string `android:"arch_variant"` Jni_libs []string `android:"arch_variant"`
EmbedJNI bool `blueprint:"mutated"` AllowDexPreopt bool `blueprint:"mutated"`
EmbedJNI bool `blueprint:"mutated"`
StripDex bool `blueprint:"mutated"`
} }
type AndroidApp struct { type AndroidApp struct {
@@ -139,6 +141,42 @@ func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
a.generateAndroidBuildActions(ctx) a.generateAndroidBuildActions(ctx)
} }
// Returns whether this module should have the dex file stored uncompressed in the APK, or stripped completely. If
// stripped, the code will still be present on the device in the dexpreopted files.
// This is only necessary for APKs, and not jars, because APKs are signed and the dex file should not be uncompressed
// or removed after the signature has been generated. For jars, which are not signed, the dex file is uncompressed
// or removed at installation time in Make.
func (a *AndroidApp) uncompressOrStripDex(ctx android.ModuleContext) (uncompress, strip bool) {
if ctx.Config().UnbundledBuild() {
return false, false
}
strip = ctx.Config().DefaultStripDex()
// TODO(ccross): don't strip dex installed on partitions that may be updated separately (like vendor)
// TODO(ccross): don't strip dex on modules with LOCAL_APK_LIBRARIES equivalent
// TODO(ccross): don't strip dex on modules that are preopted to system_other
// Uncompress dex in APKs of privileged apps, and modules used by privileged apps.
if ctx.Config().UncompressPrivAppDex() &&
(Bool(a.appProperties.Privileged) ||
inList(ctx.ModuleName(), ctx.Config().ModulesLoadedByPrivilegedModules())) {
uncompress = true
// If the dex files is store uncompressed, don't strip it, we will reuse the uncompressed dex from the APK
// instead of copying it into the odex file.
strip = false
}
// If dexpreopt is disabled, don't strip the dex file
if !a.appProperties.AllowDexPreopt ||
!BoolDefault(a.deviceProperties.Dex_preopt.Enabled, true) ||
ctx.Config().DisableDexPreopt(ctx.ModuleName()) {
strip = false
}
return uncompress, strip
}
func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
linkFlags := append([]string(nil), a.extraLinkFlags...) linkFlags := append([]string(nil), a.extraLinkFlags...)
@@ -184,11 +222,16 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles, staticLibProguardFlagFiles...) a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles, staticLibProguardFlagFiles...)
a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles, a.proguardOptionsFile) a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles, a.proguardOptionsFile)
a.deviceProperties.UncompressDex, a.appProperties.StripDex = a.uncompressOrStripDex(ctx)
if ctx.ModuleName() != "framework-res" { if ctx.ModuleName() != "framework-res" {
a.Module.compile(ctx, a.aaptSrcJar) a.Module.compile(ctx, a.aaptSrcJar)
} }
dexJarFile := a.dexJarFile
packageFile := android.PathForModuleOut(ctx, "package.apk") if a.appProperties.StripDex {
dexJarFile = nil
}
var certificates []certificate var certificates []certificate
@@ -226,8 +269,8 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
certificates = append([]certificate{a.certificate}, certificateDeps...) certificates = append([]certificate{a.certificate}, certificateDeps...)
CreateAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, a.outputFile, certificates) packageFile := android.PathForModuleOut(ctx, "package.apk")
CreateAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates)
a.outputFile = packageFile a.outputFile = packageFile
if ctx.ModuleName() == "framework-res" { if ctx.ModuleName() == "framework-res" {
@@ -284,6 +327,7 @@ func AndroidAppFactory() android.Module {
module.Module.properties.Instrument = true module.Module.properties.Instrument = true
module.Module.properties.Installable = proptools.BoolPtr(true) module.Module.properties.Installable = proptools.BoolPtr(true)
module.appProperties.AllowDexPreopt = true
module.AddProperties( module.AddProperties(
&module.Module.properties, &module.Module.properties,
@@ -345,6 +389,7 @@ func AndroidTestFactory() android.Module {
module.Module.properties.Instrument = true module.Module.properties.Instrument = true
module.Module.properties.Installable = proptools.BoolPtr(true) module.Module.properties.Installable = proptools.BoolPtr(true)
module.appProperties.EmbedJNI = true module.appProperties.EmbedJNI = true
module.appProperties.AllowDexPreopt = false
module.AddProperties( module.AddProperties(
&module.Module.properties, &module.Module.properties,
@@ -379,6 +424,7 @@ func AndroidTestHelperAppFactory() android.Module {
module.Module.properties.Installable = proptools.BoolPtr(true) module.Module.properties.Installable = proptools.BoolPtr(true)
module.appProperties.EmbedJNI = true module.appProperties.EmbedJNI = true
module.appProperties.AllowDexPreopt = false
module.AddProperties( module.AddProperties(
&module.Module.properties, &module.Module.properties,

View File

@@ -87,9 +87,6 @@ func CreateAppPackage(ctx android.ModuleContext, outputFile android.WritablePath
certificateArgs = append(certificateArgs, c.pem.String(), c.key.String()) certificateArgs = append(certificateArgs, c.pem.String(), c.key.String())
} }
// TODO(ccross): sometimes uncompress dex
// TODO(ccross): sometimes strip dex
ctx.Build(pctx, android.BuildParams{ ctx.Build(pctx, android.BuildParams{
Rule: signapk, Rule: signapk,
Description: "signapk", Description: "signapk",

View File

@@ -26,7 +26,7 @@ var d8 = pctx.AndroidStaticRule("d8",
blueprint.RuleParams{ blueprint.RuleParams{
Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
`${config.D8Cmd} --output $outDir $d8Flags $in && ` + `${config.D8Cmd} --output $outDir $d8Flags $in && ` +
`${config.SoongZipCmd} -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` + `${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
`${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`, `${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`,
CommandDeps: []string{ CommandDeps: []string{
"${config.D8Cmd}", "${config.D8Cmd}",
@@ -34,7 +34,7 @@ var d8 = pctx.AndroidStaticRule("d8",
"${config.MergeZipsCmd}", "${config.MergeZipsCmd}",
}, },
}, },
"outDir", "d8Flags") "outDir", "d8Flags", "zipFlags")
var r8 = pctx.AndroidStaticRule("r8", var r8 = pctx.AndroidStaticRule("r8",
blueprint.RuleParams{ blueprint.RuleParams{
@@ -46,7 +46,7 @@ var r8 = pctx.AndroidStaticRule("r8",
`-printmapping $outDict ` + `-printmapping $outDict ` +
`$r8Flags && ` + `$r8Flags && ` +
`touch "$outDict" && ` + `touch "$outDict" && ` +
`${config.SoongZipCmd} -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` + `${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
`${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`, `${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`,
CommandDeps: []string{ CommandDeps: []string{
"${config.R8Cmd}", "${config.R8Cmd}",
@@ -54,7 +54,7 @@ var r8 = pctx.AndroidStaticRule("r8",
"${config.MergeZipsCmd}", "${config.MergeZipsCmd}",
}, },
}, },
"outDir", "outDict", "r8Flags") "outDir", "outDict", "r8Flags", "zipFlags")
func (j *Module) dexCommonFlags(ctx android.ModuleContext) []string { func (j *Module) dexCommonFlags(ctx android.ModuleContext) []string {
flags := j.deviceProperties.Dxflags flags := j.deviceProperties.Dxflags
@@ -172,6 +172,11 @@ func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags,
javalibJar := android.PathForModuleOut(ctx, "dex", jarName) javalibJar := android.PathForModuleOut(ctx, "dex", jarName)
outDir := android.PathForModuleOut(ctx, "dex") outDir := android.PathForModuleOut(ctx, "dex")
zipFlags := ""
if j.deviceProperties.UncompressDex {
zipFlags = "-L 0"
}
if useR8 { if useR8 {
proguardDictionary := android.PathForModuleOut(ctx, "proguard_dictionary") proguardDictionary := android.PathForModuleOut(ctx, "proguard_dictionary")
j.proguardDictionary = proguardDictionary j.proguardDictionary = proguardDictionary
@@ -184,9 +189,10 @@ func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags,
Input: classesJar, Input: classesJar,
Implicits: r8Deps, Implicits: r8Deps,
Args: map[string]string{ Args: map[string]string{
"r8Flags": strings.Join(r8Flags, " "), "r8Flags": strings.Join(r8Flags, " "),
"outDict": j.proguardDictionary.String(), "zipFlags": zipFlags,
"outDir": outDir.String(), "outDict": j.proguardDictionary.String(),
"outDir": outDir.String(),
}, },
}) })
} else { } else {
@@ -198,8 +204,9 @@ func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags,
Input: classesJar, Input: classesJar,
Implicits: d8Deps, Implicits: d8Deps,
Args: map[string]string{ Args: map[string]string{
"d8Flags": strings.Join(d8Flags, " "), "d8Flags": strings.Join(d8Flags, " "),
"outDir": outDir.String(), "zipFlags": zipFlags,
"outDir": outDir.String(),
}, },
}) })
} }

View File

@@ -257,6 +257,8 @@ type CompilerDeviceProperties struct {
// When targeting 1.9, override the modules to use with --system // When targeting 1.9, override the modules to use with --system
System_modules *string System_modules *string
UncompressDex bool `blueprint:"mutated"`
} }
// Module contains the properties and members used by all java module types // Module contains the properties and members used by all java module types