xref: /aosp_15_r20/tools/treble/cuttlefish/build_cf_hybrid_device.py (revision 105f628577ac4ba0e277a494fbb614ed8c12a994)
1*105f6285SAndroid Build Coastguard Worker#!/usr/bin/python3
2*105f6285SAndroid Build Coastguard Worker#
3*105f6285SAndroid Build Coastguard Worker# Copyright (C) 2023 The Android Open Source Project
4*105f6285SAndroid Build Coastguard Worker#
5*105f6285SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); you may not
6*105f6285SAndroid Build Coastguard Worker# use this file except in compliance with the License. You may obtain a copy of
7*105f6285SAndroid Build Coastguard Worker# the License at
8*105f6285SAndroid Build Coastguard Worker#
9*105f6285SAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*105f6285SAndroid Build Coastguard Worker#
11*105f6285SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*105f6285SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13*105f6285SAndroid Build Coastguard Worker# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14*105f6285SAndroid Build Coastguard Worker# License for the specific language governing permissions and limitations under
15*105f6285SAndroid Build Coastguard Worker# the License.
16*105f6285SAndroid Build Coastguard Worker
17*105f6285SAndroid Build Coastguard Workerimport argparse
18*105f6285SAndroid Build Coastguard Workerimport glob
19*105f6285SAndroid Build Coastguard Workerimport os
20*105f6285SAndroid Build Coastguard Workerimport subprocess
21*105f6285SAndroid Build Coastguard Workerimport tempfile
22*105f6285SAndroid Build Coastguard Worker
23*105f6285SAndroid Build Coastguard Workerfrom build_chd_debug_ramdisk import build_chd_debug_ramdisk, ImageOptions
24*105f6285SAndroid Build Coastguard Workerfrom build_chd_utils import copy_files, merge_chd_sepolicy, unzip_otatools
25*105f6285SAndroid Build Coastguard Worker
26*105f6285SAndroid Build Coastguard Worker"""Test command:
27*105f6285SAndroid Build Coastguard Worker
28*105f6285SAndroid Build Coastguard WorkerWORKSPACE=out/dist && \
29*105f6285SAndroid Build Coastguard Workerpython3 tools/treble/cuttlefish/build_cf_hybrid_device.py \
30*105f6285SAndroid Build Coastguard Worker    --build_id 123456 \
31*105f6285SAndroid Build Coastguard Worker    --otatools_zip $WORKSPACE/otatools.zip \
32*105f6285SAndroid Build Coastguard Worker    --target chd-target \
33*105f6285SAndroid Build Coastguard Worker    --output_dir $WORKSPACE \
34*105f6285SAndroid Build Coastguard Worker    --framework_target_files_zip $WORKSPACE/device-target_files-*.zip \
35*105f6285SAndroid Build Coastguard Worker    --vendor_target_files_zip $WORKSPACE/cf_arm64_only_phone-target_files-*.zip
36*105f6285SAndroid Build Coastguard Worker"""
37*105f6285SAndroid Build Coastguard Worker
38*105f6285SAndroid Build Coastguard Worker
39*105f6285SAndroid Build Coastguard Workerdef _parse_args() -> argparse.Namespace:
40*105f6285SAndroid Build Coastguard Worker  """Parse the arguments for building cuttlefish hybrid devices.
41*105f6285SAndroid Build Coastguard Worker
42*105f6285SAndroid Build Coastguard Worker  Returns:
43*105f6285SAndroid Build Coastguard Worker    An object of the parsed arguments.
44*105f6285SAndroid Build Coastguard Worker  """
45*105f6285SAndroid Build Coastguard Worker  parser = argparse.ArgumentParser()
46*105f6285SAndroid Build Coastguard Worker
47*105f6285SAndroid Build Coastguard Worker  parser.add_argument('--build_id', required=True,
48*105f6285SAndroid Build Coastguard Worker                      help='Build id.')
49*105f6285SAndroid Build Coastguard Worker  parser.add_argument('--target', required=True,
50*105f6285SAndroid Build Coastguard Worker                      help='Target name of the cuttlefish hybrid build.')
51*105f6285SAndroid Build Coastguard Worker  parser.add_argument('--otatools_zip', required=True,
52*105f6285SAndroid Build Coastguard Worker                      help='Path to the otatools.zip.')
53*105f6285SAndroid Build Coastguard Worker  parser.add_argument('--output_dir', required=True,
54*105f6285SAndroid Build Coastguard Worker                      help='Path to the output directory of the hybrid build.')
55*105f6285SAndroid Build Coastguard Worker  parser.add_argument('--framework_target_files_zip', required=True,
56*105f6285SAndroid Build Coastguard Worker                      help='glob pattern of framework target_files zip.')
57*105f6285SAndroid Build Coastguard Worker  parser.add_argument('--vendor_target_files_zip', required=True,
58*105f6285SAndroid Build Coastguard Worker                      help='glob pattern of vendor target_files zip.')
59*105f6285SAndroid Build Coastguard Worker  parser.add_argument('--copy_file', action='append', default=[],
60*105f6285SAndroid Build Coastguard Worker                      help='The file to be copied to output directory. '
61*105f6285SAndroid Build Coastguard Worker                           'The format is <src glob pattern>:<dst path>.')
62*105f6285SAndroid Build Coastguard Worker  return parser.parse_args()
63*105f6285SAndroid Build Coastguard Worker
64*105f6285SAndroid Build Coastguard Worker
65*105f6285SAndroid Build Coastguard Workerdef run(temp_dir: str) -> None:
66*105f6285SAndroid Build Coastguard Worker  args = _parse_args()
67*105f6285SAndroid Build Coastguard Worker
68*105f6285SAndroid Build Coastguard Worker  # unzip otatools
69*105f6285SAndroid Build Coastguard Worker  otatools = os.path.join(temp_dir, 'otatools')
70*105f6285SAndroid Build Coastguard Worker  unzip_otatools(args.otatools_zip, otatools)
71*105f6285SAndroid Build Coastguard Worker
72*105f6285SAndroid Build Coastguard Worker  # get framework and vendor target files
73*105f6285SAndroid Build Coastguard Worker  matched_framework_target_files = glob.glob(args.framework_target_files_zip)
74*105f6285SAndroid Build Coastguard Worker  if not matched_framework_target_files:
75*105f6285SAndroid Build Coastguard Worker    raise ValueError('framework target files zip '
76*105f6285SAndroid Build Coastguard Worker                     f'{args.framework_target_files_zip} not found.')
77*105f6285SAndroid Build Coastguard Worker  matched_vendor_target_files = glob.glob(args.vendor_target_files_zip)
78*105f6285SAndroid Build Coastguard Worker  if not matched_vendor_target_files:
79*105f6285SAndroid Build Coastguard Worker    raise ValueError('vendor target files zip '
80*105f6285SAndroid Build Coastguard Worker                     f'{args.vendor_target_files_zip} not found.')
81*105f6285SAndroid Build Coastguard Worker
82*105f6285SAndroid Build Coastguard Worker  # merge target files
83*105f6285SAndroid Build Coastguard Worker  framework_target_files = matched_framework_target_files[0]
84*105f6285SAndroid Build Coastguard Worker  vendor_target_files = matched_vendor_target_files[0]
85*105f6285SAndroid Build Coastguard Worker  merged_target_files = os.path.join(
86*105f6285SAndroid Build Coastguard Worker      args.output_dir,
87*105f6285SAndroid Build Coastguard Worker      f'{args.target}-target_files-{args.build_id}.zip')
88*105f6285SAndroid Build Coastguard Worker  command = [
89*105f6285SAndroid Build Coastguard Worker      os.path.join(otatools, 'bin', 'merge_target_files'),
90*105f6285SAndroid Build Coastguard Worker      '--path', otatools,
91*105f6285SAndroid Build Coastguard Worker      '--framework-target-files', framework_target_files,
92*105f6285SAndroid Build Coastguard Worker      '--vendor-target-files', vendor_target_files,
93*105f6285SAndroid Build Coastguard Worker      '--output-target-files', merged_target_files,
94*105f6285SAndroid Build Coastguard Worker      '--avb-resolve-rollback-index-location-conflict'
95*105f6285SAndroid Build Coastguard Worker  ]
96*105f6285SAndroid Build Coastguard Worker  subprocess.run(command, check=True)
97*105f6285SAndroid Build Coastguard Worker
98*105f6285SAndroid Build Coastguard Worker  # create images from the merged target files
99*105f6285SAndroid Build Coastguard Worker  img_zip_path = os.path.join(args.output_dir,
100*105f6285SAndroid Build Coastguard Worker                              f'{args.target}-img-{args.build_id}.zip')
101*105f6285SAndroid Build Coastguard Worker  command = [
102*105f6285SAndroid Build Coastguard Worker      os.path.join(otatools, 'bin', 'img_from_target_files'),
103*105f6285SAndroid Build Coastguard Worker      merged_target_files,
104*105f6285SAndroid Build Coastguard Worker      img_zip_path]
105*105f6285SAndroid Build Coastguard Worker  subprocess.run(command, check=True)
106*105f6285SAndroid Build Coastguard Worker
107*105f6285SAndroid Build Coastguard Worker  # merge CHD debug sepolicy
108*105f6285SAndroid Build Coastguard Worker  # TODO (b/315474132): remove this when the CHD sepolicy issue is resolved.
109*105f6285SAndroid Build Coastguard Worker  chd_sepolicy = None
110*105f6285SAndroid Build Coastguard Worker  try:
111*105f6285SAndroid Build Coastguard Worker    chd_sepolicy = merge_chd_sepolicy(
112*105f6285SAndroid Build Coastguard Worker        framework_target_files, vendor_target_files, otatools, args.output_dir)
113*105f6285SAndroid Build Coastguard Worker  except Exception as error:
114*105f6285SAndroid Build Coastguard Worker    print(f'Warning - cannot generate chd_merged_sepolicy: {error}')
115*105f6285SAndroid Build Coastguard Worker
116*105f6285SAndroid Build Coastguard Worker  # copy files
117*105f6285SAndroid Build Coastguard Worker  copy_files(args.copy_file, args.output_dir)
118*105f6285SAndroid Build Coastguard Worker
119*105f6285SAndroid Build Coastguard Worker  # build the CHD vendor boot debug image by adding chd_sepolicy and
120*105f6285SAndroid Build Coastguard Worker  # chd_debug_prop (if present) into the Cuttlefish's vendor_boot-debug.img.
121*105f6285SAndroid Build Coastguard Worker  files_to_add = []
122*105f6285SAndroid Build Coastguard Worker  if chd_sepolicy and os.path.exists(chd_sepolicy):
123*105f6285SAndroid Build Coastguard Worker    files_to_add.append(f'{chd_sepolicy}:precompiled_sepolicy')
124*105f6285SAndroid Build Coastguard Worker  chd_debug_prop = os.path.join(args.output_dir, 'chd_debug.prop')
125*105f6285SAndroid Build Coastguard Worker  if os.path.exists(chd_debug_prop):
126*105f6285SAndroid Build Coastguard Worker    # rename the debug prop file as `adb_debug.prop` because this is the
127*105f6285SAndroid Build Coastguard Worker    # file name that property init expects.
128*105f6285SAndroid Build Coastguard Worker    files_to_add.append(f'{chd_debug_prop}:adb_debug.prop')
129*105f6285SAndroid Build Coastguard Worker
130*105f6285SAndroid Build Coastguard Worker  cf_debug_img = os.path.join(args.output_dir, 'vendor_boot-debug.img')
131*105f6285SAndroid Build Coastguard Worker  chd_debug_image_userdebug = 'vendor_boot-chd_debug.img'
132*105f6285SAndroid Build Coastguard Worker  chd_debug_image_user = 'vendor_boot-chd_debug_user.img'
133*105f6285SAndroid Build Coastguard Worker  if os.path.exists(cf_debug_img):
134*105f6285SAndroid Build Coastguard Worker    for image_name in [chd_debug_image_userdebug, chd_debug_image_user]:
135*105f6285SAndroid Build Coastguard Worker      image_path = os.path.join(args.output_dir, image_name)
136*105f6285SAndroid Build Coastguard Worker      image_dir = os.path.join(temp_dir, image_name)
137*105f6285SAndroid Build Coastguard Worker      os.mkdir(image_dir)
138*105f6285SAndroid Build Coastguard Worker      image_option = ImageOptions(
139*105f6285SAndroid Build Coastguard Worker          input_image=cf_debug_img,
140*105f6285SAndroid Build Coastguard Worker          output_image=image_path,
141*105f6285SAndroid Build Coastguard Worker          otatools_dir=otatools,
142*105f6285SAndroid Build Coastguard Worker          temp_dir=image_dir,
143*105f6285SAndroid Build Coastguard Worker          files_to_add=files_to_add)
144*105f6285SAndroid Build Coastguard Worker
145*105f6285SAndroid Build Coastguard Worker      # Remove userdebug_plat_sepolicy.cil from CHD's debug ramdisk to build a
146*105f6285SAndroid Build Coastguard Worker      # debug ramdisk for user builds.
147*105f6285SAndroid Build Coastguard Worker      if image_name == chd_debug_image_user:
148*105f6285SAndroid Build Coastguard Worker        image_option.files_to_remove = ['userdebug_plat_sepolicy.cil']
149*105f6285SAndroid Build Coastguard Worker
150*105f6285SAndroid Build Coastguard Worker      try:
151*105f6285SAndroid Build Coastguard Worker        build_chd_debug_ramdisk(image_option)
152*105f6285SAndroid Build Coastguard Worker      except Exception as error:
153*105f6285SAndroid Build Coastguard Worker        print(f'Warning - cannot build {image_name}: {error}')
154*105f6285SAndroid Build Coastguard Worker
155*105f6285SAndroid Build Coastguard Worker
156*105f6285SAndroid Build Coastguard Workerif __name__ == '__main__':
157*105f6285SAndroid Build Coastguard Worker  with tempfile.TemporaryDirectory() as temp_dir:
158*105f6285SAndroid Build Coastguard Worker    run(temp_dir)
159