app_import.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  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. package java
  15. // This file contains the module implementations for android_app_import and android_test_import.
  16. import (
  17. "reflect"
  18. "github.com/google/blueprint"
  19. "github.com/google/blueprint/proptools"
  20. "android/soong/android"
  21. "android/soong/provenance"
  22. )
  23. func init() {
  24. RegisterAppImportBuildComponents(android.InitRegistrationContext)
  25. initAndroidAppImportVariantGroupTypes()
  26. }
  27. var (
  28. uncompressEmbeddedJniLibsRule = pctx.AndroidStaticRule("uncompress-embedded-jni-libs", blueprint.RuleParams{
  29. Command: `if (zipinfo $in 'lib/*.so' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then ` +
  30. `${config.Zip2ZipCmd} -i $in -o $out -0 'lib/**/*.so'` +
  31. `; else cp -f $in $out; fi`,
  32. CommandDeps: []string{"${config.Zip2ZipCmd}"},
  33. Description: "Uncompress embedded JNI libs",
  34. })
  35. uncompressDexRule = pctx.AndroidStaticRule("uncompress-dex", blueprint.RuleParams{
  36. Command: `if (zipinfo $in '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then ` +
  37. `${config.Zip2ZipCmd} -i $in -o $out -0 'classes*.dex'` +
  38. `; else cp -f $in $out; fi`,
  39. CommandDeps: []string{"${config.Zip2ZipCmd}"},
  40. Description: "Uncompress dex files",
  41. })
  42. checkJniAndDexLibsAreUncompressedRule = pctx.AndroidStaticRule("check-jni-and-dex-libs-are-uncompressed", blueprint.RuleParams{
  43. // grep -v ' stor ' will search for lines that don't have ' stor '. stor means the file is stored uncompressed
  44. Command: "if (zipinfo $in 'lib/*.so' '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then " +
  45. "echo $in: Contains compressed JNI libraries and/or dex files >&2;" +
  46. "exit 1; " +
  47. "else " +
  48. "touch $out; " +
  49. "fi",
  50. Description: "Check for compressed JNI libs or dex files",
  51. })
  52. )
  53. func RegisterAppImportBuildComponents(ctx android.RegistrationContext) {
  54. ctx.RegisterModuleType("android_app_import", AndroidAppImportFactory)
  55. ctx.RegisterModuleType("android_test_import", AndroidTestImportFactory)
  56. }
  57. type AndroidAppImport struct {
  58. android.ModuleBase
  59. android.DefaultableModuleBase
  60. android.ApexModuleBase
  61. prebuilt android.Prebuilt
  62. properties AndroidAppImportProperties
  63. dpiVariants interface{}
  64. archVariants interface{}
  65. outputFile android.Path
  66. certificate Certificate
  67. dexpreopter
  68. usesLibrary usesLibrary
  69. installPath android.InstallPath
  70. hideApexVariantFromMake bool
  71. provenanceMetaDataFile android.OutputPath
  72. }
  73. type AndroidAppImportProperties struct {
  74. // A prebuilt apk to import
  75. Apk *string `android:"path"`
  76. // The name of a certificate in the default certificate directory or an android_app_certificate
  77. // module name in the form ":module". Should be empty if presigned or default_dev_cert is set.
  78. Certificate *string
  79. // Names of extra android_app_certificate modules to sign the apk with in the form ":module".
  80. Additional_certificates []string
  81. // Set this flag to true if the prebuilt apk is already signed. The certificate property must not
  82. // be set for presigned modules.
  83. Presigned *bool
  84. // Name of the signing certificate lineage file or filegroup module.
  85. Lineage *string `android:"path"`
  86. // For overriding the --rotation-min-sdk-version property of apksig
  87. RotationMinSdkVersion *string
  88. // Sign with the default system dev certificate. Must be used judiciously. Most imported apps
  89. // need to either specify a specific certificate or be presigned.
  90. Default_dev_cert *bool
  91. // Specifies that this app should be installed to the priv-app directory,
  92. // where the system will grant it additional privileges not available to
  93. // normal apps.
  94. Privileged *bool
  95. // Names of modules to be overridden. Listed modules can only be other binaries
  96. // (in Make or Soong).
  97. // This does not completely prevent installation of the overridden binaries, but if both
  98. // binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
  99. // from PRODUCT_PACKAGES.
  100. Overrides []string
  101. // Optional name for the installed app. If unspecified, it is derived from the module name.
  102. Filename *string
  103. // If set, create package-export.apk, which other packages can
  104. // use to get PRODUCT-agnostic resource data like IDs and type definitions.
  105. Export_package_resources *bool
  106. // Optional. Install to a subdirectory of the default install path for the module
  107. Relative_install_path *string
  108. // Whether the prebuilt apk can be installed without additional processing. Default is false.
  109. Preprocessed *bool
  110. // Whether or not to skip checking the preprocessed apk for proper alignment and uncompressed
  111. // JNI libs and dex files. Default is false
  112. Skip_preprocessed_apk_checks *bool
  113. }
  114. func (a *AndroidAppImport) IsInstallable() bool {
  115. return true
  116. }
  117. // Updates properties with variant-specific values.
  118. func (a *AndroidAppImport) processVariants(ctx android.LoadHookContext) {
  119. config := ctx.Config()
  120. dpiProps := reflect.ValueOf(a.dpiVariants).Elem().FieldByName("Dpi_variants")
  121. // Try DPI variant matches in the reverse-priority order so that the highest priority match
  122. // overwrites everything else.
  123. // TODO(jungjw): Can we optimize this by making it priority order?
  124. for i := len(config.ProductAAPTPrebuiltDPI()) - 1; i >= 0; i-- {
  125. MergePropertiesFromVariant(ctx, &a.properties, dpiProps, config.ProductAAPTPrebuiltDPI()[i])
  126. }
  127. if config.ProductAAPTPreferredConfig() != "" {
  128. MergePropertiesFromVariant(ctx, &a.properties, dpiProps, config.ProductAAPTPreferredConfig())
  129. }
  130. archProps := reflect.ValueOf(a.archVariants).Elem().FieldByName("Arch")
  131. archType := ctx.Config().AndroidFirstDeviceTarget.Arch.ArchType
  132. MergePropertiesFromVariant(ctx, &a.properties, archProps, archType.Name)
  133. if String(a.properties.Apk) == "" {
  134. // Disable this module since the apk property is still empty after processing all matching
  135. // variants. This likely means there is no matching variant, and the default variant doesn't
  136. // have an apk property value either.
  137. a.Disable()
  138. }
  139. }
  140. func MergePropertiesFromVariant(ctx android.EarlyModuleContext,
  141. dst interface{}, variantGroup reflect.Value, variant string) {
  142. src := variantGroup.FieldByName(proptools.FieldNameForProperty(variant))
  143. if !src.IsValid() {
  144. return
  145. }
  146. err := proptools.ExtendMatchingProperties([]interface{}{dst}, src.Interface(), nil, proptools.OrderAppend)
  147. if err != nil {
  148. if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
  149. ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
  150. } else {
  151. panic(err)
  152. }
  153. }
  154. }
  155. func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) {
  156. cert := android.SrcIsModule(String(a.properties.Certificate))
  157. if cert != "" {
  158. ctx.AddDependency(ctx.Module(), certificateTag, cert)
  159. }
  160. for _, cert := range a.properties.Additional_certificates {
  161. cert = android.SrcIsModule(cert)
  162. if cert != "" {
  163. ctx.AddDependency(ctx.Module(), certificateTag, cert)
  164. } else {
  165. ctx.PropertyErrorf("additional_certificates",
  166. `must be names of android_app_certificate modules in the form ":module"`)
  167. }
  168. }
  169. a.usesLibrary.deps(ctx, true)
  170. }
  171. func (a *AndroidAppImport) uncompressEmbeddedJniLibs(
  172. ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
  173. // Test apps don't need their JNI libraries stored uncompressed. As a matter of fact, messing
  174. // with them may invalidate pre-existing signature data.
  175. if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || Bool(a.properties.Preprocessed)) {
  176. ctx.Build(pctx, android.BuildParams{
  177. Rule: android.Cp,
  178. Output: outputPath,
  179. Input: inputPath,
  180. })
  181. return
  182. }
  183. ctx.Build(pctx, android.BuildParams{
  184. Rule: uncompressEmbeddedJniLibsRule,
  185. Input: inputPath,
  186. Output: outputPath,
  187. })
  188. }
  189. // Returns whether this module should have the dex file stored uncompressed in the APK.
  190. func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool {
  191. if ctx.Config().UnbundledBuild() || proptools.Bool(a.properties.Preprocessed) {
  192. return false
  193. }
  194. // Uncompress dex in APKs of priv-apps if and only if DONT_UNCOMPRESS_PRIV_APPS_DEXS is false.
  195. if a.Privileged() {
  196. return ctx.Config().UncompressPrivAppDex()
  197. }
  198. return shouldUncompressDex(ctx, &a.dexpreopter)
  199. }
  200. func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
  201. a.generateAndroidBuildActions(ctx)
  202. }
  203. func (a *AndroidAppImport) InstallApkName() string {
  204. return a.BaseModuleName()
  205. }
  206. func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext) {
  207. if a.Name() == "prebuilt_framework-res" {
  208. 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.")
  209. }
  210. apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
  211. if !apexInfo.IsForPlatform() {
  212. a.hideApexVariantFromMake = true
  213. }
  214. numCertPropsSet := 0
  215. if String(a.properties.Certificate) != "" {
  216. numCertPropsSet++
  217. }
  218. if Bool(a.properties.Presigned) {
  219. numCertPropsSet++
  220. }
  221. if Bool(a.properties.Default_dev_cert) {
  222. numCertPropsSet++
  223. }
  224. if numCertPropsSet != 1 {
  225. ctx.ModuleErrorf("One and only one of certficate, presigned, and default_dev_cert properties must be set")
  226. }
  227. _, _, certificates := collectAppDeps(ctx, a, false, false)
  228. // TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
  229. // TODO: LOCAL_PACKAGE_SPLITS
  230. srcApk := a.prebuilt.SingleSourcePath(ctx)
  231. // TODO: Install or embed JNI libraries
  232. // Uncompress JNI libraries in the apk
  233. jnisUncompressed := android.PathForModuleOut(ctx, "jnis-uncompressed", ctx.ModuleName()+".apk")
  234. a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed.OutputPath)
  235. var pathFragments []string
  236. relInstallPath := String(a.properties.Relative_install_path)
  237. if Bool(a.properties.Privileged) {
  238. pathFragments = []string{"priv-app", relInstallPath, a.BaseModuleName()}
  239. } else if ctx.InstallInTestcases() {
  240. pathFragments = []string{relInstallPath, a.BaseModuleName(), ctx.DeviceConfig().DeviceArch()}
  241. } else {
  242. pathFragments = []string{"app", relInstallPath, a.BaseModuleName()}
  243. }
  244. installDir := android.PathForModuleInstall(ctx, pathFragments...)
  245. a.dexpreopter.isApp = true
  246. a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk")
  247. a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
  248. a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
  249. a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
  250. a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
  251. if a.usesLibrary.enforceUsesLibraries() {
  252. a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
  253. }
  254. a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
  255. if a.dexpreopter.uncompressedDex {
  256. dexUncompressed := android.PathForModuleOut(ctx, "dex-uncompressed", ctx.ModuleName()+".apk")
  257. ctx.Build(pctx, android.BuildParams{
  258. Rule: uncompressDexRule,
  259. Input: jnisUncompressed,
  260. Output: dexUncompressed,
  261. })
  262. jnisUncompressed = dexUncompressed
  263. }
  264. apkFilename := proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".apk")
  265. // TODO: Handle EXTERNAL
  266. // Sign or align the package if package has not been preprocessed
  267. if proptools.Bool(a.properties.Preprocessed) {
  268. output := srcApk
  269. if !proptools.Bool(a.properties.Skip_preprocessed_apk_checks) {
  270. writableOutput := android.PathForModuleOut(ctx, "validated-prebuilt", apkFilename)
  271. a.validatePreprocessedApk(ctx, srcApk, writableOutput)
  272. output = writableOutput
  273. }
  274. a.outputFile = output
  275. a.certificate = PresignedCertificate
  276. } else if !Bool(a.properties.Presigned) {
  277. // If the certificate property is empty at this point, default_dev_cert must be set to true.
  278. // Which makes processMainCert's behavior for the empty cert string WAI.
  279. a.certificate, certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx)
  280. signed := android.PathForModuleOut(ctx, "signed", apkFilename)
  281. var lineageFile android.Path
  282. if lineage := String(a.properties.Lineage); lineage != "" {
  283. lineageFile = android.PathForModuleSrc(ctx, lineage)
  284. }
  285. rotationMinSdkVersion := String(a.properties.RotationMinSdkVersion)
  286. SignAppPackage(ctx, signed, jnisUncompressed, certificates, nil, lineageFile, rotationMinSdkVersion)
  287. a.outputFile = signed
  288. } else {
  289. alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename)
  290. TransformZipAlign(ctx, alignedApk, jnisUncompressed)
  291. a.outputFile = alignedApk
  292. a.certificate = PresignedCertificate
  293. }
  294. // TODO: Optionally compress the output apk.
  295. if apexInfo.IsForPlatform() {
  296. a.installPath = ctx.InstallFile(installDir, apkFilename, a.outputFile)
  297. artifactPath := android.PathForModuleSrc(ctx, *a.properties.Apk)
  298. a.provenanceMetaDataFile = provenance.GenerateArtifactProvenanceMetaData(ctx, artifactPath, a.installPath)
  299. }
  300. // TODO: androidmk converter jni libs
  301. }
  302. func (a *AndroidAppImport) validatePreprocessedApk(ctx android.ModuleContext, srcApk android.Path, dstApk android.WritablePath) {
  303. alignmentStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "alignment.stamp")
  304. ctx.Build(pctx, android.BuildParams{
  305. Rule: checkZipAlignment,
  306. Input: srcApk,
  307. Output: alignmentStamp,
  308. })
  309. compressionStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "compression.stamp")
  310. ctx.Build(pctx, android.BuildParams{
  311. Rule: checkJniAndDexLibsAreUncompressedRule,
  312. Input: srcApk,
  313. Output: compressionStamp,
  314. })
  315. ctx.Build(pctx, android.BuildParams{
  316. Rule: android.Cp,
  317. Input: srcApk,
  318. Output: dstApk,
  319. Validations: []android.Path{
  320. alignmentStamp,
  321. compressionStamp,
  322. },
  323. })
  324. }
  325. func (a *AndroidAppImport) Prebuilt() *android.Prebuilt {
  326. return &a.prebuilt
  327. }
  328. func (a *AndroidAppImport) Name() string {
  329. return a.prebuilt.Name(a.ModuleBase.Name())
  330. }
  331. func (a *AndroidAppImport) OutputFile() android.Path {
  332. return a.outputFile
  333. }
  334. func (a *AndroidAppImport) JacocoReportClassesFile() android.Path {
  335. return nil
  336. }
  337. func (a *AndroidAppImport) Certificate() Certificate {
  338. return a.certificate
  339. }
  340. func (a *AndroidAppImport) ProvenanceMetaDataFile() android.OutputPath {
  341. return a.provenanceMetaDataFile
  342. }
  343. func (a *AndroidAppImport) PrivAppAllowlist() android.OptionalPath {
  344. return android.OptionalPath{}
  345. }
  346. var dpiVariantGroupType reflect.Type
  347. var archVariantGroupType reflect.Type
  348. var supportedDpis = []string{"ldpi", "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"}
  349. func initAndroidAppImportVariantGroupTypes() {
  350. dpiVariantGroupType = createVariantGroupType(supportedDpis, "Dpi_variants")
  351. archNames := make([]string, len(android.ArchTypeList()))
  352. for i, archType := range android.ArchTypeList() {
  353. archNames[i] = archType.Name
  354. }
  355. archVariantGroupType = createVariantGroupType(archNames, "Arch")
  356. }
  357. // Populates all variant struct properties at creation time.
  358. func (a *AndroidAppImport) populateAllVariantStructs() {
  359. a.dpiVariants = reflect.New(dpiVariantGroupType).Interface()
  360. a.AddProperties(a.dpiVariants)
  361. a.archVariants = reflect.New(archVariantGroupType).Interface()
  362. a.AddProperties(a.archVariants)
  363. }
  364. func (a *AndroidAppImport) Privileged() bool {
  365. return Bool(a.properties.Privileged)
  366. }
  367. func (a *AndroidAppImport) DepIsInSameApex(_ android.BaseModuleContext, _ android.Module) bool {
  368. // android_app_import might have extra dependencies via uses_libs property.
  369. // Don't track the dependency as we don't automatically add those libraries
  370. // to the classpath. It should be explicitly added to java_libs property of APEX
  371. return false
  372. }
  373. func (a *AndroidAppImport) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
  374. return android.SdkSpecPrivate
  375. }
  376. func (a *AndroidAppImport) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
  377. return android.SdkSpecPrivate.ApiLevel
  378. }
  379. func (a *AndroidAppImport) LintDepSets() LintDepSets {
  380. return LintDepSets{}
  381. }
  382. var _ android.ApexModule = (*AndroidAppImport)(nil)
  383. // Implements android.ApexModule
  384. func (j *AndroidAppImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
  385. sdkVersion android.ApiLevel) error {
  386. // Do not check for prebuilts against the min_sdk_version of enclosing APEX
  387. return nil
  388. }
  389. func createVariantGroupType(variants []string, variantGroupName string) reflect.Type {
  390. props := reflect.TypeOf((*AndroidAppImportProperties)(nil))
  391. variantFields := make([]reflect.StructField, len(variants))
  392. for i, variant := range variants {
  393. variantFields[i] = reflect.StructField{
  394. Name: proptools.FieldNameForProperty(variant),
  395. Type: props,
  396. }
  397. }
  398. variantGroupStruct := reflect.StructOf(variantFields)
  399. return reflect.StructOf([]reflect.StructField{
  400. {
  401. Name: variantGroupName,
  402. Type: variantGroupStruct,
  403. },
  404. })
  405. }
  406. // android_app_import imports a prebuilt apk with additional processing specified in the module.
  407. // DPI-specific apk source files can be specified using dpi_variants. Example:
  408. //
  409. // android_app_import {
  410. // name: "example_import",
  411. // apk: "prebuilts/example.apk",
  412. // dpi_variants: {
  413. // mdpi: {
  414. // apk: "prebuilts/example_mdpi.apk",
  415. // },
  416. // xhdpi: {
  417. // apk: "prebuilts/example_xhdpi.apk",
  418. // },
  419. // },
  420. // presigned: true,
  421. // }
  422. func AndroidAppImportFactory() android.Module {
  423. module := &AndroidAppImport{}
  424. module.AddProperties(&module.properties)
  425. module.AddProperties(&module.dexpreoptProperties)
  426. module.AddProperties(&module.usesLibrary.usesLibraryProperties)
  427. module.populateAllVariantStructs()
  428. android.AddLoadHook(module, func(ctx android.LoadHookContext) {
  429. module.processVariants(ctx)
  430. })
  431. android.InitApexModule(module)
  432. android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
  433. android.InitDefaultableModule(module)
  434. android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk")
  435. module.usesLibrary.enforce = true
  436. return module
  437. }
  438. type AndroidTestImport struct {
  439. AndroidAppImport
  440. testProperties struct {
  441. // list of compatibility suites (for example "cts", "vts") that the module should be
  442. // installed into.
  443. Test_suites []string `android:"arch_variant"`
  444. // list of files or filegroup modules that provide data that should be installed alongside
  445. // the test
  446. Data []string `android:"path"`
  447. // Install the test into a folder named for the module in all test suites.
  448. Per_testcase_directory *bool
  449. }
  450. data android.Paths
  451. }
  452. func (a *AndroidTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
  453. a.generateAndroidBuildActions(ctx)
  454. a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
  455. }
  456. func (a *AndroidTestImport) InstallInTestcases() bool {
  457. return true
  458. }
  459. // android_test_import imports a prebuilt test apk with additional processing specified in the
  460. // module. DPI or arch variant configurations can be made as with android_app_import.
  461. func AndroidTestImportFactory() android.Module {
  462. module := &AndroidTestImport{}
  463. module.AddProperties(&module.properties)
  464. module.AddProperties(&module.dexpreoptProperties)
  465. module.AddProperties(&module.testProperties)
  466. module.populateAllVariantStructs()
  467. android.AddLoadHook(module, func(ctx android.LoadHookContext) {
  468. module.processVariants(ctx)
  469. })
  470. module.dexpreopter.isTest = true
  471. android.InitApexModule(module)
  472. android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
  473. android.InitDefaultableModule(module)
  474. android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk")
  475. return module
  476. }