app_import.go 18 KB

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