build-apex-bundle.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. #!/usr/bin/env python
  2. #
  3. # Copyright (C) 2022 The Android Open Source Project
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. #
  17. """A tool to create an APEX bundle out of Soong-built base.zip"""
  18. from __future__ import print_function
  19. import argparse
  20. import sys
  21. import tempfile
  22. import zipfile
  23. import os
  24. import json
  25. import subprocess
  26. def parse_args():
  27. """Parse commandline arguments."""
  28. parser = argparse.ArgumentParser()
  29. parser.add_argument(
  30. '--overwrite',
  31. action='store_true',
  32. help='If set, any previous existing output will be overwritten')
  33. parser.add_argument('--output', help='specify the output .aab file')
  34. parser.add_argument(
  35. 'input', help='specify the input <apex name>-base.zip file')
  36. return parser.parse_args()
  37. def build_bundle(input, output, overwrite):
  38. base_zip = zipfile.ZipFile(input)
  39. tmpdir = tempfile.mkdtemp()
  40. tmp_base_zip = os.path.join(tmpdir, 'base.zip')
  41. tmp_bundle_config = os.path.join(tmpdir, 'bundle_config.json')
  42. bundle_config = None
  43. abi = []
  44. # This block performs three tasks
  45. # - extract/load bundle_config.json from input => bundle_config
  46. # - get ABI from input => abi
  47. # - discard bundle_config.json from input => tmp/base.zip
  48. with zipfile.ZipFile(tmp_base_zip, 'a') as out:
  49. for info in base_zip.infolist():
  50. # discard bundle_config.json
  51. if info.filename == 'bundle_config.json':
  52. bundle_config = json.load(base_zip.open(info.filename))
  53. continue
  54. # get ABI from apex/{abi}.img
  55. dir, basename = os.path.split(info.filename)
  56. name, ext = os.path.splitext(basename)
  57. if dir == 'apex' and ext == '.img':
  58. abi.append(name)
  59. # copy entries to tmp/base.zip
  60. out.writestr(info, base_zip.open(info.filename).read())
  61. base_zip.close()
  62. if not bundle_config:
  63. raise ValueError(f'bundle_config.json not found in {input}')
  64. if len(abi) != 1:
  65. raise ValueError(f'{input} should have only a single apex/*.img file')
  66. # add ABI to tmp/bundle_config.json
  67. apex_config = bundle_config['apex_config']
  68. if 'supported_abi_set' not in apex_config:
  69. apex_config['supported_abi_set'] = []
  70. supported_abi_set = apex_config['supported_abi_set']
  71. supported_abi_set.append({'abi': abi})
  72. with open(tmp_bundle_config, 'w') as out:
  73. json.dump(bundle_config, out)
  74. # invoke bundletool
  75. cmd = [
  76. 'bundletool', 'build-bundle', '--config', tmp_bundle_config, '--modules',
  77. tmp_base_zip, '--output', output
  78. ]
  79. if overwrite:
  80. cmd.append('--overwrite')
  81. subprocess.check_call(cmd)
  82. def main():
  83. """Program entry point."""
  84. try:
  85. args = parse_args()
  86. build_bundle(args.input, args.output, args.overwrite)
  87. # pylint: disable=broad-except
  88. except Exception as err:
  89. print('error: ' + str(err), file=sys.stderr)
  90. sys.exit(-1)
  91. if __name__ == '__main__':
  92. main()