diff options
author | Dennis Shen <dzshen@google.com> | 2022-08-11 00:49:31 +0000 |
---|---|---|
committer | Dennis Shen <dzshen@google.com> | 2022-09-23 14:13:12 +0000 |
commit | 2208d93bff8ba4787d08e165a787aa67e4ecd337 (patch) | |
tree | 19b9a0088f5ace7207a50df594f836a784f0e87a | |
parent | 8c9c3ced74a3d1b0ab969b6c4fd8d31cbfbb1111 (diff) | |
download | apex-2208d93bff8ba4787d08e165a787aa67e4ecd337.tar.gz |
cherrypick of aosp/2181619
Create an apexer wrapper for DCLA
apexer_with_DCLA_preprocessing is an apexer wrapper that will be called
by soong build system. It does some preprocessing work which involves
placing the native shared libs in desired location:
/lib(64)?/foo.so/<sha256 foo.so>/foo.so
and updated canned_fs_config before calling into apexer binary.
BUG: 241096765
Change-Id: Iaebedda111ca034d19c3d3031afc3041780448a9
Merged-In: Iaebedda111ca034d19c3d3031afc3041780448a9
-rw-r--r-- | tools/Android.bp | 16 | ||||
-rw-r--r-- | tools/apexer_with_DCLA_preprocessing.py | 119 |
2 files changed, 135 insertions, 0 deletions
diff --git a/tools/Android.bp b/tools/Android.bp index bdcc2893..3e1d0b49 100644 --- a/tools/Android.bp +++ b/tools/Android.bp @@ -134,3 +134,19 @@ sh_test_host { "libziparchive", ], } + +python_binary_host { + name: "apexer_with_DCLA_preprocessing", + srcs: [ + "apexer_with_DCLA_preprocessing.py", + ], + version: { + py2: { + enabled: false, + }, + py3: { + enabled: true, + embedded_launcher: true, + }, + }, +} diff --git a/tools/apexer_with_DCLA_preprocessing.py b/tools/apexer_with_DCLA_preprocessing.py new file mode 100644 index 00000000..707b0e51 --- /dev/null +++ b/tools/apexer_with_DCLA_preprocessing.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 + +"""This is a wrapper function of apexer. It provides opportunity to do +some artifact preprocessing before calling into apexer. Some of these +artifact preprocessing are difficult or impossible to do in soong or +bazel such as placing native shared libs in DCLA. It is better to do +these in a binary so that the DCLA preprocessing logic can be reused +regardless of the build system +""" + +import argparse +from glob import glob +import hashlib +import os +import shutil +import subprocess +import sys +import tempfile + +def ParseArgs(argv): + parser = argparse.ArgumentParser( + description='wrapper to run apexer for DCLA') + parser.add_argument( + '--apexer', + help='path to apexer binary') + parser.add_argument( + '--canned_fs_config', + help='path to canned_fs_config file') + parser.add_argument( + 'input_dir', + metavar='INPUT_DIR', + help='the directory having files to be packaged') + parser.add_argument( + 'output', + metavar='OUTPUT', + help='name of the APEX file') + parser.add_argument( + 'rest_args', + nargs='*', + help='remaining flags that will be passed as-is to apexer') + return parser.parse_args(argv) + +def RunCommand(cmd: list[str]) -> None: + """Construct a command line from parts and run it.""" + try: + res = subprocess.run( + cmd, + check=True, + stdout=subprocess.PIPE, + universal_newlines=True, + stderr=subprocess.PIPE) + except subprocess.CalledProcessError as err: + print(err.stderr) + raise err + +def GetDigest(file_path: str) -> str: + """Get sha512 digest of a file """ + digester = hashlib.sha512() + with open(file_path, 'rb') as f: + bytes_to_digest = f.read() + digester.update(bytes_to_digest) + return digester.hexdigest() + +def PlaceDCLANativeSharedLibs(image_dir: str, canned_fs_config: str) -> str: + """Place native shared libs for DCLA in a special way. + + Traditional apex has native shared libs placed under /lib(64)? inside + the apex. However, for DCLA, it needs to be placed in a special way: + + /lib(64)?/foo.so/<sha512 foo.so>/foo.so + + This function moves the shared libs to desired location and update + canned_fs_config file accordingly + """ + + # remove all .so entries from canned_fs_config + parent_dir = os.path.dirname(canned_fs_config) + updated_canned_fs_config = os.path.join(parent_dir, 'updated_canned_fs_config') + with open(canned_fs_config, 'r') as f: + lines = f.readlines() + with open(updated_canned_fs_config, 'w') as f: + for line in lines: + segs = line.split(' ') + if not segs[0].endswith('.so'): + f.write(line) + else: + with tempfile.TemporaryDirectory() as tmp_dir: + # move native libs + lib_file = os.path.join(image_dir, segs[0][1:]) + digest = GetDigest(lib_file) + lib_name = os.path.basename(lib_file) + dest_dir = os.path.join(lib_file, digest) + + shutil.move(lib_file, os.path.join(tmp_dir, lib_name)) + os.makedirs(dest_dir, exist_ok=True) + shutil.move(os.path.join(tmp_dir, lib_name), + os.path.join(dest_dir, lib_name)) + + # add canned_fs_config entries + f.write(f'{segs[0]} 0 2000 0755\n') + f.write(f'{os.path.join(segs[0], digest)} 0 2000 0755\n') + f.write(f'{os.path.join(segs[0], digest, lib_name)} 1000 1000 0644\n') + + # return the modified canned_fs_config + return updated_canned_fs_config + +def main(argv): + args = ParseArgs(argv) + args.canned_fs_config = PlaceDCLANativeSharedLibs( + args.input_dir, args.canned_fs_config) + + cmd = [args.apexer, '--canned_fs_config', args.canned_fs_config] + cmd.extend(args.rest_args) + cmd.extend([args.input_dir, args.output]) + + RunCommand(cmd) + +if __name__ == "__main__": + main(sys.argv[1:]) |