1// Copyright 2020 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package java 16 17// This file contains the module implementations for android_app_import and android_test_import. 18 19import ( 20 "fmt" 21 "reflect" 22 "strings" 23 24 "github.com/google/blueprint" 25 26 "github.com/google/blueprint/proptools" 27 28 "android/soong/android" 29 "android/soong/provenance" 30) 31 32func init() { 33 RegisterAppImportBuildComponents(android.InitRegistrationContext) 34 35 initAndroidAppImportVariantGroupTypes() 36} 37 38var ( 39 uncompressEmbeddedJniLibsRule = pctx.AndroidStaticRule("uncompress-embedded-jni-libs", blueprint.RuleParams{ 40 Command: `if (zipinfo $in 'lib/*.so' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then ` + 41 `${config.Zip2ZipCmd} -i $in -o $out -0 'lib/**/*.so'` + 42 `; else cp -f $in $out; fi`, 43 CommandDeps: []string{"${config.Zip2ZipCmd}"}, 44 Description: "Uncompress embedded JNI libs", 45 }) 46 47 uncompressDexRule = pctx.AndroidStaticRule("uncompress-dex", blueprint.RuleParams{ 48 Command: `if (zipinfo $in '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then ` + 49 `${config.Zip2ZipCmd} -i $in -o $out -0 'classes*.dex'` + 50 `; else cp -f $in $out; fi`, 51 CommandDeps: []string{"${config.Zip2ZipCmd}"}, 52 Description: "Uncompress dex files", 53 }) 54 55 checkPresignedApkRule = pctx.AndroidStaticRule("check-presigned-apk", blueprint.RuleParams{ 56 Command: "build/soong/scripts/check_prebuilt_presigned_apk.py --aapt2 ${config.Aapt2Cmd} --zipalign ${config.ZipAlign} $extraArgs $in $out", 57 CommandDeps: []string{"build/soong/scripts/check_prebuilt_presigned_apk.py", "${config.Aapt2Cmd}", "${config.ZipAlign}"}, 58 Description: "Check presigned apk", 59 }, "extraArgs") 60) 61 62func RegisterAppImportBuildComponents(ctx android.RegistrationContext) { 63 ctx.RegisterModuleType("android_app_import", AndroidAppImportFactory) 64 ctx.RegisterModuleType("android_test_import", AndroidTestImportFactory) 65} 66 67type AndroidAppImport struct { 68 android.ModuleBase 69 android.DefaultableModuleBase 70 android.ApexModuleBase 71 prebuilt android.Prebuilt 72 73 properties AndroidAppImportProperties 74 dpiVariants interface{} 75 archVariants interface{} 76 arch_dpiVariants interface{} 77 78 outputFile android.Path 79 certificate Certificate 80 81 dexpreopter 82 83 usesLibrary usesLibrary 84 85 installPath android.InstallPath 86 87 hideApexVariantFromMake bool 88 89 provenanceMetaDataFile android.OutputPath 90} 91 92type AndroidAppImportProperties struct { 93 // A prebuilt apk to import 94 Apk *string `android:"path"` 95 96 // The name of a certificate in the default certificate directory or an android_app_certificate 97 // module name in the form ":module". Should be empty if presigned or default_dev_cert is set. 98 Certificate *string 99 100 // Names of extra android_app_certificate modules to sign the apk with in the form ":module". 101 Additional_certificates []string 102 103 // Set this flag to true if the prebuilt apk is already signed. The certificate property must not 104 // be set for presigned modules. 105 Presigned *bool 106 107 // Name of the signing certificate lineage file or filegroup module. 108 Lineage *string `android:"path"` 109 110 // For overriding the --rotation-min-sdk-version property of apksig 111 RotationMinSdkVersion *string 112 113 // Sign with the default system dev certificate. Must be used judiciously. Most imported apps 114 // need to either specify a specific certificate or be presigned. 115 Default_dev_cert *bool 116 117 // Specifies that this app should be installed to the priv-app directory, 118 // where the system will grant it additional privileges not available to 119 // normal apps. 120 Privileged *bool 121 122 // Names of modules to be overridden. Listed modules can only be other binaries 123 // (in Make or Soong). 124 // This does not completely prevent installation of the overridden binaries, but if both 125 // binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed 126 // from PRODUCT_PACKAGES. 127 Overrides []string 128 129 // Optional name for the installed app. If unspecified, it is derived from the module name. 130 Filename *string 131 132 // If set, create package-export.apk, which other packages can 133 // use to get PRODUCT-agnostic resource data like IDs and type definitions. 134 Export_package_resources *bool 135 136 // Optional. Install to a subdirectory of the default install path for the module 137 Relative_install_path *string 138 139 // Whether the prebuilt apk can be installed without additional processing. Default is false. 140 Preprocessed *bool 141 142 // Whether or not to skip checking the preprocessed apk for proper alignment and uncompressed 143 // JNI libs and dex files. Default is false 144 Skip_preprocessed_apk_checks *bool 145 146 // Name of the source soong module that gets shadowed by this prebuilt 147 // If unspecified, follows the naming convention that the source module of 148 // the prebuilt is Name() without "prebuilt_" prefix 149 Source_module_name *string 150 151 // Path to the .prebuilt_info file of the prebuilt app. 152 // In case of mainline modules, the .prebuilt_info file contains the build_id that was used 153 // to generate the prebuilt. 154 Prebuilt_info *string `android:"path"` 155} 156 157func (a *AndroidAppImport) IsInstallable() bool { 158 return true 159} 160 161// Updates properties with variant-specific values. 162// This happens as a DefaultableHook instead of a LoadHook because we want to run it after 163// soong config variables are applied. 164func (a *AndroidAppImport) processVariants(ctx android.DefaultableHookContext) { 165 config := ctx.Config() 166 dpiProps := reflect.ValueOf(a.dpiVariants).Elem().FieldByName(DpiGroupName) 167 168 // Try DPI variant matches in the reverse-priority order so that the highest priority match 169 // overwrites everything else. 170 // TODO(jungjw): Can we optimize this by making it priority order? 171 for i := len(config.ProductAAPTPrebuiltDPI()) - 1; i >= 0; i-- { 172 MergePropertiesFromVariant(ctx, &a.properties, dpiProps, config.ProductAAPTPrebuiltDPI()[i]) 173 } 174 if config.ProductAAPTPreferredConfig() != "" { 175 MergePropertiesFromVariant(ctx, &a.properties, dpiProps, config.ProductAAPTPreferredConfig()) 176 } 177 archProps := reflect.ValueOf(a.archVariants).Elem().FieldByName(ArchGroupName) 178 archType := ctx.Config().AndroidFirstDeviceTarget.Arch.ArchType 179 MergePropertiesFromVariant(ctx, &a.properties, archProps, archType.Name) 180 181 // Process "arch" includes "dpi_variants" 182 archStructPtr := reflect.ValueOf(a.arch_dpiVariants).Elem().FieldByName(ArchGroupName) 183 if archStruct := archStructPtr.Elem(); archStruct.IsValid() { 184 archPartPropsPtr := archStruct.FieldByName(proptools.FieldNameForProperty(archType.Name)) 185 if archPartProps := archPartPropsPtr.Elem(); archPartProps.IsValid() { 186 archDpiPropsPtr := archPartProps.FieldByName(DpiGroupName) 187 if archDpiProps := archDpiPropsPtr.Elem(); archDpiProps.IsValid() { 188 for i := len(config.ProductAAPTPrebuiltDPI()) - 1; i >= 0; i-- { 189 MergePropertiesFromVariant(ctx, &a.properties, archDpiProps, config.ProductAAPTPrebuiltDPI()[i]) 190 } 191 if config.ProductAAPTPreferredConfig() != "" { 192 MergePropertiesFromVariant(ctx, &a.properties, archDpiProps, config.ProductAAPTPreferredConfig()) 193 } 194 } 195 } 196 } 197 198 if String(a.properties.Apk) == "" { 199 // Disable this module since the apk property is still empty after processing all matching 200 // variants. This likely means there is no matching variant, and the default variant doesn't 201 // have an apk property value either. 202 a.Disable() 203 } 204} 205 206func MergePropertiesFromVariant(ctx android.EarlyModuleContext, 207 dst interface{}, variantGroup reflect.Value, variant string) { 208 src := variantGroup.FieldByName(proptools.FieldNameForProperty(variant)) 209 if !src.IsValid() { 210 return 211 } 212 213 err := proptools.ExtendMatchingProperties([]interface{}{dst}, src.Interface(), nil, proptools.OrderAppend) 214 if err != nil { 215 if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { 216 ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) 217 } else { 218 panic(err) 219 } 220 } 221} 222 223func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) { 224 cert := android.SrcIsModule(String(a.properties.Certificate)) 225 if cert != "" { 226 ctx.AddDependency(ctx.Module(), certificateTag, cert) 227 } 228 229 for _, cert := range a.properties.Additional_certificates { 230 cert = android.SrcIsModule(cert) 231 if cert != "" { 232 ctx.AddDependency(ctx.Module(), certificateTag, cert) 233 } else { 234 ctx.PropertyErrorf("additional_certificates", 235 `must be names of android_app_certificate modules in the form ":module"`) 236 } 237 } 238 239 a.usesLibrary.deps(ctx, true) 240} 241 242func (a *AndroidAppImport) uncompressEmbeddedJniLibs( 243 ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) { 244 // Test apps don't need their JNI libraries stored uncompressed. As a matter of fact, messing 245 // with them may invalidate pre-existing signature data. 246 if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || Bool(a.properties.Preprocessed)) { 247 ctx.Build(pctx, android.BuildParams{ 248 Rule: android.Cp, 249 Output: outputPath, 250 Input: inputPath, 251 }) 252 return 253 } 254 255 ctx.Build(pctx, android.BuildParams{ 256 Rule: uncompressEmbeddedJniLibsRule, 257 Input: inputPath, 258 Output: outputPath, 259 }) 260} 261 262// Returns whether this module should have the dex file stored uncompressed in the APK. 263func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool { 264 if ctx.Config().UnbundledBuild() || proptools.Bool(a.properties.Preprocessed) { 265 return false 266 } 267 268 // Uncompress dex in APKs of priv-apps if and only if DONT_UNCOMPRESS_PRIV_APPS_DEXS is false. 269 if a.Privileged() { 270 return ctx.Config().UncompressPrivAppDex() 271 } 272 273 return shouldUncompressDex(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), &a.dexpreopter) 274} 275 276func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { 277 a.generateAndroidBuildActions(ctx) 278} 279 280func (a *AndroidAppImport) InstallApkName() string { 281 return a.BaseModuleName() 282} 283 284func (a *AndroidAppImport) BaseModuleName() string { 285 return proptools.StringDefault(a.properties.Source_module_name, a.ModuleBase.Name()) 286} 287 288func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext) { 289 if a.Name() == "prebuilt_framework-res" { 290 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.") 291 } 292 293 apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) 294 if !apexInfo.IsForPlatform() { 295 a.hideApexVariantFromMake = true 296 } 297 298 if Bool(a.properties.Preprocessed) { 299 if a.properties.Presigned != nil && !*a.properties.Presigned { 300 ctx.ModuleErrorf("Setting preprocessed: true implies presigned: true, so you cannot set presigned to false") 301 } 302 t := true 303 a.properties.Presigned = &t 304 } 305 306 numCertPropsSet := 0 307 if String(a.properties.Certificate) != "" { 308 numCertPropsSet++ 309 } 310 if Bool(a.properties.Presigned) { 311 numCertPropsSet++ 312 } 313 if Bool(a.properties.Default_dev_cert) { 314 numCertPropsSet++ 315 } 316 if numCertPropsSet != 1 { 317 ctx.ModuleErrorf("One and only one of certficate, presigned (implied by preprocessed), and default_dev_cert properties must be set") 318 } 319 320 // TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK 321 // TODO: LOCAL_PACKAGE_SPLITS 322 323 srcApk := a.prebuilt.SingleSourcePath(ctx) 324 325 // TODO: Install or embed JNI libraries 326 327 // Uncompress JNI libraries in the apk 328 jnisUncompressed := android.PathForModuleOut(ctx, "jnis-uncompressed", ctx.ModuleName()+".apk") 329 a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed.OutputPath) 330 331 var pathFragments []string 332 relInstallPath := String(a.properties.Relative_install_path) 333 334 if Bool(a.properties.Privileged) { 335 pathFragments = []string{"priv-app", relInstallPath, a.BaseModuleName()} 336 } else if ctx.InstallInTestcases() { 337 pathFragments = []string{relInstallPath, a.BaseModuleName(), ctx.DeviceConfig().DeviceArch()} 338 } else { 339 pathFragments = []string{"app", relInstallPath, a.BaseModuleName()} 340 } 341 342 installDir := android.PathForModuleInstall(ctx, pathFragments...) 343 a.dexpreopter.isApp = true 344 a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk") 345 a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned) 346 a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx) 347 348 a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries() 349 a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx) 350 if a.usesLibrary.shouldDisableDexpreopt { 351 a.dexpreopter.disableDexpreopt() 352 } 353 354 if a.usesLibrary.enforceUsesLibraries() { 355 a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk, &a.dexpreopter.classLoaderContexts) 356 } 357 358 a.dexpreopter.dexpreopt(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), jnisUncompressed) 359 if a.dexpreopter.uncompressedDex { 360 dexUncompressed := android.PathForModuleOut(ctx, "dex-uncompressed", ctx.ModuleName()+".apk") 361 ctx.Build(pctx, android.BuildParams{ 362 Rule: uncompressDexRule, 363 Input: jnisUncompressed, 364 Output: dexUncompressed, 365 }) 366 jnisUncompressed = dexUncompressed 367 } 368 369 apkFilename := proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".apk") 370 371 // TODO: Handle EXTERNAL 372 373 // Sign or align the package if package has not been preprocessed 374 375 if proptools.Bool(a.properties.Preprocessed) { 376 validationStamp := a.validatePresignedApk(ctx, srcApk) 377 output := android.PathForModuleOut(ctx, apkFilename) 378 ctx.Build(pctx, android.BuildParams{ 379 Rule: android.Cp, 380 Input: srcApk, 381 Output: output, 382 Validation: validationStamp, 383 }) 384 a.outputFile = output 385 a.certificate = PresignedCertificate 386 } else if !Bool(a.properties.Presigned) { 387 // If the certificate property is empty at this point, default_dev_cert must be set to true. 388 // Which makes processMainCert's behavior for the empty cert string WAI. 389 _, _, certificates := collectAppDeps(ctx, a, false, false) 390 a.certificate, certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx) 391 signed := android.PathForModuleOut(ctx, "signed", apkFilename) 392 var lineageFile android.Path 393 if lineage := String(a.properties.Lineage); lineage != "" { 394 lineageFile = android.PathForModuleSrc(ctx, lineage) 395 } 396 397 rotationMinSdkVersion := String(a.properties.RotationMinSdkVersion) 398 399 SignAppPackage(ctx, signed, jnisUncompressed, certificates, nil, lineageFile, rotationMinSdkVersion) 400 a.outputFile = signed 401 } else { 402 validationStamp := a.validatePresignedApk(ctx, srcApk) 403 alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename) 404 TransformZipAlign(ctx, alignedApk, jnisUncompressed, []android.Path{validationStamp}) 405 a.outputFile = alignedApk 406 a.certificate = PresignedCertificate 407 } 408 409 // TODO: Optionally compress the output apk. 410 411 if apexInfo.IsForPlatform() { 412 a.installPath = ctx.InstallFile(installDir, apkFilename, a.outputFile) 413 artifactPath := android.PathForModuleSrc(ctx, *a.properties.Apk) 414 a.provenanceMetaDataFile = provenance.GenerateArtifactProvenanceMetaData(ctx, artifactPath, a.installPath) 415 } 416 417 providePrebuiltInfo(ctx, 418 prebuiltInfoProps{ 419 baseModuleName: a.BaseModuleName(), 420 isPrebuilt: true, 421 prebuiltInfo: a.properties.Prebuilt_info, 422 }, 423 ) 424 425 // TODO: androidmk converter jni libs 426} 427 428func (a *AndroidAppImport) validatePresignedApk(ctx android.ModuleContext, srcApk android.Path) android.Path { 429 stamp := android.PathForModuleOut(ctx, "validated-prebuilt", "check.stamp") 430 var extraArgs []string 431 if a.Privileged() { 432 extraArgs = append(extraArgs, "--privileged") 433 } 434 if proptools.Bool(a.properties.Skip_preprocessed_apk_checks) { 435 extraArgs = append(extraArgs, "--skip-preprocessed-apk-checks") 436 } 437 if proptools.Bool(a.properties.Preprocessed) { 438 extraArgs = append(extraArgs, "--preprocessed") 439 } 440 441 ctx.Build(pctx, android.BuildParams{ 442 Rule: checkPresignedApkRule, 443 Input: srcApk, 444 Output: stamp, 445 Args: map[string]string{ 446 "extraArgs": strings.Join(extraArgs, " "), 447 }, 448 }) 449 return stamp 450} 451 452func (a *AndroidAppImport) Prebuilt() *android.Prebuilt { 453 return &a.prebuilt 454} 455 456func (a *AndroidAppImport) Name() string { 457 return a.prebuilt.Name(a.ModuleBase.Name()) 458} 459 460func (a *AndroidAppImport) OutputFile() android.Path { 461 return a.outputFile 462} 463 464func (a *AndroidAppImport) OutputFiles(tag string) (android.Paths, error) { 465 switch tag { 466 case "": 467 return []android.Path{a.outputFile}, nil 468 default: 469 return nil, fmt.Errorf("unsupported module reference tag %q", tag) 470 } 471} 472 473func (a *AndroidAppImport) JacocoReportClassesFile() android.Path { 474 return nil 475} 476 477func (a *AndroidAppImport) Certificate() Certificate { 478 return a.certificate 479} 480 481func (a *AndroidAppImport) ProvenanceMetaDataFile() android.OutputPath { 482 return a.provenanceMetaDataFile 483} 484 485func (a *AndroidAppImport) PrivAppAllowlist() android.OptionalPath { 486 return android.OptionalPath{} 487} 488 489const ( 490 ArchGroupName = "Arch" 491 DpiGroupName = "Dpi_variants" 492) 493 494var dpiVariantGroupType reflect.Type 495var archVariantGroupType reflect.Type 496var archdpiVariantGroupType reflect.Type 497var supportedDpis = []string{"ldpi", "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"} 498 499func initAndroidAppImportVariantGroupTypes() { 500 dpiVariantGroupType = createVariantGroupType(supportedDpis, DpiGroupName) 501 502 archNames := make([]string, len(android.ArchTypeList())) 503 for i, archType := range android.ArchTypeList() { 504 archNames[i] = archType.Name 505 } 506 archVariantGroupType = createVariantGroupType(archNames, ArchGroupName) 507 archdpiVariantGroupType = createArchDpiVariantGroupType(archNames, supportedDpis) 508} 509 510// Populates all variant struct properties at creation time. 511func (a *AndroidAppImport) populateAllVariantStructs() { 512 a.dpiVariants = reflect.New(dpiVariantGroupType).Interface() 513 a.AddProperties(a.dpiVariants) 514 515 a.archVariants = reflect.New(archVariantGroupType).Interface() 516 a.AddProperties(a.archVariants) 517 518 a.arch_dpiVariants = reflect.New(archdpiVariantGroupType).Interface() 519 a.AddProperties(a.arch_dpiVariants) 520} 521 522func (a *AndroidAppImport) Privileged() bool { 523 return Bool(a.properties.Privileged) 524} 525 526func (a *AndroidAppImport) DepIsInSameApex(_ android.BaseModuleContext, _ android.Module) bool { 527 // android_app_import might have extra dependencies via uses_libs property. 528 // Don't track the dependency as we don't automatically add those libraries 529 // to the classpath. It should be explicitly added to java_libs property of APEX 530 return false 531} 532 533func (a *AndroidAppImport) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { 534 return android.SdkSpecPrivate 535} 536 537func (a *AndroidAppImport) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { 538 return android.SdkSpecPrivate.ApiLevel 539} 540 541func (a *AndroidAppImport) LintDepSets() LintDepSets { 542 return LintDepSets{} 543} 544 545var _ android.ApexModule = (*AndroidAppImport)(nil) 546 547// Implements android.ApexModule 548func (j *AndroidAppImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, 549 sdkVersion android.ApiLevel) error { 550 // Do not check for prebuilts against the min_sdk_version of enclosing APEX 551 return nil 552} 553 554func createVariantGroupType(variants []string, variantGroupName string) reflect.Type { 555 props := reflect.TypeOf((*AndroidAppImportProperties)(nil)) 556 557 variantFields := make([]reflect.StructField, len(variants)) 558 for i, variant := range variants { 559 variantFields[i] = reflect.StructField{ 560 Name: proptools.FieldNameForProperty(variant), 561 Type: props, 562 } 563 } 564 565 variantGroupStruct := reflect.StructOf(variantFields) 566 return reflect.StructOf([]reflect.StructField{ 567 { 568 Name: variantGroupName, 569 Type: variantGroupStruct, 570 }, 571 }) 572} 573 574func createArchDpiVariantGroupType(archNames []string, dpiNames []string) reflect.Type { 575 props := reflect.TypeOf((*AndroidAppImportProperties)(nil)) 576 577 dpiVariantFields := make([]reflect.StructField, len(dpiNames)) 578 for i, variant_dpi := range dpiNames { 579 dpiVariantFields[i] = reflect.StructField{ 580 Name: proptools.FieldNameForProperty(variant_dpi), 581 Type: props, 582 } 583 } 584 dpiVariantGroupStruct := reflect.StructOf(dpiVariantFields) 585 dpi_struct := reflect.StructOf([]reflect.StructField{ 586 { 587 Name: DpiGroupName, 588 Type: reflect.PointerTo(dpiVariantGroupStruct), 589 }, 590 }) 591 592 archVariantFields := make([]reflect.StructField, len(archNames)) 593 for i, variant_arch := range archNames { 594 archVariantFields[i] = reflect.StructField{ 595 Name: proptools.FieldNameForProperty(variant_arch), 596 Type: reflect.PointerTo(dpi_struct), 597 } 598 } 599 archVariantGroupStruct := reflect.StructOf(archVariantFields) 600 601 return_struct := reflect.StructOf([]reflect.StructField{ 602 { 603 Name: ArchGroupName, 604 Type: reflect.PointerTo(archVariantGroupStruct), 605 }, 606 }) 607 return return_struct 608} 609 610func (a *AndroidAppImport) UsesLibrary() *usesLibrary { 611 return &a.usesLibrary 612} 613 614var _ ModuleWithUsesLibrary = (*AndroidAppImport)(nil) 615 616// android_app_import imports a prebuilt apk with additional processing specified in the module. 617// DPI-specific apk source files can be specified using dpi_variants. Example: 618// 619// android_app_import { 620// name: "example_import", 621// apk: "prebuilts/example.apk", 622// dpi_variants: { 623// mdpi: { 624// apk: "prebuilts/example_mdpi.apk", 625// }, 626// xhdpi: { 627// apk: "prebuilts/example_xhdpi.apk", 628// }, 629// }, 630// presigned: true, 631// } 632func AndroidAppImportFactory() android.Module { 633 module := &AndroidAppImport{} 634 module.AddProperties(&module.properties) 635 module.AddProperties(&module.dexpreoptProperties) 636 module.AddProperties(&module.usesLibrary.usesLibraryProperties) 637 module.populateAllVariantStructs() 638 module.SetDefaultableHook(func(ctx android.DefaultableHookContext) { 639 module.processVariants(ctx) 640 }) 641 642 android.InitApexModule(module) 643 android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) 644 android.InitDefaultableModule(module) 645 android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk") 646 647 module.usesLibrary.enforce = true 648 649 return module 650} 651 652type AndroidTestImport struct { 653 AndroidAppImport 654 655 testProperties struct { 656 // list of compatibility suites (for example "cts", "vts") that the module should be 657 // installed into. 658 Test_suites []string `android:"arch_variant"` 659 660 // list of files or filegroup modules that provide data that should be installed alongside 661 // the test 662 Data []string `android:"path"` 663 664 // Install the test into a folder named for the module in all test suites. 665 Per_testcase_directory *bool 666 } 667 668 data android.Paths 669} 670 671func (a *AndroidTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { 672 a.generateAndroidBuildActions(ctx) 673 674 a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data) 675} 676 677func (a *AndroidTestImport) InstallInTestcases() bool { 678 return true 679} 680 681// android_test_import imports a prebuilt test apk with additional processing specified in the 682// module. DPI or arch variant configurations can be made as with android_app_import. 683func AndroidTestImportFactory() android.Module { 684 module := &AndroidTestImport{} 685 module.AddProperties(&module.properties) 686 module.AddProperties(&module.dexpreoptProperties) 687 module.AddProperties(&module.testProperties) 688 module.populateAllVariantStructs() 689 module.SetDefaultableHook(func(ctx android.DefaultableHookContext) { 690 module.processVariants(ctx) 691 }) 692 693 module.dexpreopter.isTest = true 694 695 android.InitApexModule(module) 696 android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) 697 android.InitDefaultableModule(module) 698 android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk") 699 700 return module 701} 702