Regenerate odm or vendor using combined sepolicy if --rebuild-sepolicy.
This allows merged devices to boot using a precompiled_sepolicy built from merged sources, rather than recompiling this sepolicy at boot time every boot. Bug: 178727214 Test: Merge an R+S build using --rebuild-sepolicy and --vendor-otatools. Observe odm.img is rebuilt by the vendor otatools.zip when merging. Observe device boots using ODM's precompiled_sepolicy file. Test: Same as above, for S+S. Test: Merge an S+S build using --rebuild-sepolicy and *not* --vendor-otatools. Observe odm.img is rebuilt without using a separate otatools.zip. Observe device boots using ODM's precompiled_sepolicy file. Change-Id: I9595b8a3296d6deec21db8f0c9bc5b7ec4debd57
This commit is contained in:
@@ -78,6 +78,14 @@ Usage: merge_target_files [args]
|
|||||||
If provided, duplicate APK/APEX keys are ignored and the value from the
|
If provided, duplicate APK/APEX keys are ignored and the value from the
|
||||||
framework is used.
|
framework is used.
|
||||||
|
|
||||||
|
--rebuild-sepolicy
|
||||||
|
If provided, rebuilds odm.img or vendor.img to include merged sepolicy
|
||||||
|
files. If odm is present then odm is preferred.
|
||||||
|
|
||||||
|
--vendor-otatools otatools.zip
|
||||||
|
If provided, use this otatools.zip when recompiling the odm or vendor
|
||||||
|
image to include sepolicy.
|
||||||
|
|
||||||
--keep-tmp
|
--keep-tmp
|
||||||
Keep tempoary files for debugging purposes.
|
Keep tempoary files for debugging purposes.
|
||||||
"""
|
"""
|
||||||
@@ -129,6 +137,8 @@ OPTIONS.output_super_empty = None
|
|||||||
OPTIONS.rebuild_recovery = False
|
OPTIONS.rebuild_recovery = False
|
||||||
# TODO(b/150582573): Remove this option.
|
# TODO(b/150582573): Remove this option.
|
||||||
OPTIONS.allow_duplicate_apkapex_keys = False
|
OPTIONS.allow_duplicate_apkapex_keys = False
|
||||||
|
OPTIONS.vendor_otatools = None
|
||||||
|
OPTIONS.rebuild_sepolicy = False
|
||||||
OPTIONS.keep_tmp = False
|
OPTIONS.keep_tmp = False
|
||||||
|
|
||||||
# In an item list (framework or vendor), we may see entries that select whole
|
# In an item list (framework or vendor), we may see entries that select whole
|
||||||
@@ -666,7 +676,7 @@ def copy_file_contexts(framework_target_files_dir, vendor_target_files_dir,
|
|||||||
os.path.join(output_target_files_dir, 'META', 'vendor_file_contexts.bin'))
|
os.path.join(output_target_files_dir, 'META', 'vendor_file_contexts.bin'))
|
||||||
|
|
||||||
|
|
||||||
def compile_split_sepolicy(product_out, partition_map, output_policy):
|
def compile_split_sepolicy(product_out, partition_map):
|
||||||
"""Uses secilc to compile a split sepolicy file.
|
"""Uses secilc to compile a split sepolicy file.
|
||||||
|
|
||||||
Depends on various */etc/selinux/* and */etc/vintf/* files within partitions.
|
Depends on various */etc/selinux/* and */etc/vintf/* files within partitions.
|
||||||
@@ -674,7 +684,6 @@ def compile_split_sepolicy(product_out, partition_map, output_policy):
|
|||||||
Args:
|
Args:
|
||||||
product_out: PRODUCT_OUT directory, containing partition directories.
|
product_out: PRODUCT_OUT directory, containing partition directories.
|
||||||
partition_map: A map of partition name -> relative path within product_out.
|
partition_map: A map of partition name -> relative path within product_out.
|
||||||
output_policy: The name of the output policy created by secilc.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A command list that can be executed to create the compiled sepolicy.
|
A command list that can be executed to create the compiled sepolicy.
|
||||||
@@ -709,7 +718,7 @@ def compile_split_sepolicy(product_out, partition_map, output_policy):
|
|||||||
# Use the same flags and arguments as selinux.cpp OpenSplitPolicy().
|
# Use the same flags and arguments as selinux.cpp OpenSplitPolicy().
|
||||||
cmd = ['secilc', '-m', '-M', 'true', '-G', '-N']
|
cmd = ['secilc', '-m', '-M', 'true', '-G', '-N']
|
||||||
cmd.extend(['-c', kernel_sepolicy_version])
|
cmd.extend(['-c', kernel_sepolicy_version])
|
||||||
cmd.extend(['-o', output_policy])
|
cmd.extend(['-o', os.path.join(product_out, 'META/combined_sepolicy')])
|
||||||
cmd.extend(['-f', '/dev/null'])
|
cmd.extend(['-f', '/dev/null'])
|
||||||
|
|
||||||
required_policy_files = (
|
required_policy_files = (
|
||||||
@@ -747,7 +756,8 @@ def validate_merged_apex_info(output_target_files_dir, partitions):
|
|||||||
Depends on the <partition>/apex/* APEX files within partitions.
|
Depends on the <partition>/apex/* APEX files within partitions.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
output_target_files_dir: Output directory containing merged partition directories.
|
output_target_files_dir: Output directory containing merged partition
|
||||||
|
directories.
|
||||||
partitions: A list of all the partitions in the output directory.
|
partitions: A list of all the partitions in the output directory.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
@@ -965,6 +975,92 @@ def generate_images(target_files_dir, rebuild_recovery):
|
|||||||
add_img_to_target_files.main(add_img_args)
|
add_img_to_target_files.main(add_img_args)
|
||||||
|
|
||||||
|
|
||||||
|
def rebuild_image_with_sepolicy(target_files_dir,
|
||||||
|
vendor_otatools=None,
|
||||||
|
vendor_target_files=None):
|
||||||
|
"""Rebuilds odm.img or vendor.img to include merged sepolicy files.
|
||||||
|
|
||||||
|
If odm is present then odm is preferred -- otherwise vendor is used.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
target_files_dir: Path to the extracted merged target-files package.
|
||||||
|
vendor_otatools: If not None, path to an otatools.zip from the vendor build
|
||||||
|
that is used when recompiling the image.
|
||||||
|
vendor_target_files: Expected if vendor_otatools is not None. Path to the
|
||||||
|
vendor target-files zip.
|
||||||
|
"""
|
||||||
|
partition = 'vendor'
|
||||||
|
if os.path.exists(os.path.join(target_files_dir, 'ODM')) or os.path.exists(
|
||||||
|
os.path.join(target_files_dir, 'IMAGES/odm.img')):
|
||||||
|
partition = 'odm'
|
||||||
|
partition_img = '{}.img'.format(partition)
|
||||||
|
|
||||||
|
logger.info('Recompiling %s using the merged sepolicy files.', partition_img)
|
||||||
|
|
||||||
|
# Copy the combined SEPolicy file and framework hashes to the image that is
|
||||||
|
# being rebuilt.
|
||||||
|
def copy_selinux_file(input_path, output_filename):
|
||||||
|
shutil.copy(
|
||||||
|
os.path.join(target_files_dir, input_path),
|
||||||
|
os.path.join(target_files_dir, partition.upper(), 'etc/selinux',
|
||||||
|
output_filename))
|
||||||
|
|
||||||
|
copy_selinux_file('META/combined_sepolicy', 'precompiled_sepolicy')
|
||||||
|
copy_selinux_file('SYSTEM/etc/selinux/plat_sepolicy_and_mapping.sha256',
|
||||||
|
'precompiled_sepolicy.plat_sepolicy_and_mapping.sha256')
|
||||||
|
copy_selinux_file(
|
||||||
|
'SYSTEM_EXT/etc/selinux/system_ext_sepolicy_and_mapping.sha256',
|
||||||
|
'precompiled_sepolicy.system_ext_sepolicy_and_mapping.sha256')
|
||||||
|
copy_selinux_file('PRODUCT/etc/selinux/product_sepolicy_and_mapping.sha256',
|
||||||
|
'precompiled_sepolicy.product_sepolicy_and_mapping.sha256')
|
||||||
|
|
||||||
|
if not vendor_otatools:
|
||||||
|
# Remove the partition from the merged target-files archive. It will be
|
||||||
|
# rebuilt later automatically by generate_images().
|
||||||
|
os.remove(os.path.join(target_files_dir, 'IMAGES', partition_img))
|
||||||
|
else:
|
||||||
|
# TODO(b/192253131): Remove the need for vendor_otatools by fixing
|
||||||
|
# backwards-compatibility issues when compiling images on R from S+.
|
||||||
|
if not vendor_target_files:
|
||||||
|
raise ValueError(
|
||||||
|
'Expected vendor_target_files if vendor_otatools is not None.')
|
||||||
|
logger.info(
|
||||||
|
'%s recompilation will be performed using the vendor otatools.zip',
|
||||||
|
partition_img)
|
||||||
|
|
||||||
|
# Unzip the vendor build's otatools.zip and target-files archive.
|
||||||
|
vendor_otatools_dir = common.MakeTempDir(
|
||||||
|
prefix='merge_target_files_vendor_otatools_')
|
||||||
|
vendor_target_files_dir = common.MakeTempDir(
|
||||||
|
prefix='merge_target_files_vendor_target_files_')
|
||||||
|
common.UnzipToDir(vendor_otatools, vendor_otatools_dir)
|
||||||
|
common.UnzipToDir(vendor_target_files, vendor_target_files_dir)
|
||||||
|
|
||||||
|
# Copy the partition contents from the merged target-files archive to the
|
||||||
|
# vendor target-files archive.
|
||||||
|
shutil.rmtree(os.path.join(vendor_target_files_dir, partition.upper()))
|
||||||
|
shutil.copytree(
|
||||||
|
os.path.join(target_files_dir, partition.upper()),
|
||||||
|
os.path.join(vendor_target_files_dir, partition.upper()))
|
||||||
|
|
||||||
|
# Delete then rebuild the partition.
|
||||||
|
os.remove(os.path.join(vendor_target_files_dir, 'IMAGES', partition_img))
|
||||||
|
rebuild_partition_command = [
|
||||||
|
os.path.join(vendor_otatools_dir, 'bin', 'add_img_to_target_files'),
|
||||||
|
'--verbose',
|
||||||
|
'--add_missing',
|
||||||
|
vendor_target_files_dir,
|
||||||
|
]
|
||||||
|
logger.info('Recompiling %s: %s', partition_img,
|
||||||
|
' '.join(rebuild_partition_command))
|
||||||
|
common.RunAndCheckOutput(rebuild_partition_command, verbose=True)
|
||||||
|
|
||||||
|
# Move the newly-created image to the merged target files dir.
|
||||||
|
shutil.move(
|
||||||
|
os.path.join(vendor_target_files_dir, 'IMAGES', partition_img),
|
||||||
|
os.path.join(target_files_dir, 'IMAGES', partition_img))
|
||||||
|
|
||||||
|
|
||||||
def generate_super_empty_image(target_dir, output_super_empty):
|
def generate_super_empty_image(target_dir, output_super_empty):
|
||||||
"""Generates super_empty image from target package.
|
"""Generates super_empty image from target package.
|
||||||
|
|
||||||
@@ -1049,7 +1145,8 @@ def merge_target_files(temp_dir, framework_target_files, framework_item_list,
|
|||||||
framework_misc_info_keys, vendor_target_files,
|
framework_misc_info_keys, vendor_target_files,
|
||||||
vendor_item_list, output_target_files, output_dir,
|
vendor_item_list, output_target_files, output_dir,
|
||||||
output_item_list, output_ota, output_img,
|
output_item_list, output_ota, output_img,
|
||||||
output_super_empty, rebuild_recovery):
|
output_super_empty, rebuild_recovery, vendor_otatools,
|
||||||
|
rebuild_sepolicy):
|
||||||
"""Merges two target files packages together.
|
"""Merges two target files packages together.
|
||||||
|
|
||||||
This function takes framework and vendor target files packages as input,
|
This function takes framework and vendor target files packages as input,
|
||||||
@@ -1085,6 +1182,9 @@ def merge_target_files(temp_dir, framework_target_files, framework_item_list,
|
|||||||
merged target files package and saves it at this path.
|
merged target files package and saves it at this path.
|
||||||
rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
|
rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
|
||||||
devices and write it to the system image.
|
devices and write it to the system image.
|
||||||
|
vendor_otatools: Path to an otatools zip used for recompiling vendor images.
|
||||||
|
rebuild_sepolicy: If true, rebuild odm.img (if target uses ODM) or
|
||||||
|
vendor.img using a merged precompiled_sepolicy file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logger.info('starting: merge framework %s and vendor %s into output %s',
|
logger.info('starting: merge framework %s and vendor %s into output %s',
|
||||||
@@ -1137,14 +1237,14 @@ def merge_target_files(temp_dir, framework_target_files, framework_item_list,
|
|||||||
partition_map=filtered_partitions)
|
partition_map=filtered_partitions)
|
||||||
|
|
||||||
# Check that the split sepolicy from the multiple builds can compile.
|
# Check that the split sepolicy from the multiple builds can compile.
|
||||||
split_sepolicy_cmd = compile_split_sepolicy(
|
split_sepolicy_cmd = compile_split_sepolicy(output_target_files_temp_dir,
|
||||||
product_out=output_target_files_temp_dir,
|
filtered_partitions)
|
||||||
partition_map=filtered_partitions,
|
|
||||||
output_policy=os.path.join(output_target_files_temp_dir,
|
|
||||||
'META/combined.policy'))
|
|
||||||
logger.info('Compiling split sepolicy: %s', ' '.join(split_sepolicy_cmd))
|
logger.info('Compiling split sepolicy: %s', ' '.join(split_sepolicy_cmd))
|
||||||
common.RunAndCheckOutput(split_sepolicy_cmd)
|
common.RunAndCheckOutput(split_sepolicy_cmd)
|
||||||
# TODO(b/178864050): Run tests on the combined.policy file.
|
# Include the compiled policy in an image if requested.
|
||||||
|
if rebuild_sepolicy:
|
||||||
|
rebuild_image_with_sepolicy(output_target_files_temp_dir, vendor_otatools,
|
||||||
|
vendor_target_files)
|
||||||
|
|
||||||
# Run validation checks on the pre-installed APEX files.
|
# Run validation checks on the pre-installed APEX files.
|
||||||
validate_merged_apex_info(output_target_files_temp_dir, partition_map.keys())
|
validate_merged_apex_info(output_target_files_temp_dir, partition_map.keys())
|
||||||
@@ -1261,6 +1361,10 @@ def main():
|
|||||||
OPTIONS.rebuild_recovery = True
|
OPTIONS.rebuild_recovery = True
|
||||||
elif o == '--allow-duplicate-apkapex-keys':
|
elif o == '--allow-duplicate-apkapex-keys':
|
||||||
OPTIONS.allow_duplicate_apkapex_keys = True
|
OPTIONS.allow_duplicate_apkapex_keys = True
|
||||||
|
elif o == '--vendor-otatools':
|
||||||
|
OPTIONS.vendor_otatools = a
|
||||||
|
elif o == '--rebuild-sepolicy':
|
||||||
|
OPTIONS.rebuild_sepolicy = True
|
||||||
elif o == '--keep-tmp':
|
elif o == '--keep-tmp':
|
||||||
OPTIONS.keep_tmp = True
|
OPTIONS.keep_tmp = True
|
||||||
else:
|
else:
|
||||||
@@ -1289,6 +1393,8 @@ def main():
|
|||||||
'output-super-empty=',
|
'output-super-empty=',
|
||||||
'rebuild_recovery',
|
'rebuild_recovery',
|
||||||
'allow-duplicate-apkapex-keys',
|
'allow-duplicate-apkapex-keys',
|
||||||
|
'vendor-otatools=',
|
||||||
|
'rebuild-sepolicy',
|
||||||
'keep-tmp',
|
'keep-tmp',
|
||||||
],
|
],
|
||||||
extra_option_handler=option_handler)
|
extra_option_handler=option_handler)
|
||||||
@@ -1342,7 +1448,9 @@ def main():
|
|||||||
output_ota=OPTIONS.output_ota,
|
output_ota=OPTIONS.output_ota,
|
||||||
output_img=OPTIONS.output_img,
|
output_img=OPTIONS.output_img,
|
||||||
output_super_empty=OPTIONS.output_super_empty,
|
output_super_empty=OPTIONS.output_super_empty,
|
||||||
rebuild_recovery=OPTIONS.rebuild_recovery), OPTIONS.keep_tmp)
|
rebuild_recovery=OPTIONS.rebuild_recovery,
|
||||||
|
vendor_otatools=OPTIONS.vendor_otatools,
|
||||||
|
rebuild_sepolicy=OPTIONS.rebuild_sepolicy), OPTIONS.keep_tmp)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@@ -265,10 +265,10 @@ class MergeTargetFilesTest(test_utils.ReleaseToolsTestCase):
|
|||||||
'system': 'system',
|
'system': 'system',
|
||||||
'product': 'product',
|
'product': 'product',
|
||||||
'vendor': 'vendor',
|
'vendor': 'vendor',
|
||||||
}, os.path.join(product_out_dir, 'policy'))
|
})
|
||||||
self.assertEqual(' '.join(cmd),
|
self.assertEqual(' '.join(cmd),
|
||||||
('secilc -m -M true -G -N -c 30 '
|
('secilc -m -M true -G -N -c 30 '
|
||||||
'-o {OTP}/policy -f /dev/null '
|
'-o {OTP}/META/combined_sepolicy -f /dev/null '
|
||||||
'{OTP}/system/etc/selinux/plat_sepolicy.cil '
|
'{OTP}/system/etc/selinux/plat_sepolicy.cil '
|
||||||
'{OTP}/system/etc/selinux/mapping/30.0.cil '
|
'{OTP}/system/etc/selinux/mapping/30.0.cil '
|
||||||
'{OTP}/vendor/etc/selinux/vendor_sepolicy.cil '
|
'{OTP}/vendor/etc/selinux/vendor_sepolicy.cil '
|
||||||
|
Reference in New Issue
Block a user