Use apexd_host for host-side APEX extraction

Host-side simulation of APEX activation is done by a new tool
'apexd_host'. This simplies checkvintf invocation for local builds and
for target-files.

For local builds, checkvintf no londer depends on $OUT/apex, a flattened
view of APEXes. In fact, the build system doesn't need to install
$OUT/apex. They are installed for now only for its side-effect of
installing symbol files. We'd better not rely on $OUT/apex.

For target-files, scanning/activating apexes are extracted and moved to
the new tool. Now check_target_files_vintf is not more efficient because
it doesn't copy .apex files to a temporary directory.

Bug: 260358957
Bug: 288826922
Test: m (running checkvintf) # for local builds
Test: m target-files-package && check_garget_files_vintf target-files.zip
Test: atest releasetools_test
Change-Id: Iba23f429d96f9ec31814196aa14bdbb800649218
This commit is contained in:
Jooyung Han 2023-06-27 16:12:32 +09:00
parent 2ac1f2fabc
commit c9542abbbd
5 changed files with 39 additions and 134 deletions

View file

@ -4827,25 +4827,24 @@ ifeq (,$(TARGET_BUILD_UNBUNDLED))
intermediates := $(call intermediates-dir-for,PACKAGING,check_vintf_all)
check_vintf_all_deps :=
APEX_OUT := $(PRODUCT_OUT)/apex
# -----------------------------------------------------------------
# Create apex-info-file.xml
# Activate vendor APEXes for checkvintf
apex_dirs := \
$(TARGET_OUT)/apex/% \
$(TARGET_OUT_SYSTEM_EXT)/apex/% \
$(TARGET_OUT_VENDOR)/apex/% \
$(TARGET_OUT_ODM)/apex/% \
$(TARGET_OUT_PRODUCT)/apex/% \
apex_files := $(sort $(filter $(apex_dirs), $(INTERNAL_ALLIMAGES_FILES)))
APEX_OUT := $(intermediates)/apex
APEX_INFO_FILE := $(APEX_OUT)/apex-info-list.xml
# dump_apex_info scans $(PRODUCT_OUT)/apex and writes apex-info-list.xml there.
# This relies on the fact that rules for .apex files install the contents in $(PRODUCT_OUT)/apex.
$(APEX_INFO_FILE): $(HOST_OUT_EXECUTABLES)/dump_apex_info $(apex_files)
@echo "Creating apex-info-file in $(PRODUCT_OUT) "
$< --root_dir $(PRODUCT_OUT)
# apexd_host scans/activates APEX files and writes /apex/apex-info-list.xml
$(APEX_INFO_FILE): $(HOST_OUT_EXECUTABLES)/apexd_host $(apex_files)
@echo "Extracting apexes..."
@rm -rf $(APEX_OUT)
@mkdir -p $(APEX_OUT)
$< --vendor_path $(TARGET_OUT_VENDOR) \
--apex_path $(APEX_OUT)
apex_files :=
apex_dirs :=
@ -5299,7 +5298,6 @@ INTERNAL_OTATOOLS_MODULES += \
apex_compression_tool \
deapexer \
debugfs_static \
dump_apex_info \
fsck.erofs \
make_erofs \
merge_zips \

View file

@ -99,9 +99,8 @@ python_defaults {
"releasetools_common",
],
required: [
"apexd_host",
"checkvintf",
"deapexer",
"dump_apex_info",
],
}

View file

@ -129,8 +129,9 @@ def CheckVintfFromExtractedTargetFiles(input_tmp, info_dict=None):
dirmap = GetDirmap(input_tmp)
# Simulate apexd from target-files.
dirmap['/apex'] = PrepareApexDirectory(input_tmp)
# Simulate apexd with target-files.
# add a mapping('/apex' => ${input_tmp}/APEX) to dirmap
PrepareApexDirectory(input_tmp, dirmap)
args_for_skus = GetArgsForSkus(info_dict)
shipping_api_level_args = GetArgsForShippingApiLevel(info_dict)
@ -204,7 +205,8 @@ def GetVintfApexUnzipPatterns():
return patterns
def PrepareApexDirectory(inp):
def PrepareApexDirectory(inp, dirmap):
""" Prepare /apex directory before running checkvintf
Apex binaries do not support dirmaps, in order to use these binaries we
@ -212,93 +214,25 @@ def PrepareApexDirectory(inp):
expected device locations.
This simulates how apexd activates APEXes.
1. create {inp}/APEX which is treated as a "/" on device.
2. copy apexes from target-files to {root}/{partition}/apex.
3. mount apexes under {root}/{partition}/apex at {root}/apex.
4. generate info files with dump_apex_info.
We'll get the following layout
{inp}/APEX/apex # Activated APEXes + some info files
{inp}/APEX/system/apex # System APEXes
{inp}/APEX/vendor/apex # Vendor APEXes
...
Args:
inp: path to the directory that contains the extracted target files archive.
Returns:
directory representing /apex on device
1. create {inp}/APEX which is treated as a "/apex" on device.
2. invoke apexd_host with vendor APEXes.
"""
deapexer = 'deapexer'
debugfs_path = 'debugfs'
fsckerofs_path = 'fsck.erofs'
if OPTIONS.search_path:
debugfs_path = os.path.join(OPTIONS.search_path, 'bin', 'debugfs_static')
deapexer_path = os.path.join(OPTIONS.search_path, 'bin', 'deapexer')
fsckerofs_path = os.path.join(OPTIONS.search_path, 'bin', 'fsck.erofs')
if os.path.isfile(deapexer_path):
deapexer = deapexer_path
def ExtractApexes(path, outp):
# Extract all APEXes found in input path.
logger.info('Extracting APEXs in %s', path)
for f in os.listdir(path):
logger.info(' adding APEX %s', os.path.basename(f))
apex = os.path.join(path, f)
if os.path.isdir(apex) and os.path.isfile(os.path.join(apex, 'apex_manifest.pb')):
info = ParseApexManifest(os.path.join(apex, 'apex_manifest.pb'))
# Flattened APEXes may have symlinks for libs (linked to /system/lib)
# We need to blindly copy them all.
shutil.copytree(apex, os.path.join(outp, info.name), symlinks=True)
elif os.path.isfile(apex) and apex.endswith(('.apex', '.capex')):
cmd = [deapexer,
'--debugfs_path', debugfs_path,
'info',
apex]
info = json.loads(common.RunAndCheckOutput(cmd))
cmd = [deapexer,
'--debugfs_path', debugfs_path,
'--fsckerofs_path', fsckerofs_path,
'extract',
apex,
os.path.join(outp, info['name'])]
common.RunAndCheckOutput(cmd)
else:
logger.info(' .. skipping %s (is it APEX?)', path)
root_dir_name = 'APEX'
root_dir = os.path.join(inp, root_dir_name)
extracted_root = os.path.join(root_dir, 'apex')
apex_dir = os.path.join(inp, 'APEX')
# checkvintf needs /apex dirmap
dirmap['/apex'] = apex_dir
# Always create /apex directory for dirmap
os.makedirs(extracted_root)
os.makedirs(apex_dir)
create_info_file = False
# Invoke apexd_host to activate vendor APEXes for checkvintf
apex_host = os.path.join(OPTIONS.search_path, 'bin', 'apexd_host')
cmd = [apex_host, '--tool_path', OPTIONS.search_path]
cmd += ['--apex_path', dirmap['/apex']]
if '/vendor' in dirmap:
cmd += ['--vendor_path', dirmap['/vendor']]
common.RunAndCheckOutput(cmd)
# Loop through search path looking for and processing apex/ directories.
for device_path, target_files_rel_paths in DIR_SEARCH_PATHS.items():
# checkvintf only needs vendor apexes. skip other partitions for efficiency
if device_path not in ['/vendor', '/odm']:
continue
# First, copy VENDOR/apex/foo.apex to APEX/vendor/apex/foo.apex
# Then, extract the contents to APEX/apex/foo/
for target_files_rel_path in target_files_rel_paths:
inp_partition = os.path.join(inp, target_files_rel_path,"apex")
if os.path.exists(inp_partition):
apex_dir = root_dir + os.path.join(device_path + "/apex");
os.makedirs(root_dir + device_path)
shutil.copytree(inp_partition, apex_dir, symlinks=True)
ExtractApexes(apex_dir, extracted_root)
create_info_file = True
if create_info_file:
### Dump apex info files
dump_cmd = ['dump_apex_info', '--root_dir', root_dir]
common.RunAndCheckOutput(dump_cmd)
return extracted_root
def CheckVintfFromTargetFiles(inp, info_dict=None):
"""

View file

@ -50,6 +50,7 @@ python_binary_host {
"releasetools_ota_from_target_files",
],
required: [
"apexd_host",
"checkvintf",
"host_init_verifier",
"secilc",

View file

@ -118,39 +118,12 @@ def MergeDexopt(temp_dir, output_target_files_dir):
apex_extract_root_dir = os.path.join(temp_dir, 'apex')
os.makedirs(apex_extract_root_dir)
# The directory structure for updatable APEXes is:
#
# SYSTEM
# apex
# com.android.adbd.apex
# com.android.appsearch.apex
# com.android.art.apex
# ...
apex_root = os.path.join(output_target_files_dir, 'SYSTEM', 'apex')
for apex in (glob.glob(os.path.join(apex_root, '*.apex')) +
glob.glob(os.path.join(apex_root, '*.capex'))):
logging.info(' apex: %s', apex)
# deapexer is in the same directory as the merge_target_files binary extracted
# from otatools.zip.
apex_json_info = subprocess.check_output(['deapexer', 'info', apex])
logging.info(' info: %s', apex_json_info)
apex_info = json.loads(apex_json_info)
apex_name = apex_info['name']
logging.info(' name: %s', apex_name)
apex_extract_dir = os.path.join(apex_extract_root_dir, apex_name)
os.makedirs(apex_extract_dir)
# deapexer uses debugfs_static/fsck.erofs from otatools.zip.
command = [
'deapexer',
'--debugfs_path',
'debugfs_static',
'--fsckerofs_path',
'fsck.erofs',
'extract',
apex,
apex_extract_dir,
'apexd_host',
'--system_path',
os.path.join(temp_dir, 'system'),
'--apex_path',
apex_extract_root_dir,
]
logging.info(' running %s', command)
subprocess.check_call(command)