5780d57a71
android_app_import and android_test_import modules with processed: true and skip_preprocessed_apk_checks are used directly from the source tree. If the source file name doesn t match the module name and the file is used as test data it can result in the wrong filename being used. Copy the source file to an output file with the correct name first. Bug: 290376750 Test: m CtsAppSecurityHostTestCases Change-Id: I4a6dd1c5e48db7085ea41035def31f0844948a46
607 lines
20 KiB
Go
607 lines
20 KiB
Go
// Copyright 2020 Google Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package java
|
|
|
|
// This file contains the module implementations for android_app_import and android_test_import.
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
|
|
"github.com/google/blueprint"
|
|
|
|
"github.com/google/blueprint/proptools"
|
|
|
|
"android/soong/android"
|
|
"android/soong/provenance"
|
|
)
|
|
|
|
func init() {
|
|
RegisterAppImportBuildComponents(android.InitRegistrationContext)
|
|
|
|
initAndroidAppImportVariantGroupTypes()
|
|
}
|
|
|
|
var (
|
|
uncompressEmbeddedJniLibsRule = pctx.AndroidStaticRule("uncompress-embedded-jni-libs", blueprint.RuleParams{
|
|
Command: `if (zipinfo $in 'lib/*.so' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then ` +
|
|
`${config.Zip2ZipCmd} -i $in -o $out -0 'lib/**/*.so'` +
|
|
`; else cp -f $in $out; fi`,
|
|
CommandDeps: []string{"${config.Zip2ZipCmd}"},
|
|
Description: "Uncompress embedded JNI libs",
|
|
})
|
|
|
|
uncompressDexRule = pctx.AndroidStaticRule("uncompress-dex", blueprint.RuleParams{
|
|
Command: `if (zipinfo $in '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then ` +
|
|
`${config.Zip2ZipCmd} -i $in -o $out -0 'classes*.dex'` +
|
|
`; else cp -f $in $out; fi`,
|
|
CommandDeps: []string{"${config.Zip2ZipCmd}"},
|
|
Description: "Uncompress dex files",
|
|
})
|
|
|
|
checkJniAndDexLibsAreUncompressedRule = pctx.AndroidStaticRule("check-jni-and-dex-libs-are-uncompressed", blueprint.RuleParams{
|
|
// grep -v ' stor ' will search for lines that don't have ' stor '. stor means the file is stored uncompressed
|
|
Command: "if (zipinfo $in 'lib/*.so' '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then " +
|
|
"echo $in: Contains compressed JNI libraries and/or dex files >&2;" +
|
|
"exit 1; " +
|
|
"else " +
|
|
"touch $out; " +
|
|
"fi",
|
|
Description: "Check for compressed JNI libs or dex files",
|
|
})
|
|
)
|
|
|
|
func RegisterAppImportBuildComponents(ctx android.RegistrationContext) {
|
|
ctx.RegisterModuleType("android_app_import", AndroidAppImportFactory)
|
|
ctx.RegisterModuleType("android_test_import", AndroidTestImportFactory)
|
|
}
|
|
|
|
type AndroidAppImport struct {
|
|
android.ModuleBase
|
|
android.DefaultableModuleBase
|
|
android.ApexModuleBase
|
|
prebuilt android.Prebuilt
|
|
|
|
properties AndroidAppImportProperties
|
|
dpiVariants interface{}
|
|
archVariants interface{}
|
|
|
|
outputFile android.Path
|
|
certificate Certificate
|
|
|
|
dexpreopter
|
|
|
|
usesLibrary usesLibrary
|
|
|
|
installPath android.InstallPath
|
|
|
|
hideApexVariantFromMake bool
|
|
|
|
provenanceMetaDataFile android.OutputPath
|
|
}
|
|
|
|
type AndroidAppImportProperties struct {
|
|
// A prebuilt apk to import
|
|
Apk *string `android:"path"`
|
|
|
|
// The name of a certificate in the default certificate directory or an android_app_certificate
|
|
// module name in the form ":module". Should be empty if presigned or default_dev_cert is set.
|
|
Certificate *string
|
|
|
|
// Names of extra android_app_certificate modules to sign the apk with in the form ":module".
|
|
Additional_certificates []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
|
|
|
|
// Name of the signing certificate lineage file or filegroup module.
|
|
Lineage *string `android:"path"`
|
|
|
|
// For overriding the --rotation-min-sdk-version property of apksig
|
|
RotationMinSdkVersion *string
|
|
|
|
// Sign with the default system dev certificate. Must be used judiciously. Most imported apps
|
|
// need to either specify a specific certificate or be presigned.
|
|
Default_dev_cert *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
|
|
|
|
// Optional name for the installed app. If unspecified, it is derived from the module name.
|
|
Filename *string
|
|
|
|
// If set, create package-export.apk, which other packages can
|
|
// use to get PRODUCT-agnostic resource data like IDs and type definitions.
|
|
Export_package_resources *bool
|
|
|
|
// Optional. Install to a subdirectory of the default install path for the module
|
|
Relative_install_path *string
|
|
|
|
// Whether the prebuilt apk can be installed without additional processing. Default is false.
|
|
Preprocessed *bool
|
|
|
|
// Whether or not to skip checking the preprocessed apk for proper alignment and uncompressed
|
|
// JNI libs and dex files. Default is false
|
|
Skip_preprocessed_apk_checks *bool
|
|
}
|
|
|
|
func (a *AndroidAppImport) IsInstallable() bool {
|
|
return true
|
|
}
|
|
|
|
// Updates properties with variant-specific values.
|
|
func (a *AndroidAppImport) processVariants(ctx android.LoadHookContext) {
|
|
config := ctx.Config()
|
|
|
|
dpiProps := reflect.ValueOf(a.dpiVariants).Elem().FieldByName("Dpi_variants")
|
|
// Try DPI variant matches in the reverse-priority order so that the highest priority match
|
|
// overwrites everything else.
|
|
// TODO(jungjw): Can we optimize this by making it priority order?
|
|
for i := len(config.ProductAAPTPrebuiltDPI()) - 1; i >= 0; i-- {
|
|
MergePropertiesFromVariant(ctx, &a.properties, dpiProps, config.ProductAAPTPrebuiltDPI()[i])
|
|
}
|
|
if config.ProductAAPTPreferredConfig() != "" {
|
|
MergePropertiesFromVariant(ctx, &a.properties, dpiProps, config.ProductAAPTPreferredConfig())
|
|
}
|
|
|
|
archProps := reflect.ValueOf(a.archVariants).Elem().FieldByName("Arch")
|
|
archType := ctx.Config().AndroidFirstDeviceTarget.Arch.ArchType
|
|
MergePropertiesFromVariant(ctx, &a.properties, archProps, archType.Name)
|
|
|
|
if String(a.properties.Apk) == "" {
|
|
// Disable this module since the apk property is still empty after processing all matching
|
|
// variants. This likely means there is no matching variant, and the default variant doesn't
|
|
// have an apk property value either.
|
|
a.Disable()
|
|
}
|
|
}
|
|
|
|
func MergePropertiesFromVariant(ctx android.EarlyModuleContext,
|
|
dst interface{}, variantGroup reflect.Value, variant string) {
|
|
src := variantGroup.FieldByName(proptools.FieldNameForProperty(variant))
|
|
if !src.IsValid() {
|
|
return
|
|
}
|
|
|
|
err := proptools.ExtendMatchingProperties([]interface{}{dst}, src.Interface(), nil, proptools.OrderAppend)
|
|
if err != nil {
|
|
if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
|
|
ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
|
|
} else {
|
|
panic(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) {
|
|
cert := android.SrcIsModule(String(a.properties.Certificate))
|
|
if cert != "" {
|
|
ctx.AddDependency(ctx.Module(), certificateTag, cert)
|
|
}
|
|
|
|
for _, cert := range a.properties.Additional_certificates {
|
|
cert = android.SrcIsModule(cert)
|
|
if cert != "" {
|
|
ctx.AddDependency(ctx.Module(), certificateTag, cert)
|
|
} else {
|
|
ctx.PropertyErrorf("additional_certificates",
|
|
`must be names of android_app_certificate modules in the form ":module"`)
|
|
}
|
|
}
|
|
|
|
a.usesLibrary.deps(ctx, true)
|
|
}
|
|
|
|
func (a *AndroidAppImport) uncompressEmbeddedJniLibs(
|
|
ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
|
|
// Test apps don't need their JNI libraries stored uncompressed. As a matter of fact, messing
|
|
// with them may invalidate pre-existing signature data.
|
|
if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || Bool(a.properties.Preprocessed)) {
|
|
ctx.Build(pctx, android.BuildParams{
|
|
Rule: android.Cp,
|
|
Output: outputPath,
|
|
Input: inputPath,
|
|
})
|
|
return
|
|
}
|
|
|
|
ctx.Build(pctx, android.BuildParams{
|
|
Rule: uncompressEmbeddedJniLibsRule,
|
|
Input: inputPath,
|
|
Output: outputPath,
|
|
})
|
|
}
|
|
|
|
// Returns whether this module should have the dex file stored uncompressed in the APK.
|
|
func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool {
|
|
if ctx.Config().UnbundledBuild() || proptools.Bool(a.properties.Preprocessed) {
|
|
return false
|
|
}
|
|
|
|
// Uncompress dex in APKs of priv-apps if and only if DONT_UNCOMPRESS_PRIV_APPS_DEXS is false.
|
|
if a.Privileged() {
|
|
return ctx.Config().UncompressPrivAppDex()
|
|
}
|
|
|
|
return shouldUncompressDex(ctx, &a.dexpreopter)
|
|
}
|
|
|
|
func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|
a.generateAndroidBuildActions(ctx)
|
|
}
|
|
|
|
func (a *AndroidAppImport) InstallApkName() string {
|
|
return a.BaseModuleName()
|
|
}
|
|
|
|
func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext) {
|
|
if a.Name() == "prebuilt_framework-res" {
|
|
ctx.ModuleErrorf("prebuilt_framework-res found. This used to have special handling in soong, but was removed due to prebuilt_framework-res no longer existing. This check is to ensure it doesn't come back without readding the special handling.")
|
|
}
|
|
|
|
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
|
|
if !apexInfo.IsForPlatform() {
|
|
a.hideApexVariantFromMake = true
|
|
}
|
|
|
|
numCertPropsSet := 0
|
|
if String(a.properties.Certificate) != "" {
|
|
numCertPropsSet++
|
|
}
|
|
if Bool(a.properties.Presigned) {
|
|
numCertPropsSet++
|
|
}
|
|
if Bool(a.properties.Default_dev_cert) {
|
|
numCertPropsSet++
|
|
}
|
|
if numCertPropsSet != 1 {
|
|
ctx.ModuleErrorf("One and only one of certficate, presigned, and default_dev_cert properties must be set")
|
|
}
|
|
|
|
_, _, certificates := collectAppDeps(ctx, a, false, false)
|
|
|
|
// TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
|
|
// 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)
|
|
|
|
var pathFragments []string
|
|
relInstallPath := String(a.properties.Relative_install_path)
|
|
|
|
if Bool(a.properties.Privileged) {
|
|
pathFragments = []string{"priv-app", relInstallPath, a.BaseModuleName()}
|
|
} else if ctx.InstallInTestcases() {
|
|
pathFragments = []string{relInstallPath, a.BaseModuleName(), ctx.DeviceConfig().DeviceArch()}
|
|
} else {
|
|
pathFragments = []string{"app", relInstallPath, a.BaseModuleName()}
|
|
}
|
|
|
|
installDir := android.PathForModuleInstall(ctx, pathFragments...)
|
|
a.dexpreopter.isApp = true
|
|
a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk")
|
|
a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
|
|
a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
|
|
|
|
a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
|
|
a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
|
|
|
|
if a.usesLibrary.enforceUsesLibraries() {
|
|
a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
|
|
}
|
|
|
|
a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
|
|
if a.dexpreopter.uncompressedDex {
|
|
dexUncompressed := android.PathForModuleOut(ctx, "dex-uncompressed", ctx.ModuleName()+".apk")
|
|
ctx.Build(pctx, android.BuildParams{
|
|
Rule: uncompressDexRule,
|
|
Input: jnisUncompressed,
|
|
Output: dexUncompressed,
|
|
})
|
|
jnisUncompressed = dexUncompressed
|
|
}
|
|
|
|
apkFilename := proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".apk")
|
|
|
|
// TODO: Handle EXTERNAL
|
|
|
|
// Sign or align the package if package has not been preprocessed
|
|
|
|
if proptools.Bool(a.properties.Preprocessed) {
|
|
var output android.WritablePath
|
|
if !proptools.Bool(a.properties.Skip_preprocessed_apk_checks) {
|
|
output = android.PathForModuleOut(ctx, "validated-prebuilt", apkFilename)
|
|
a.validatePreprocessedApk(ctx, srcApk, output)
|
|
} else {
|
|
// If using the input APK unmodified, still make a copy of it so that the output filename has the
|
|
// right basename.
|
|
output = android.PathForModuleOut(ctx, apkFilename)
|
|
ctx.Build(pctx, android.BuildParams{
|
|
Rule: android.Cp,
|
|
Input: srcApk,
|
|
Output: output,
|
|
})
|
|
}
|
|
a.outputFile = output
|
|
a.certificate = PresignedCertificate
|
|
} else if !Bool(a.properties.Presigned) {
|
|
// If the certificate property is empty at this point, default_dev_cert must be set to true.
|
|
// Which makes processMainCert's behavior for the empty cert string WAI.
|
|
a.certificate, certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx)
|
|
signed := android.PathForModuleOut(ctx, "signed", apkFilename)
|
|
var lineageFile android.Path
|
|
if lineage := String(a.properties.Lineage); lineage != "" {
|
|
lineageFile = android.PathForModuleSrc(ctx, lineage)
|
|
}
|
|
|
|
rotationMinSdkVersion := String(a.properties.RotationMinSdkVersion)
|
|
|
|
SignAppPackage(ctx, signed, jnisUncompressed, certificates, nil, lineageFile, rotationMinSdkVersion)
|
|
a.outputFile = signed
|
|
} else {
|
|
alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename)
|
|
TransformZipAlign(ctx, alignedApk, jnisUncompressed)
|
|
a.outputFile = alignedApk
|
|
a.certificate = PresignedCertificate
|
|
}
|
|
|
|
// TODO: Optionally compress the output apk.
|
|
|
|
if apexInfo.IsForPlatform() {
|
|
a.installPath = ctx.InstallFile(installDir, apkFilename, a.outputFile)
|
|
artifactPath := android.PathForModuleSrc(ctx, *a.properties.Apk)
|
|
a.provenanceMetaDataFile = provenance.GenerateArtifactProvenanceMetaData(ctx, artifactPath, a.installPath)
|
|
}
|
|
|
|
// TODO: androidmk converter jni libs
|
|
}
|
|
|
|
func (a *AndroidAppImport) validatePreprocessedApk(ctx android.ModuleContext, srcApk android.Path, dstApk android.WritablePath) {
|
|
alignmentStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "alignment.stamp")
|
|
ctx.Build(pctx, android.BuildParams{
|
|
Rule: checkZipAlignment,
|
|
Input: srcApk,
|
|
Output: alignmentStamp,
|
|
})
|
|
compressionStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "compression.stamp")
|
|
ctx.Build(pctx, android.BuildParams{
|
|
Rule: checkJniAndDexLibsAreUncompressedRule,
|
|
Input: srcApk,
|
|
Output: compressionStamp,
|
|
})
|
|
ctx.Build(pctx, android.BuildParams{
|
|
Rule: android.Cp,
|
|
Input: srcApk,
|
|
Output: dstApk,
|
|
Validations: []android.Path{
|
|
alignmentStamp,
|
|
compressionStamp,
|
|
},
|
|
})
|
|
}
|
|
|
|
func (a *AndroidAppImport) Prebuilt() *android.Prebuilt {
|
|
return &a.prebuilt
|
|
}
|
|
|
|
func (a *AndroidAppImport) Name() string {
|
|
return a.prebuilt.Name(a.ModuleBase.Name())
|
|
}
|
|
|
|
func (a *AndroidAppImport) OutputFile() android.Path {
|
|
return a.outputFile
|
|
}
|
|
|
|
func (a *AndroidAppImport) OutputFiles(tag string) (android.Paths, error) {
|
|
switch tag {
|
|
case "":
|
|
return []android.Path{a.outputFile}, nil
|
|
default:
|
|
return nil, fmt.Errorf("unsupported module reference tag %q", tag)
|
|
}
|
|
}
|
|
|
|
func (a *AndroidAppImport) JacocoReportClassesFile() android.Path {
|
|
return nil
|
|
}
|
|
|
|
func (a *AndroidAppImport) Certificate() Certificate {
|
|
return a.certificate
|
|
}
|
|
|
|
func (a *AndroidAppImport) ProvenanceMetaDataFile() android.OutputPath {
|
|
return a.provenanceMetaDataFile
|
|
}
|
|
|
|
func (a *AndroidAppImport) PrivAppAllowlist() android.OptionalPath {
|
|
return android.OptionalPath{}
|
|
}
|
|
|
|
var dpiVariantGroupType reflect.Type
|
|
var archVariantGroupType reflect.Type
|
|
var supportedDpis = []string{"ldpi", "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"}
|
|
|
|
func initAndroidAppImportVariantGroupTypes() {
|
|
dpiVariantGroupType = createVariantGroupType(supportedDpis, "Dpi_variants")
|
|
|
|
archNames := make([]string, len(android.ArchTypeList()))
|
|
for i, archType := range android.ArchTypeList() {
|
|
archNames[i] = archType.Name
|
|
}
|
|
archVariantGroupType = createVariantGroupType(archNames, "Arch")
|
|
}
|
|
|
|
// Populates all variant struct properties at creation time.
|
|
func (a *AndroidAppImport) populateAllVariantStructs() {
|
|
a.dpiVariants = reflect.New(dpiVariantGroupType).Interface()
|
|
a.AddProperties(a.dpiVariants)
|
|
|
|
a.archVariants = reflect.New(archVariantGroupType).Interface()
|
|
a.AddProperties(a.archVariants)
|
|
}
|
|
|
|
func (a *AndroidAppImport) Privileged() bool {
|
|
return Bool(a.properties.Privileged)
|
|
}
|
|
|
|
func (a *AndroidAppImport) DepIsInSameApex(_ android.BaseModuleContext, _ android.Module) bool {
|
|
// android_app_import might have extra dependencies via uses_libs property.
|
|
// Don't track the dependency as we don't automatically add those libraries
|
|
// to the classpath. It should be explicitly added to java_libs property of APEX
|
|
return false
|
|
}
|
|
|
|
func (a *AndroidAppImport) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
|
|
return android.SdkSpecPrivate
|
|
}
|
|
|
|
func (a *AndroidAppImport) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
|
|
return android.SdkSpecPrivate.ApiLevel
|
|
}
|
|
|
|
func (a *AndroidAppImport) LintDepSets() LintDepSets {
|
|
return LintDepSets{}
|
|
}
|
|
|
|
var _ android.ApexModule = (*AndroidAppImport)(nil)
|
|
|
|
// Implements android.ApexModule
|
|
func (j *AndroidAppImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
|
|
sdkVersion android.ApiLevel) error {
|
|
// Do not check for prebuilts against the min_sdk_version of enclosing APEX
|
|
return nil
|
|
}
|
|
|
|
func createVariantGroupType(variants []string, variantGroupName string) reflect.Type {
|
|
props := reflect.TypeOf((*AndroidAppImportProperties)(nil))
|
|
|
|
variantFields := make([]reflect.StructField, len(variants))
|
|
for i, variant := range variants {
|
|
variantFields[i] = reflect.StructField{
|
|
Name: proptools.FieldNameForProperty(variant),
|
|
Type: props,
|
|
}
|
|
}
|
|
|
|
variantGroupStruct := reflect.StructOf(variantFields)
|
|
return reflect.StructOf([]reflect.StructField{
|
|
{
|
|
Name: variantGroupName,
|
|
Type: variantGroupStruct,
|
|
},
|
|
})
|
|
}
|
|
|
|
// android_app_import imports a prebuilt apk with additional processing specified in the module.
|
|
// DPI-specific apk source files can be specified using dpi_variants. Example:
|
|
//
|
|
// android_app_import {
|
|
// name: "example_import",
|
|
// apk: "prebuilts/example.apk",
|
|
// dpi_variants: {
|
|
// mdpi: {
|
|
// apk: "prebuilts/example_mdpi.apk",
|
|
// },
|
|
// xhdpi: {
|
|
// apk: "prebuilts/example_xhdpi.apk",
|
|
// },
|
|
// },
|
|
// presigned: true,
|
|
// }
|
|
func AndroidAppImportFactory() android.Module {
|
|
module := &AndroidAppImport{}
|
|
module.AddProperties(&module.properties)
|
|
module.AddProperties(&module.dexpreoptProperties)
|
|
module.AddProperties(&module.usesLibrary.usesLibraryProperties)
|
|
module.populateAllVariantStructs()
|
|
android.AddLoadHook(module, func(ctx android.LoadHookContext) {
|
|
module.processVariants(ctx)
|
|
})
|
|
|
|
android.InitApexModule(module)
|
|
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
|
|
android.InitDefaultableModule(module)
|
|
android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk")
|
|
|
|
module.usesLibrary.enforce = true
|
|
|
|
return module
|
|
}
|
|
|
|
type AndroidTestImport struct {
|
|
AndroidAppImport
|
|
|
|
testProperties struct {
|
|
// list of compatibility suites (for example "cts", "vts") that the module should be
|
|
// installed into.
|
|
Test_suites []string `android:"arch_variant"`
|
|
|
|
// list of files or filegroup modules that provide data that should be installed alongside
|
|
// the test
|
|
Data []string `android:"path"`
|
|
|
|
// Install the test into a folder named for the module in all test suites.
|
|
Per_testcase_directory *bool
|
|
}
|
|
|
|
data android.Paths
|
|
}
|
|
|
|
func (a *AndroidTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|
a.generateAndroidBuildActions(ctx)
|
|
|
|
a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
|
|
}
|
|
|
|
func (a *AndroidTestImport) InstallInTestcases() bool {
|
|
return true
|
|
}
|
|
|
|
// android_test_import imports a prebuilt test apk with additional processing specified in the
|
|
// module. DPI or arch variant configurations can be made as with android_app_import.
|
|
func AndroidTestImportFactory() android.Module {
|
|
module := &AndroidTestImport{}
|
|
module.AddProperties(&module.properties)
|
|
module.AddProperties(&module.dexpreoptProperties)
|
|
module.AddProperties(&module.testProperties)
|
|
module.populateAllVariantStructs()
|
|
android.AddLoadHook(module, func(ctx android.LoadHookContext) {
|
|
module.processVariants(ctx)
|
|
})
|
|
|
|
module.dexpreopter.isTest = true
|
|
|
|
android.InitApexModule(module)
|
|
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
|
|
android.InitDefaultableModule(module)
|
|
android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk")
|
|
|
|
return module
|
|
}
|