• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
19from __future__ import print_function
20
21import argparse
22import sys
23import tempfile
24import zipfile
25import os
26import json
27import subprocess
28
29
30def parse_args():
31  """Parse commandline arguments."""
32  parser = argparse.ArgumentParser()
33  parser.add_argument(
34      '--overwrite',
35      action='store_true',
36      help='If set, any previous existing output will be overwritten')
37  parser.add_argument('--output', help='specify the output .aab file')
38  parser.add_argument(
39      'input', help='specify the input <apex name>-base.zip file')
40  return parser.parse_args()
41
42
43def build_bundle(input, output, overwrite):
44  base_zip = zipfile.ZipFile(input)
45
46  tmpdir = tempfile.mkdtemp()
47  tmp_base_zip = os.path.join(tmpdir, 'base.zip')
48  tmp_bundle_config = os.path.join(tmpdir, 'bundle_config.json')
49
50  bundle_config = None
51  abi = []
52
53  # This block performs three tasks
54  # - extract/load bundle_config.json from input => bundle_config
55  # - get ABI from input => abi
56  # - discard bundle_config.json from input => tmp/base.zip
57  with zipfile.ZipFile(tmp_base_zip, 'a') as out:
58    for info in base_zip.infolist():
59
60      # discard bundle_config.json
61      if info.filename == 'bundle_config.json':
62        bundle_config = json.load(base_zip.open(info.filename))
63        continue
64
65      # get ABI from apex/{abi}.img
66      dir, basename = os.path.split(info.filename)
67      name, ext = os.path.splitext(basename)
68      if dir == 'apex' and ext == '.img':
69        abi.append(name)
70
71      # copy entries to tmp/base.zip
72      out.writestr(info, base_zip.open(info.filename).read())
73
74  base_zip.close()
75
76  if not bundle_config:
77    raise ValueError(f'bundle_config.json not found in {input}')
78  if len(abi) != 1:
79    raise ValueError(f'{input} should have only a single apex/*.img file')
80
81  # add ABI to tmp/bundle_config.json
82  apex_config = bundle_config['apex_config']
83  if 'supported_abi_set' not in apex_config:
84    apex_config['supported_abi_set'] = []
85  supported_abi_set = apex_config['supported_abi_set']
86  supported_abi_set.append({'abi': abi})
87
88  with open(tmp_bundle_config, 'w') as out:
89    json.dump(bundle_config, out)
90
91  # invoke bundletool
92  cmd = [
93      'bundletool', 'build-bundle', '--config', tmp_bundle_config, '--modules',
94      tmp_base_zip, '--output', output
95  ]
96  if overwrite:
97    cmd.append('--overwrite')
98  subprocess.check_call(cmd)
99
100
101def main():
102  """Program entry point."""
103  try:
104    args = parse_args()
105    build_bundle(args.input, args.output, args.overwrite)
106
107  # pylint: disable=broad-except
108  except Exception as err:
109    print('error: ' + str(err), file=sys.stderr)
110    sys.exit(-1)
111
112
113if __name__ == '__main__':
114  main()
115