app_import.go 17 KB

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