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