app_import.go 18 KB

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