summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Shen <dzshen@google.com>2022-08-11 00:49:31 +0000
committerDennis Shen <dzshen@google.com>2022-09-23 14:13:12 +0000
commit2208d93bff8ba4787d08e165a787aa67e4ecd337 (patch)
tree19b9a0088f5ace7207a50df594f836a784f0e87a
parent8c9c3ced74a3d1b0ab969b6c4fd8d31cbfbb1111 (diff)
downloadapex-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.bp16
-rw-r--r--tools/apexer_with_DCLA_preprocessing.py119
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:])