Merge "Add android_app_import."

am: e7d52c779f

Change-Id: I28dba5eeceda144703b416d541c66b13970f823f
This commit is contained in:
Jaewoong Jung 2019-05-02 07:11:35 -07:00 committed by android-build-merger
commit 5fa44dfb04
6 changed files with 286 additions and 31 deletions

View file

@ -590,6 +590,32 @@ func (dstubs *Droidstubs) AndroidMk() android.AndroidMkData {
}
}
func (app *AndroidAppImport) AndroidMk() android.AndroidMkData {
return android.AndroidMkData{
Class: "APPS",
OutputFile: android.OptionalPathForPath(app.outputFile),
Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
Extra: []android.AndroidMkExtraFunc{
func(w io.Writer, outputFile android.Path) {
if Bool(app.properties.Privileged) {
fmt.Fprintln(w, "LOCAL_PRIVILEGED_MODULE := true")
}
if app.certificate != nil {
fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", app.certificate.Pem.String())
} else {
fmt.Fprintln(w, "LOCAL_CERTIFICATE := PRESIGNED")
}
if len(app.properties.Overrides) > 0 {
fmt.Fprintln(w, "LOCAL_OVERRIDES_PACKAGES :=", strings.Join(app.properties.Overrides, " "))
}
if len(app.dexpreopter.builtInstalled) > 0 {
fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", app.dexpreopter.builtInstalled)
}
},
},
}
}
func androidMkWriteTestData(data android.Paths, ret *android.AndroidMkData) {
var testFiles []string
for _, d := range data {

View file

@ -34,6 +34,7 @@ func init() {
android.RegisterModuleType("android_test_helper_app", AndroidTestHelperAppFactory)
android.RegisterModuleType("android_app_certificate", AndroidAppCertificateFactory)
android.RegisterModuleType("override_android_app", OverrideAndroidAppModuleFactory)
android.RegisterModuleType("android_app_import", AndroidAppImportFactory)
}
// AndroidManifest.xml merging
@ -302,37 +303,38 @@ func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, ctx android.ModuleContext
return jniJarFile
}
func (a *AndroidApp) certificateBuildActions(certificateDeps []Certificate, ctx android.ModuleContext) []Certificate {
cert := a.getCertString(ctx)
certModule := android.SrcIsModule(cert)
if certModule != "" {
a.certificate = certificateDeps[0]
certificateDeps = certificateDeps[1:]
} else if cert != "" {
defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
a.certificate = Certificate{
defaultDir.Join(ctx, cert+".x509.pem"),
defaultDir.Join(ctx, cert+".pk8"),
// Reads and prepends a main cert from the default cert dir if it hasn't been set already, i.e. it
// isn't a cert module reference. Also checks and enforces system cert restriction if applicable.
func processMainCert(m android.ModuleBase, certPropValue string, certificates []Certificate, ctx android.ModuleContext) []Certificate {
if android.SrcIsModule(certPropValue) == "" {
var mainCert Certificate
if certPropValue != "" {
defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
mainCert = Certificate{
defaultDir.Join(ctx, certPropValue+".x509.pem"),
defaultDir.Join(ctx, certPropValue+".pk8"),
}
} else {
pem, key := ctx.Config().DefaultAppCertificate(ctx)
mainCert = Certificate{pem, key}
}
} else {
pem, key := ctx.Config().DefaultAppCertificate(ctx)
a.certificate = Certificate{pem, key}
certificates = append([]Certificate{mainCert}, certificates...)
}
if !a.Module.Platform() {
certPath := a.certificate.Pem.String()
if !m.Platform() {
certPath := certificates[0].Pem.String()
systemCertPath := ctx.Config().DefaultAppCertificateDir(ctx).String()
if strings.HasPrefix(certPath, systemCertPath) {
enforceSystemCert := ctx.Config().EnforceSystemCertificate()
whitelist := ctx.Config().EnforceSystemCertificateWhitelist()
if enforceSystemCert && !inList(a.Module.Name(), whitelist) {
if enforceSystemCert && !inList(m.Name(), whitelist) {
ctx.PropertyErrorf("certificate", "The module in product partition cannot be signed with certificate in system.")
}
}
}
return append([]Certificate{a.certificate}, certificateDeps...)
return certificates
}
func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
@ -346,25 +348,26 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
dexJarFile := a.dexBuildActions(ctx)
jniLibs, certificateDeps := a.collectAppDeps(ctx)
jniLibs, certificateDeps := collectAppDeps(ctx)
jniJarFile := a.jniBuildActions(jniLibs, ctx)
if ctx.Failed() {
return
}
certificates := a.certificateBuildActions(certificateDeps, ctx)
certificates := processMainCert(a.ModuleBase, a.getCertString(ctx), certificateDeps, ctx)
a.certificate = certificates[0]
// Build a final signed app package.
// TODO(jungjw): Consider changing this to installApkName.
packageFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".apk")
CreateAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates)
CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates)
a.outputFile = packageFile
for _, split := range a.aapt.splits {
// Sign the split APKs
packageFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"_"+split.suffix+".apk")
CreateAppPackage(ctx, packageFile, split.path, nil, nil, certificates)
CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates)
a.extraOutputFiles = append(a.extraOutputFiles, packageFile)
}
@ -390,7 +393,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
}
}
func (a *AndroidApp) collectAppDeps(ctx android.ModuleContext) ([]jniLib, []Certificate) {
func collectAppDeps(ctx android.ModuleContext) ([]jniLib, []Certificate) {
var jniLibs []jniLib
var certificates []Certificate
@ -412,7 +415,6 @@ func (a *AndroidApp) collectAppDeps(ctx android.ModuleContext) ([]jniLib, []Cert
}
} else {
ctx.ModuleErrorf("jni_libs dependency %q must be a cc library", otherName)
}
} else if tag == certificateTag {
if dep, ok := module.(*AndroidAppCertificate); ok {
@ -620,3 +622,135 @@ func OverrideAndroidAppModuleFactory() android.Module {
android.InitOverrideModule(m)
return m
}
type AndroidAppImport struct {
android.ModuleBase
android.DefaultableModuleBase
prebuilt android.Prebuilt
properties AndroidAppImportProperties
outputFile android.Path
certificate *Certificate
dexpreopter
}
type AndroidAppImportProperties struct {
// A prebuilt apk to import
Apk string
// The name of a certificate in the default certificate directory, blank to use the default
// product certificate, or an android_app_certificate module name in the form ":module".
Certificate *string
// Set this flag to true if the prebuilt apk is already signed. The certificate property must not
// be set for presigned modules.
Presigned *bool
// Specifies that this app should be installed to the priv-app directory,
// where the system will grant it additional privileges not available to
// normal apps.
Privileged *bool
// Names of modules to be overridden. Listed modules can only be other binaries
// (in Make or Soong).
// This does not completely prevent installation of the overridden binaries, but if both
// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
// from PRODUCT_PACKAGES.
Overrides []string
}
func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) {
cert := android.SrcIsModule(String(a.properties.Certificate))
if cert != "" {
ctx.AddDependency(ctx.Module(), certificateTag, cert)
}
}
func (a *AndroidAppImport) uncompressEmbeddedJniLibs(
ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
rule := android.NewRuleBuilder()
rule.Command().
Textf(`if (zipinfo %s 'lib/*.so' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, inputPath).
Tool(ctx.Config().HostToolPath(ctx, "zip2zip")).
FlagWithInput("-i ", inputPath).
FlagWithOutput("-o ", outputPath).
FlagWithArg("-0 ", "'lib/**/*.so'").
Textf(`; else cp -f %s %s; fi`, inputPath, outputPath)
rule.Build(pctx, ctx, "uncompress-embedded-jni-libs", "Uncompress embedded JIN libs")
}
func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if String(a.properties.Certificate) == "" && !Bool(a.properties.Presigned) {
ctx.PropertyErrorf("certificate", "No certificate specified for prebuilt")
}
if String(a.properties.Certificate) != "" && Bool(a.properties.Presigned) {
ctx.PropertyErrorf("certificate", "Certificate can't be specified for presigned modules")
}
_, certificates := collectAppDeps(ctx)
// TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
// TODO: LOCAL_DPI_VARIANTS
// TODO: LOCAL_PACKAGE_SPLITS
srcApk := a.prebuilt.SingleSourcePath(ctx)
// TODO: Install or embed JNI libraries
// Uncompress JNI libraries in the apk
jnisUncompressed := android.PathForModuleOut(ctx, "jnis-uncompressed", ctx.ModuleName()+".apk")
a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed.OutputPath)
// TODO: Uncompress dex if applicable
installDir := android.PathForModuleInstall(ctx, "app", a.BaseModuleName())
a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk")
a.dexpreopter.isInstallable = true
a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
dexOutput := a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
// Sign or align the package
// TODO: Handle EXTERNAL
if !Bool(a.properties.Presigned) {
certificates = processMainCert(a.ModuleBase, *a.properties.Certificate, certificates, ctx)
if len(certificates) != 1 {
ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates)
}
a.certificate = &certificates[0]
signed := android.PathForModuleOut(ctx, "signed", ctx.ModuleName()+".apk")
SignAppPackage(ctx, signed, dexOutput, certificates)
a.outputFile = signed
} else {
alignedApk := android.PathForModuleOut(ctx, "zip-aligned", ctx.ModuleName()+".apk")
TransformZipAlign(ctx, alignedApk, dexOutput)
a.outputFile = alignedApk
}
// TODO: Optionally compress the output apk.
ctx.InstallFile(installDir, a.BaseModuleName()+".apk", a.outputFile)
// TODO: androidmk converter jni libs
}
func (a *AndroidAppImport) Prebuilt() *android.Prebuilt {
return &a.prebuilt
}
func (a *AndroidAppImport) Name() string {
return a.prebuilt.Name(a.ModuleBase.Name())
}
// android_app_import imports a prebuilt apk with additional processing specified in the module.
func AndroidAppImportFactory() android.Module {
module := &AndroidAppImport{}
module.AddProperties(&module.properties)
module.AddProperties(&module.dexpreoptProperties)
InitJavaModule(module, android.DeviceSupported)
android.InitSingleSourcePrebuiltModule(module, &module.properties.Apk)
return module
}

View file

@ -62,7 +62,7 @@ var combineApk = pctx.AndroidStaticRule("combineApk",
CommandDeps: []string{"${config.MergeZipsCmd}"},
})
func CreateAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate) {
unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk"
@ -83,6 +83,11 @@ func CreateAppPackage(ctx android.ModuleContext, outputFile android.WritablePath
Output: unsignedApk,
})
SignAppPackage(ctx, outputFile, unsignedApk, certificates)
}
func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate) {
var certificateArgs []string
var deps android.Paths
for _, c := range certificates {
@ -93,7 +98,7 @@ func CreateAppPackage(ctx android.ModuleContext, outputFile android.WritablePath
ctx.Build(pctx, android.BuildParams{
Rule: Signapk,
Description: "signapk",
Output: outputFile,
Output: signedApk,
Input: unsignedApk,
Implicits: deps,
Args: map[string]string{

View file

@ -968,3 +968,87 @@ func TestOverrideAndroidApp(t *testing.T) {
}
}
}
func TestAndroidAppImport(t *testing.T) {
ctx := testJava(t, `
android_app_import {
name: "foo",
apk: "prebuilts/apk/app.apk",
certificate: "platform",
dex_preopt: {
enabled: true,
},
}
`)
variant := ctx.ModuleForTests("foo", "android_common")
// Check dexpreopt outputs.
if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
t.Errorf("can't find dexpreopt outputs")
}
// Check cert signing flag.
signedApk := variant.Output("signed/foo.apk")
signingFlag := signedApk.Args["certificates"]
expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8"
if expected != signingFlag {
t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
}
}
func TestAndroidAppImport_NoDexPreopt(t *testing.T) {
ctx := testJava(t, `
android_app_import {
name: "foo",
apk: "prebuilts/apk/app.apk",
certificate: "platform",
dex_preopt: {
enabled: false,
},
}
`)
variant := ctx.ModuleForTests("foo", "android_common")
// Check dexpreopt outputs. They shouldn't exist.
if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule != nil ||
variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule != nil {
t.Errorf("dexpreopt shouldn't have run.")
}
}
func TestAndroidAppImport_Presigned(t *testing.T) {
ctx := testJava(t, `
android_app_import {
name: "foo",
apk: "prebuilts/apk/app.apk",
presigned: true,
dex_preopt: {
enabled: true,
},
}
`)
variant := ctx.ModuleForTests("foo", "android_common")
// Check dexpreopt outputs.
if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
t.Errorf("can't find dexpreopt outputs")
}
// Make sure stripping wasn't done.
stripRule := variant.Output("dexpreopt/foo.apk")
if !strings.HasPrefix(stripRule.RuleParams.Command, "cp -f") {
t.Errorf("unexpected, non-skipping strip command: %q", stripRule.RuleParams.Command)
}
// Make sure signing was skipped and aligning was done instead.
if variant.MaybeOutput("signed/foo.apk").Rule != nil {
t.Errorf("signing rule shouldn't be included.")
}
if variant.MaybeOutput("zip-aligned/foo.apk").Rule == nil {
t.Errorf("can't find aligning rule")
}
}

View file

@ -22,11 +22,12 @@ import (
type dexpreopter struct {
dexpreoptProperties DexpreoptProperties
installPath android.OutputPath
uncompressedDex bool
isSDKLibrary bool
isTest bool
isInstallable bool
installPath android.OutputPath
uncompressedDex bool
isSDKLibrary bool
isTest bool
isInstallable bool
isPresignedPrebuilt bool
builtInstalled string
}
@ -177,6 +178,8 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo
NoCreateAppImage: !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true),
ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false),
PresignedPrebuilt: d.isPresignedPrebuilt,
NoStripping: Bool(d.dexpreoptProperties.Dex_preopt.No_stripping),
StripInputPath: dexJarFile,
StripOutputPath: strippedDexJarFile.OutputPath,

View file

@ -63,6 +63,7 @@ func testContext(config android.Config, bp string,
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(AndroidAppCertificateFactory))
ctx.RegisterModuleType("android_app_import", android.ModuleFactoryAdaptor(AndroidAppImportFactory))
ctx.RegisterModuleType("android_library", android.ModuleFactoryAdaptor(AndroidLibraryFactory))
ctx.RegisterModuleType("android_test", android.ModuleFactoryAdaptor(AndroidTestFactory))
ctx.RegisterModuleType("android_test_helper_app", android.ModuleFactoryAdaptor(AndroidTestHelperAppFactory))
@ -163,6 +164,8 @@ func testContext(config android.Config, bp string,
"prebuilts/sdk/tools/core-lambda-stubs.jar": nil,
"prebuilts/sdk/Android.bp": []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "current"],}`),
"prebuilts/apk/app.apk": nil,
// For framework-res, which is an implicit dependency for framework
"AndroidManifest.xml": nil,
"build/make/target/product/security/testkey": nil,